Причини втрати глибокого навчання Нен


83

Можливо, занадто загальне питання, але чи може хтось пояснити, що могло б спричинити розбіжність Свертової нейронної мережі?

Особливості:

Я використовую модель iris_training Tensorflow з деякими своїми даними і продовжую отримувати

ПОМИЛКА: тензорпотік: Модель розходиться з втратами = NaN.

Простежити...

tensorflow.contrib.learn.python.learn.monitors.NanLossDuringTrainingError: втрата NaN під час навчання.

Трекбек виник із рядка:

 tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                        hidden_units=[300, 300, 300],
                                        #optimizer=tf.train.ProximalAdagradOptimizer(learning_rate=0.001, l1_regularization_strength=0.00001),                                                          
                                        n_classes=11,
                                        model_dir="/tmp/iris_model")

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


5
Це природна властивість стохастичного градієнтного спуску, якщо швидкість навчання занадто велика, SGD може розходитися в нескінченність
Ярослав Булатов,

@YaroslavBulatov Я пробував із цим AdagradOptiizer зі швидкістю навчання близько 1E-15. Можливо, мої дані не підходять для SGD, чи можете ви запропонувати інший алгоритм? Все ще нова для Tensorflow та Deep Learning.
Безкоштовна URL-

У моєму випадку нормалізація допомогла
Дмитро

Рішенням для мене було використання tf.losses.sparse_softmax_cross_entropy(y, logits)замість власної реалізації використання Safe Softmaxtf.nn.Softmax
Едуардо Рейс

Відповіді:


128

Багато речей, які я бачив, змушують модель розходитися.

  1. Занадто високий рівень навчання. Часто можна сказати, чи це так, якщо втрати починають збільшуватися, а потім розходяться до нескінченності.

  2. Я не знайомий з класифікатором DNNC, але я здогадуюсь, що він використовує категоріальну функцію перехресної ентропії. Це включає в себе журнал прогнозу, який розходиться, коли прогнозування наближається до нуля. Ось чому люди зазвичай додають невелике значення епсилону до передбачення, щоб запобігти цій розбіжності. Я припускаю, DNNClassifier, ймовірно, робить це або використовує tensorflow opp для цього. Можливо, справа не в цьому.

  3. Можуть існувати й інші проблеми числової стабільності, такі як ділення на нуль, де додавання епсилону може допомогти. Інший менш очевидний, якщо квадратний корінь, похідна якого може розходитися, якщо не правильно спрощений при роботі з кінцевими числами точності. І все ж я знову сумніваюся, що це питання у випадку з DNNClassifier.

  4. У вас можуть виникнути проблеми з вхідними даними. Спробуйте зателефонувати assert not np.any(np.isnan(x))на вхідні дані, щоб переконатися, що ви не вводите nan. Також переконайтесь, що всі цільові значення є дійсними. Нарешті, переконайтесь, що дані нормалізовані належним чином. Ймовірно, ви хочете, щоб пікселі мали діапазон [-1, 1], а не [0, 255].

  5. Етикетки повинні знаходитися в області функції втрат, тому, якщо використовується функція логарифмічної втрати, всі мітки повинні бути невід’ємними (як зазначив evan pu та коментарі нижче).


1
дякую за поломку. Моя проблема полягала в тому, що мої мітки були симетричними навколо нуля (тобто [-5, ..., 5]). Переміщення вирішило проблему.
Безкоштовна URL-

4
Мітки повинні бути двійковими. 1 або 0. Інакше категорична функція перехресної ентропії не мала б сенсу.
chasep255,

tf.keras.utils.normalize(data)було корисно для нормалізації даних.
транзистор1

під "двійковим" означає, що вони повинні бути кодованими одноразово, тобто вектором (1,0,0, ...., 0) для прикладів першого класу, (0,1,0, .... 0) для прикладів другого класу та (0, ...., 0,1) для прикладів останнього класу. Кількість вихідних вузлів має бути такою ж, як і кількість класів, які у вас є.
Андре Хольцнер,

1
Ви - мій герой! Коли я пробую приклад лінійної регресії ( toptal.com/machine-learning/… ) з іншим набором даних, скажімо Цельсія Фаренгейту, я отримую W, b, втрачаю все 'nan'. Але слідуючи вашій відповіді, я змінив learning_rate = 0,01 на learning_rate = 0,001, тоді все працювало ідеально!
палтус

12

Якщо ви тренуєтесь для перехресної ентропії, ви хочете додати невелике число, як 1e-8, до вашої ймовірності виходу.

Оскільки log (0) є негативною нескінченністю, коли ваша модель досить навчена розподіл вихідних даних буде дуже перекошеною, наприклад, скажімо, я роблю вихід 4 класу, на початку моя ймовірність виглядає так

0.25 0.25 0.25 0.25

але до кінця ймовірність, ймовірно, буде виглядати так

1.0 0 0 0

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


Я використовую функцію categorical_crossentropyвтрати від keras, чи це вже реалізовано?
StayFoolish

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

4

Якщо цілі числа використовуються як цілі, переконайтесь, що вони не симетричні при 0.

Тобто, не використовуйте класи -1, 0, 1. Замість них використовуйте 0, 1, 2.


1
Чи хотіли б Ви трохи прокоментувати причини, чому Ви процитували посилання?
gsimard

