Уровень пакетной нормализации Keras является сломанным PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

Слой нормализации партии Keras нарушен

ОБНОВЛЕНИЕ: К сожалению, мой Pull-запрос к Keras, который изменил поведение слоя нормализации партии, не был принят. Вы можете прочитать подробности здесь, Для тех из вас, кто достаточно смел, чтобы возиться с пользовательскими реализациями, вы можете найти код в моя ветка, Я мог бы сохранить его и объединить с последней стабильной версией Keras (2.1.6, 2.2.2 и 2.2.4) пока я им пользуюсь, но без обещаний.

Большинство людей, которые работают в Deep Learning, либо использовали, либо слышали о Keras, Для тех из вас, у кого нет, это отличная библиотека, которая абстрагирует базовые фреймворки Deep Learning, такие как TensorFlow, Theano и CNTK, и предоставляет API высокого уровня для обучения ИНС. Он прост в использовании, обеспечивает быстрое создание прототипов и дружелюбное активное сообщество. Я активно использовал его и периодически вносил свой вклад в проект, и я определенно рекомендую его всем, кто хочет работать над Deep Learning.

Несмотря на то, что Keras сделал мою жизнь проще, довольно часто меня укусило странное поведение слоя Batch Normalization. Его поведение по умолчанию изменилось с течением времени, тем не менее, оно по-прежнему вызывает проблемы у многих пользователей, и в результате есть несколько связанных открытые вопросы на Github. В этом посте я постараюсь создать пример того, почему слой BatchNormalization в Keras не очень хорошо работает с Transfer Learning, я предоставлю код, который устраняет проблему, и приведу примеры с результатами заплата.

В подразделах ниже я представляю, как использовать Transfer Learning в Deep Learning, что такое уровень нормализации партии, как работает learnining_phase и как Keras изменял поведение BN с течением времени. Если вы уже знаете это, вы можете спокойно перейти непосредственно к разделу 2.

1.1 Использование трансферного обучения крайне важно для глубокого обучения

Одна из причин, по которой Deep Learning подвергался критике в прошлом, заключается в том, что он требует слишком много данных. Это не всегда верно; Есть несколько методов для устранения этого ограничения, одним из которых является трансферное обучение.

Предположим, вы работаете с приложением Computer Vision и хотите создать классификатор, который отличает кошек от собак. Вам на самом деле не нужны миллионы изображений кошек / собак для обучения модели. Вместо этого вы можете использовать предварительно обученный классификатор и настраивать верхние свертки с меньшим количеством данных. Идея заключается в том, что, поскольку предварительно обученная модель была подогнана к изображениям, нижние свертки могут распознавать такие функции, как линии, ребра и другие полезные шаблоны, что означает, что вы можете использовать его веса либо как хорошие значения инициализации, либо частично переобучить сеть своими данными ,
Уровень пакетной нормализации Keras является сломанным PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
Keras поставляется с несколькими предварительно обученными моделями и простыми в использовании примерами того, как точно настроить модели. Вы можете прочитать больше на документации.

1.2 Что такое слой нормализации партии?

Слой нормализации партии был представлен в 2014 году Иоффе и Сегеди. Он решает проблему исчезающего градиента путем стандартизации выходных данных предыдущего уровня, ускоряет обучение, сокращая количество требуемых итераций, и позволяет обучать более глубокие нейронные сети. Объяснение того, как это работает, выходит за рамки этого поста, но я настоятельно рекомендую вам прочитать оригинальная бумага, Упрощенное объяснение состоит в том, что он изменяет масштаб ввода, вычитая его среднее значение и деля его со стандартным отклонением; он также может научиться отменять преобразование, если это необходимо.
Уровень пакетной нормализации Keras является сломанным PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

1.3 Что такое фазы обучения в Керасе?

Некоторые слои работают по-разному во время обучения и режима вывода. Наиболее заметными примерами являются уровни нормализации партии и выпадения. В случае BN во время обучения мы используем среднее значение и дисперсию мини-партии для изменения масштаба ввода. С другой стороны, при выводе мы используем скользящее среднее и дисперсию, которые были оценены во время обучения.

