Использование нескольких выходных меток в keras ImageDataGenerator.flow () и использование model.fit_generator () - PullRequest
1 голос
/ 05 января 2020

У меня есть модель нейронной сети с одним входом и несколькими выходами, последние уровни которой

out1 = Dense(168, activation = 'softmax')(dense)
out2 = Dense(11, activation = 'softmax')(dense)
out3 = Dense(7, activation = 'softmax')(dense)

model = Model(inputs=inputs, outputs=[out1,out2,out3])

Y-метки для каждого изображения:

train
>>

              image_id    class_1   class_2  class_3    

0              Train_0         15         9        5    
1              Train_1        159         0        0
...
...
...
453651    Train_453651          0        15       34
453652    Train_453652         18         0        7

РЕДАКТИРОВАТЬ: -

train.iloc[:,1:4].nunique()
>>
class_1        168
class_2         11
class_3          7
dtype: int64

Итак, глядя на эти разные классы, я должен использовать categorical_crossentropy или sparse_categorical_crossentropy? и как мне использовать Y_labels в потоке для приведенного ниже кода?

imgs_arr = df.iloc[:,1:].values.reshape(df.shape[0],137,236,1)
# 32332 columns representing pixels of 137*236 and single channel images.
# converting it to (samples,w,h,c) format

Y = train.iloc[:,1:].values #need help from here

image_data_gen = ImageDataGenerator(validation_split=0.25)
train_gen = image_data_gen.flow(x=imgs_arr, y=Y, batch_size=32,subset='training')
valid_gen = image_data_gen.flow(x=imgs_arr,y=Y,subset='validation')

это правильный путь для передачи Y или использовать Y=[y1,y2,y3] где

y1=train.iloc[:,1].values
y2=train.iloc[:,2].values
y3=train.iloc[:,3].values

Ответы [ 2 ]

2 голосов
/ 06 января 2020

Ой ....

По сообщению, указанному в вашем flow, вам понадобится один выход. Так что вам нужно сделать разделение внутри вашей модели. (Keras не смог следовать своим собственным стандартам)

Это означает что-то вроде:

Y = train.iloc[:,1:].values #shape = (50210, 3)

С одним выходом вроде:

out = Dense(168+11+7, activation='linear')(dense)

И функцией потерь, которая обрабатывает разделение:

def custom_loss(y_true, y_pred):
    true1 = y_true[:,0:1]
    true2 = y_true[:,1:2]
    true3 = y_true[:,2:3]

    out1 = y_pred[:,0:168]
    out2 = y_pred[:,168:168+11]
    out3 = y_pred[:,168+11:]

    out1 = K.softmax(out1, axis=-1)
    out2 = K.softmax(out2, axis=-1)
    out3 = K.softmax(out3, axis=-1)

    loss1 = K.sparse_categorical_crossentropy(true1, out1, from_logits=False, axis=-1)
    loss2 = K.sparse_categorical_crossentropy(true2, out2, from_logits=False, axis=-1)
    loss3 = K.sparse_categorical_crossentropy(true3, out3, from_logits=False, axis=-1)

    return loss1+loss2+loss3

Скомпилируйте модель с помощью loss=custom_loss.

Тогда flow должен перестать жаловаться, когда вы делаете flow.

Просто убедитесь, что X и Y точно в одном и том же порядке: imgs_arr[i] соответствует Y[i] правильно.

0 голосов
/ 26 января 2020

Другой обходной путь:

  1. Создайте массив кортежей и передайте его методу потока ImageDataGenerator.
  2. Создайте метод итератора, который принимает итератор, созданный на предыдущем шаге , Этот итератор преобразует обратно массив кортежей в список массивов.

Вот методы для реализации описанных выше шагов:

def make_array_of_tuple(tuple_of_arrays):
    array_0 = tuple_of_arrays[0]
    array_of_tuple = np.empty(array_0.shape[0], dtype=np.object)
    for i, tuple_of_array_elements in enumerate(zip(*tuple_of_arrays)):
        array_of_tuple[i] = tuple_of_array_elements
    return array_of_tuple

def convert_to_list_of_arrays(array_of_tuple):
    array_length = array_of_tuple.shape[0]
    tuple_length = len(array_of_tuple[0])
    array_list = [
        np.empty(array_length, dtype=np.uint8) for i in range(tuple_length) ]
    for i, array_element_tuple in enumerate(array_of_tuple):
        for array, tuple_element in zip(array_list, array_element_tuple):
            array[i] = tuple_element
    return array_list

def tuple_of_arrays_flow(original_flow):
    while True:
        (X, array_of_tuple) = next(original_flow)
        list_of_arrays = convert_to_list_of_arrays(array_of_tuple)
        yield X, list_of_arrays

Чтобы вызвать метод ImageDataGenerator flow () и получить поток, используемый для модели:

y_train = make_array_of_tuple((y_train_1, y_train_2, y_train_3))
orig_image_flow = train_image_generator.flow(X_train, y=y_train)
train_image_flow = tuple_of_arrays_flow(orig_image_flow)

Размер y_train такой же, как у X_train, поэтому его следует принять. 'train_image_flow' возвращает список массивов, которые должны быть приняты мульти-выходной моделью Keras.

ДОБАВЛЕНО (2019/01/26)

Еще одна идея, проще чем выше:

  1. Передать массив индексов, который содержит 0, 1, 2, ..., в ImageDataGenerator.flow ().
  2. В итераторе выберите элементы в массивах для множественного вывода с использованием возвращенного массива индексов из исходного потока.

Вот реализация:

def make_multi_output_flow(image_gen, X, y_list, batch_size):
    y_item_0 = y_list[0]
    y_indices = np.arange(y_item_0.shape[0])
    orig_flow = image_gen.flow(X, y=y_indices, batch_size=batch_size)

    while True:
        (X, y_next_i) = next(orig_flow)
        y_next = [ y_item[y_next_i] for y_item in y_list ]
        yield X, y_next

Это пример вызова метода выше.

y_train = [y_train_1, y_train_2, y_train_3]
multi_output_flow = make_multi_output_flow(
    image_data_generator, X_train, y_train, batch_size)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...