恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

损失函数与交叉熵:从MLP到LeNet如何驱动模型训练

  • 首页
  • 资讯中心
  • /
  • 损失函数与交叉熵:从MLP到LeNet如何驱动模型训练

相关资讯

IP6558车充SOC:单芯片实现PD3.1 45W升降压与硬件级协议闭环 2026/9/12 16:15:08
Envoy Injected Credentials 深入指南:向代理请求注入 Basic Auth、Bearer Token 与 OAuth2 访问令牌 2026/9/12 16:15:08
Beads 的 `bd metrics` 命令:匿名使用指标的状态查看、数据透明与一键开关 2026/9/12 16:15:08

最新资讯

img 的 crossorigin 属性:图片跨域的正确打开方式
ubuntu关键配置
Parallel Web Web Extract 技能实战指南:用 parallel-cli 精准抓取网页、文章与 PDF 内容
Harbor Buzz Orchestra 编排器 Persona 全解:M1 hello-world 团队协作基准的角色设计
Metabase 用户与用户组管理完整指南:账户生命周期、属性配置与权限组设计
VScode设置中文界面

今日推荐

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现
【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)
【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

本周热门

超人会飞不算本事:系统稳定依赖清晰规则与边界设计
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论
基于CNN的调制信号识别:MATLAB实现时频图分类实战

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

损失函数与交叉熵:从MLP到LeNet如何驱动模型训练