Keras знает, в каком режиме работать, потому что у него есть встроенный механизм, называемый Learning_phase. Фаза обучения определяет, находится ли сеть в режиме обучения или тестирования. Если он не установлен вручную пользователем, во время fit () сеть работает с learning_phase = 1 (режим обучения). Во время создания прогнозов (например, когда мы вызываем методы pred () и Assessment () или на этапе проверки fit ()) сеть работает с Learning_phase = 0 (тестовый режим). Несмотря на то, что это не рекомендуется, пользователь также может статически изменить Learning_phase на определенное значение, но это должно произойти до того, как какая-либо модель или тензор будут добавлены на график. Если Learning_phase установлен статически, Keras будет заблокирован в зависимости от того, какой режим выбрал пользователь.

1.4 Как Keras внедрил пакетную нормализацию с течением времени?

Keras несколько раз менял поведение нормализации партии, но последнее значительное обновление произошло в Keras 2.1.3. До v2.1.3, когда слой BN был заморожен (trainable = False), он продолжал обновлять статистику своей партии, что вызывало эпические головные боли у пользователей.

Это была не просто странная политика, это было на самом деле неправильно. Представьте себе, что слой BN существует между извилинами; если слой заморожен, с ним не должно произойти никаких изменений. Если мы частично обновим его веса, и следующие слои также будут заморожены, у них никогда не будет возможности приспособиться к обновлениям статистики мини-пакета, что приведет к увеличению ошибки. К счастью, начиная с версии 2.1.3, когда слой BN заморожен, он больше не обновляет свою статистику. Но достаточно ли этого? Нет, если вы используете трансферное обучение.

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

2.1 Техническое описание проблемы

Проблема с текущей реализацией Keras состоит в том, что, когда слой BN заморожен, он продолжает использовать статистику мини-пакета во время обучения. Я полагаю, что лучший подход, когда BN заморожен, состоит в использовании скользящего среднего и дисперсии, которые он изучил во время обучения. Зачем? По тем же причинам, по которым статистика мини-партии не должна обновляться при замораживании слоя: это может привести к плохим результатам, потому что следующие слои не обучены должным образом.

Предположим, что вы строите модель Computer Vision, но у вас недостаточно данных, поэтому вы решили использовать один из предварительно обученных CNN из Keras и настроить его. К сожалению, тем самым вы не получите никаких гарантий, что среднее значение и дисперсия вашего нового набора данных в слоях BN будут аналогичны исходному набору данных. Помните, что в данный момент во время обучения ваша сеть всегда будет использовать статистику мини-пакетов, либо слой BN заморожен, либо нет; также во время вывода вы будете использовать ранее изученную статистику замороженных слоев BN. В результате, если вы настроите верхние слои, их веса будут скорректированы на среднее значение / дисперсию new набор данных. Тем не менее, во время вывода они получат данные, которые масштабируются по-разному потому что среднее / дисперсия оригинал набор данных будет использоваться.
Уровень пакетной нормализации Keras является сломанным PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
Выше я приведу упрощенную (и нереальную) архитектуру для демонстрационных целей. Давайте предположим, что мы настраиваем модель от Convolution k + 1 до верхней части сети (правая сторона), и мы сохраняем замерзшую нижнюю часть (левая сторона). Во время обучения все слои BN от 1 до k будут использовать среднее / дисперсию ваших тренировочных данных. Это будет иметь негативные последствия для замороженных ReLU, если среднее значение и дисперсия для каждого BN не будут близки к тем, которые были изучены во время предварительной подготовки. Это также приведет к обучению остальной части сети (от CONV k + 1 и более поздних) с входами, которые имеют различные масштабы по сравнению с тем, что будет получено во время вывода. Во время обучения ваша сеть может адаптироваться к этим изменениям, тем не менее, как только вы перейдете в режим прогнозирования, Keras будет использовать другую статистику стандартизации, что ускорит распределение входных данных в следующих слоях, что приведет к плохим результатам.

