TensorFlow简单神经网络训练时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




