Потеря NaN при тренировке регрессионной сети

У меня есть матрица данных в "однократной кодировке" (все единицы и нули) с 260 000 строк и 35 столбцов. Я использую Keras для обучения простой нейронной сети для прогнозирования непрерывной переменной. Код для создания сети следующий:

model = Sequential()
model.add(Dense(1024, input_shape=(n_train,)))
model.add(Activation('relu'))
model.add(Dropout(0.1))

model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.1))

model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dropout(0.1))
model.add(Dense(1))

sgd = SGD(lr=0.01, nesterov=True);
#rms = RMSprop()
#model.compile(loss='categorical_crossentropy', optimizer=rms, metrics=['accuracy'])
model.compile(loss='mean_absolute_error', optimizer=sgd)
model.fit(X_train, Y_train, batch_size=32, nb_epoch=3, verbose=1, validation_data=(X_test,Y_test), callbacks=[EarlyStopping(monitor='val_loss', patience=4)] )

Однако в процессе обучения я вижу, что потеря уменьшается красиво, но в середине второй эпохи она идет на nan:

Train on 260000 samples, validate on 64905 samples
Epoch 1/3
260000/260000 [==============================] - 254s - loss: 16.2775 - val_loss:
 13.4925
Epoch 2/3
 88448/260000 [=========>....................] - ETA: 161s - loss: nan

Я попытался использовать RMSProp вместо SGD, я попробовал tanh вместо relu, я пробовал с и без выпада, все безрезультатно. Я попытался использовать меньшую модель, т.е. Только с одним скрытым слоем и с той же проблемой (она становится нан в другой точке). Однако он работает с меньшими возможностями, т.е. Если имеется только 5 столбцов и дает неплохие прогнозы. Кажется, что есть что-то переполнение, но я не могу себе представить, почему - потеря не является неоправданно большой.

Python версия 2.7.11, работающая на Linux-машине, только CPU. Я тестировал его с последней версией Theano, и я также получаю Nans, поэтому я попытался перейти к Theano 0.8.2 и иметь такую ​​же проблему. С последней версией Keras такая же проблема, а также с версией 0.3.2.

Ответы

Ответ 1

Регрессия с нейронными сетями трудно получить, потому что вывод неограничен, поэтому вы особенно склонны к проблеме взрывающихся градиентов (вероятная причина nans),

Исторически одним из ключевых решений для взрывающихся градиентов было снижение скорости обучения, но с появлением алгоритмов адаптивной скорости обучения для каждого параметра, таких как Адам, вам больше не нужно устанавливать скорость обучения, чтобы получить хорошую производительность. Существует очень мало оснований использовать SGD с импульсом больше, если вы не являетесь нервным сетью и не знаете, как настроить график обучения.

Вот некоторые вещи, которые вы могли бы попробовать:

  • Нормализовать ваши результаты с помощью квантильной нормализации или z скоринга. Чтобы быть строгим, вычислите это преобразование на данных обучения, а не на весь набор данных. Например, при нормализации квантилей, если пример находится в 60-м процентиле обучающего набора, он получает значение 0,6. (Вы можете также сдвинуть нормированные значения квантиля на 0,5, чтобы 0-й процентиль составлял -0,5, а 100-й процентиль - +0,5).

  • Добавьте регуляризацию, либо увеличив скорость отсева, либо добавив штрафы L1 и L2 к весам. Регуляция L1 аналогична выбору элементов, и поскольку вы сказали, что уменьшение числа функций до 5 дает хорошую производительность, L1 также может быть.

  • Если это все еще не помогает, уменьшите размер вашей сети. Это не всегда лучшая идея, так как это может нанести вред производительности, но в вашем случае у вас есть большое количество нейронов первого уровня (1024) по сравнению с функциями ввода (35), поэтому это может помочь.

  • Увеличьте размер партии от 32 до 128. 128 довольно стандартный и потенциально может повысить стабильность оптимизации.

Ответ 2

Ответ на 1 "неплох. Однако все исправления, по-видимому, устраняют проблему косвенно, а не напрямую. Я бы рекомендовал использовать градиентную обрезку, которая будет просто скопировать любые градиенты, которые превышают определенное значение.