2.2 Как вы можете обнаружить, если вы затронуты?

Один из способов его обнаружения - установить статическую фазу обучения Keras на 1 (режим поезда) и 0 (тестовый режим) и оценить вашу модель в каждом случае. Если существует значительная разница в точности в одном и том же наборе данных, проблема затрагивает вас. Стоит отметить, что из-за того, как механизм learning_phase реализован в Keras, обычно не рекомендуется связываться с ним. Изменения в learning_phase не окажут влияния на модели, которые уже скомпилированы и используются; как вы можете видеть на примерах в следующих подразделах, лучший способ сделать это - начать с чистого сеанса и изменить learning_phase до того, как какой-либо тензор будет определен в графе.

Другой способ обнаружить проблему при работе с двоичными классификаторами - это проверить точность и AUC. Если точность близка к 50%, но AUC близка к 1 (а также вы наблюдаете различия между режимом поезд / тестирование в одном и том же наборе данных), это может означать, что вероятности не соответствуют масштабу из-за статистики BN. Точно так же для регрессии вы можете использовать корреляцию MSE и Spearman, чтобы обнаружить ее.

2.3 Как мы можем это исправить?

Я считаю, что проблема может быть решена, если замороженные слои BN на самом деле просто: постоянно заблокированы в тестовом режиме. С точки зрения реализации, обучаемый флаг должен быть частью вычислительного графа, и поведение BN должно зависеть не только от обучения_фазы, но и от значения обучаемого свойства. Вы можете найти подробную информацию о моей реализации на Github.

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

2.4 Оценка эффектов патча

Несмотря на то, что я недавно написал вышеупомянутую реализацию, идея, лежащая в ее основе, тщательно проверена на реальных проблемах с использованием различных обходных путей, которые имеют тот же эффект. Например, несоответствия между режимами обучения и тестирования можно избежать, разделив сеть на две части (замороженная и незамерзшая) и выполнив кэшированное обучение (однажды передав данные через замороженную модель, а затем используя их для обучения незамерзшей сети). Тем не менее, поскольку «поверь мне, что я делал это раньше», как правило, не имеет никакого значения, ниже я приведу несколько примеров, которые демонстрируют влияние новой реализации на практике.

Вот несколько важных моментов об эксперименте:

  1. Я буду использовать крошечный объем данных, чтобы намеренно переобучить модель, и я буду обучать и проверять модель на том же наборе данных. Поступая так, я ожидаю почти идеальной точности и идентичной производительности набора данных для поезда / проверки.
  2. Если во время проверки я получу значительно более низкую точность для того же набора данных, у меня будет четкое указание на то, что текущая политика BN отрицательно влияет на производительность модели во время вывода.
  3. Любая предварительная обработка будет происходить за пределами генераторов. Это сделано, чтобы обойти ошибку, которая была введена в v2.1.5 (в настоящее время исправлена ​​в следующей версии v2.1.6 и последней версии master).
  4. Мы заставим Keras использовать различные этапы обучения во время оценки. Если мы обнаружим различия между заявленной точностью, мы узнаем, что на нас влияет текущая политика BN.

Код для эксперимента показан ниже:

import numpy as np
from keras.datasets import cifar10
from scipy.misc import imresize

from keras.preprocessing.image import ImageDataGenerator
from keras.applications.resnet50 import ResNet50, preprocess_input
from keras.models import Model, load_model
from keras.layers import Dense, Flatten
from keras import backend as K


seed = 42
epochs = 10
records_per_class = 100

# We take only 2 classes from CIFAR10 and a very small sample to intentionally overfit the model.
# We will also use the same data for train/test and expect that Keras will give the same accuracy.
(x, y), _ = cifar10.load_data()

def filter_resize(category):
   # We do the preprocessing here instead in the Generator to get around a bug on Keras 2.1.5.
   return [preprocess_input(imresize(img, (224,224)).astype('float')) for img in x[y.flatten()==category][:records_per_class]]

