У меня возникла проблема с Keras, когда функция оценки дает другое значение потери при обучении (намного выше) и значение точности (намного ниже) по сравнению со значением, которое я получаю во время обучения. Я знаю, что этот вопрос уже задавался в нескольких местах ( здесь , здесь ), но я думаю, что моя проблема другая и до сих пор не ответил на этих форумах.
Объяснение задачи
Это должно быть очень простым заданием. Все, что я делаю, это переписываю свой собственный набор данных из 256 изображений (29x29x3) с 256 выходными классами (по одному на каждое изображение).
Dataset
Дело 1
x_train = Все значения пикселей на изображении = i, где я переходит от 0 до 255.
y_train = i
Дело 2
x_train = Центр 5 * 5 патча значений пикселей на изображении = i, где i изменяется от 0 до 255. Все остальные значения пикселей одинаковы для всех изображений.
y_train = i
Это дает мне 256 изображений для тренировочных данных в каждом случае. (Было бы более понятно, если вы просто посмотрите на код)
Вот мой код для воспроизведения проблемы -
from __future__ import print_function
import os
import keras
from keras.datasets import mnist
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D, Activation
from keras.layers.normalization import BatchNormalization
from keras.callbacks import ModelCheckpoint, LearningRateScheduler, Callback
from keras import backend as K
from keras.regularizers import l2
import matplotlib.pyplot as plt
import PIL.Image
import numpy as np
from IPython.display import clear_output
# The GPU id to use, usually either "0" or "1"
os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"]="1"
# To suppress the warnings
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
## Hyperparamters
batch_size = 256
num_classes = 256
l2_reg=0.0
epochs = 500
## input image dimensions
img_rows, img_cols = 29, 29
## Train Image (I took a random image from ImageNet)
train_img_name = 'n01871265_279.JPEG'
ret = PIL.Image.open(train_img_name) #Opening the image
ret = ret.resize((img_rows, img_cols)) #Resizing the image
img = np.asarray(ret, dtype=np.uint8).astype(np.float32) #Converting it to numpy array
print(img.shape) # (29, 29, 3)
## Creating the training data
#############################
x_train = np.zeros((256, img_rows, img_cols, 3))
y_train = np.zeros((256,), dtype=int)
for i in range(len(y_train)):
temp_img = np.copy(img)
## Case1 of dataset
# temp_img[:, :, :] = i # changing all the pixel values
## Case2 of dataset
temp_img[12:16, 12:16, :] = i # changing the centre block of 5*5 pixels
x_train[i, :, :, :] = temp_img
y_train[i] = i
##############################
## Common stuff in Keras
if K.image_data_format() == 'channels_first':
print('Channels First')
x_train = x_train.reshape(x_train.shape[0], 3, img_rows, img_cols)
input_shape = (3, img_rows, img_cols)
else:
print('Channels Last')
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 3)
input_shape = (img_rows, img_cols, 3)
## Normalizing the pixel values
x_train = x_train.astype('float32')
x_train /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
## convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
## Model definition
def model_toy(mom):
model = Sequential()
model.add( Conv2D(filters=64, kernel_size=(7, 7), strides=(1,1), input_shape=input_shape, kernel_regularizer=l2(l2_reg)) )
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
#Default parameters kept same as PyTorch
#Meaning of PyTorch momentum is different from Keras momentum.
# PyTorch mom = 0.1 is same as Keras mom = 0.9
model.add( Conv2D(filters=128, kernel_size=(7, 7), strides=(1, 1), kernel_regularizer=l2(l2_reg)))
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
model.add(Conv2D(filters=256, kernel_size=(5, 5), strides=(1, 1), kernel_regularizer=l2(l2_reg)))
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
model.add(Conv2D(filters=512, kernel_size=(5, 5), strides=(1, 1), kernel_regularizer=l2(l2_reg)))
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
model.add(Conv2D(filters=1024, kernel_size=(5, 5), strides=(1, 1), kernel_regularizer=l2(l2_reg)))
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
model.add( Conv2D( filters=2048, kernel_size=(3, 3), strides=(1, 1), kernel_regularizer=l2(l2_reg) ) )
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
model.add(Conv2D(filters=4096, kernel_size=(3, 3), strides=(1, 1), kernel_regularizer=l2(l2_reg)))
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
# Passing it to a dense layer
model.add(Flatten())
model.add(Dense(1024, kernel_regularizer=l2(l2_reg)))
model.add(Activation('relu'))
model.add(BatchNormalization(momentum=mom, epsilon=0.00001))
# Output Layer
model.add(Dense(num_classes, kernel_regularizer=l2(l2_reg)))
model.add(Activation('softmax'))
return model
mom = 0.9 #0
model = model_toy(mom)
model.summary()
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adam(lr=0.001),
#optimizer=keras.optimizers.SGD(lr=0.01, momentum=0.9, decay=0.0, nesterov=True),
metrics=['accuracy'])
history = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
shuffle=True,
)
print('Training results')
print('-------------------------------------------')
score = model.evaluate(x_train, y_train, verbose=1)
print('Training loss:', score[0])
print('Training accuracy:', score[1])
print('-------------------------------------------')
Небольшая заметка - Мне удалось успешно выполнить эту задачу в PyTorch. Просто моя настоящая задача требует, чтобы у меня была модель Keras. Вот почему я изменил значения по умолчанию для слоя BatchNorm (основная причина проблемы) в соответствии со значениями, которые я использовал для обучения модели PyTorch.
Вот изображение, которое я использовал в своем коде.
Вот результаты тренировок.
Case1 набора данных
Case2 набора данных
Если вы посмотрите на эти два файла, вы сможете заметить расхождения в потере обучения во время обучения и умозаключения.
(я установил размер своей партии равным размеру моих тренировочных данных, чтобы избежать некоторых причин, по которым BatchNorm обычно создает проблемы, как упоминалось здесь )
Затем я посмотрел исходный код Keras, чтобы узнать, можно ли каким-либо образом заставить слой BatchNorm использовать статистику пакета вместо скользящего среднего и дисперсии.
Здесь - формула обновления, которую Keras (backend - TF) использует для обновления среднего значения и дисперсии.
#running_stat -= (1 - momentum) * (running_stat - batch_stat)
Так что, если я установлю значение импульса равным 0, это будет означать, что значение, присвоенное runing_stat, всегда будет равно batch_stat на этапе обучения. Таким образом, значение, которое он будет использовать в режиме вывода, также будет таким же (близким), что и статистика пакета / набора данных.
Вот результаты этого небольшого эксперимента с той же проблемой, которая все еще возникает.
Case1 набора данных
Case2 набора данных
Среда программирования - Python-3.5.2, tenorflow-1.10.0, keras-2.2.4
Я пробовал то же самое с tenorflow-1.12.0, keras-2.2.2, но это все равно не решило проблему.