Рівень пакетної нормалізації Keras зламано PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

Шар пакетної нормалізації Keras порушений

ОНОВЛЕННЯ: На жаль, мій Pull-Request до Keras, який змінив поведінку шару пакетної нормалізації, не був прийнятий. Ви можете прочитати деталі тут. Для тих із вас, хто досить сміливий, щоб возитися з користувацькими реалізаціями, ви можете знайти код моя філія. Я можу підтримувати його та об’єднувати з останньою стабільною версією Keras (2.1.6, 2.2.2 та 2.2.4) поки я ним користуюся, але не обіцяю.

Більшість людей, які працюють у сфері глибокого навчання, або користувалися, або чули Керас. Для тих із вас, хто цього не зробив, це чудова бібліотека, яка абстрагує базові фреймворки глибокого навчання, такі як TensorFlow, Theano та CNTK, і надає API високого рівня для навчання ШНМ. Він простий у використанні, забезпечує швидке створення прототипів і має дружню активну спільноту. Я активно використовую його та періодично роблю внесок у проект протягом досить тривалого часу, і я безумовно рекомендую його всім, хто хоче працювати над глибоким навчанням.

Незважаючи на те, що Keras полегшив моє життя, мене багато разів кусала дивна поведінка шару пакетної нормалізації. Його поведінка за замовчуванням змінилася з часом, проте це все ще викликає проблеми у багатьох користувачів, і в результаті існує кілька пов’язаних відкриті питання на Github. У цій публікації в блозі я спробую пояснити, чому шар BatchNormalization Keras не працює добре з Transfer Learning, я надам код, який вирішує проблему, і наведу приклади з результатами ділянку.

У нижченаведених підрозділах я розповім про те, як Transfer Learning використовується в Deep Learning, що таке шар пакетної нормалізації, як працює learnining_phase і як Keras змінив поведінку BN з часом. Якщо ви вже знаєте це, ви можете безпечно перейти безпосередньо до розділу 2.

1.1 Використання трансферного навчання має вирішальне значення для глибокого навчання

Однією з причин, чому глибоке навчання критикували в минулому, є те, що воно вимагає занадто багато даних. Це не завжди вірно; Існує кілька методів, щоб подолати це обмеження, одна з яких – трансферне навчання.

Припустимо, що ви працюєте над програмою Computer Vision і хочете створити класифікатор, який відрізняє котів від собак. Насправді вам не потрібні мільйони зображень кішки/собаки, щоб навчити модель. Замість цього ви можете використовувати попередньо навчений класифікатор і точно налаштувати верхні згортки з меншою кількістю даних. Ідея полягає в тому, що, оскільки попередньо навчена модель була пристосована до зображень, нижні згортки можуть розпізнавати такі функції, як лінії, краю та інші корисні шаблони, що означає, що ви можете використовувати її ваги або як хороші значення ініціалізації, або частково перенавчати мережу зі своїми даними. .
Рівень пакетної нормалізації Keras зламано PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.
Keras постачається з кількома попередньо навченими моделями та простими у використанні прикладами того, як точно налаштувати моделі. Ви можете прочитати більше на документація.

1.2 Що таке шар пакетної нормалізації?

Шар пакетної нормалізації був представлений у 2014 році Іоффе та Сегеді. Він вирішує проблему зникаючого градієнта шляхом стандартизації виводу попереднього шару, прискорює навчання, зменшуючи кількість необхідних ітерацій, і дозволяє навчати більш глибокі нейронні мережі. Пояснення того, як це працює, виходить за рамки цієї публікації, але я настійно закликаю вас прочитати оригінальний папір. Занадто спрощене пояснення полягає в тому, що він змінює масштаб вхідних даних шляхом віднімання його середнього значення та ділення на його стандартне відхилення; він також може навчитися скасувати перетворення, якщо це необхідно.
Рівень пакетної нормалізації Keras зламано PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

1.3 Що таке навчання_фаза в Keras?

Деякі рівні працюють по-різному під час навчання та в режимі висновку. Найпомітнішими прикладами є шари пакетної нормалізації та випадання. У випадку BN під час навчання ми використовуємо середнє значення та дисперсію міні-пакету, щоб змінити масштаб вхідних даних. З іншого боку, під час висновку ми використовуємо ковзну середню та дисперсію, яка була оцінена під час навчання.

Keras знає, в якому режимі працювати, оскільки має вбудований механізм під назвою фаза навчання. Фаза навчання контролює, чи працює мережа в режимі навчання чи тесту. Якщо користувач не встановлює його вручну, під час fit() мережа працює з learning_phase=1 (режим поїзда). Під час створення передбачень (наприклад, коли ми викликаємо методи predict() & evaluate() або на етапі перевірки fit()) мережа працює з learning_phase=0 (тестовий режим). Незважаючи на те, що це не рекомендується, користувач також може статично змінити Learning_phase на конкретне значення, але це має статися до того, як будь-яка модель або тензор буде додано до графіка. Якщо навчання_фаза встановлено статично, Keras буде заблоковано в будь-якому режимі, який вибрав користувач.

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

