ImageDataGenerator flow_from_dataframe multi_output регрессия и проблема с синтаксисом классификации

Контекст

Я использую генератор изображений tensorflow.keras.preprocessing.image ImageDataGenerator.

from tensorflow.keras.preprocessing.image import ImageDataGenerator

Я изо всех сил пытался найти пример пользовательского генератора multi_output, который передает вектор с плавающей запятой (например, 4 вектора, представляющий ограничивающую рамку) в качестве метки для одной из двух сетевых головок и вектор с горячим кодированием (например, 3 класса ) в качестве метки к другой головке.

Первая головка сети выполнит регрессию на ограничивающей рамке из 4 векторов.

Первая глава

а вторая головка сети выполнит классификацию по одному горячему 3-вектору.

Вторая глава

У меня есть структура, очень похожая на найденную здесь.

Единственная разница в том, что я не хочу загружать все изображения в память сразу, отсюда мое желание использовать генератор.

Я думаю, что мой код близок, но множество примеров, которые я нашел, не совсем то, что мне нужно.

Это то, что у меня было сначала (см. Дополнительные сведения ниже о том, что у меня есть сейчас):

def generate_image_generator(generator, data_directory, data_items, target_size, classes, batch_size, shuffle, class_mode):
frames=[]
for di in data_items:
    df = pd.read_csv(data_directory+di["file"])
    #df["cls"] = df["cls"].apply(lambda x: x.split(","))
    frames.append(df)
df = pd.concat(frames)
a = pd.get_dummies(df['cls'], prefix='cls')
df = pd.concat([df, pd.get_dummies(df['cls'], prefix='cls')], axis=1)
df.head()
#                                              y_col=(['sxu', 'syu', 'exu', 'eyu'], 'cls'),
genImages = generator.flow_from_dataframe(dataframe=df, directory=data_directory, target_size=target_size,
                                          x_col="file",
                                          y_col=[('sxu', 'syu', 'exu', 'eyu'), ('cls_airplane', 'cls_face', 'cls_motorcycle')],
                                          class_mode="multi_output",
                                          classes=classes, batch_size=batch_size, shuffle=shuffle, seed=2)

Обратите особое внимание на следующие две строки:

 y_col=[('sxu', 'syu', 'exu', 'eyu'), ('cls_airplane', 'cls_face', 'cls_motorcycle')],
 class_mode="multi_output",

В первой строке должен быть указан список с двумя элементами метки (по одному для каждой из двух головок в моей модели, головка 4-векторной регрессии и головка классификации 3 векторов)

Образец из CSV-файла, загруженного в кадр данных pandas, показан ниже.

    id,file,sx,sy,ex,ey,cls,sxu,syu,exu,eyu,w,h
0,motorcycle.0001.jpg,31,19,233,141,motorcycle,0.1183206106870229,0.11801242236024845,0.8893129770992366,0.8757763975155279,262,161
1,motorcycle.0002.jpg,32,15,232,142,motorcycle,0.12167300380228137,0.09259259259259259,0.8821292775665399,0.8765432098765432,263,162

Обратите внимание, что в приведенном выше коде я добавляю дополнительные горячие столбцы (cls_motorcycle, cls_face, cls_airplane) в кадр данных pandas. Это столбцы, на которые ссылается второй кортеж в моем массиве y_col.

Дополненный кадр данных pandas, который включает в себя мои горячие столбцы

Ошибка

Я использую реализацию keras tensorflow. Ошибка, которую я получаю, является ключевой ошибкой в ​​кадре данных pandas.

Полная трассировка стека

Ясно, что keras tensorflow не нравится список кортежей, которые я передаю для меток multi_output. Он считает, что первый кортеж в списке на самом деле является одним ключом в один столбец, а не четырьмя ключами в четыре столбца.

Вопрос

Как настроить flow_from_dataframe с multi_output метка регрессии для одной головы и метка классификации для второй головы?

Дополнительная информация

Теперь я попытался сделать следующее (обратите внимание, что теперь я получаю 2-кортеж для метки - это последнее состояние моих усилий), и я думаю, что продвинулся дальше. Однако я пока не думаю, что это правильно (трассировка стека ниже фрагмент кода):

def generate_image_generator(generator, data_directory, data_items, target_size, classes, batch_size, shuffle, class_mode):
frames=[]
for di in data_items:
    df = pd.read_csv(data_directory+di["file"])
    frames.append(df)
df = pd.concat(frames)

labels = ['sxu', 'syu', 'exu', 'eyu', 'cls_onehot']
df['cls_onehot'] = df['cls'].str.get_dummies().values.tolist()

genImages = generator.flow_from_dataframe(dataframe=df, directory=data_directory, target_size=target_size,
                                          x_col="file",
                                          y_col=labels,
                                          class_mode="multi_output",
                                          classes=classes, batch_size=batch_size, shuffle=shuffle, seed=2)

while True:
    images, labels = genImages.next()
    yield images[0], ([labels[0], labels[1], labels[2], labels[3]], labels[4])

Я иду дальше, так что, возможно, мой генератор сейчас в порядке, но теперь я вижу следующую трассировку (когда я начинаю тренировать модель):

Новая трассировка стека во время первой эпохи обучения

В следующем представлении отладки pycharm вы можете видеть изображения и метки в том виде, в каком они существуют в той точке, которую дает генератор. Обратите внимание, мой размер партии составляет 5.

Пакет изображений и ярлыков, полученных генератором


person David Sargrad    schedule 01.03.2021    source источник


Ответы (1)


Кажется, это правильный ответ:

def generate_image_generator(generator, data_directory, data_items, target_size, classes, batch_size, shuffle, class_mode):
frames=[]
for di in data_items:
    df = pd.read_csv(data_directory+di["file"])
    frames.append(df)
df = pd.concat(frames)

df['cls_onehot'] = df['cls'].str.get_dummies().values.tolist()
df['bbox'] = df[['sxu', 'syu', 'exu', 'eyu']].values.tolist()

genImages = generator.flow_from_dataframe(dataframe=df, directory=data_directory, target_size=target_size,
                                          x_col="file",
                                          y_col=['bbox', 'cls_onehot'],
                                          class_mode="multi_output",
                                          classes=classes, batch_size=batch_size, shuffle=shuffle, seed=2)

while True:
    images, labels = genImages.next()
    targets = {
        'class_label': labels[1],
        'bounding_box': labels[0]
    }
    yield images, targets
person David Sargrad    schedule 01.03.2021
comment
:( У меня все еще есть проблемы с этим. Кажется, что обучение никогда не хочет заканчиваться. Любая помощь с этим пользовательским генератором будет оценена по достоинству. - person David Sargrad; 02.03.2021
comment
Ok. Похоже, это действительно правильный ответ. Моя единственная оставшаяся проблема заключалась в том, что я забыл установить шаги на эпоху, когда я вызывал подгонку; следовательно, тензорный поток будет соответствовать навсегда - person David Sargrad; 02.03.2021