You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

TensorFlow简单神经网络训练时loss始终为nan的原因排查

解决神经网络Loss始终为NaN的问题

我帮你梳理下导致Loss变成NaN的几个常见原因,结合你的代码来看,优先排查这些点:

1. 输入特征未做归一化/标准化

这是最常见的原因!你的代码里直接把CSV读进来转成float32就喂给模型了,如果不同特征的数值范围差异极大(比如有的特征是几百上千,有的是0.001),会导致神经网络前向传播时数值爆炸,反向传播梯度溢出,最终Loss变成NaN。

解决方法:用标准化把特征缩放到均值为0、方差为1的范围,或者用归一化缩放到0-1之间。比如用sklearn的StandardScaler

from sklearn.preprocessing import StandardScaler

# 先把pandas转成numpy(你已经做了xtrain = xtrain.values)
scaler = StandardScaler()
xtrain = scaler.fit_transform(xtrain)
xtest = scaler.transform(xtest)

2. 标签格式与损失函数不匹配

你用的是tf.nn.softmax_cross_entropy_with_logits,这个函数对标签的格式有明确要求:

  • 如果标签是one-hot编码(比如每个样本是[0,1,0,0,0]这样的数组),那没问题,但要确保标签里只有0和1,没有NaN或其他异常值;
  • 如果标签是类别索引(比如每个样本是0-4的整数),那应该用tf.nn.sparse_softmax_cross_entropy_with_logits,否则会因为把整数当成概率分布计算,导致数值异常。

检查与解决

  • 先打印ytrain[:5]看看标签格式;
  • 如果是类别索引,修改损失函数部分:
with tf.name_scope("loss"):
    # 若y是one-hot则转成索引,若y本身是索引直接传y即可
    y_labels = tf.argmax(y, 1)
    loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y_labels))

3. 学习率相对过高(未归一化放大了问题)

虽然你用的是0.001的学习率,但如果数据没归一化,这个学习率相对于超大的特征值来说可能还是太大,导致参数更新时一步迈得太大,数值溢出成NaN。

解决方法:先尝试把学习率调小到0.0001,同时配合数据归一化一起测试。

4. 数值不稳定(ReLU+大输入导致溢出)

ReLU激活函数在输入很大时会直接输出对应大值,导致后续层的logits数值极大,计算softmax时e^超大数会变成无穷大,进而Loss变成NaN。

解决方法:在隐藏层后加入Batch Normalization稳定数值分布:

with tf.name_scope("dnn"):
    he_init = tf.contrib.layers.variance_scaling_initializer()
    hidden1 = tf.layers.dense(X, n_hidden1, kernel_initializer=he_init, name="hidden1")
    # 加入BatchNorm
    bn1 = tf.layers.batch_normalization(hidden1, training=training, momentum=0.9)
    hidden1_act = tf.nn.relu(bn1)
    
    hidden2 = tf.layers.dense(hidden1_act, n_hidden2, kernel_initializer=he_init, name="hidden2")
    bn2 = tf.layers.batch_normalization(hidden2, training=training, momentum=0.9)
    hidden2_act = tf.nn.relu(bn2)
    
    logits = tf.layers.dense(hidden2_act, n_outputs, name="outputs")

然后训练时记得传入training=True

sess.run(training_op, feed_dict={X: xtrain, y: ytrain, training: True})

5. 数据本身存在NaN/无穷大值

检查你的训练/测试数据里有没有缺失值或异常值,比如CSV里的空白、'NA',转成float32后会变成NaN,导致模型计算异常。

检查代码

print("xtrain是否有NaN:", np.isnan(xtrain).any())
print("xtrain是否有无穷大:", np.isinf(xtrain).any())
print("ytrain是否有NaN:", np.isnan(ytrain).any())
print("ytrain是否有无穷大:", np.isinf(ytrain).any())

如果输出True,需要先处理数据,比如用均值填充NaN,或者删除异常样本。


建议你按顺序排查:先检查数据有没有异常值,然后做特征归一化,再看标签和损失函数的匹配问题,这几个步骤大概率能解决Loss为NaN的问题。

内容的提问来源于stack exchange,提问作者moritz

火山引擎 最新活动