Keras кілька разів змінював поведінку пакетної нормалізації, але останнє значне оновлення відбулося у Keras 2.1.3. До версії 2.1.3, коли шар BN був заморожений (придатний для навчання = False), він постійно оновлював свою пакетну статистику, що викликало епічну головну біль у його користувачів.

Це була не просто дивна політика, а насправді неправильна. Уявіть, що між згортками існує шар BN; якщо шар заморожений, з ним не повинно відбуватися жодних змін. Якщо ми частково оновимо його ваги, а наступні шари також будуть заморожені, вони ніколи не отримають можливості пристосуватися до оновлень міні-пакетної статистики, що призведе до більшої помилки. На щастя, починаючи з версії 2.1.3, коли шар BN заморожений, він більше не оновлює свою статистику. Але чи достатньо цього? Ні, якщо ви використовуєте трансферне навчання.

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

2.1 Технічний опис проблеми

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

Припустимо, що ви створюєте модель Computer Vision, але у вас недостатньо даних, тому ви вирішили використати одну з попередньо підготовлених CNN від Keras і налаштувати її. На жаль, таким чином ви не отримаєте жодних гарантій, що середнє значення та дисперсія вашого нового набору даних всередині шарів BN будуть подібними до тих, що були в оригінальному наборі даних. Пам'ятайте, що на даний момент під час навчання ваша мережа завжди буде використовувати статистику міні-пакету, або шар BN заморожений, чи ні; також під час висновку ви будете використовувати раніше вивчену статистику заморожених шарів BN. В результаті, якщо ви точно налаштуєте верхні шари, їх вага буде скориговано до середнього/дисперсії new набір даних. Тим не менш, під час висновку вони отримають дані, які масштабуються інакше тому що середнє/дисперсія оригінал буде використаний набір даних.
Рівень пакетної нормалізації Keras зламано PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.
Вище я наводжу спрощену (і нереалістичну) архітектуру для демонстраційних цілей. Припустимо, що ми точно налаштуємо модель від згортки k+1 до верхньої частини мережі (права сторона), а нижню частину (ліва) залишимо замороженою. Під час навчання всі рівні BN від 1 до k використовуватимуть середнє/дисперсію ваших навчальних даних. Це матиме негативний вплив на заморожені ReLU, якщо середнє значення та дисперсія для кожного BN не будуть близькими до тих, які були отримані під час попереднього навчання. Це також призведе до того, що решта мережі (від CONV k+1 і пізніших) буде навчатися за допомогою вхідних даних, які мають різні масштаби порівняно з тим, що отримає під час висновку. Під час навчання ваша мережа може адаптуватися до цих змін, але в той момент, коли ви перейдете в режим прогнозування, Keras використовуватиме різну статистику стандартизації, що прискорить розподіл вхідних даних наступних шарів, що призведе до поганих результатів.

2.2 Як ви можете виявити, що ви постраждали?

Один із способів виявити це — статично встановити фазу навчання Keras на 1 (режим поїзда) і на 0 (тестовий режим) і оцінювати вашу модель у кожному випадку. Якщо є значна різниця в точності на одному наборі даних, проблема стосується вас. Варто зазначити, що через те, як механізм Learning_phase реалізовано в Keras, зазвичай не радиться з ним возитися. Зміни у фазі навчання не матимуть впливу на моделі, які вже скомпільовані та використовуються; як ви можете побачити на прикладах у наступних підрозділах, найкращий спосіб зробити це — почати з чистого сеансу та змінити learning_phase до того, як будь-який тензор буде визначено на графіку.

Інший спосіб виявити проблему під час роботи з бінарними класифікаторами — перевірити точність і AUC. Якщо точність близька до 50%, але AUC близька до 1 (а також ви помічаєте відмінності між режимом навчання/тесту на одному наборі даних), можливо, ймовірності виходять за межі масштабу через статистику BN. Аналогічно, для регресії ви можете використовувати MSE та кореляцію Спірмена, щоб її виявити.

2.3 Як ми можемо це виправити?

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

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

2.4 Оцінка впливу пластиру

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

Ось кілька важливих моментів щодо експерименту:

  1. Я буду використовувати невелику кількість даних, щоб навмисно переобладнати модель, і я буду навчати та перевіряти модель на тому самому наборі даних. Роблячи це, я очікую майже ідеальної точності та ідентичної продуктивності набору даних поїзда/валідації.
  2. Якщо під час перевірки я отримаю значно нижчу точність для того самого набору даних, у мене буде чітка ознака того, що поточна політика BN негативно впливає на продуктивність моделі під час висновку.
  3. Будь-яка попередня обробка відбуватиметься за межами генераторів. Це зроблено для того, щоб обійти помилку, яка була введена у версії 2.1.5 (наразі виправлено в майбутній версії 2.1.6 та останньому майстер).
  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 різні конфігурації фази навчання: 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 до Keras із виправленням, і, сподіваюся, воно буде прийнято.

Якщо вам сподобалася ця публікація в блозі, знайдіть час, щоб поділитися нею у Facebook або Twitter. 🙂

Часова мітка:

Більше від Датабокс