Comments 11
Думаю, что этот эффект связан с тем, что сеть затачивается под одну (или несколько цифр) последних цифр, если подавать ей примеры все скопом: сначала все "1", затем все "2" и т.д. Связано это с тем, что у нейронов нет памяти и проблемой затухающего градиента. Если хочется, чтобы сеть корректно работала на всех последовательностях, то, вероятно, нужно смотреть в сторону LSTM. Вопрос только зачем. Разве что как исследование.
Не думаю, что LSTM тут поможет: проблема не сколько в архитектуре сети, сколько в принципе обучения. Условно, сначала нейроны скатываются по максимальному градиенту для одной цифры, а потом для другой. При этом, если цифры идут блоками (сначала 1, потом 2 итд), то пересечения множеств нейронов, используемых для распознавания каждой цифры будут значительно больше, чем при случайном порядке.
В таком случае, LSTM должен чутка вытаскивать. Сложно сказать, насколько сильно он вытащит. Но, вероятно, профит будет. Т.е. нейроны будут скатываться по градиенту для одной цифры. Но потом они будут куда меньше скатывать по градиенту для другой цифры.
Максимальный градиент — странный предмет. Вроде бы он есть, а вроде и нет
Вообще тема вроде-бы баянистая в популярной литературе не раз перетёртая.
step 0
('Test accuracy:', 0.97360000000000002)
('Test accuracy:', 0.9758)
('Test accuracy:', 0.77300000000000002)
step 1
('Test accuracy:', 0.97460000000000002)
('Test accuracy:', 0.97509999999999997)
('Test accuracy:', 0.88370000000000004)
step 2
('Test accuracy:', 0.97550000000000003)
('Test accuracy:', 0.97299999999999998)
('Test accuracy:', 0.83389999999999997)
Эта последовательность «9» в конце приводит к переобучению, но предыдущие результаты не затираются, когда они есть.
Статья, в том числе, о том, что на одинаковой последовательности MLP не учится совсем.
но предыдущие результаты не затираются, когда они есть.
Ваш эксперимент как раз показывает, что это не так.
Test accuracy как раз и равен около 0.1, т.к. на девятках, которые были последними, тестовые примеры проходят успешно, и девятки как раз составляют 1/10 от общего числа тестовых примеров, с учетом равномерного распределения. И если в тестовом наборе (x_test, y_test) оставить только 9ки, то Test accuracy будет стремится к единице, даже при упорядочивании примеров, и к нули, если из тестового множества убрать все девятки.
PS. Извиняюсь за телеграфный стиль
from keras import backend as K_B
from keras.datasets import mnist
from keras.layers import Input, Dense, Dropout
from keras.models import Sequential
from keras.optimizers import RMSprop
from keras.utils import np_utils
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
batch_size = 12
epochs = 12
hidden_size = 512
(X_train, y_train), (X_test, y_test) = mnist.load_data()
num_train, width, height = X_train.shape
num_test = X_test.shape[0]
num_classes = np.unique(y_train).shape[0]
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255.
X_test /= 255.
X_train = X_train.reshape(num_train, height * width)
X_test = X_test.reshape(num_test, height * width)
XX_train = np.copy(X_train)
yy_train = np.copy(y_train)
XX_test = np.copy(X_test)
yy_test = np.copy(y_test)
perm = np.arange(num_train, dtype='int')
j = 0
for k in xrange(num_classes):
for i in xrange(num_train):
if (yy_train[i] == k):
perm[j] = i
j += 1
for k in xrange(num_train):
X_train[k,...] = XX_train[perm[k],...]
y_train[k] = yy_train[perm[k]]
Y_train = np_utils.to_categorical(y_train, num_classes)
Y_test = np_utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(width * height,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer=RMSprop(), # RMSprop(),'adam'
metrics=['accuracy'])
history = model.fit(X_train, Y_train,
shuffle = False,
batch_size=batch_size,
epochs=epochs,
verbose=2,
validation_data=(X_test, Y_test))
for n in xrange(10):
j = 0
i = 0
for k in xrange(num_test):
if (yy_test[k] >= 8 ):
X_test[j,...] = XX_test[k,...]
y_test[j] = yy_test[k]
else:
X_test[j,...] = X_test[i,...]
y_test[j] = y_test[i]
i += 1
j += 1
Y_test = np_utils.to_categorical(y_test, num_classes)
score = model.evaluate(X_test, Y_test, verbose=0)
print ' remove ', 9 - n
print('Test accuracy:', score[1])
Если сделать всё тоже, но в тестовой последовательности оставить только «8» и «9» то сеть совсем ничего не понимает. Т.е. тренируем на упорядоченной последовательности, а результат получаем на test, но без некоторых цифр.
Epoch 1/12
22s — loss: 12.7203 — acc: 0.2105 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 2/12
22s — loss: 13.0790 — acc: 0.1885 — val_loss: 14.4487 — val_acc: 0.1028
Epoch 3/12
22s — loss: 11.0910 — acc: 0.3115 — val_loss: 14.4550 — val_acc: 0.1028
Epoch 4/12
22s — loss: 11.5997 — acc: 0.2798 — val_loss: 14.6790 — val_acc: 0.0892
Epoch 5/12
22s — loss: 10.4851 — acc: 0.3490 — val_loss: 14.6563 — val_acc: 0.0892
Epoch 6/12
22s — loss: 9.7669 — acc: 0.3937 — val_loss: 14.5344 — val_acc: 0.0982
Epoch 7/12
22s — loss: 9.6686 — acc: 0.3999 — val_loss: 14.5332 — val_acc: 0.0982
Epoch 8/12
22s — loss: 9.5976 — acc: 0.4043 — val_loss: 14.5219 — val_acc: 0.0982
Epoch 9/12
22s — loss: 7.6871 — acc: 0.5226 — val_loss: 14.4882 — val_acc: 0.1009
Epoch 10/12
22s — loss: 9.9656 — acc: 0.3814 — val_loss: 14.5188 — val_acc: 0.0982
Epoch 11/12
22s — loss: 9.6053 — acc: 0.4038 — val_loss: 14.5128 — val_acc: 0.0982
Epoch 12/12
22s — loss: 9.5696 — acc: 0.4060 — val_loss: 14.4895 — val_acc: 0.0982
remove 9
('Test accuracy:', 0.00020000000000000001)
remove 8
('Test accuracy:', 0.00020000000000000001)
remove 7
('Test accuracy:', 0.00020000000000000001)
remove 6
('Test accuracy:', 0.00020000000000000001)
remove 5
('Test accuracy:', 0.00020000000000000001)
remove 4
('Test accuracy:', 0.00020000000000000001)
remove 3
('Test accuracy:', 0.00020000000000000001)
remove 2
('Test accuracy:', 0.00020000000000000001)
remove 1
('Test accuracy:', 0.00020000000000000001)
remove 0
('Test accuracy:', 0.00020000000000000001)
for n in xrange(10):
j = 0
i = 0
for k in xrange(num_test):
if (yy_test[k] != 9 - n ):
X_test[j,...] = XX_test[k,...]
y_test[j] = yy_test[k]
else:
X_test[j,...] = X_test[i,...]
y_test[j] = y_test[i]
i += 1
j += 1
Y_test = np_utils.to_categorical(y_test, num_classes)
score = model.evaluate(X_test, Y_test, verbose=0)
print ' remove ', 9 - n
print('Test accuracy:', score[1])
Epoch 1/12
22s — loss: 12.7232 — acc: 0.2104 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 2/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 3/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 4/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 5/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 6/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 7/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 8/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 9/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 10/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 11/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
Epoch 12/12
22s — loss: 14.3070 — acc: 0.1124 — val_loss: 14.2887 — val_acc: 0.1135
remove 9
('Test accuracy:', 0.1278)
remove 8
('Test accuracy:', 0.12670000000000001)
remove 7
('Test accuracy:', 0.12839999999999999)
remove 6
('Test accuracy:', 0.12659999999999999)
remove 5
('Test accuracy:', 0.1258)
remove 4
('Test accuracy:', 0.12759999999999999)
remove 3
('Test accuracy:', 0.12790000000000001)
remove 2
('Test accuracy:', 0.1285)
remove 1
('Test accuracy:', 0.0)
remove 0
('Test accuracy:', 0.12709999999999999)
Некоторые аспекты качества обучающих последовательностей