You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LeNet-5 CPU实现中Softmax+交叉熵损失函数改写后MNIST识别失效问题排查

LeNet-5 CPU实现中Softmax+交叉熵损失函数改写后MNIST识别失效问题排查

嘿,我来帮你梳理下为啥你的交叉熵+Softmax改写完之后,MNIST识别没效果——毕竟原版本用MSE损失能跑到96%以上的准确率,说明模型架构本身是没问题的。

最可能的原因:学习率不匹配

原代码用的是MSE损失,而交叉熵损失的梯度量级和MSE完全不是一个路子。你写的交叉熵梯度公式softmax输出 - 标签的one-hot向量是对的,但这个梯度的幅度和原MSE损失的梯度差异很大。原来适配MSE的学习率,放到交叉熵上可能太大导致模型发散,或者太小导致训练收敛极慢。

解决办法:把学习率大幅降低试试(比如除以10或者100),多试几个值找合适的范围。比如原学习率是0.01,先改成0.001跑一轮看看效果。

潜在的数值不稳定问题(log(0)风险)

在训练初期或者模型初始化不好的时候,正确标签对应的Softmax概率可能会非常接近0,这时候-log(0)会得到负无穷,直接把数值搞崩,后续的梯度更新全乱套。

解决办法:给log里的数值加个极小的epsilon(比如1e-10),避免出现log(0)的情况:

inner = -log(softmax_output[label] + 1e-10);

这个小数值不会影响损失计算的准确性,但能彻底避免数值异常。

可以优化的冗余代码(不影响功能,但更简洁)

你代码里的softmax_output数组其实是多余的——loss数组在计算完Softmax之后已经存了输出值,直接用它来计算梯度就行,不用额外开数组:

// 计算Softmax
double sum_exp = 0;
for (int i = 0; i < count; ++i)
{
    double exp_val = exp(input[i] - max_input);
    sum_exp += exp_val;
    loss[i] = exp_val;
}
for (int i = 0; i < count; ++i)
{
    loss[i] /= sum_exp;
}
// 现在loss里存的就是Softmax输出,直接用来计算梯度
double inner = -log(loss[label] + 1e-10);
for (int i = 0; i < count; ++i)
{
    loss[i] = loss[i] - (i == label);
}

验证步骤

  1. 先加上epsilon解决log(0)的问题,排除数值异常的可能;
  2. 调整学习率,从原学习率的1/10开始尝试;
  3. 训练时打印损失值inner,如果出现inf或者nan,那就是数值稳定性的锅;如果损失在下降但准确率上不去,基本就是学习率不合适。

备注:内容来源于stack exchange,提问作者bssrdf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 12:13:09