@gsimard Чесно кажучи, я не пам’ятаю, оскільки деякий час працював із цим.
Рок Повшич,

@gsimard, це через причину 5 у прийнятій відповіді. В логістичних регресійних функціях часто використовуються логарифми, які визначаються лише на невід’ємних числах
Безкоштовна URL-

1
@Zroach Ні, у моєму випадку негативні числа підтримувались, але причиною того, що це не
спрацювало,

4

У моєму випадку я отримав NAN при встановленні віддалених цілочисельних ЕТИКЕТ. тобто:

  • Ярлики [0..100] навчання пройшло нормально,
  • Мітки [0..100] плюс одна додаткова мітка 8000, тоді я отримав NAN.

Отже, не використовуйте дуже далеку етикетку.

EDIT Ви можете побачити ефект у наступному простому коді:

from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np

X=np.random.random(size=(20,5))
y=np.random.randint(0,high=5, size=(20,1))

model = Sequential([
            Dense(10, input_dim=X.shape[1]),
            Activation('relu'),
            Dense(5),
            Activation('softmax')
            ])
model.compile(optimizer = "Adam", loss = "sparse_categorical_crossentropy", metrics = ["accuracy"] )

print('fit model with labels in range 0..5')
history = model.fit(X, y, epochs= 5 )

X = np.vstack( (X, np.random.random(size=(1,5))))
y = np.vstack( ( y, [[8000]]))
print('fit model with labels in range 0..5 plus 8000')
history = model.fit(X, y, epochs= 5 )

Результат показує NAN після додавання мітки 8000:

fit model with labels in range 0..5
Epoch 1/5
20/20 [==============================] - 0s 25ms/step - loss: 1.8345 - acc: 0.1500
Epoch 2/5
20/20 [==============================] - 0s 150us/step - loss: 1.8312 - acc: 0.1500
Epoch 3/5
20/20 [==============================] - 0s 151us/step - loss: 1.8273 - acc: 0.1500
Epoch 4/5
20/20 [==============================] - 0s 198us/step - loss: 1.8233 - acc: 0.1500
Epoch 5/5
20/20 [==============================] - 0s 151us/step - loss: 1.8192 - acc: 0.1500
fit model with labels in range 0..5 plus 8000
Epoch 1/5
21/21 [==============================] - 0s 142us/step - loss: nan - acc: 0.1429
Epoch 2/5
21/21 [==============================] - 0s 238us/step - loss: nan - acc: 0.2381
Epoch 3/5
21/21 [==============================] - 0s 191us/step - loss: nan - acc: 0.2381
Epoch 4/5
21/21 [==============================] - 0s 191us/step - loss: nan - acc: 0.2381
Epoch 5/5
21/21 [==============================] - 0s 188us/step - loss: nan - acc: 0.2381

Цікаво. Я думаю, це залежить від вашої функції втрат. Ви можете вказати, як ви вимірювали збитки?
Безкоштовна URL-

1
Я використовував, як є, "sparse_categorical_crossentropy"
Гвідо,

2

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

Джерело: https://github.com/tensorflow/tensor2tensor/issues/574


0

Може допомогти регуляризація. Для класифікатора є вагомий випадок регуляризації діяльності, будь то двійковий чи багатокласний класифікатор. Для регресора регуляризація ядра може бути більш доречною.


0

Я хотів би підключити деякі (неглибокі) причини, з якими я зіткнувся, наступним чином:

  1. ми могли оновити наш словник (для завдань NLP), але модель та підготовлені дані використовували інший.
  2. можливо, ми переробили наші дані (двійковий файл tf_record), але ми завантажили стару модель. Оброблені дані можуть суперечити попереднім.
  3. можливо, нам слід навчити модель з нуля, але ми забули видалити контрольні точки, і модель автоматично завантажила останні параметри.

Сподіваюся, що це допомагає.


0

Причина nan, infабо -infчасто виходить з того , що division by 0.0в TensorFlow не приводить розподіл на нуль виключення. Це може привести до nan, infабо -inf«значення». У ваших навчальних даних, які ви можете мати, 0.0і, отже, у вашій функції втрат може статися, що ви виконуєте a division by 0.0.

a = tf.constant([2., 0., -2.])
b = tf.constant([0., 0., 0.])
c = tf.constant([1., 1., 1.])
print((a / b) + c)

Результатом є такий тензор:

tf.Tensor([ inf  nan -inf], shape=(3,), dtype=float32)

Додавання маленького eplison(наприклад, 1e-5) часто робить трюк. Крім того, оскільки TensorFlow 2 tf.math.division_no_nanвизначає можливість.


0

Хоча більшість пунктів вже обговорено. Але я хотів би ще раз виділити ще одну причину для NaN, яка відсутня.

tf.estimator.DNNClassifier(
    hidden_units, feature_columns, model_dir=None, n_classes=2, weight_column=None,
    label_vocabulary=None, optimizer='Adagrad', activation_fn=tf.nn.relu,
    dropout=None, config=None, warm_start_from=None,
    loss_reduction=losses_utils.ReductionV2.SUM_OVER_BATCH_SIZE, batch_norm=False
)

За замовчуванням функцією активації є "Relu". Можливо, що проміжний шар генерує негативне значення, а "Relu" перетворює його на 0. Що поступово припиняє тренування.

Я спостерігав, що "LeakyRelu" може вирішити подібні проблеми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.