TensorFlow模型训练准确率始终为0且loss为NaN,求问题排查
解决训练准确率为0且Loss为NaN的问题
核心问题根源
- 损失函数与标签不兼容:
SparseCategoricalCrossentropy专门用于多分类任务,要求标签是从0开始的连续非负整数(比如0、1),但你的标签是1和-1,这会直接导致损失计算出现NaN,模型完全无法学习。 - 输出层与任务不匹配:当前是二分类任务,你用了2个神经元的输出层,但搭配错误的损失函数,导致模型输出和标签无法对应,准确率始终为0。
- 数据未归一化:输入数据如果没缩放到合理范围(比如0-1),容易引发梯度爆炸,也是Loss出现NaN的常见原因。
具体修复方案
方案1:调整标签适配原损失函数
把标签从[-1,1]转换为[0,1],让它符合SparseCategoricalCrossentropy的要求:
import numpy as np # 转换标签:-1替换为0,1保持不变 train_labels = np.where(train_labels == -1, 0, train_labels) # 把标签从(7000,1)转为一维数组(7000,),避免形状不匹配问题 train_labels = train_labels.flatten() # 模型结构可以保留,输出层对应2类 model = tf.keras.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28, 5)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(2)]) model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) model.fit(X_train, train_labels, epochs=10)
方案2:改用二分类专用损失函数(更推荐)
直接用BinaryCrossentropy,同时调整输出层为1个神经元(二分类任务的标准配置):
import numpy as np # 可选:把标签转成0/1,不转的话需确保损失函数适配,但转后更直观 train_labels = np.where(train_labels == -1, 0, train_labels) train_labels = train_labels.flatten() model = tf.keras.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28, 5)), tf.keras.layers.Dense(128, activation='relu'), tf.keras.layers.Dense(1, activation='sigmoid')]) # 二分类用1个神经元+Sigmoid激活 model.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy(), metrics=['accuracy']) model.fit(X_train, train_labels, epochs=10)
数据预处理必做检查
- 排查异常值:检查输入数据是否存在NaN或无穷大值:
print(np.isnan(X_train).any()) print(np.isinf(X_train).any())
如果结果为True,需要清理这些异常数据。
- 归一化输入:将输入数据缩放到0-1范围,避免梯度爆炸:
X_train = X_train / 255.0 X_test = X_test / 255.0
关键提醒
你换了CNN、逻辑回归等多种模型都无效,核心问题都出在标签与损失函数不匹配上,先解决这个基础问题,再测试不同模型的效果。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

