Keras fit_generator не предсказывает так же, как fit - PullRequest
1 голос
/ 28 сентября 2019

Я пытаюсь обучить модель в Керасе сегментации изображений (U-Net) и начал с создания двух списков, содержащих мои поезда (и проверочные) изображения и маски.Затем я обучил модель, как показано ниже.

x_train_val = # list of images (nr_images, 256, 256, 3)
y_train_val = # list of masks (nr_images, 256, 256, 1)

# Define model
def standard_unet():
    inputs = Input((img_size, img_size, 3))

    s = Lambda(lambda x: x / 255) (inputs)

    c1 = Conv2D(8, (3, 3), activation='relu', padding='same') (inputs)
    c1 = Conv2D(8, (3, 3), activation='relu', padding='same') (c1)
    p1 = MaxPooling2D((2, 2)) (c1)

    c2 = Conv2D(16, (3, 3), activation='relu', padding='same') (p1)
    c2 = Conv2D(16, (3, 3), activation='relu', padding='same') (c2)
    p2 = MaxPooling2D((2, 2)) (c2)

    c3 = Conv2D(32, (3, 3), activation='relu', padding='same') (p2)
    c3 = Conv2D(32, (3, 3), activation='relu', padding='same') (c3)
    p3 = MaxPooling2D((2, 2)) (c3)

    c4 = Conv2D(64, (3, 3), activation='relu', padding='same') (p3)
    c4 = Conv2D(64, (3, 3), activation='relu', padding='same') (c4)
    p4 = MaxPooling2D(pool_size=(2, 2)) (c4)

    c5 = Conv2D(128, (3, 3), activation='relu', padding='same') (p4)
    c5 = Conv2D(128, (3, 3), activation='relu', padding='same') (c5)

    u6 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same') (c5)
    u6 = concatenate([u6, c4])
    c6 = Conv2D(64, (3, 3), activation='relu', padding='same') (u6)
    c6 = Conv2D(64, (3, 3), activation='relu', padding='same') (c6)

    u7 = Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same') (c6)
    u7 = concatenate([u7, c3])
    c7 = Conv2D(32, (3, 3), activation='relu', padding='same') (u7)
    c7 = Conv2D(32, (3, 3), activation='relu', padding='same') (c7)

    u8 = Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same') (c7)
    u8 = concatenate([u8, c2])
    c8 = Conv2D(16, (3, 3), activation='relu', padding='same') (u8)
    c8 = Conv2D(16, (3, 3), activation='relu', padding='same') (c8)

    u9 = Conv2DTranspose(8, (2, 2), strides=(2, 2), padding='same') (c8)
    u9 = concatenate([u9, c1], axis=3)
    c9 = Conv2D(8, (3, 3), activation='relu', padding='same') (u9)
    c9 = Conv2D(8, (3, 3), activation='relu', padding='same') (c9)

    outputs = Conv2D(1, (1, 1), activation='sigmoid') (c9)

    model = Model(inputs=[inputs], outputs=[outputs])

    return model

# IoU metric
def mean_iou(y_true, y_pred):
    prec = []
    for t in np.arange(0.5, 1.0, 0.05):
        y_pred_ = tf.to_int32(y_pred > t)
        score, up_opt = tf.metrics.mean_iou(y_true, y_pred_, 2)
        K.get_session().run(tf.local_variables_initializer())
        with tf.control_dependencies([up_opt]):
            score = tf.identity(score)
        prec.append(score)
    return K.mean(K.stack(prec), axis=0)

# Dice coef loss
def dice_coef(y_true, y_pred):
    smooth = 1.
    y_true_f = K.flatten(y_true)
    y_pred_f = K.flatten(y_pred)
    intersection = K.sum(y_true_f * y_pred_f)
    return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)

def bce_dice_loss(y_true, y_pred):
    return 0.5 * binary_crossentropy(y_true, y_pred) - dice_coef(y_true, y_pred)

# Model compiling
K.clear_session()
model = standard_unet()
model.compile(optimizer='adam', loss=bce_dice_loss, metrics=[mean_iou])

# Fitting
model.fit(x_train_val, y_train_val, validation_split=0.1, epochs=20)

Это работает точно так, как задумано, и я получаю приличные результаты, когда пытаюсь прогнозировать на тестовых изображениях.Поскольку я хочу увеличить количество тренировочных образов, я попытался использовать ImageDataGenerator и train_generator, используя следующую функцию.

# Runtime data augmentation
def get_train_test_augmented(x_data=x_train_val, y_data=y_train_val, validation_split=0.1, batch_size=32):
    x_train, x_valid, y_train, y_valid = train_test_split(x_data, y_data,
                                                          train_size=1-validation_split,
                                                          test_size=validation_split)

    data_gen_args = dict(rotation_range=45.,
                         width_shift_range=0.1,
                         height_shift_range=0.1,
                         horizontal_flip=True,
                         vertical_flip=True,
                         fill_mode='reflect')  #use 'constant'??

    x_datagen = ImageDataGenerator(**data_gen_args)
    y_datagen = ImageDataGenerator(**data_gen_args)
    x_datagen.fit(x_train, augment=True)
    y_datagen.fit(y_train, augment=True)
    x_train_augmented = x_datagen.flow(x_train, batch_size=batch_size, shuffle=True)
    y_train_augmented = y_datagen.flow(y_train, batch_size=batch_size, shuffle=True)

    # combine generators into one which yields image and masks
    train_generator = zip(x_train_augmented, y_train_augmented)

    return train_generator

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

train_generator = get_train_test_augmented()
model.fit_generator(train_generator, epochs=20)

Кто-нибудь сталкивался с такой же проблемой с прогнозированием пустых изображений или знает, как ее решить?Спасибо, BBQuercus.

1 Ответ

1 голос
/ 29 сентября 2019

Вы делаете генерацию изображения отдельно с генераторами изображения и маски, что произойдет, если случайное преобразование не будет одинаковым для входного изображения и метки (маски).Более того, вы перетасовываете оба генератора, поэтому они даже не соответствуют друг другу (изображение и маска в генераторе подгонки).

В этом комментарии к выпуску github также говорится ои предложите создать дополнительный генератор, чтобы объединить оба.

Попробуйте заполнить оба генератора одним и тем же семенем и посмотрите, изменит ли он что-нибудь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...