训练回归网络时的 NaN 损失

NaN loss when training regression network

我在 "one-hot encoding" 中有一个数据矩阵(全为 1 和 0),有 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)] )

然而,在训练过程中,我看到损失减少得很好,但在第二个 epoch 的中间,它变成了 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,我试过有和没有辍学,都无济于事。我尝试了一个较小的模型,即只有一个隐藏层,并且出现了同样的问题(它在不同的点变成了 nan)。然而,它确实适用于较少的特征,即如果只有 5 列,并且给出了相当好的预测。似乎有某种溢出,但我无法想象为什么 - 损失根本不是不合理的大。

Python 版本 2.7.11,运行 在 linux 机器上,仅 CPU。我用最新版本的 Theano 测试了它,我也得到了 Nans,所以我尝试去 Theano 0.8.2 并遇到同样的问题。用最新版的Keras也有同样的问题,用0.3.2版本也一样。

神经网络回归很难工作,因为输出是无限的,所以你特别容易出现 exploding gradients problem(nans 的可能原因)。

从历史上看,梯度爆炸的一个关键解决方案是降低学习率,但随着像 Adam 这样的按参数自适应学习率算法的出现,您不再需要设置学习率来获得良好的性能。除非您是神经网络狂热者并且知道如何调整学习计划,否则几乎没有理由再使用带有动量的 SGD。

以下是您可以尝试的一些方法:

  1. 通过 quantile normalizing or z scoring 标准化您的输出。严格来说,在训练数据上计算这个转换,而不是在整个数据集上。例如,对于分位数归一化,如果示例位于训练集的第 60 个百分位数,则其值为 0.6。 (您还可以将分位数标准化值向下移动 0.5,以便第 0 个百分位数为 -0.5,第 100 个百分位数为 +0.5)。

  2. 添加正则化,通过增加丢失率或向权重添加 L1 和 L2 惩罚。 L1正则化类似于特征选择,既然你说将特征数量减少到5个性能好,L1也可能。

  3. 如果这些仍然没有帮助,请缩小您的网络规模。这并不总是最好的主意,因为它会损害性能,但在您的情况下,相对于输入特征 (35),您有大量的第一层神经元 (1024),因此它可能会有所帮助。

  4. 将批量大小从 32 增加到 128。128 是相当标准的,可能会增加优化的稳定性。

1" 的回答非常好。但是,所有的修复似乎都间接地而不是直接地解决了这个问题。我建议使用渐变裁剪,它将裁剪任何高于特定值的渐变。