x = np.stack(filter_resize(3)+filter_resize(5))
records_per_class = x.shape[0] // 2
y = np.array([[1,0]]*records_per_class + [[0,1]]*records_per_class)


# We will use a pre-trained model and finetune the top layers.
np.random.seed(seed)
base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3))
l = Flatten()(base_model.output)
predictions = Dense(2, activation='softmax')(l)
model = Model(inputs=base_model.input, outputs=predictions)

for layer in model.layers[:140]:
   layer.trainable = False

for layer in model.layers[140:]:
   layer.trainable = True

model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit_generator(ImageDataGenerator().flow(x, y, seed=42), epochs=epochs, validation_data=ImageDataGenerator().flow(x, y, seed=42))

# Store the model on disk
model.save('tmp.h5')


# In every test we will clear the session and reload the model to force Learning_Phase values to change.
print('DYNAMIC LEARNING_PHASE')
K.clear_session()
model = load_model('tmp.h5')
# This accuracy should match exactly the one of the validation set on the last iteration.
print(model.evaluate_generator(ImageDataGenerator().flow(x, y, seed=42)))


print('STATIC LEARNING_PHASE = 0')
K.clear_session()
K.set_learning_phase(0)
model = load_model('tmp.h5')
# Again the accuracy should match the above.
print(model.evaluate_generator(ImageDataGenerator().flow(x, y, seed=42)))


print('STATIC LEARNING_PHASE = 1')
K.clear_session()
K.set_learning_phase(1)
model = load_model('tmp.h5')
# The accuracy will be close to the one of the training set on the last iteration.
print(model.evaluate_generator(ImageDataGenerator().flow(x, y, seed=42)))

Давайте проверим результаты на Keras v2.1.5:

Epoch 1/10
1/7 [===>..........................] - ETA: 25s - loss: 0.8751 - acc: 0.5312
2/7 [=======>......................] - ETA: 11s - loss: 0.8594 - acc: 0.4531
3/7 [===========>..................] - ETA: 7s - loss: 0.8398 - acc: 0.4688 
4/7 [================>.............] - ETA: 4s - loss: 0.8467 - acc: 0.4844
5/7 [====================>.........] - ETA: 2s - loss: 0.7904 - acc: 0.5437
6/7 [========================>.....] - ETA: 1s - loss: 0.7593 - acc: 0.5625
7/7 [==============================] - 12s 2s/step - loss: 0.7536 - acc: 0.5744 - val_loss: 0.6526 - val_acc: 0.6650

Epoch 2/10
1/7 [===>..........................] - ETA: 4s - loss: 0.3881 - acc: 0.8125
2/7 [=======>......................] - ETA: 3s - loss: 0.3945 - acc: 0.7812
3/7 [===========>..................] - ETA: 2s - loss: 0.3956 - acc: 0.8229
4/7 [================>.............] - ETA: 1s - loss: 0.4223 - acc: 0.8047
5/7 [====================>.........] - ETA: 1s - loss: 0.4483 - acc: 0.7812
6/7 [========================>.....] - ETA: 0s - loss: 0.4325 - acc: 0.7917
7/7 [==============================] - 8s 1s/step - loss: 0.4095 - acc: 0.8089 - val_loss: 0.4722 - val_acc: 0.7700

Epoch 3/10
1/7 [===>..........................] - ETA: 4s - loss: 0.2246 - acc: 0.9375
2/7 [=======>......................] - ETA: 3s - loss: 0.2167 - acc: 0.9375
3/7 [===========>..................] - ETA: 2s - loss: 0.2260 - acc: 0.9479
4/7 [================>.............] - ETA: 2s - loss: 0.2179 - acc: 0.9375
5/7 [====================>.........] - ETA: 1s - loss: 0.2356 - acc: 0.9313
6/7 [========================>.....] - ETA: 0s - loss: 0.2392 - acc: 0.9427
7/7 [==============================] - 8s 1s/step - loss: 0.2288 - acc: 0.9456 - val_loss: 0.4282 - val_acc: 0.7800

