Модель Кераса для сиамской сети не учится и всегда прогнозирует один и тот же результат

Я пытаюсь обучить сиамскую нейронную сеть с помощью Keras, чтобы определить, принадлежат ли 2 изображения к одному классу или нет. Мои данные перемешаны и имеют равное количество положительных и отрицательных примеров. Моя модель ничего не изучает и всегда предсказывает один и тот же результат. Каждый раз я получаю одни и те же потери, точность проверки и потерю проверки.

Результат обучения

def convert(row):
    return imread(row)

def contrastive_loss(y_true, y_pred):
    margin = 1
    square_pred = K.square(y_pred)
    margin_square = K.square(K.maximum(margin - y_pred, 0))
    return K.mean(y_true * square_pred + (1 - y_true) * margin_square)

def SiameseNetwork(input_shape):
    top_input = Input(input_shape)

    bottom_input = Input(input_shape)

    # Network
    model = Sequential()
    model.add(Conv2D(96,(7,7),activation='relu',input_shape=input_shape))
    model.add(MaxPooling2D())
    model.add(Conv2D(256,(5,5),activation='relu',input_shape=input_shape))
    model.add(MaxPooling2D())
    model.add(Conv2D(256,(5,5),activation='relu',input_shape=input_shape))
    model.add(MaxPooling2D())
    model.add(Flatten())
    model.add(Dense(4096,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1024,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(512,activation='relu'))
    model.add(Dropout(0.5))

    encoded_top = model(top_input)
    encoded_bottom = model(bottom_input)

    L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))    
    L1_distance = L1_layer([encoded_top, encoded_bottom])

    prediction = Dense(1,activation='sigmoid')(L1_distance)
    siamesenet = Model(inputs=[top_input,bottom_input],outputs=prediction)
    return siamesenet

data = pd.read_csv('shuffleddata.csv')
print('Converting X1....')

X1 = [convert(x) for x in data['X1']]

print('Converting X2....')

X2 = [convert(x) for x in data['X2']]

print('Converting Y.....')
Y = [0 if data['Y'][i] == 'Negative' else 1 for i in range(len(data['Y']))]

input_shape = (53,121,3,)
model = SiameseNetwork(input_shape)
model.compile(loss=contrastive_loss,optimizer='sgd',metrics=['accuracy'])
print(model.summary())
model.fit(X1,Y,batch_size=32,epochs=20,shuffle=True,validation_split = 0.2)
model.save('Siamese.h5')

3 ответа

Решение

Упоминание решения этой проблемы в этом разделе (даже если оно присутствует в разделе комментариев) для пользы сообщества.

Поскольку Модель отлично работает с другими стандартными наборами данных, решение состоит в том, чтобы использовать больше данных. Модель не обучается, потому что в ней меньше данных для обучения.

Модель отлично работает с большим количеством данных, как указано в комментариях и в ответе службы поддержки Tensorflow. Также работает небольшая настройка модели. Изменение количества фильтров во 2-м и 3-м сверточных слоях с 256 до 64 уменьшает количество обучаемых параметров на большое количество, и поэтому модель начала обучение.

Я хочу упомянуть здесь несколько вещей, которые могут быть полезны другим:

1) Стратификация данных / случайная выборка

При использовании Keras использует последние x процентов данных в качестве данных проверки. Это означает, что если данные упорядочены по классам, например, потому что «пары» или «тройки» составлены в последовательности, данные проверки будут поступать только из классов (или класса), содержащихся в последних x процентах данных. В этом случае набор проверки будет бесполезен. Таким образом, важно дополнить входные данные, чтобы убедиться, что набор проверки содержит случайные выборки из каждого класса.

Документы для сказать:

Плавающее значение между 0 и 1. Часть обучающих данных, которая будет использоваться в качестве данных проверки. Модель выделит эту часть обучающих данных, не будет обучаться на ней и будет оценивать потери и любые метрики модели на этих данных в конце каждой эпохи. Данные проверки выбираются из последних выборок в предоставленных данных x и y перед перемешиванием

2) Выбор оптимизатора

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

[...] сочетает в себе преимущества [...] AdaGrad для работы с разреженными градиентами и способность RMSProp справляться с нестационарными задачами.

согласно Kingma и Ba (2014, стр. 10).

      from keras.optimizers import Adam
...
model.compile(loss=contrastive_loss, optimizer=keras.optimizers.Adam(lr=0.0001))

3) Ранняя остановка / скорость обучения

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

      from keras.callbacks import EarlyStopping
from keras.callbacks import ReduceLROnPlateau
...
early_stopping = EarlyStopping(monitor='val_loss', patience=50, mode='auto', restore_best_weights=True)
reduce_on_plateau = ReduceLROnPlateau(monitor="val_loss", factor=0.8, patience=15, cooldown=5, verbose=0)
...
hist = model.fit([img_1, img_2], y, 
            validation_split=.2, 
            batch_size=128, 
            verbose=1, 
            epochs=9999,
            callbacks=[early_stopping])

4) Инициализация ядра

Также может быть полезна инициализация ядра (с небольшой SD).

      # Layer 1
    seq.add(Conv2D(8, (5,5), input_shape=input_shape, 
        kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.01, seed=None), 
        data_format="channels_first"))
    seq.add(Activation('relu'))
    seq.add(MaxPooling2D(pool_size=(2, 2))) 
    seq.add(Dropout(0.1))

5) Переоснащение

Я заметил, что вместо того, чтобы использовать отсев для борьбы с переобучением, довольно полезно добавить немного шума. В этом случае просто добавьте GaussianNoise в начало сети.

Другие вопросы по тегам