在 Keras 中,您可以使用 clipnorm=1(参见 https://keras.io/optimizers/)简单地裁剪所有范数大于 1 的梯度。

我以前遇到过同样的问题。我搜索并找到了这个问题和答案。上面提到的所有这些技巧对于训练深度神经网络都很重要。我都试过了,但还是得到了 NAN。

我也在这里找到这个问题。 https://github.com/fchollet/keras/issues/2134。 我引用作者总结如下:

I wanted to point this out so that it's archived for others who may experience this problem in future. I was running into my loss function suddenly returning a nan after it go so far into the training process. I checked the relus, the optimizer, the loss function, my dropout in accordance with the relus, the size of my network and the shape of the network. I was still getting loss that eventually turned into a nan and I was getting quite fustrated.

Then it dawned on me. I may have some bad input. It turns out, one of the images that I was handing to my CNN (and doing mean normalization on) was nothing but 0's. I wasn't checking for this case when I subtracted the mean and normalized by the std deviation and thus I ended up with an exemplar matrix which was nothing but nan's. Once I fixed my normalization function, my network now trains perfectly.

我同意上面的观点:输入对你的网络很敏感。 在我的例子中,我使用密度估计的对数值作为输入。绝对值可能非常大,经过几步梯度后可能会导致 NaN。我认为输入检查是必要的。首先,您应该确保输入 包括 -inf 或 inf,或一些绝对值非常大的数字。

我尝试了此页面上的所有建议以及许多其他建议,但均无济于事。我们使用 pandas 导入 csv 文件,然后使用 keras Tokenizer 和文本输入来创建词汇表和词向量矩阵。在注意到一些 CSV 文件导致 nan 而其他文件工作后,突然我们查看了文件的编码并意识到 ascii 文件不适用于 keras,导致 nan 丢失和 0.0000e+00 的准确性;但是,utf-8 和 utf-16 文件 有效 !突破.

如果您在尝试这些建议后执行文本分析并得到 nan 损失,请使用 file -i {input} (linux) 或 file -I {input} (osx ) 来发现您的文件类型。如果您有 ISO-8859-1us-ascii,请尝试转换为 utf-8utf-16le。还没有尝试过后者,但我想它也会起作用。希望这可以帮助非常沮丧的人!

训练一开始,我在第一个时期就得到了 nan 的损失。就像从输入数据中删除 nas 一样简单的解决方案对我有用 (df.dropna())

我希望这对遇到类似问题的人有所帮助

我遇到了一个非常相似的问题,这就是我如何得到它 运行。

您可以尝试的第一件事是将激活更改为 LeakyReLU,而不是使用 Relu 或 Tanh。原因是通常,层中的许多节点的激活值为零,反向传播不会更新这些节点的权重,因为它们的梯度也为零。这也称为 'dying 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))

此外,输出特征(您试图预测的连续变量)可能是一个不平衡的数据集,并且有太多的 0。解决此问题的一种方法是使用平滑。为此,您可以将此列中所有值的分子加 1,然后将此列中的每个值除以 1/(此列中所有值的平均值)

这实质上将所有值从 0 移动到大于 0 的值(可能仍然非常小)。这可以防止曲线预测 0 并最小化损失(最终使其成为 NaN)。较小的值比较大的值受到的影响更大,但总体而言,数据集的平均值保持不变。

我的 logloss、MAE 和其他人都是 NA 时遇到了类似的问题。我查看了数据并发现,我几乎没有包含 NA 的特征。我用近似值估算了 NA,并且能够解决这个问题。

我在使用 LSTM 时遇到了同样的问题,问题是我的数据在标准化后有一些 nan 值,因此,如果你看到你有 nan 值,我们应该在标准化后检查输入模型数据:

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

你可以通过像这样向 Std 添加一个小值 (0.000001) 来解决这个问题,

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

我遇到了同样的问题,我正在使用 Keras 解决多元回归问题。后来我意识到,我的数据集中的某些值是 nan,这导致了 nan 损失。 我使用了命令:

df=df.dropna()

它解决了我的问题。

我在使用 keras 时遇到了类似的问题。第二批输入后loss转为NAN

我试过:

  1. 使用softmax作为输出密集层的激活
  2. 在输入中删除 nan
  3. 标准化输入

然而,这并没有奏效。所以,然后我尝试:

  1. 降低学习率

问题已解决。

我的 RNN 与 keras LSTM 层有同样的问题,所以我尝试了上面的每个解决方案。我已经缩放了我的数据(使用 sklearn.preprocessing.MinMaxScaler),缩放后我的数据中没有 NaN 值。使用 LeakyRelU 或改变学习率等解决方案没有帮助。

所以我决定将缩放器从 MinMaxScaler 更改为 StandardScaler,即使我没有 NaN 值,我发现它很奇怪但它起作用了!

我的 keras CNN 遇到了与其他人相同的问题,我尝试了上述所有解决方案:降低学习率、从训练数据中删除无效性、规范化数据、添加丢失层和... 但无法解决 nan 问题,我尝试将分类器(最后)层中的激活函数从 sigmoid 更改为 softmax。有效! 尝试将最后一层的激活函数更改为 softmax!

在我的例子中,问题是我复制粘贴了我之前的二进制分类工作,并在输出层上使用了 sigmoid 激活而不是 softmax(新网络是关于多类分类的) .

总结这里和这个 github 讨论中提到的不同解决方案,这当然取决于您的具体情况:

  • 添加正则化以将 l1 或 l2 惩罚添加到权重。否则,尝试使用较小的 l2 reg。即 l2(0.001),如果已经存在则删除它。
  • 尝试较小的 Dropout 率。
  • 剪辑渐变以防止它们爆炸。例如在 Keras 中你可以使用 clipnorm=1。或裁剪值=1。作为优化器的参数。
  • 检查输入的有效性(没有 NaN 或有时为 0)。即 df.isnull().any()
  • 用更容易处理的 Adam 替换优化器。有时也用 rmsprop 替换 sgd 会有所帮助。
  • 使用具有大量正则化的 RMSProp 来防止梯度爆炸。
  • 尝试规范化您的数据,或检查您的规范化过程是否引入了任何错误值。
  • 验证您使用的激活函数是否正确(例如,使用 softmax 而不是 sigmoid 进行多个 class class化)。
  • 尝试增加批量大小(例如 32 到 64 或 128)以增加优化的稳定性。
  • 尝试降低你的学习率。
  • 检查您最后一批的大小,这可能与批大小不同。

我在尝试创建边界框回归量时遇到了同样的问题。 我的神经网络层数比你的大。我增加了 dropout 值并得到了合适的结果。

如果有 NAN 值,请尝试检查您的数据。删除 NAN 值可以解决我的问题。

正在为我的分类网络获取 NaN。 在这里回答可能对某人有帮助。

犯了一个错误-

训练标签中 类 的数量是 5。即从 0 到 4。

在分类的最后一个密集层中有 4 个节点,这意味着 4 类 这就是问题所在。

将最后一层网络中的节点数更改为 5 解决了我的问题。

我有一个类似的问题,我尝试将我的激活从 Sigmoid 更改为 Softmax,从 RelU 更改为 LeakyRelU,问题得到解决。所以我想只要一开始输入中没有 NaN,并且您已经尝试降低学习率,可行的解决方案就是使用您的激活!

当我的训练数据条目之一包含 nan 时,我遇到了这个问题

我遇到了同样的问题。成功地可以使用 keras 进行回归。 将您的所有数据转换为四舍五入的数字,这解决了我的问题。 例如。 23.43 至 23

我的情况:

Train Loss: nan, Train Accuracy: 0.0, Validation Loss: nan, Validation Accuracy: 0.0

后来我发现是因为我的标签 1, 2, 3, 4 不是以 0 开头的。 所以我重新标记它们,使用 0, 1, 2, 3 而不是 1, 2, 3, 4 作为标签。 问题已解决!

希望我的回答对您有所帮助!

我遇到了同样的问题。查看数据,发现是数据采集出错了

在 keras 中,class 标签从 0 开始。例如,如果您有 7 个 classes,那么要么从 0 到 6 开始标记它们,然后提供最后一个密集层(使用softmax 激活函数),单位 = 7。或者,如果您应该将数据标记为 1 到 7,在这种情况下,您必须设置 units=8(在最后一个密集层中)。

我得到了二进制分类的 nan 值,然后我将损失函数从分类 cross-entropy 更改为 'binary cross entropy',它工作正常。

顺便说一句,它似乎是一个 垂死的梯度 而不是爆炸。

  • 当所有训练实例的输入均为负时,神经元死亡。

here 'adam' 优化器帮助对抗 NaN。 但是关于你的情况 - 可以肯定的是,你有 scaled dataset & loss='mean_squared_error'(与你的相反)

model.compile(optimizer = 'adam', loss = keras.losses.mean_squared_error, metrics=keras.metrics.mean_absolute_error)