Я очень плохо знаком с машинным обучением и начал внедрять сиамскую сеть, чтобы проверять уровень сходства рукописных цифр, тренируюсь с набором данных MNIST, но у меня серьезные проблемы с потерями.
Сетевая модель
import keras
from keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, Lambda
from keras.models import Sequential, Model
from keras.optimizers import Adam
import keras.backend as K
import cv2
from keras.datasets import mnist
import numpy as np
import random
def siameseNet(input_shape):
input1 = Input(input_shape)
input2 = Input(input_shape)
model = Sequential()
model.add(Conv2D(50, (5,5), activation='relu', input_shape=input_shape))
model.add(MaxPooling2D())
model.add(Conv2D(100, (3,3), activation='relu'))
model.add(MaxPooling2D())
model.add(Conv2D(100, (3,3), activation='relu'))
model.add(Flatten())
model.add(Dense(2048, activation='sigmoid'))
input_model_1 = model(input1)
input_model_2 = model(input2)
distance_func = Lambda(lambda t: K.abs(t[0]-t[1]))
distance_layer = distance_func([input_model_1, input_model_2])
prediction = Dense(1,activation='sigmoid')(distance_layer)
network = Model(inputs=[input1,input2],outputs=prediction)
return network
Обучающие данные
Мой pairs
объект представляет собой массив numpy
с двумя массивами, содержащими изображения с одинаковым индексом, первая половина массива является изображением той же категории,вторая половина другой категории.
category
объект представляет собой простой массив, содержащий такое же количество выборок из обучающего набора, первая половина которого равна 0
, чтобы указать значение Y для того же изображения, ивторая половина установлена на 1
.
И pairs
, и category
заполняются следующей функцией:
INPUT_SHAPE = (28,28,1)
def loadData():
(X_train, Y_train), _ = mnist.load_data()
n_samples = 20000
arrPairs = [np.zeros((n_samples, INPUT_SHAPE[0], INPUT_SHAPE[1],INPUT_SHAPE[2])) for i in range(2)]
category = np.zeros((n_samples))
category[n_samples//2:] = 1
for i in range(n_samples):
if i%1000==0:
print(i)
cur_category = Y_train[i]
img = random.choice(X_train[Y_train==cur_category]).reshape(28,28,1)
_, img = cv2.threshold(img, .8, 1, cv2.THRESH_BINARY)
arrPairs[0][i] = img.reshape(28,28,1)
if category[i] == 1:
img = random.choice(X_train[Y_train!=cur_category])
else:
img = random.choice(X_train[Y_train==cur_category])
_, img = cv2.threshold(img, .8, 1, cv2.THRESH_BINARY)
arrPairs[1][i] = img.reshape(28,28,1)
arrPairs[0] = arrPairs[0]/255
return arrPairs, category
Результаты обучения
pairs, category = loadData()
model = siameseNet(INPUT_SHAPE)
model.compile(optimizer=Adam(lr=0.0005),loss="binary_crossentropy")
model.fit(pairs, category, epochs=5, verbose=1, validation_split=0.2)
Train on 16000 samples, validate on 4000 samples
Epoch 1/5
16000/16000 [==============================] - 6s 353us/step - loss: 0.6660 - val_loss: 0.9474
Epoch 2/5
16000/16000 [==============================] - 5s 287us/step - loss: 0.6628 - val_loss: 0.9335
Epoch 3/5
16000/16000 [==============================] - 5s 287us/step - loss: 0.6627 - val_loss: 0.8487
Epoch 4/5
16000/16000 [==============================] - 5s 287us/step - loss: 0.6625 - val_loss: 0.9954
Epoch 5/5
16000/16000 [==============================] - 5s 288us/step - loss: 0.6616 - val_loss: 0.9133
Но что бы я ни пытался, потери не уменьшатся, поэтому я буду неправильно прогнозировать.
Я пытался изменить активации, увеличивая и уменьшая сложность сети (добавляя иудаление слоев, а также увеличение и уменьшение параметров Conv2D
), но ничего из этого не сработало, поэтому я предполагаю, что это архитектурная проблема, которую мне не хватает
Обновление: Линии, использованные для тестирования:
test_pairs = [np.zeros((2, INPUT_SHAPE[0], INPUT_SHAPE[1],INPUT_SHAPE[2])) for i in range(2)]
test_pairs[0][0] = cv2.cvtColor(cv2.imread('test1_samenumber.png'), cv2.COLOR_BGR2GRAY).reshape(28,28,1);
test_pairs[1][0] = cv2.cvtColor(cv2.imread('test2_samenumber.png'), cv2.COLOR_BGR2GRAY).reshape(28,28,1);
pred = model.predict(test_pairs)
print(pred)
Какие из них:
[[0.32230237]
[0.44603676]]