Epoch 4/10
1/7 [===>..........................] - ETA: 4s - loss: 0.2183 - acc: 0.9688
2/7 [=======>......................] - ETA: 3s - loss: 0.1899 - acc: 0.9844
3/7 [===========>..................] - ETA: 2s - loss: 0.1887 - acc: 0.9792
4/7 [================>.............] - ETA: 1s - loss: 0.1995 - acc: 0.9531
5/7 [====================>.........] - ETA: 1s - loss: 0.1932 - acc: 0.9625
6/7 [========================>.....] - ETA: 0s - loss: 0.1819 - acc: 0.9688
7/7 [==============================] - 8s 1s/step - loss: 0.1743 - acc: 0.9747 - val_loss: 0.3778 - val_acc: 0.8400

Epoch 5/10
1/7 [===>..........................] - ETA: 3s - loss: 0.0973 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0828 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0851 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0897 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0928 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0936 - acc: 1.0000
7/7 [==============================] - 8s 1s/step - loss: 0.1337 - acc: 0.9838 - val_loss: 0.3916 - val_acc: 0.8100

Epoch 6/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0747 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0852 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0812 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0831 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0779 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0766 - acc: 1.0000
7/7 [==============================] - 8s 1s/step - loss: 0.0813 - acc: 1.0000 - val_loss: 0.3637 - val_acc: 0.8550

Epoch 7/10
1/7 [===>..........................] - ETA: 1s - loss: 0.2478 - acc: 0.8750
2/7 [=======>......................] - ETA: 2s - loss: 0.1966 - acc: 0.9375
3/7 [===========>..................] - ETA: 2s - loss: 0.1528 - acc: 0.9583
4/7 [================>.............] - ETA: 1s - loss: 0.1300 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.1193 - acc: 0.9750
6/7 [========================>.....] - ETA: 0s - loss: 0.1196 - acc: 0.9792
7/7 [==============================] - 8s 1s/step - loss: 0.1084 - acc: 0.9838 - val_loss: 0.3546 - val_acc: 0.8600

Epoch 8/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0539 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.0900 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0815 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0740 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0700 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0701 - acc: 1.0000
7/7 [==============================] - 8s 1s/step - loss: 0.0695 - acc: 1.0000 - val_loss: 0.3269 - val_acc: 0.8600

Epoch 9/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0306 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0377 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0898 - acc: 0.9583
4/7 [================>.............] - ETA: 1s - loss: 0.0773 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.0742 - acc: 0.9750
6/7 [========================>.....] - ETA: 0s - loss: 0.0708 - acc: 0.9792
7/7 [==============================] - 8s 1s/step - loss: 0.0659 - acc: 0.9838 - val_loss: 0.3604 - val_acc: 0.8600

Epoch 10/10
1/7 [===>..........................] - ETA: 3s - loss: 0.0354 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0381 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0354 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0828 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.0791 - acc: 0.9750
6/7 [========================>.....] - ETA: 0s - loss: 0.0794 - acc: 0.9792
7/7 [==============================] - 8s 1s/step - loss: 0.0704 - acc: 0.9838 - val_loss: 0.3615 - val_acc: 0.8600

DYNAMIC LEARNING_PHASE
[0.3614931714534759, 0.86]

STATIC LEARNING_PHASE = 0
[0.3614931714534759, 0.86]

STATIC LEARNING_PHASE = 1
[0.025861846953630446, 1.0]

Как мы видим выше, во время обучения модель очень хорошо усваивает данные и достигает на тренировочном наборе почти идеальной точности. По-прежнему в конце каждой итерации, оценивая модель в одном и том же наборе данных, мы получаем значительные различия в потерях и точности. Обратите внимание, что мы не должны получать это; мы специально переписали модель в конкретном наборе данных, и наборы данных для обучения / проверки идентичности.

