训练回归网络时NaN损失


73

我有一个“一键编码”(全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)] )

但是,在训练过程中,我看到损失下降得很好,但是在第二个时期的中间,它就变成了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,仅在CPU上的Linux机器上运行。我使用最新版的Theano进行了测试,并且我也得到了Nans,因此我尝试使用Theano 0.8.2并遇到了同样的问题。与最新版本的Keras具有相同的问题,并且也与0.3.2版本相同。


尝试使用单个隐藏层的loss ='mean_squared_error',optimizer ='adam'-仍然是nans吗?
1英寸

@ 1''将以上模型与Adam优化器一起使用时,我得到了nans。仅一层,它在训练的三个时期内都不会使人烦恼。
The_Anomaly '16

对于将来的读者,这是一个相关的keras主题。github.com/keras-team/keras/issues/2134 通过结合这里提到的所有建议,我取得了一些成功。例如,添加批处理规范,改变学习率,优化器,添加clip_by_value,clip_by_global_norm,最后,多次梳理代码中的错误也有帮助,例如在一个转换层之后缺少批处理规范层。:)
pangyuteng

Answers:


115

由于输出是无穷大的,因此难以使用神经网络进行回归,因此,您特别容易出现爆炸梯度问题(可能是nans的原因)。

从历史上看,爆炸梯度的一种关键解决方案是降低学习率,但是随着像Adam这样的每参数自适应学习率算法的出现,您不再需要设置学习率即可获得良好的性能。除非您是神经网络的恶魔并且知道如何调整学习时间表,否则几乎没有理由再使用SGD了。

您可以尝试以下操作:

  1. 通过分位数归一化z评分对输出进行归一化。为严格起见,请根据训练数据而不是整个数据集计算此转换。例如,使用分位数归一化,如果示例位于训练集的第60个百分位数中,则其值为0.6。(您也可以将分位数归一化值向下移动0.5,以使第0个百分位数为-0.5,第100个百分位数为+0.5)。

  2. 通过增加辍学率或对权重添加L1和L2惩罚来增加正则化。L1正则化类似于特征选择,并且由于您说过将特征数减少到5可以提供良好的性能,因此L1也可以。

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

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


2
关于1.为什么不规范整个输出集?另外,我可以改用缩放吗?
伊兰(Eran)

9
@Eran如果在决定如何进行归一化时使用整个数据集(训练+测试),则会将有关测试集的信息间接合并到训练集中,这是训练测试污染的一种形式。但是,只要在决定如何进行标准化时仅使用训练集,就可以使用缩放或任何其他提供良好性能的标准化。
1 ''

检查批次大小,发现它太小(16),将批次大小增加到128即可!
allenyllee

48

以1“表示的答案是非常好的。但是,所有修复似乎都是间接解决了问题,而不是直接解决了问题。我建议您使用渐变剪切,它会剪切超过某个值的所有渐变。

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


14
有道理!例如,这是一种完全合法的策略,经常与循环神经网络一起使用。但是,在诉诸此方法之前,最好先检查一下简单的优化是否正确。
1

这应被标记为正确的解决方案,因为它实际上解决了特定问题,而不是就更广泛的主题提供建议。
HAL9000

相同的keras链接表明不再支持渐变裁剪。有类似的解决方案吗?
NeStack

这对所有优化程序都有效吗?设置为1.0总是一个好主意吗?
CMCDragonkai

是的,它应该跨优化器工作。如果您的优化问题足够简单/稳定,则不需要这样做,并且可能会使训练变慢而无济于事。
pir

32

我以前也遇到过同样的问题。我搜索并找到此问题和答案。上面提到的所有技巧都对训练深度神经网络很重要。我尝试了全部,但仍然得到了NAN。

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

我想指出这一点,以便将来可能遇到此问题的其他人将其存档。进入训练过程后,我突然遇到了损失函数,突然返回了一个Nan。我检查了规则,优化器,损失函数,根据规则,网络规模和网络形状的辍学情况。我仍然在遭受损失,最终变成了难缠,变得越来越沮丧。

然后它突然降临在我身上。我可能有一些不好的输入。事实证明,我提交给CNN的图像之一(并且进行均值归一化)只不过是0。当我减去均值并通过std偏差对其进行归一化时,我并没有检查这种情况,因此我得到的样本矩阵只是nan。固定归一化功能后,我的网络现在可以完美训练。

我同意以上观点:输入对您的网络敏感。就我而言,我将密度估算的对数值用作输入。绝对值可能会非常大,可能需要经过几步梯度才能得到NaN。我认为输入检查是必要的。首先,您应确保输入中不包含-inf或inf或绝对值中的某些非常大的数字。