В Keras вы можете использовать clipnorm=1 (см. https://keras.io/optimizers/), чтобы просто скопировать все градиенты с нормой выше 1.

Ответ 3

Я сталкивался с той же проблемой раньше. Я ищу и нахожу этот вопрос и ответы. Все упомянутые выше уловки важны для обучения глубокой нейронной сети. Я перепробовал их все, но все равно получил NAN.

Я также нахожу этот вопрос здесь. https://github.com/fchollet/keras/issues/2134. Я процитировал резюме автора следующим образом:

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

Затем меня осенило. У меня может быть плохой вклад. Оказывается, один из изображения, которые я передавал на мой CNN (и делал нормальную нормализацию на) было только 0. Я не проверял этот случай, когда я вычел среднее и нормализовал по стандартному отклонению и, таким образом, я в конечном итоге с образцом матрицы, которая была ничем иным, как нан. Однажды я исправил мою функцию нормализации, теперь моя сеть работает отлично.

Я согласен с приведенной выше точкой зрения: вход чувствителен для вашей сети. В моем случае, я использую лог-значение оценки плотности в качестве входных данных. Абсолютное значение может быть очень большим, что может привести к NaN после нескольких шагов градиента. Я думаю, что проверка ввода необходима. Во-первых, вы должны убедиться, что входные данные не содержат include -inf или inf, а также некоторые чрезвычайно большие числа в абсолютном значении.

Ответ 4

Я столкнулся с очень похожей проблемой, и вот как я ее запустил.

Первое, что вы можете попробовать, это изменить активацию на LeakyReLU вместо использования Relu или Tanh. Причина в том, что часто многие узлы в ваших слоях имеют активацию нуля, и обратное распространение не обновляет веса для этих узлов, потому что их градиент также равен нулю. Это также называется проблемой "умирающего ReLU" (вы можете прочитать об этом здесь: https://datascience.stackexchange.com/questions/5706/what-is-the-dying-relu-problem-in-neural-networks).

Для этого вы можете импортировать активацию LeakyReLU, используя:

from keras.layers.advanced_activations import LeakyReLU

и включите его в свои слои следующим образом:

model.add(Dense(800,input_shape=(num_inputs,)))
model.add(LeakyReLU(alpha=0.1))

Кроме того, возможно, что выходная функция (непрерывная переменная, которую вы пытаетесь предсказать) является несбалансированным набором данных и имеет слишком много нулей. Одним из способов решения этой проблемы является использование сглаживания. Вы можете сделать это, добавив 1 к числителю всех ваших значений в этом столбце и разделив каждое из значений в этом столбце на 1/(среднее всех значений в этом столбце)

Это существенно сдвигает все значения от 0 до значения больше 0 (которое может быть очень маленьким). Это препятствует тому, чтобы кривая предсказывала 0 с и минимизировала потери (в конечном счете делая это NaN). Меньшие значения влияют сильнее, чем большие значения, но в целом среднее значение набора данных остается тем же.

Ответ 5

Я столкнулся с той же проблемой при использовании LSTM, проблема в том, что мои данные после стандартизации имеют некоторое значение nan, поэтому мы должны проверить входные данные модели после стандартизации, если вы видите, что у вас будет значение nan:

print(np.any(np.isnan(X_test)))
print(np.any(np.isnan(y_test)))

Вы можете решить эту проблему, добавив небольшое значение (0,000001) к Std следующим образом:

def standardize(train, test):


    mean = np.mean(train, axis=0)
    std = np.std(train, axis=0)+0.000001

    X_train = (train - mean) / std
    X_test = (test - mean) /std
    return X_train, X_test

Ответ 6

Я получил убыток как нан в первой же эпохе, как только началось обучение. Решение, столь же простое, как удаление nas из входных данных, сработало для меня (df.dropna())

Я надеюсь, что это помогает кому-то, сталкивающемуся с подобной проблемой

Ответ 7

Я попробовал каждое предложение на этой странице и многие другие безрезультатно. Мы импортировали CSV файлы с пандами, а затем использовали keras Tokenizer с вводом текста для создания словарей и матриц векторов слов. После того, как заметил, некоторые файлы CSV привели к нан в то время как другие работали, вдруг мы смотрели на кодировании файлов и понял, что файлы в формате ASCII не работали с keras, что приводит к nan потери и точности 0.0000e+00; однако файлы utf-8 и utf-16 работали ! Прорвать.

Если вы выполняете текстовый анализ и получаете nan после file -i {input} использования этих предложений, используйте file -i {input} (linux) или file -i {input} (osx), чтобы определить тип вашего файла. Если у вас ISO-8859-1 или us-ascii, попробуйте конвертировать в utf-8 или utf-16le. Не пробовал последнее, но я думаю, что это сработает. Надеюсь, это поможет кому-то очень и очень разочарованному!

Ответ 8

У меня была похожая проблема с моим logloss, MAE и другие были все NA. Я посмотрел на данные и обнаружил, что у меня мало особенностей с NA. Я вменял NA с приблизительными значениями и смог решить проблему.

Ответ 9

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

df=df.dropna()

И это решило мою проблему.