После завершения обучения мы оцениваем модель с использованием 3 различных конфигураций Learning_phase: Dynamic, Static = 0 (тестовый режим) и Static = 1 (обучающий режим). Как мы видим, первые две конфигурации дадут идентичные результаты с точки зрения потерь и точности, а их значение соответствует заявленной точности модели при проверке, установленной на последней итерации. Тем не менее, как только мы переключаемся в режим обучения, мы наблюдаем огромное несоответствие (улучшение). Почему это то? Как мы уже говорили ранее, веса сети настраиваются с расчетом на получение данных, масштабированных со средним значением / дисперсией обучающих данных. К сожалению, эта статистика отличается от той, что хранится в слоях BN. Поскольку слои BN были заморожены, эта статистика никогда не обновлялась. Такое несоответствие значений статистики BN приводит к ухудшению точности при выводе.

Давайте посмотрим, что произойдет, когда мы применим заплата:

Epoch 1/10
1/7 [===>..........................] - ETA: 26s - loss: 0.9992 - acc: 0.4375
2/7 [=======>......................] - ETA: 12s - loss: 1.0534 - acc: 0.4375
3/7 [===========>..................] - ETA: 7s - loss: 1.0592 - acc: 0.4479 
4/7 [================>.............] - ETA: 4s - loss: 0.9618 - acc: 0.5000
5/7 [====================>.........] - ETA: 2s - loss: 0.8933 - acc: 0.5250
6/7 [========================>.....] - ETA: 1s - loss: 0.8638 - acc: 0.5417
7/7 [==============================] - 13s 2s/step - loss: 0.8357 - acc: 0.5570 - val_loss: 0.2414 - val_acc: 0.9450

Epoch 2/10
1/7 [===>..........................] - ETA: 4s - loss: 0.2331 - acc: 0.9688
2/7 [=======>......................] - ETA: 2s - loss: 0.3308 - acc: 0.8594
3/7 [===========>..................] - ETA: 2s - loss: 0.3986 - acc: 0.8125
4/7 [================>.............] - ETA: 1s - loss: 0.3721 - acc: 0.8281
5/7 [====================>.........] - ETA: 1s - loss: 0.3449 - acc: 0.8438
6/7 [========================>.....] - ETA: 0s - loss: 0.3168 - acc: 0.8646
7/7 [==============================] - 9s 1s/step - loss: 0.3165 - acc: 0.8633 - val_loss: 0.1167 - val_acc: 0.9950

Epoch 3/10
1/7 [===>..........................] - ETA: 1s - loss: 0.2457 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.2592 - acc: 0.9688
3/7 [===========>..................] - ETA: 2s - loss: 0.2173 - acc: 0.9688
4/7 [================>.............] - ETA: 1s - loss: 0.2122 - acc: 0.9688
5/7 [====================>.........] - ETA: 1s - loss: 0.2003 - acc: 0.9688
6/7 [========================>.....] - ETA: 0s - loss: 0.1896 - acc: 0.9740
7/7 [==============================] - 9s 1s/step - loss: 0.1835 - acc: 0.9773 - val_loss: 0.0678 - val_acc: 1.0000

Epoch 4/10
1/7 [===>..........................] - ETA: 1s - loss: 0.2051 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.1652 - acc: 0.9844
3/7 [===========>..................] - ETA: 2s - loss: 0.1423 - acc: 0.9896
4/7 [================>.............] - ETA: 1s - loss: 0.1289 - acc: 0.9922
5/7 [====================>.........] - ETA: 1s - loss: 0.1225 - acc: 0.9938
6/7 [========================>.....] - ETA: 0s - loss: 0.1149 - acc: 0.9948
7/7 [==============================] - 9s 1s/step - loss: 0.1060 - acc: 0.9955 - val_loss: 0.0455 - val_acc: 1.0000

Epoch 5/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0769 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.0846 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0797 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0736 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0914 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0858 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0808 - acc: 1.0000 - val_loss: 0.0346 - val_acc: 1.0000

Epoch 6/10
1/7 [===>..........................] - ETA: 1s - loss: 0.1267 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.1039 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0893 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0780 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0758 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0789 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0738 - acc: 1.0000 - val_loss: 0.0248 - val_acc: 1.0000

