【问题标题】:NaN loss when training regression network训练回归网络时的 NaN 损失
【发布时间】:2016-09-10 23:53:16
【问题描述】:

我有一个具有 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,我尝试了有无dropout,但都无济于事。我尝试了一个较小的模型,即只有一个隐藏层,同样的问题(它在不同的点变成了 nan)。但是,它确实适用于较少的特征,即如果只有 5 列,并且给出了相当好的预测。似乎有某种溢出,但我无法想象为什么——损失一点也不大。

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

【问题讨论】:

  • 尝试 loss='mean_squared_error', optimizer='adam' 与单个隐藏层 - 仍然是 nans?
  • @1'' 将上述模型与 Adam 优化器一起使用时,我得到了 nans。只有一层,它不会在三个训练周期中给出 nans。
  • 对于未来的读者,这里是一个相关的 keras 线程。 github.com/keras-team/keras/issues/2134 通过结合这里提到的所有建议,我取得了一些成功。例如添加batchnorm,改变学习率,优化器,添加clip_by_value,clip_by_global_norm,最后,多次梳理代码以查找错误也有帮助,例如在一个卷积层之后缺少批处理规范层。 :)
  • 检查 NAN 值它解决了我的问题... :)

标签: python keras neural-network theano loss-function


【解决方案1】:

在 keras 中,类标签从 0 开始。例如,如果您有 7 个类,则可以从 0 到 6 开始标记它们,并以units=7 提供最后一个密集层(使用softmax 激活函数)。或者,如果您应该从 1 到 7 标记数据,在这种情况下,您必须设置 units=8(在最后一个密集层中)。

【讨论】:

  • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
【解决方案2】:

我遇到了同样的问题。检查数据,我意识到在数据采集过程中发生了错误。

【讨论】:

  • 更多评论
【解决方案3】:

我的情况:

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 作为标签。 问题解决了!

希望我的回答有帮助!

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          犯了一个错误-

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

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

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

          【讨论】:

            【解决方案8】:

            如果有 NAN 值,请尝试检查您的数据。删除 NAN 值为我解决了这个问题。

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                【解决方案10】:

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

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

                【讨论】:

                • 公平点!这是一个完全合法的策略,例如,经常与循环神经网络一起使用。但是,在使用此方法之前,最好检查一下简单的优化是否没有出错。
                • 这应该被标记为正确的解决方案,因为它实际上解决了特定问题,而不是就更广泛的主题提供建议。
                • 同一个 keras 链接表明不再支持渐变剪裁。有类似的解决方案吗?
                • 这对所有优化器都有效吗?设置为 1.0 总是一个好主意吗?
                • 是的,它应该可以跨优化器工作。如果您的优化问题足够简单/稳定,那么这不是必需的,并且可能会减慢训练速度而不会产生任何好处。
                【解决方案11】:

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

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

                【讨论】:

                  【解决方案12】:

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

                  【讨论】:

                    【解决方案13】:

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

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

                    我想指出这一点,以便将其存档以供其他可能 以后遇到这个问题。我遇到了我的损失函数 在它进入训练过程之后突然返回一个nan。 我检查了 relus、优化器、损失函数、我的 dropout 根据relus,我的网络大小和形状 网络。我仍然在失去最终变成了一个nan 我变得非常沮丧。

                    然后我就明白了。我可能有一些不好的输入。事实证明,其中之一 我交给我的 CNN 的图像(并进行平均归一化 on) 只不过是 0。我没有检查这个案子 减去平均值并通过标准偏差归一化,因此我 最终得到了一个示例矩阵,它不过是 nan 的。有一次,我 修复了我的归一化函数,我的网络现在可以完美训练了。

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

                    【讨论】:

                    • 我遇到了和你一样的问题。在检查我的数据时,我发现多个地方有 inf 数据点。把它们拿出来解决了这个问题。
                    • 这解决了我的问题,我的嵌入矩阵中有多个 NaN :) 谢谢。
                    • 我将输入图像 (png) 从 0-255 (uint8) 缩放到 0.-1.(float32),我从来没有想过输入是罪魁祸首....添加一个 tf .clip_by_value 在将输入传递给网络进行训练之前似乎解决了我长达 9 个月的调试之旅......
                    • 另外,请注意np.isnan(np.inf) == False。为确保您的示例不包含 NaN 或 Infs,您可以执行 assert np.all(np.isfinite(X)) 之类的操作。 (这让我多次感到困惑:我认为我的数据很好,因为我正在检查 NaN。但我忘记了 np.isnan 没有注意到 Infs!)
                    • @pangyuteng 您能否详细说明导致您的错误的原因?如果输入总是按 /255 缩放到 0-1,我看不出这会如何导致 NaN...
                    【解决方案14】:

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

                    【讨论】:

                      【解决方案15】:

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

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

                      【讨论】:

                        【解决方案16】:

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

                        我尝试过:

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

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

                        1. 降低学习率

                        问题解决了。

                        【讨论】:

                          【解决方案17】:

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

                          df=df.dropna()

                          它解决了我的问题。

                          【讨论】:

                          • 没错,我们提供给 NeuralNet 的数据中不应该有任何 NaN 值。
                          【解决方案18】:

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

                          【讨论】:

                            【解决方案19】:

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

                            【讨论】:

                              【解决方案20】:

                              我遇到了一个非常相似的问题,这就是我让它运行的方式。

                              您可以尝试的第一件事是将激活更改为 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)。较小的值比较大的值受到的影响更大,但总的来说,数据集的平均值保持不变。

                              【讨论】:

                                【解决方案21】:

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

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

                                【讨论】:

                                • 你是如何从第一个 epoch 中删除 nans 的?在我开始训练之前我有 nans
                                【解决方案22】:

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

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

                                【讨论】:

                                  【解决方案23】:

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

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

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

                                  1. 通过quantile normalizingz 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. 为什么不规范化整个输出集?另外,我可以使用缩放代替吗?
                                  • @Eran 如果您在决定如何规范化时使用整个数据集(训练 + 测试),那么您就是在将有关测试集的信息间接合并到训练集中,这是训练测试的一种形式污染。不过,只要您在决定如何标准化时只使用训练集,您就可以使用缩放或任何其他类型的标准化,以提供良好的性能。
                                  • 检查batch size,发现太小了(16),将batch size增加到128就可以了!
                                  • 我关于批量大小的经验法则是,它应该与内存允许的一样大,但最多为观察次数的 1%。 1% 会给你 100 个随机批次,这意味着你仍然有随机梯度下降的随机部分。
                                  猜你喜欢
                                  • 2021-12-17
                                  • 2020-10-17
                                  • 1970-01-01
                                  • 2016-12-20
                                  • 2021-12-12
                                  • 2020-08-06
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2022-06-14
                                  相关资源
                                  最近更新 更多