大模型训练时,误差信号要从输出层一路传回输入层,梯度消失就发生在这条回传路上。所谓梯度消失,是误差信号每往回传一层就被削弱一点,传到浅层时已经弱到推不动参数更新,深层网络因此训不动。它不挑模型,只在网络够深、链路够长时格外明显。
信号在链路里怎么变弱
把一次训练拆成三步看。进来的是损失值:模型这一轮预测和目标的差距,被换算成一个数。发生的是反传:这个数沿网络逐层往回分摊,每层算出一个梯度,告诉自己这层和输出偏差的关系。出去的是参数更新:各层按梯度调参数,进入下一轮前向。梯度消失发生在中间那步,分摊时信号逐层衰减。
衰减的机制可以用一个直观画面理解。梯度往回传时,每层都要乘上一个和权重、激活函数导数相关的系数。系数小于一时,乘一次就缩一次,几十层叠下来,浅层拿到的梯度可能只剩原始的几十亿分之一。更新量因此趋近于零,参数几乎不动,梯度爆炸则是同一个过程的失控版本。
一层层看梯度流
靠近输出的层最先收到信号,它们离损失最近,梯度大、更新快,表现就是模型很快学会输出层的表面规律。中间的层收到的信号已经打折扣,学得慢半拍。最靠近输入的层最吃亏,梯度可能小到可以忽略,这些层基本停留在初始状态,相当于白建。
这带来一个训练中的典型现象:损失曲线降得不难看,模型却在需要深层抽象的任务上表现平平。因为真正负责特征提炼的深层没被训起来,出面干活的是浅层套路。代码语料这类需要模式提炼的数据上,这个问题会更暴露。
为什么深层先受影响
原因在于链式求导的连乘结构。误差往回传,每过一层就是一次连乘,层数越多,连乘项越多。任何一个环节的系数偏小,乘积就朝零俯冲,而且越往浅层冲得越狠。这也是为什么早期几层的网络很少遇到它,网络一深,它立刻变成主要矛盾。层数从十几层加到几十层,连乘项数量翻几倍,问题的严重程度是指数级上升的。
激活函数的选择在这里影响很大。让梯度在区间内保持不塌陷的函数,等于给回传链路留了条宽通道;而在某些区间会把输出压平的函数,正好卡在回传要道上。奖励模型训练里同样依赖稳定的反传,缓解手段是同一套思路。
常见的缓解手段
工程上常用的办法有四个。换激活函数,让梯度在更大区间内保持有效,是最基础的一招。加残差连接,给梯度开一条跨层的直达通道,绕过逐层衰减。做归一化,把每层的输出尺度稳住,防止系数整体偏小。改初始化,让起始权重落在梯度友好的区间,从源头提高信号强度。
四招各掐一段链路,改的分别是函数、通路、尺度和起点。
| 缓解手段 | 具体做法 | 掐住链路的哪一环 |
|---|---|---|
| 换激活函数 | 让梯度在更大区间内保持有效 | 给回传链路留一条宽通道,不让梯度塌陷 |
| 加残差连接 | 给梯度开一条跨层的直达通道 | 绕过逐层衰减,不必每层都乘一次 |
| 做归一化 | 把每层的输出尺度稳住 | 防止系数整体偏小 |
| 改初始化 | 让起始权重落在梯度友好的区间 | 从源头提高信号强度 |
这些手段今天已经是标配。用 ModelScope 或 DeepSeek 的开源实现做训练,框架默认配置里大多已经内置。理解梯度消失的价值在于:当损失曲线表现诡异时,你知道该往链路衰减的方向排查,而不是盲目改学习率。
速查表:梯度消失=反传时梯度逐层衰减到零;根因是链式求导的连乘;信号弱的浅层先停工;缓解靠激活函数、残差连接、归一化、初始化四件套。
关于梯度消失,问得最多的三个
- 梯度消失只发生在很深的网络吗?浅层网络链路短,连乘项少,确实很少遇到;网络一深,它立刻变成主要矛盾。
- 损失下降正常能排除梯度消失吗?不能,浅层停工时损失照样降,只是模型学的是表面套路,深层抽象没训起来。
- 调大学习率能救吗?治标不治本,学习率放大会同时放大噪声,甚至诱发梯度爆炸,该修的是链路衰减。