Epoch 7/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0344 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0385 - acc: 1.0000
3/7 [===========>..................] - ETA: 3s - loss: 0.0467 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0445 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0446 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0429 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0421 - acc: 1.0000 - val_loss: 0.0202 - val_acc: 1.0000

Epoch 8/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0319 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0300 - acc: 1.0000
3/7 [===========>..................] - ETA: 3s - loss: 0.0320 - acc: 1.0000
4/7 [================>.............] - ETA: 2s - loss: 0.0307 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0303 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0291 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0358 - acc: 1.0000 - val_loss: 0.0167 - val_acc: 1.0000

Epoch 9/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0246 - acc: 1.0000
2/7 [=======>......................] - ETA: 3s - loss: 0.0255 - acc: 1.0000
3/7 [===========>..................] - ETA: 3s - loss: 0.0258 - acc: 1.0000
4/7 [================>.............] - ETA: 2s - loss: 0.0250 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0252 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0260 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0327 - acc: 1.0000 - val_loss: 0.0143 - val_acc: 1.0000

Epoch 10/10
1/7 [===>..........................] - ETA: 4s - loss: 0.0251 - acc: 1.0000
2/7 [=======>......................] - ETA: 2s - loss: 0.0228 - acc: 1.0000
3/7 [===========>..................] - ETA: 2s - loss: 0.0217 - acc: 1.0000
4/7 [================>.............] - ETA: 1s - loss: 0.0249 - acc: 1.0000
5/7 [====================>.........] - ETA: 1s - loss: 0.0244 - acc: 1.0000
6/7 [========================>.....] - ETA: 0s - loss: 0.0239 - acc: 1.0000
7/7 [==============================] - 9s 1s/step - loss: 0.0290 - acc: 1.0000 - val_loss: 0.0127 - val_acc: 1.0000

DYNAMIC LEARNING_PHASE
[0.012697912137955427, 1.0]

STATIC LEARNING_PHASE = 0
[0.012697912137955427, 1.0]

STATIC LEARNING_PHASE = 1
[0.01744014158844948, 1.0]

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

2.5 Как патч работает с реальным набором данных?

Так как же патч работает в более реалистичном эксперименте? Давайте используем предварительно обученный Keras ResNet50 (изначально подходящий для imagenet), удалим верхний классификационный слой и настроим его с патчем и без него и сравним результаты. Для данных мы будем использовать CIFAR10 (стандартное разделение поезда / теста, предоставляемое Keras), и мы изменим размеры изображений до 224 × 224, чтобы сделать их совместимыми с входным размером ResNet50.

Мы сделаем 10 эпох, чтобы обучить верхний слой классификации, используя RSMprop, а затем мы сделаем еще 5, чтобы точно настроить все после 139-го слоя, используя SGD (lr = 1e-4, импульс = 0.9). Без патча наша модель достигает точности 87.44%. Используя патч, мы получаем точность 92.36%, почти на 5 баллов выше.

2.6 Должны ли мы применить такое же исправление к другим слоям, таким как Dropout?

Пакетная нормализация - не единственный слой, который работает по-разному между режимами обучения и тестирования. Выпадение и его варианты также имеют тот же эффект. Должны ли мы применять одну и ту же политику ко всем этим слоям? Я верю нет (хотя я хотел бы услышать ваши мысли по этому поводу). Причина в том, что Dropout используется для того, чтобы избежать перегрузки, поэтому его постоянная привязка к режиму прогнозирования во время тренировки потеряет свою цель. Что вы думаете?

Я твердо верю, что это несоответствие должно быть решено в Керасе. Я видел еще более глубокие эффекты (от 100% до 50% точности) в реальных приложениях, вызванные этой проблемой. я планирую отправить уже отправил PR Керасу с исправлением и, надеюсь, оно будет принято.

Если вам понравился этот пост, пожалуйста, найдите время, чтобы поделиться им в Facebook или Twitter. 🙂

Отметка времени:

Больше от Датумбокс