Keras网络训练Loss为nan、准确率无变化问题求助
解决Keras模型训练时Loss为NaN且准确率固定的问题
我完全懂这种卡在NaN损失和纹丝不动的准确率上的挫败感——咱们从你的代码和训练现象入手,一步步排查解决:
一、先排查代码里的潜在风险点
1. 权重初始化与激活函数的冲突
你的第一层用了tanh激活+init='normal'(注意Keras新版本中该参数已更名为kernel_initializer),tanh的饱和区间是±1,如果权重初始化的方差过大,会导致大量神经元的激活值直接饱和到±1,梯度趋近于0,后续更新时极易出现数值不稳定,甚至直接产生NaN。
- 建议把第一层的初始化改成
kernel_initializer='glorot_normal'(即Xavier初始化),它专门针对tanh这类对称激活函数设计,能让输入输出的方差保持一致,避免激活饱和。 - 或者直接把
tanh换成relu,它的抗饱和能力更强,配合he_normal初始化效果会更稳定。
2. 交叉熵损失的数值稳定性问题
你使用的categorical_crossentropy损失,如果模型输出的softmax结果出现极接近0的数值,计算log(0)会直接得到NaN。
- 可以尝试在编译时对损失做数值裁剪,或者如果你的标签是整数形式(而非one-hot),换成
sparse_categorical_crossentropy,它的数值稳定性更好。
3. 优化器与学习率的适配问题
你用的是SGD+0.01的学习率,对于503维输入、1000个神经元的模型来说,这个学习率可能过高——如果存在梯度爆炸的情况,一步更新就会让权重变成NaN。
- 先把学习率降到0.001甚至0.0001试试,或者换成自适应优化器比如Adam,它会自动调整学习率,数值稳定性更优。
二、再深挖数据的隐藏问题
你说已经检查了NaN和做了归一化,但还有几个容易忽略的点要确认:
- 是否存在Inf值? 数据里的无穷大比NaN更隐蔽,用
np.isinf(x_train).any()和np.isinf(y_train).any()检查一下。 - 标签是否完全合规? 确认所有y_train的one-hot向量都是严格的
[1,0]或[0,1],有没有出现[0,0]、[1,1]或其他异常值?这类标签会直接导致交叉熵计算出NaN。 - 归一化是否彻底? 你的输入例子有负数,用的是[-1,1]的归一化?有没有个别特征的数值范围特别极端(比如某个特征最大值是1000、最小值是-1000),导致整体归一化后仍存在异常值?可以用
x_train.max()和x_train.min()查看,确保所有特征都落在合理区间(比如[-1,1]或[0,1])。
三、训练参数的调整
你的batch_size设为1000,对于99804个样本来说,batch size过大——大batch会降低梯度估计的方差,但也更容易出现数值不稳定,尤其是当梯度本身就很大的时候。
- 先把batch_size降到32或64试试,小batch的梯度更新更频繁,数值稳定性更好,也更容易定位问题。
四、调试小技巧
可以在训练前加一段代码,检查模型的初始输出是否异常:
# 取一小批数据,验证模型初始输出 sample_x = x_train[:10] sample_y = y_train[:10] preds = model.predict(sample_x) print("初始预测输出:", preds) print("预测输出的和:", preds.sum(axis=1)) # softmax输出的和应接近1 print("小批量交叉熵损失:", model.evaluate(sample_x, sample_y, verbose=0))
如果初始输出就有0或者无穷大,那问题肯定出在模型初始化或者数据上。
内容的提问来源于stack exchange,提问作者Максим
相关产品推荐
相关产品推荐

