我有一个具有 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 版本。
神经网络的回归很难发挥作用,因为输出是无界的,所以你特别容易出现 exploding gradients problem(可能是 nans 的原因)。
从历史上看,梯度爆炸的一个关键解决方案是降低学习率,但随着像 Adam 这样的每参数自适应学习率算法的出现,您不再需要设置学习率来获得良好的性能。除非您是神经网络爱好者并且知道如何调整学习计划,否则几乎没有理由再使用 SGD 和动量。
以下是您可以尝试的一些事情:
通过分位数归一化或 z 评分来归一化您的输出。严格地说,在训练数据上计算这种转换,而不是在整个数据集上。例如,对于分位数归一化,如果一个示例位于训练集的第 60 个百分位,则它的值为 0.6。 (您也可以将分位数归一化值向下移动 0.5,使第 0 个百分位数为 -0.5,第 100 个百分位数为 +0.5)。添加正则化,可以通过增加 dropout 率或向权重添加 L1 和 L2 惩罚。 L1 正则化类似于特征选择,既然你说将特征数量减少到 5 个可以获得良好的性能,L1 也可以。如果这些仍然没有帮助,请减小您的网络规模。这并不总是最好的主意,因为它会损害性能,但在您的情况下,相对于输入特征 (35),您有大量的第一层神经元 (1024),因此它可能会有所帮助。将批量大小从 32 增加到 128。128 是相当标准的,可能会增加优化的稳定性。
1" 的答案非常好。但是,所有修复似乎都是间接而不是直接解决问题。我建议使用渐变剪裁,它将剪裁任何高于某个值的渐变。
在 Keras 中,您可以使用 clipnorm=1
(参见 https://keras.io/optimizers/)简单地裁剪范数高于 1 的所有渐变。
我以前也遇到过同样的问题。我搜索并找到这个问题和答案。上面提到的所有这些技巧对于训练深度神经网络都很重要。我都试过了,但还是得到了 NAN。
我也在这里找到了这个问题。 https://github.com/fchollet/keras/issues/2134。我引用了作者的总结如下:
我想指出这一点,以便将其存档以供将来可能遇到此问题的其他人使用。在我的损失函数进入训练过程之后,我突然返回了一个 nan。我检查了 relus、优化器、损失函数、根据 relus 的 dropout、我的网络大小和网络的形状。我仍然感到损失,最终变成了一个 nan,我感到非常沮丧。然后我恍然大悟。我可能有一些不好的输入。事实证明,我交给 CNN 的其中一张图像(并进行平均归一化)只不过是 0。当我减去平均值并通过标准偏差进行归一化时,我没有检查这种情况,因此我最终得到了一个示例矩阵,它只不过是 nan 的。一旦我修复了我的标准化函数,我的网络现在就可以完美地训练了。
我同意上述观点:输入对您的网络很敏感。在我的例子中,我使用密度估计的对数值作为输入。绝对值可能非常大,经过几步梯度后可能会导致 NaN。我认为输入检查是必要的。首先,您应该确保输入不包含 -inf 或 inf,或绝对值中的一些非常大的数字。
np.isnan(np.inf) == False
。为确保您的示例不包含 NaN 或 Inf,您可以执行 assert np.all(np.isfinite(X))
之类的操作。 (这让我多次感到困惑:我认为我的数据很好,因为我正在检查 NaN。但我忘记了 np.isnan
没有注意到 Infs!)
我在使用 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
我遇到了一个非常相似的问题,这就是我让它运行的方式。
您可以尝试的第一件事是将激活更改为 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)。较小的值比较大的值受到的影响更大,但总的来说,数据集的平均值保持不变。
总结此处和此 github 讨论中提到的不同解决方案,这当然取决于您的具体情况:
添加正则化以向权重添加 l1 或 l2 惩罚。否则,请尝试使用较小的 l2 reg。即 l2(0.001),或者如果已经存在则删除它。
尝试较小的辍学率。
剪裁渐变以防止它们爆炸。例如,在 Keras 中,您可以使用 clipnorm=1。或剪辑值 = 1。作为优化器的参数。
检查输入的有效性(无 NaN 或有时为 0)。即 df.isnull().any()
用更易于处理的 Adam 替换优化器。有时也用 rmsprop 替换 sgd 会有所帮助。
使用带有大量正则化的 RMSProp 来防止梯度爆炸。
尝试规范化您的数据,或检查规范化过程中是否引入了任何错误值。
验证您是否使用了正确的激活函数(例如,使用 softmax 而不是 sigmoid 进行多类分类)。
尝试增加批量大小(例如,从 32 增加到 64 或 128)以增加优化的稳定性。
尝试降低你的学习率。
检查最后一批的大小,这可能与批次大小不同。
我有同样的问题,我使用 Keras 来解决多元回归问题。后来我意识到我的数据集中的一些值是 nan,这导致了 nan 损失。我使用了命令:
df=df.dropna()
它解决了我的问题。
就我而言,问题是我复制粘贴了我之前的二进制分类工作,并在输出层使用了 sigmoid
激活而不是 softmax
(新网络是关于多类分类的)。
当我的一个训练数据条目包含一个 nan 时,我遇到了这个问题
训练开始后,我在第一个 epoch 就以 nan 的身份遭受损失。像从输入数据中删除 nas 一样简单的解决方案对我有用 (df.dropna())
我希望这可以帮助遇到类似问题的人
我在使用 keras 时遇到了类似的问题。第二批输入后loss变成了NAN。
我尝试过了:
使用 softmax 作为输出密集层的激活 Drop nan in the input 归一化输入
然而,这并没有奏效。所以,然后我尝试:
降低学习率
问题解决了。
我的 RNN 与 keras LSTM 层有同样的问题,所以我尝试了上面的每个解决方案。我已经缩放了我的数据(使用 sklearn.preprocessing.MinMaxScaler
),缩放后我的数据中没有 NaN
值。使用 LeakyRelU 或更改学习率等解决方案没有帮助。
所以我决定将缩放器从 MinMaxScaler
更改为 StandardScaler
,即使我没有 NaN
值并且我发现它很奇怪,但它确实有效!
如果有 NAN 值,请尝试检查您的数据。删除 NAN 值为我解决了这个问题。
我尝试了此页面上的所有建议以及许多其他建议,但均无济于事。我们使用 pandas 导入 csv 文件,然后使用带有文本输入的 keras Tokenizer
创建词汇表和词向量矩阵。在注意到一些 CSV 文件导致 nan 而其他文件工作后,突然我们查看了文件的编码并意识到 ascii 文件不适用于 keras,导致 nan
丢失和 {3 };但是,utf-8 和 utf-16 文件工作!突破。
如果您在尝试这些建议后执行文本分析并丢失 nan
,请使用 file -i {input}
(linux) 或 file -I {input}
(osx) 来发现您的文件类型。如果您有 ISO-8859-1
或 us-ascii
,请尝试转换为 utf-8
或 utf-16le
。没有尝试过后者,但我想它也会起作用。希望这可以帮助非常非常沮丧的人!
我的 logloss、MAE 和其他都是 NA 时遇到了类似的问题。我查看了数据并发现,我几乎没有包含 NA 的功能。我用近似值估算了 NA,并能够解决这个问题。
我的 keras CNN 遇到了同样的问题,就像其他人一样,我尝试了上述所有解决方案:降低学习率,从训练数据中删除空值,规范化数据,添加 dropout 层......但是无法解决 nan 问题,我尝试改变分类器(最后)层中的激活函数,从 sigmoid 到 softmax。有效!尝试将最后一层的激活函数更改为 softmax!
当我尝试创建边界框回归器时,我得到了同样的结果。我的神经网络层比你的大。我增加了 dropout 值并得到了合适的结果。
正在为我的分类网络获取 NaN。在这里回答,因为它可能对某人有所帮助。
犯了一个错误——
训练标签中的类数为 5。即从 0 到 4。
在最后一个密集的分类层中有 4 个节点,这意味着 4 个类,这是问题所在。
将网络最后一层中的节点数更改为 5 为我解决了这个问题。
我遇到了类似的问题,我尝试将激活从 Sigmoid 更改为 Softmax,从 RelU 更改为 LeakyRelU,问题得到了解决。所以我想只要输入中没有 NaN,并且您尝试降低学习率,可行的解决方案就是使用您的激活!
我的情况:
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 中,类标签从 0 开始。例如,如果您有 7 个类,则要么从 0 到 6 开始标记它们,并以单位 = 7 提供最后一个密集层(使用 softmax 激活函数)。或者,如果您应该从 1 到 7 标记数据,在这种情况下,您必须设置 units=8(在最后一个密集层中)。
我得到了二进制分类的 nan
值,然后我将损失函数从分类交叉熵更改为“二进制交叉熵”,并且效果很好。
顺便说一句,它似乎是一个垂死的梯度而不是爆炸。
当所有训练实例的输入为负时,神经元就会死亡。
here 'adam' 优化器有助于对抗 NaN。但就您的情况而言 - 请确保您拥有规模化数据集 & loss='mean_squared_error' (与您的相反)
model.compile(optimizer = 'adam', loss = keras.losses.mean_squared_error, metrics=keras.metrics.mean_absolute_error)
我遇到了同样的问题。成功地您可以使用 keras 进行回归。将您的所有数据转换为解决我的问题的四舍五入数。例如。 23.43 至 23
我有同样的问题。检查数据,我意识到在数据采集过程中发生了错误。