09 从 MLP 到 LeNet:梯度下降到底在做什么?
第11讲 梯度下降到底在做什么?
很多人第一次学到“梯度下降”时,都会有一种很强的不安。
名字听起来很数学,公式看起来也很复杂:
- 梯度
- 求导
- 学习率
- 参数更新
这些词单独看都不陌生,但连在一起时,初学者最容易陷入一种状态:
公式会抄,过程会背,但并不知道它到底在做什么。
更具体一点,很多困惑都集中在下面几个问题上:
- 梯度到底是对谁求的?
- 为什么要对它求导?
- 输入 (x) 也在公式里,为什么不去改输入?
- 模型训练时,到底什么在变,什么不变?
如果这些问题没有想清楚,那后面即使继续学反向传播、神经网络训练,也很容易一直停留在“会写不会懂”的层面。
所以这一讲,我们不急着上来就堆公式,而是先把最核心的一件事讲清楚:
梯度下降,本质上是在根据损失函数的变化趋势,去调整模型参数,让模型犯的错越来越小。
而训练之所以要这样做,是因为机器一开始并不会分类,它是通过大量样本不断调整内部参数,慢慢把判断规则学出来的 。
一、梯度下降到底在解决什么问题?
前面我们已经知道,机器学习不是一个抽象的“让机器变聪明”的过程,而是在学习一种从输入到输出的映射关系。
对于分类模型来说,过程通常是这样的:
- 输入数据进入模型
- 模型给出预测结果
- 预测结果和真实答案之间会有差距
- 我们需要根据这个差距去调整模型参数
其中,模型一开始并不会分类,它只是带着一组初始参数去做计算;之所以后来能识别数字,是因为它在大量样本中不断试错、不断修正,最后学会了一套更好的分类规则 。
于是问题就来了:
既然已经知道模型当前错了多少,那参数到底该怎么改?
这正是梯度下降要解决的问题。
换句话说,梯度下降真正关心的不是“模型会不会分类”,而是:
怎样调整参数,才能让损失函数变小?
二、先把最关键的一点讲清楚:我们到底在对谁求导?
这是初学者最容易卡住的地方。
假设我们现在有一个训练样本:
- 输入:(x)
- 标签:(y)
模型根据当前参数做出预测:
[
\hat{y} = f(x; w, b)
]
然后我们用损失函数来衡量预测和真实答案之间的差距:
[
L = L(y, \hat{y}) = L(y, f(x; w,b))
]
看到这里,很多人会疑惑:
损失函数里面明明有 (x)、(y)、(w)、(b),那我们到底在对谁求导?
答案一定要非常明确:
我们是在对参数求导。
也就是:
[
\frac{\partial L}{\partial w}, \quad \frac{\partial L}{\partial b}
]
而不是去求:
- 输入怎么变
- 标签怎么变
因为训练模型时,当前这一步里:
- 输入 (x) 是给定的数据,视为常量
- 标签 (y) 是标准答案,视为常量
- 真正需要学习、需要调整的是参数 (w,b)
所以从训练的角度看,当前真正的未知数不是输入,而是参数。
这一点必须想清楚,因为后面所有“求梯度”“更新参数”的操作,都是建立在这个前提上的:
我们关心的是:参数稍微变一点,损失会怎么变。
三、为什么输入看成常量,参数看成变量?
因为训练的目标不是改数据,而是改模型。
机器学习的基本框架里,数据提供输入,标签提供标准答案,任务定义了我们到底要学什么。
这些东西一旦确定,在当前训练步骤里就已经是已知的了。
比如一张手写数字图片,它的像素值就是当前输入;
它对应的标签“这是数字 3”,也是已知答案。
训练时我们不会做的事情是:
- 把这张图片偷偷改一改
- 把标签临时换一个
- 让数据去适应模型
我们真正做的是反过来:
让模型的参数去适应数据。
而前面也已经讲过,分类模型的判断能力,本质上就是由参数塑造出来的;学习这件事,说到底就是在调参数 。
所以在求导时:
- (x, y) 看成常量
- (w, b) 看成变量
这是训练过程最自然、也是最核心的视角。
四、为什么我们优化的是损失函数?
这也是很容易被忽略的一点。
很多人会说:
“训练模型不就是为了提高准确率吗?为什么不直接优化准确率?”
因为训练时,我们需要一个可以计算、可以比较、可以优化的目标,而损失函数正是为此存在的 。
损失函数的作用,不是简单判断“对”还是“错”,而是把预测结果和真实答案之间的差距,变成一个可以优化的数值 。
这意味着什么?
意味着:
- 预测错了,损失通常会比较大
- 预测对了,也不代表损失一定很小
- 同样都是预测对,0.51 和 0.99 的把握程度不一样,损失也可能不一样
所以训练不是只关心“最后类别对没对”,而是关心:
当前预测离真实答案到底还有多远。
这就是为什么梯度下降优化的对象不是“准确率”本身,而是损失函数 。
五、梯度到底是什么?
把前面的铺垫都放好以后,现在就可以谈“梯度”了。
如果先只考虑一个参数 (w),那么梯度你可以先理解成:
损失函数对参数 (w) 的导数。
写成公式就是:
[
\frac{dL}{dw}
]
它表示的是:
如果参数 (w) 变动一点点,损失 (L) 会怎样变化。
注意这里的主语一定是“损失函数”。
也就是说,梯度不是一个脱离上下文的抽象概念,
它在训练里说的其实是:
损失函数关于参数的变化趋势。
比如:
- 梯度是正的,说明参数往增大的方向走时,损失倾向于变大
- 梯度是负的,说明参数往增大的方向走时,损失倾向于变小
- 梯度接近 0,说明当前位置可能已经比较平缓了
所以梯度并不是“模型理解了答案”,
它只是告诉我们:
在当前位置,参数往哪边改,更可能让损失下降。
六、为什么叫“梯度下降”?
这个名字其实非常形象。
你可以把损失函数想象成一片地形:
- 地势高的地方,表示损失大,说明模型错得多
- 地势低的地方,表示损失小,说明模型错得少
而模型当前的参数位置,就相当于你站在这片地形中的某个点。
现在我们的目标很简单:
从高处往低处走。
那该怎么走?
最自然的办法是:
- 先看当前位置朝哪个方向上升最快
- 然后不要顺着这个方向走
- 而是朝着相反方向走一步
这就是“梯度下降”的含义:
- 梯度:告诉你上升最快的方向
- 下降:我们偏偏朝相反方向走,让损失变小
所以它本质上并不神秘,
只是一个非常朴素的优化思路:
根据当前位置的局部变化趋势,沿着让损失减小的方向去更新参数。
七、梯度下降的更新公式到底在说什么?
最经典的参数更新公式是:
[
w \leftarrow w - \eta \frac{\partial L}{\partial w}
]
如果模型里还有偏置 (b),那它也会更新:
[
b \leftarrow b - \eta \frac{\partial L}{\partial b}
]
这个公式第一次看很吓人,但拆开以后其实只有三层意思。
1)(\frac{\partial L}{\partial w}) 是什么?
它表示的是:
损失函数对参数 (w) 的导数。
也就是:
如果 (w) 发生一点变化,损失会怎样变化。
这一项一定不能含糊。
因为训练时我们不是在对模型随便求导,而是在对损失函数关于参数求导。
2)(\eta) 是什么?
(\eta) 是学习率。
它决定每次更新时,参数走多大一步。
你可以把它理解成:
- 方向由梯度决定
- 步子大小由学习率决定
3)为什么前面是减号?
因为梯度指向的是“损失上升更快”的方向。
但训练目标是让损失下降,所以我们要朝相反方向走。
因此,更新公式里的核心逻辑就是:
参数的新值 = 参数的旧值 - 学习率 × 损失对参数的梯度
八、先用一个最简单的损失函数,理解“对损失求导”到底是什么意思
一上来就讲神经网络,很容易把问题搞复杂。
所以我们先看一个最简单的例子:
[
L(w) = w^2
]
这里故意把它写成 (L(w)),就是为了强调:
现在我们正在优化的,就是一个损失函数。
问题很直接:
怎样调整参数 (w),让损失 (L(w)) 变小?
第一步:先对损失函数求导
[
\frac{dL}{dw} = 2w
]
这个导数告诉我们:
- 当 (w > 0) 时,梯度是正的
- 当 (w < 0) 时,梯度是负的
- 当 (w = 0) 时,梯度是 0
第二步:按梯度下降公式更新
假设学习率 (\eta = 0.2),那么更新公式就是:
[
w \leftarrow w - 0.2 \cdot 2w
]
如果一开始:
[
w = 4
]
那么:
- 当前损失是 (L(4)=16)
- 当前梯度是 (\frac{dL}{dw}=8)
更新后:
[
w \leftarrow 4 - 0.2 \times 8 = 2.4
]
再来一步:
- 当前损失变成 (L(2.4)=5.76)
- 当前梯度变成 (4.8)
于是继续更新:
[
w \leftarrow 2.4 - 0.2 \times 4.8 = 1.44
]
你会发现,(w) 在逐渐接近 0,损失也在不断下降。
这个例子虽然简单,但它已经完整说明了梯度下降的本质:
先对损失函数关于参数求导,再根据这个导数去调整参数。
九、把“输入是常量,参数是变量”放进模型里看一遍
上面的例子太简单了,没有输入数据。
现在我们看一个更接近机器学习训练的形式。
假设模型非常简单:
[
\hat{y} = wx + b
]
然后定义损失函数:
[
L = (y - \hat{y})^2 = (y - (wx+b))^2
]
注意这个式子里一共有四类量:
- (x):输入
- (y):真实标签
- (w):权重
- (b):偏置
在当前这一步训练时:
- (x) 是给定样本,视为常量
- (y) 是标准答案,视为常量
- (w,b) 是模型参数,视为变量
所以我们真正关心的是:
[
\frac{\partial L}{\partial w}, \quad \frac{\partial L}{\partial b}
]
而不是去改 (x) 或 (y)。
这一点一旦想通,后面哪怕模型从线性模型变成神经网络,本质也没有变。
只不过函数形式更复杂了,但核心仍然是:
研究损失函数随着参数变化会怎样变化。
十、用代码看一遍,梯度下降到底做了什么
下面用一个最小可运行例子,把刚才的过程写成代码。
这里还是用最简单的损失函数:
[
L(w)=w^2
]
对应代码如下:
w = 4.0
lr = 0.2
def loss(w):
return w ** 2
def grad(w):
return 2 * w
for step in range(10):
current_loss = loss(w)
current_grad = grad(w)
print(f"step={step}, w={w:.6f}, loss={current_loss:.6f}, grad={current_grad:.6f}")
w = w - lr * current_grad
输出:
step=0, w=4.000000, loss=16.000000, grad=8.000000
step=1, w=2.400000, loss=5.760000, grad=4.800000
step=2, w=1.440000, loss=2.073600, grad=2.880000
step=3, w=0.864000, loss=0.746496, grad=1.728000
step=4, w=0.518400, loss=0.268739, grad=1.036800
step=5, w=0.311040, loss=0.096746, grad=0.622080
step=6, w=0.186624, loss=0.034829, grad=0.373248
step=7, w=0.111974, loss=0.012538, grad=0.223949
step=8, w=0.067185, loss=0.004514, grad=0.134369
step=9, w=0.040311, loss=0.001625, grad=0.080622
...
这段代码特别适合初学者,因为它把整个过程压缩成了三件事:
- 计算当前损失
- 计算损失函数对参数的梯度
- 根据梯度下降公式更新参数
而且你能非常清楚地看到:
我们求的是损失对参数的导数,不是别的量。
十一、放回机器学习里,梯度下降到底在更新什么?
现在把视角重新放回真正的模型训练。
训练过程通常可以理解成这样一条线:
输入数据 x
→ 模型根据当前参数做计算
→ 得到预测结果
→ 损失函数衡量预测与真实答案的差距
→ 对损失函数关于参数求导
→ 更新参数
这里面,损失函数的作用非常关键:
它把“模型到底错了多少”变成了一个可以计算、可以优化的数值 。
如果没有这一步,参数更新就没有依据,训练过程也无从谈起 。
而前面也讲过,机器并不是突然“懂了”图片,而是在大量数据中不断调整内部参数,慢慢学会了更好的分类规则 。
所以梯度下降真正更新的,就是模型内部这些参数:
- 权重
- 偏置
而不是输入样本本身。
从这个角度看,训练的本质其实很朴素:
模型先犯错,损失函数衡量它错了多少,再通过梯度下降把参数往更合适的方向推。
十二、为什么梯度下降不是“模型突然知道答案了”?
这是一个很常见的误解。
很多人看到“求梯度、更新参数”,容易产生一种感觉:
好像模型一算导数,就突然开窍了。
其实不是。
梯度并不代表模型“理解了问题”,
它只是提供了一个非常局部的信息:
在当前参数位置上,往哪个方向改,更可能让损失下降。
所以梯度下降本质上不是“顿悟”,而是一个反复试错和修正的过程。
这和前面讲机器为什么能识别数字时的逻辑是一致的:
机器不是天生会分类,而是在大量数据中不断调整参数,慢慢把判断规则学出来的 。
十三、学习率为什么也必须一起理解?
更新公式里除了梯度,还有一个非常重要的量:
[
\eta
]
它就是学习率。
很多初学者只盯着“梯度”,却忽略了学习率。
但实际上,梯度决定的是方向,学习率决定的是步子大小。
如果学习率太小
- 每次改动都很保守
- 损失虽然可能持续下降
- 但训练速度会很慢
如果学习率太大
- 参数一步跨太远
- 可能直接越过较优位置
- 甚至来回震荡,训练不稳定
所以一个完整的理解应该是:
- 梯度告诉你该往哪边走
- 学习率告诉你这一步走多大
十四、这一讲最容易混淆的几个点
1. 梯度是对输入求的
不是。
在这一步训练里,输入和标签都是已知量,通常看成常量;我们真正关心的是损失函数对参数的导数。
2. 损失函数只是判断对错
不完全是。
损失函数不是简单判断预测是否正确,而是在衡量预测和真实答案之间的差距到底有多大 。
3. 分类对了,损失就一定很小
不一定。
即使最后分类结果一样,不同置信程度对应的损失也可能不同 。
4. 梯度下降是在更新模型结构
不是。
梯度下降通常更新的是模型参数,而不是任务定义、输入数据或模型结构本身。
5. 梯度下降就是随便调参数
不是。
它不是盲目乱试,而是根据损失函数对参数的变化趋势,有方向地更新参数。
十五、总结
现在回到最开始的问题:
梯度下降到底在做什么?
如果把这一讲压缩成一句话,那么最核心的答案就是:
梯度下降是在对损失函数关于模型参数求导。训练时,把输入和标签看成已知常量,把参数看成待学习的变量;然后根据导数给出的变化趋势,沿着让损失减小的方向一步步更新参数。
再说得更直白一点,就是:
- 数据先进入模型
- 模型给出预测结果
- 损失函数衡量预测和真实答案之间差了多少
- 我们关心“损失对参数的导数”
- 然后按照让损失变小的方向更新参数
- 参数不断被修正后,模型的判断能力也就慢慢形成了
所以梯度下降并不神秘。
它做的事情其实非常朴素:
看当前哪里错了,再朝着“错得更少”的方向改一点。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)