发布时间:2026/9/12 16:15:08
损失函数与交叉熵:从MLP到LeNet如何驱动模型训练 最近在复现 LeNet-5 做手写数字识别的时候我盯着训练日志里不断下降的 loss 值突然意识到一个问题我好像一直把“损失函数”当成一个黑盒工具样本扔进去、数值出来然后反向传播更新权重。可如果换个模型——比如一个简单的 MLP——用同样的损失函数、同样的数据训练曲线的形态会有什么不同损失函数到底是在衡量什么换句话说模型的“错”是怎么被量化出来的这篇文章我想把这个看起来太基础、但很容易被忽略的问题讲清楚。我们不只谈公式我会用我实际跑过的 MNIST 实验为例从 MLP 到 LeNet 一路看下来聊聊交叉熵背后的直觉、训练曲线的含义以及那些让我反复排查的 loss 异常场景。你会看到无论模型怎么变损失函数始终在做同一件事定义模型预测与真实答案之间的“距离”。1. 损失函数到底在解决什么问题1.1 损失值不是分数而是“偏航角”当模型拿一个 28×28 的手写数字图像作为输入输出一个 10 维向量时我们怎么知道向量 [0.12, 0.02, 0.31, ...] 和真实标签“7”之间差多远最朴素的想法是看输出向量里哪个位置最大也就是取 argmax然后和真实标签比较一下对错各占一分。这样确实直观但要命的是它没有“程度”信息两个样本都预测错了一个是 0.49 的概率给了错误类另一个是 0.99 的概率给了错误类它们对参数更新的作用完全不一样。损失函数解决的就是这个问题它把“对与错”这种离散事件转换成“偏航角”这种连续信号。模型输出越离谱损失值越大梯度方向就越明确参数更新幅度也越大。反过来如果模型已经比较接近正确答案损失值会比较小梯度也不会太剧烈。所以我会把损失函数理解成“指南针”——它不直接告诉你现在方向对不对但能告诉你偏了多少度该往哪边修。在 MLP 和 LeNet 的经典分类任务中最常见的选择是交叉熵损失Cross Entropy Loss。在 PyTorch 里一个nn.CrossEntropyLoss()就能搞定但这个函数内部其实做了两件事先把上一层输出的 logits 转成概率分布softmax再计算这个概率分布和真实标签 one-hot 分布的“距离”。很多新手刚学的时候会自己写一个softmax然后接一个nn.NLLLoss其实背后的数学和直接调用CrossEntropyLoss一模一样只是用CrossEntropyLoss更稳也少一步中间变量。1.2 损失函数如何“反向驱动”模型更新先撇开卷积神经网络不谈回到最原始的 MLP。假设输入是一张展平后的 784 维图片经过两层全连接、ReLU最后输出 10 个 logits。训练时每个 batch 都会得到一个 loss这个 loss 是一个标量它度量了当前 batch 中模型输出的平均“不合适程度”。计算图会把这个标量一路反向传播到所有可训练参数w1、b1、w2、b2。梯度告诉我们如果稍微增大某个权重loss 会变大还是变小。优化器再按这个方向去更新参数。这就是损失函数更底层的意义它把所有参数对“当前模型好坏”的影响统一到了一个标量上。没有这个标量反向传播就没有源头模型更新也就无从谈起。从 MLP 到 LeNet这个“反向驱动”的机制没有变变的是用以产生 logits 的特征抽取方式。MLP 感受不了图像局部纹理LeNet 能用卷积核捕捉边缘、拐角等局部模式。可损失函数始终是那个“裁判”它判断修正后的 logits 是否更接近真实标签。可以说模型的演化是“特征表达”的演化而损失函数定义的“评分规则”则相对稳定。1.3 用一个小例子看懂交叉熵交叉熵公式看起来干巴巴L - Σ y_i * log(p_i)。其中y_i是真实标签的 one-hot 编码p_i是模型预测的概率。由于真实标签只有一个位置是 1所以公式实际上简化成了L - log(p_c)p_c就是模型分配给正确类别的概率。我当年困在这个公式里很久后来用一个例子才算真正明白。假设三分类任务真实标签是[1, 0, 0]。情况 A模型输出[0.65, 0.20, 0.15]。正确类别的概率是 0.65损失是-log(0.65) ≈ 0.43。情况 B模型输出[0.30, 0.40, 0.30]。正确类别的概率只有 0.30损失是-log(0.30) ≈ 1.20。更大的损失对应更差的预测而且损失之间的差距并不是线性关系从 0.30 提升到 0.65如果直接看准确率都是“预测正确”但交叉熵能精确感知到“信心程度”的变化。这也是为什么训练过程中准确率可能已经到 97% 了loss 还在继续下降——模型正在把正确类别的概率从 0.8 推到 0.9、0.95这对最终 argmax 结果没有影响但对模型内部特征分布的紧凑性有影响。如果你想看它的梯度行为区别更明显。MSE 配上 softmax 容易让梯度变得很小因为 softmax 本身有饱和区MSE 对 logits 的导数会乘上p_i * (1 - p_i)这类项而交叉熵配合 softmax 得出的梯度形式非常干净几乎等价于“预测概率减去真实 one-hot”这意味着错误越明显梯度越大学习效率也更高。这解释了我为什么在绝大多数分类任务里不会优先选 MSE。2. MLP 做 MNIST同一个损失函数踩过的三个坑2.1 数据不均衡时交叉熵也会“说谎”MNIST 本身是比较均衡的数据集但如果你换成自己的分类数据集比如工业质检里的缺陷检测缺陷类别可能只占 1%。这时交叉熵有一个很明显的毛病即使模型把所有样本都预测成“无缺陷”整体损失也不会太大因为每个无缺陷样本的-log(p_non_defect)都很小累积起来仍比少数缺陷样本的损失影响大。模型于是学会偷懒把所有输出概率都调到“无缺陷”类别上。我最初遇到这种情况时看到 loss 一直在下降还觉得训练正常直到看验证集的召回率才发现异常。解决思路也不复杂一是给少数类别一个更大的权重PyTorch 里CrossEntropyLoss(weight...)可以做二是用 Focal Loss 这类改良版本它会让模型更关注难样本。这里的关键是损失函数只是“尺子”尺子刻度偏了测量结果自然失真。2.2 训练损失一直降验证损失却反弹该信谁MLP 在小数据集上特别容易过拟合。我印象很深的一次是训练到 40 个 epoch 后训练 loss 稳定降到 0.02验证 loss 却在 0.15 附近开始反弹准确率也不动了。这说明模型开始“死记硬背”训练样本的噪声而不是学习通用特征。这个问题不是损失函数本身错了而是训练目标与泛化目标不一致。训练损失衡量的是模型对训练集分布的拟合程度验证损失衡量的是对未知数据的预测能力。日常训练时我应该同时盯两个曲线如果训练 loss 下降而验证 loss 持续上升就该考虑早停、加 Dropout 或减小模型容量。损失函数本身不会提醒你过拟合它只是忠实地报告“训练集误差”和“验证集误差”。后来我习惯在训练脚本里加一个最简单的早停逻辑当验证 loss 连续几个 epoch 不再下降时保存当前最佳模型并停止训练。这比固定 epoch 数要稳得多。2.3 logits、softmax 和损失函数的分工另一个常见的坑是混淆模型输出和概率。很多教程会画一个“输出经过 softmax 得到概率再计算损失”的流程图但实际工程里nn.CrossEntropyLoss接收的是裸 logits而不是 softmax 之后的结果。原因是 softmax 在数值上等价于一个“归一化指数函数”直接作用到 logits 上会得到一个和为 1 的概率向量但如果在进入损失函数之前显式做 softmax中间变量会带来额外的数值误差尤其当 logits 比较大时exp可能溢出。PyTorch 的实现把 softmax 和 log 融合在了一起内部做了数值稳定处理我们在外部就不需要也不能再传 softmax 后的值。推理时如果想看概率再单独用softmax也不迟。训练阶段只保留 logits 和标签作为损失函数的输入是最标准也最稳妥的做法。我记得刚开始写 MLP 代码时总喜欢在 forward 最后加一个torch.softmax然后再把结果送进CrossEntropyLoss结果训练得非常慢后来才反应过来这个操作画蛇添足。从这件事也能看出理解损失函数的输入输出格式有时候比背公式更重要。3. LeNet-5卷积网络里的损失函数为什么没变3.1 从 MLP 到 LeNet变化的只是特征抽取方式LeNet-5 是 1998 年提出的经典卷积网络结构大致是“卷积-池化-卷积-池化-全连接-全连接-输出”。它的设计动机很朴素图像是二维结构用全连接网络把像素铺平后会丢掉空间位置关系。而卷积层用一个小窗口滑过整张图天然保留了局部邻域特征。但只要我们还在做分类任务最后输出层仍然是一个 10 维向量损失函数仍然可以选择交叉熵。换句话说MLP 和 LeNet 的“模型骨架”发生了变化但“训练信号”的作用机制没有变化。LeNet 里的卷积核、池化层负责把原始像素逐步抽象成更高级的特征最后一层全连接把这些特征映射成类别得分交叉熵负责衡量这些得分与真实标签的一致性。我体会到这种“变化中的不变”是在把训练好的 LeNet 权重拿出来可视化卷积核时。前几层卷积核学到的是边缘、颜色斑块很像人类视觉皮层对低级特征的响应。这些特征让 logits 更容易区分不同数字损失函数于是更快下降。损失函数本身没有参与提取特征但梯度通过它传到卷积核决定了卷积核更新方向。3.2 相同损失函数训练曲线形态完全不同我之前在同一台机器、同一份 MNIST 数据上对比过一个两层 MLP 和一个简化版 LeNet-5。初始学习率都设成 0.01batch size 都是 64损失函数都是CrossEntropyLoss。MLP 的 loss 曲线下降得很猛前 5 个 epoch 就能从 2.3 掉到 0.8 左右但后面会慢慢钝化最终验证准确率大约在 97%。LeNet 的前 5 个 epoch 下降幅度略小因为卷积层参数更多、特征提取更复杂但曲线的尾部更平滑验证准确率能到 99% 以上。损失函数在两者中只是“裁判”但两个模型对训练数据的拟合方式不同loss 曲线的形状就不同。需要提醒的是这里的“下降略慢”不代表 LeNet 更差。它的特征表达更有效所以在后续 epoch 中能持续学习到更精细的模式。而 MLP 很早就开始陷入过拟合或饱和状态loss 下降速度会明显放缓。看曲线时不能只看前几个 epoch要把整个训练趋势放在同一个坐标系里看。3.3 卷积网络里也能从损失值窥见特征质量有一个小试验我做过三次每次都很有意思把 LeNet 的最后一层全连接从 10 维换成一个更大的中间层比如 256 维然后在验证集上把倒数第二层的特征拿出来做可视化比如 TSNE。一旦分类损失降得够低特征空间里同一类别的点会聚成明显的簇。这说明损失函数不仅在驱动参数也在推动特征空间发生“聚类形变”。从这个角度理解损失函数衡量的是“特征好不好用”而不是“特征长什么样”。同一份数据用 LeNet 训练出的特征比 MLP 更贴近类别边界是因为卷积结构给特征提取带来了归纳偏置。损失函数只需要负责判断“类别得分是否合理”剩下的事情交给模型结构去表达。所以从 MLP 到 LeNet损失函数没有从交叉熵变成别的什么真正改变的是“谁在提供特征”。对初学者来说不要太纠结于“卷积网络应该配什么损失”先理解损失函数衡量的是预测分布与真实分布的差异再去调整结构思路会清晰很多。4. 损失函数的现代演变从图像分类到目标检测与 LLM4.1 分类任务里的加权交叉熵和 Focal Loss交叉熵在类别均衡时很有效但真实场景很少有完美的均衡数据。加权交叉熵是最直接的改进给样本量少的类别乘一个更大的权重让它的 loss 在总损失中占据更高比例。PyTorch 里这样写weights torch.tensor([1.0, 1.0, 5.0, ...]) loss_fn nn.CrossEntropyLoss(weightweights)这个方法简单有效但权重设置需要经验设太大容易让模型在少数类上过拟合设太小又起不到作用。Focal Loss 是另一个思路它在交叉熵基础上增加一个(1 - p_t)^γ调制因子。p_t是模型对正确类别的预测概率γ 0会让已经分得很好的样本贡献的 loss 变小从而让模型把注意力放到困难样本上。目标检测里常见的前景背景不平衡问题用 Focal Loss 效果很好。这算是交叉熵在分类领域的一次重要演化。4.2 YOLO 系列里的“组合损失”目标检测任务不再只是输出一个类别概率还要回归边界框位置。所以 YOLO 系列的损失函数通常是一个多任务组合包含分类损失、定位损失和置信度损失。分类部分用的是交叉熵或其变体定位部分常用 CIoU Loss置信度部分用 BCE Loss。以 YOLOv8 为例它的 loss 由多个分支组成在训练日志里会看到box_loss、cls_loss、dfl_loss几项。它们各自承担不同的职责cls_loss衡量预测类别是否正确box_loss衡量预测框和真实框的重合程度dfl_loss用于优化边界框的分布建模。最终总损失是它们的加权和。这启发我重新理解损失函数的角色当任务变得复杂损失函数也会变成“多裁判”体系。每个分支有自己明确的衡量目标模型在多个目标之间做权衡。如果你在训练一个检测模型只看总 loss 可能掩盖某个分支的问题比如box_loss在降而cls_loss在涨这需要拆开来看。4.3 LLM 预训练里的交叉熵还是那个交叉熵很多人以为大模型预训练的损失函数会复杂到看不懂其实核心还是交叉熵。语言模型的任务是“给定前文预测下一个 token”输出层会在词表大小上产生一个概率分布真实标签是下一个 token 的 one-hot 向量损失函数同样是-log(p_next_token)。只不过词表可能有几万甚至十几万个 token算力消耗大但公式本质没变。如果你在训练一个 GPT 风格的小模型torch 的CrossEntropyLoss完全可以胜任只需注意输入形状是[batch, seq_len, vocab_size]标签是[batch, seq_len]通常要先把 logits 和标签展平或者使用支持多维输入的版本。理解了这一点再去看llm 预训练 损失函数这个热词相关的讨论你会发现大家争论的往往不是“用什么损失”而是“数据质量和训练稳定性如何影响损失变化”。4.4 不同任务怎么选损失函数我给自己总结了一套最简单的选择思路任务类型典型损失说明多分类CrossEntropyLoss默认选择配合 softmax多标签分类BCEWithLogitsLoss每个类别独立判断目标检测Cls Loss Box Loss DFL多任务加权组合回归MSELoss / SmoothL1Loss对离群点敏感度不同类别不均衡Weighted CE / Focal Loss让模型关注难样本遇到新任务我一般用最经典的损失函数起步跑通 baseline再根据失败样本去调损失或权重。一上来就设计花哨的损失函数往往本末倒置。5. 损失函数使用与排查的实战心得5.1 损失变成 NaN最先检查什么训练中途 loss 变成 NaN几乎每个炼丹的人都会遇到。结合我从 MLP 到 LeNet 的实践经验最常见的排查顺序是检查学习率是不是太大。之前用 0.1 的学习率训练一个小 CNNloss 在前几个 step 就变成 NaN降到 0.001 后恢复正常。梯度爆炸是 NaN 的头号原因。检查数据里有没有 NaN 或无穷值。图像任务里虽然少见但某些预处理不小心用了除以 0 的归一化会出现这个问题。检查标签是否越界。比如类别数是 10但标签里出现了 10这会让损失内部索引出错。检查模型输出是否未经过数值稳定处理。如果自己手写 softmax遇到特别大的 logits 可能溢出建议直接用框架自带损失。我还习惯在训练脚本里加一个断言如果 loss 是 NaN立刻终止训练并 dump 当前 batch 的数据和模型输出。这比事后看日志高效得多。5.2 损失下降但准确率不涨问题出在哪这种情况看着最让人抓狂loss 在降测试准确率却原地踏步。我总结了几类原因类别不均衡。模型可能只是在调整输出概率的“置信度”但没有改变最终的 argmax 结果。模型容量不足。损失下降来自拟合训练集噪声对验证集没有泛化能力。评估指标与损失目标不一致。比如用交叉熵优化但评价用的是 F1两者不一定同向变化。遇到这种情况我不会盲目调损失函数而是先看数据和标签有没有问题再看评估脚本是否正确。很多时候不是损失函数设计错了而是“裁判”和“观众”的标准不一致。没必要把验证 loss 当作天条。我的原则是训练 loss 用来判断模型是否收敛验证 loss 用来判断是否过拟合最终以业务指标为准。如果验证 loss 已经很低但线上效果不行可能是训练集分布与真实分布不一致这时候要回头处理数据而不是继续优化损失函数。5.3 用验证集损失做早停注意什么早停Early Stopping是我常用的技巧但有一个前提验证集不能太小否则验证 loss 噪声会很大导致早停误判。我用 MNIST 时验证集 10000 张图相对比较稳定但如果只有几百张验证 loss 波动会很大建议用更大的验证集或者对验证损失做平滑后再判断。另一个细节是保存模型的时机我一般会保存验证 loss 最低时的权重而不是最后一个 epoch 的权重。因为最后几个 epoch 可能已经过拟合了。即使不需要严格早停把“最佳验证损失”对应的模型存下来也几乎不会亏。5.4 绘制和观察损失曲线的实操建议很多人问怎么画 loss 曲线其实很简单。训练时把每个 step 或每个 epoch 的 loss 记录到列表里最后用 matplotlib 画出来。但要注意三点每个 step 的 loss 波动大建议用滑动平均或按 epoch 聚合后再画曲线会更平滑。训练 loss 和验证 loss 要画在同一张图里方便观察过拟合拐点。如果用的是 YOLO 这类多任务模型最好把每个分支的 loss 分开画只看总 loss 会漏掉很多信息。我通常在训练脚本里埋一个history字典记录train_loss、val_loss、train_acc、val_acc训练完直接pd.DataFrame(history).plot()很省事。观察曲线时重点看趋势不要被单次波动吓到。6. 损失函数是训练过程中的“北极星”从 MLP 到 LeNet再到后来的 YOLO 和 LLM模型结构越来越复杂但损失函数始终扮演着“北极星”的角色它告诉我们当前位置与目标的距离也决定了接下来该往哪个方向调整。我早期踩过不少坑总喜欢一遇到效果不好就换损失函数后来才明白损失函数不是万能药。它更像一个仪表盘能不能用好取决于模型结构、数据质量、学习率调度等一系列配套因素。就拿最基础的交叉熵来说它在 MNIST 上配合 LeNet 稳得一批但换到不均衡数据场景就得考虑加权或者 Focal Loss。损失函数的选择本质上是对“任务目标”的数学化表达。最后再说一个小技巧也是我最近才养成的习惯每次开始一个新训练任务我会先把损失函数和评估指标的公式都写在实验笔记里再对照着看训练曲线。这看起来有点多余却能让你在模型不收敛时迅速定位问题——到底是“模型在优化一个错误的目标”还是“目标没表达好”一清二楚。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号