我和你有同样的问题。在检查数据时,我发现了多个带有inf数据点的地方。把那些带出去解决了问题。
troymyname00

这为我解决了这个问题,我的嵌入矩阵中有多个NaN :)谢谢。
Aldo Canepa '18

我将输入图像(png)从0-255(uint8)缩放到0.-1。(float32),我从没想过输入是罪魁祸首....在将输入传递给输入前添加tf.clip_by_value。培训的网络似乎解决了我9个月的调试之旅...
pangyuteng

另外,请注意np.isnan(np.inf) == False。为确保您的示例都不包含NaN或Infs,可以执行assert np.all(np.isfinite(X))。(这让我好几次了:我认为我的数据很好,因为我正在检查NaN。但是我忘了np.isnan没有注意到Infs!)
Jack Kelly

13

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

您可以尝试的第一件事是将激活更改为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))

此外,输出功能(您要尝试预测的连续变量)可能是不平衡的数据集,并且具有太多的0。解决此问题的一种方法是使用平滑。您可以通过在此列中所有值的分子上加1并将该列中的每个值除以1 /(此列中所有值的平均值)来完成此操作

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


11

我在使用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

9

总结这里以及本github讨论中提到的不同解决方案,这当然取决于您的特定情况:

  • 添加正则化将权重增加l1或l2罚分。否则,请尝试使用较小的l2 reg。即l2(0.001),或者如果已经存在则将其删除。
  • 尝试较小的辍学率。
  • 裁剪渐变以防止其爆炸。例如,在Keras中,您可以使用clipnorm = 1。或clipvalue = 1。作为优化器的参数。
  • 检查输入的有效性(无NaN或有时为0)。即df.isnull()。any()
  • 用更易于处理的Adam替换优化器。有时也用rmsprop替换sgd会有所帮助。
  • 将RMSProp与重正则化配合使用可防止梯度爆炸。
  • 尝试对数据进行规范化,或者检查规范化过程中是否引入了任何不良值。
  • 验证您使用的是正确的激活功能(例如,使用softmax代替Sigmoid进行多类分类)。
  • 尝试增加批量大小(例如32至64或128)以提高优化的稳定性。
  • 尝试降低学习率。
  • 检查最后一批的大小,该大小可能与批大小不同。

2

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

我希望这可以帮助遇到类似问题的人


1
您是如何从第一个时期删除Nans的?在开始培训之前,我
先要先吃点楠

2

我的keras LSTM层的RNN存在相同的问题,因此我从上面尝试了每种解决方案。我已经按比例缩放了数据sklearn.preprocessing.MinMaxScaler,没有NaN值。使用LeakyRelU或更改学习率等解决方案均无济于事。

所以我决定将缩放器从更改MinMaxScalerStandardScaler,即使我没有NaN值,但发现它很奇怪,但仍然有效!


2

就我而言,问题是我复制粘贴了以前的工作以进行二进制分类,并sigmoid在输出层而不是使用激活softmax(新网络涉及多类分类)。


2

尝试检查您的数据是否有NAN值。删除NAN值可以为我解决问题。


1

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

如果nan尝试这些建议后正在执行文本分析并迷失了方向,请使用file -i {input}(linux)或file -I {input}(osx)查找文件类型。如果你有ISO-8859-1或者us-ascii,尝试转换为utf-8utf-16le。还没有尝试过后者,但是我想它也可以。希望这可以帮助某人非常沮丧!


1

我的logloss,MAE和其他均为NA时也遇到了类似的问题。我查看了一下数据,发现其中几乎没有带有NA的功能。我用近似值估算了NA并能够解决该问题。


1

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

df=df.dropna()

它解决了我的问题。


1

我在使用keras时遇到了类似的问题。输入第二批后,损失变为NAN。

我尝试过了:

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

但是,那没有用。所以,然后我尝试:

  1. 降低学习率

问题解决了。


1

我的keras CNN遇到了同样的问题,就像其他我尝试过上述所有解决方案一样:降低学习率,从训练数据中删除无效性,对数据进行规范化,添加辍学层……从Sigmoid到softmax的分类器(最后)层中的激活函数。有效!尝试将最后一层的激活功能更改为softmax!


0

当我尝试创建边界框回归器时,我得到了同样的东西。我的神经网络比你的神经网络更大。我增加了辍学价值,并得到了合适的结果。


0

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

犯了一个大错-

培训标签中的课程数量为5。即从0到4。

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

将网络最后一层的节点数减少到5可为我解决此问题。


0

我遇到了类似的问题,我尝试将激活方式从Sigmoid更改为Softmax,从RelU更改为LeakyRelU,此问题已解决。因此,我想只要开始时没有输入NaN,并且您已尝试降低学习率,可行的解决方案就是发挥激活作用!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.