讲解稿 · 第 03 章第 05 节:优化¶
口播时长:约 15–20 分钟|建议语速:中速,公式处停顿两拍|字数:约 4300 字
导语(约 80 秒)¶
先给你一个画面。
你站在一座起雾的山坡上,目标是走到最低点。你看不见整座山,也没有地图。你只能用脚感受当前位置往哪个方向下降最快,然后迈一步,再感受一次。步子太小,半天走不到;步子太大,可能直接跨过谷底,在两边来回震荡。
训练机器学习模型时,计算机面对的就是这座山。山的高度是损失函数,你站的位置是模型参数,向下迈步就是更新参数。区别只在于:真实神经网络的“山坡”不是二维或三维,而可能有几百万甚至几十亿个方向。
比如损失函数
把当前位置取成 \((0, 0)\),损失是 \(10\);最低点在 \((3, -1)\),损失是 \(0\)。优化要回答的不是“最低点长什么样”,而是:只利用当前位置的局部信息,怎样一步步走到那里?
这正是这一节要解决的问题。前面四节我们学会了求导、求梯度、做泰勒近似,今天我们把它们用到极致。
复习昨日 & 今日路线(约 50 秒)¶
上一节讲了函数逼近:用泰勒级数把复杂函数换成多项式。今天你会看到,一阶泰勒给出梯度下降,二阶泰勒给出牛顿法。这不是巧合,是同一套工具的不同用途。
再回引 Ch02 §04 的核心框架:线性映射可以由矩阵表示。今天我们会把它兑现到微积分里——导数描述局部线性变化,梯度和 Jacobian 就是这种线性映射的矩阵表达。
下一节将进入概率与统计的世界:那是从确定性的微积分跨入不确定性的第一步。
核心概念一:临界点只是候选人,不是获奖者(约 3 分钟)¶
1. 直觉¶
在一维曲线上,谷底和山顶通常有一个共同特征:切线水平,瞬时斜率为零。
因此,找极值的第一步不是直接找最低点,而是先找导数的零点。不过这里容易踩坑:斜率为零,只说明这一刻变平了,不保证函数随后掉头。
2. 定义与定理边界¶
\(f'(c) = 0\) 时,\(c\) 称为函数 \(f\) 的临界点 (critical point)。例如对
有
所以临界点是 \(x = -1\) 和 \(x = 1\)。
这是定义:它规定“临界点”这个名字怎样使用,不需要从其他结论推出。
接着使用二阶导数检验定理。若 \(f'(c) = 0\),那么:
- \(f''(c) > 0\),则 \(c\) 是局部极小点;
- \(f''(c) < 0\),则 \(c\) 是局部极大点;
- \(f''(c) = 0\),检验没有结论。
这三条是从导数理论推出的定理,不是独立定义,更不是公理。
3. 例子¶
继续算刚才的函数:
在 \(x = -1\) 处,
所以 \(x = -1\) 是局部极大点。
在 \(x = 1\) 处,
所以 \(x = 1\) 是局部极小点。
黑板动作:画一条先升、后降、再升的三次曲线;在 \((-1, 2)\) 画水平切线并标“极大”,在 \((1, -2)\) 画水平切线并标“极小”。
4. 反例¶
取一个纯净反例:
它在 \(x = 0\) 满足 \(g'(0) = 0\),但 \(0\) 左右函数都保持递增,没有从降变升,也没有从升变降。因此 \(x = 0\) 不是极大点或极小点,而是水平拐点。再算
这不表示“既是极大又是极小”,只表示二阶导数检验失效。
5. 一句话总结¶
导数为零负责筛选候选点,二阶导数负责判断局部形状。
学生常问
- 问:不可导的点会不会也是极值点?
答:会,例如 \(|x|\) 在 \(x = 0\) 取得极小值,但导数不存在,所以完整搜索还要检查不可导点和区间端点。 - 问:\(f''(c) = 0\) 后怎么办?
答:看一阶导数左右符号、更高阶导数,或直接比较附近函数值。
⏸️ 暂停思考 · 第一次
对 \(h(x) = x^4\),有 \(h'(0) = 0\)、\(h''(0) = 0\)。二阶检验失效,但 \(h(x) \geq 0 = h(0)\)。所以 \(x = 0\) 是什么点?
答案:全局极小点。请留意,“检验失效”不等于“没有极值”。
核心概念二:凸性决定局部低谷是否可信(约 3 分钟)¶
1. 直觉¶
把函数图像想成一只碗。若碗里没有暗坑,小球停下的位置就是整体最低处;若地形高低起伏,小球可能停在某个局部低谷,却错过更低的位置。
2. 定义与推论边界¶
函数 \(f\) 是凸函数 (convex function),是指对任意 \(x, y\) 和 \(t \in [0, 1]\),
例如取 \(f(x) = x^2\)、\(x = 0\)、\(y = 2\)、\(t = \frac12\):
几何上,这表示图像上两点之间的弦不落到图像下方。这是凸性的定义。
若二次可导且整个区间内 \(f''(x) \geq 0\),则 \(f\) 为凸函数;凸函数的每个局部极小点都是全局极小点。这些是由定义推出的判据与定理。
但凸函数不保证极小点唯一。例如常数函数 \(f(x) = 0\) 是凸函数,每个点都是全局极小点。只有再叠加严格凸等条件,才可保证至多一个极小点。
3. 例子¶
看二次函数
它的一阶、二阶导数分别是
所以它严格凸。令 \(f'(x) = 0\) 得 \(x = 3\),并且
由于凸性,这不只是局部极小值,也是全局极小值。
4. 反例¶
取
它不是凸函数,因为
在 \(x = -1\) 和 \(x = 1\) 都有全局低谷,中间 \(x = 0\) 还有局部高点。这个反例只破坏凸性,不涉及不可导或边界问题。
5. 一句话总结¶
凸性保证局部极小可信;严格凸性进一步排除多个极小点。
学生常问
- 问:看到 \(f''(c) > 0\),能否断言函数全局凸?
答:不能;单点二阶导数只描述单点附近,凸性要求整个定义域满足条件。 - 问:神经网络损失通常凸吗?
答:通常不凸,因此实际训练只能依靠算法、初始化和经验寻找足够好的解。
核心概念三:梯度是局部线性映射,也是最陡上升方向(约 4 分钟)¶
1. 直觉¶
在二维山坡上,斜率不再只有一个。向东、向北、向东北走,高度变化都可能不同。我们需要一个对象,把所有方向的局部变化一次装进去,这就是梯度。
2. 定义,以及与 Ch02 的连接¶
对标量函数 \(f: \mathbb{R}^n \to \mathbb{R}\),梯度定义为
\(\nabla f\) 读作“\(f\) 的梯度”,它由所有偏导数组成。数字例:若
则
现在兑现 Ch02 §04 的“线性映射 = 矩阵”框架。微分把很小的输入变化 \(d\mathbf{x}\) 映射成输出变化 \(df\):
这里 \(J_f\) 是 \(f\) 的 Jacobian 行向量,形状为 \(1 \times n\);梯度默认是列向量,形状为 \(n \times 1\),所以
例如在 \((1, 2)\) 处取 \(d\mathbf{x} = (0.01, -0.02)^\top\):
这就是一次 \(1 \times 2\) 乘 \(2 \times 1\) 的矩阵乘法。单变量时更简单:
其中 \(f'(x)\) 是 \(1 \times 1\) 矩阵。于是“导数是斜率”和“导数是局部线性映射”并不冲突:前者是一维直觉,后者是能推广到高维的表达。Ch02 矩阵乘法框架今天终于在微积分里落地。
3. 例子:梯度下降¶
由于梯度指向最陡上升方向,要下降就取反方向:
\(\eta\) 是学习率 (learning rate),表示每次沿负梯度走多远。数字例:再考虑
有
从 \(\mathbf{x}_0 = (0, 0)^\top\) 出发,取 \(\eta = 0.1\):
Step 1:算梯度
Step 2:更新参数
Step 3:验算损失
损失从 \(10\) 降到 \(6.4\),方向正确 ✓。
黑板动作:画同心椭圆等高线,在 \((0, 0)\) 画梯度箭头,再画反向更新箭头指向 \((3, -1)\)。
4. 反例¶
学习率不是越大越快。对 \(r(x) = x^2\),更新式为
取 \(x_0 = 1\)、\(\eta = 1.1\):
绝对值越来越大,算法发散。函数仍然光滑、严格凸,唯一改变的是学习率过大,因此这是一个纯净反例。
5. 一句话总结¶
梯度把局部变化写成线性映射;负梯度给出局部最陡下降方向。
PyTorch autograd 形状卡¶
import torch
params = torch.tensor([0.0, 0.0], requires_grad=True) # shape: [2]
target = torch.tensor([3.0, -1.0]) # shape: [2]
loss = ((params - target) ** 2).sum() # shape: []
loss.backward()
print(params.grad) # tensor([-6., 2.]), shape: [2]
with torch.no_grad():
params -= 0.1 * params.grad # [2] - scalar*[2] -> [2]
params.grad.zero_()
loss 必须是标量,shape 是 [];params.grad 与 params 同形,都是 [2]。数学上 Jacobian 是 \(1 \times 2\) 行向量,而 PyTorch 对标量损失返回与参数同形的梯度 [2]。这是 Ch02 矩阵乘法在深度学习里的真实运行形态。
学生常问
- 问:梯度是行向量还是列向量?
答:本书默认梯度为列向量;标量函数的 Jacobian 是它的转置。 - 问:一次更新后损失一定下降吗?
答:不一定;学习率过大、函数不光滑或数值误差都可能使损失上升。
⏸️ 暂停思考 · 第二次
若当前位置梯度是 \((4, -2)^\top\),学习率 \(\eta = 0.25\),梯度下降的位移是多少?
位移是 \(-\eta \nabla f = (-1, 0.5)^\top\)。别把“梯度方向”和“下降方向”写成同一个方向。
核心概念四:牛顿法利用曲率,约束优化改变可走方向(约 3 分钟)¶
1. 直觉¶
梯度下降只问“坡往哪边下”,牛顿法还问“坡有多弯”。如果知道曲率,就能直接跳到二次近似的底部。
约束优化则反过来:不是我们走得不好,而是我们必须踩在一条曲线或曲面上,比如“在预算 \(x + y = 10\) 内找最高产出”。在这种情况下,我们需要拉格朗日乘子。
2. 定义与公式¶
牛顿法 (Newton's method) 用切线求零点:
用于优化(找极小)时换成
多维版本依赖 Hessian \(H\):
拉格朗日乘子法解约束优化:
定义拉格朗日函数:
最优点处三个偏导都为零:
几何上,最优处 \(f\) 和 \(g\) 的梯度必须平行——否则沿约束曲面还能继续让 \(f\) 变化。
3. 例子:求 \(\sqrt{5}\)¶
取 \(f(x) = x^2 - 5\),\(f'(x) = 2x\)。从 \(x_0 = 2\) 开始:
Step 1:
Step 2:
Step 3:验算:
已经精确到小数点后四位 ✓。这就是二次收敛——每走一步,正确的十进制位数大约翻一倍。
4. 例子:拉格朗日乘子手算¶
约束 \(x^2 + y^2 = 1\),求 \(f(x, y) = x^2 y\) 的极大。构造
求偏导:
由第一个方程(假设 \(x \neq 0\))得 \(\lambda = y\);代入第二个得 \(x^2 = 2y^2\);再结合约束 \(2y^2 + y^2 = 1\),解得
黑板动作:画单位圆,画函数梯度、约束梯度在极值点处的平行关系。
5. 反例(纯净)¶
牛顿法在初值过远或 \(f'(x)\) 过小时会翻车。取
它满足 \(h(0) = 0\),但 \(h'(0)\) 不存在。直接套用牛顿公式会除以零或得到不收敛的迭代。这个反例只破坏导数存在性,不掺杂数值误差。
6. 一句话总结¶
牛顿法靠曲率(Hessian)走大步;拉格朗日乘子把约束翻译成梯度平行条件。
⏸️ 暂停思考 · 第三次
牛顿法求 \(x^2 - 2 = 0\) 的根,从 \(x_0 = 1.5\) 出发。下一步 \(x_1\) 是多少?手算一下。
答案:\(x_1 = 1.5 - (1.5^2 - 2)/(2 \cdot 1.5) = 1.5 - 0.25/3 \approx 1.4167\)。真实 \(\sqrt{2} \approx 1.4142\),一步就接近到 0.002。
一个走完全程的例子(约 2.5 分钟)¶
好,咱们用一个例子把今天的概念全串起来。
问题:用梯度下降找 \(f(x, y) = (x-3)^2 + (y+1)^2\) 的最小值,最低点在 \((3, -1)\),最小值是 \(0\)。
第一步,画等高线。这是同心圆,圆心在 \((3, -1)\)。我们从 \(\mathbf{x}_0 = (0, 0)^\top\) 出发,这位于最大圆上。
第二步,初始化。取学习率 \(\eta = 0.1\),损失 \(f(0, 0) = 10\)。
第三步,迭代 5 步(用更新式 \(\mathbf{x}_{k+1} = \mathbf{x}_k - \eta\, \nabla f(\mathbf{x}_k)\)):
| 步 | 位置 | 损失 |
|---|---|---|
| 0 | (0.0000, 0.0000) | 10.0000 |
| 1 | (0.6000, -0.2000) | 6.4000 |
| 2 | (1.0800, -0.3600) | 4.0960 |
| 3 | (1.4640, -0.4880) | 2.6214 |
| 4 | (1.7712, -0.5904) | 1.6777 |
| 5 | (2.0170, -0.6723) | 1.0737 |
每步损失都下降 ✓,参数稳定向 \((3, -1)\) 收敛。
第四步,验证凸性。$$ f''(x, y) = \begin{pmatrix} 2 & 0 \ 0 & 2 \end{pmatrix} $$,特征值都是 \(2 > 0\),严格凸,所以找到的极小一定是全局极小,没有“骗人低谷”。
第五步,连到牛顿法。如果换成牛顿法多走一步:
一步就跳到精确最小点。这就是曲率带来的加速。
整套动作串起来:从一阶梯度(梯度下降)→ 二阶梯度(牛顿法)→ 二阶导数矩阵(Hessian)决定凸性。
易错点回头看(约 80 秒)¶
三条最常翻车的地方。
-
很多人以为:导数为零的点就是极值点。其实是:仅是临界点,可能是极大、极小或拐点。因为二阶导数还控制着附近是上升还是下降。数字反例:\(x^3\) 在 \(x = 0\) 处 \(f'(0) = 0\),但那是水平拐点。
-
很多人以为:凸函数必有唯一全局极小。其实是:凸函数保证局部极小即全局极小,但常数函数每个点都是极小。因为“局部极小即全局”只排除“骗人低谷”,不排除“平坦底部”。要把“唯一”也写进来,必须额外要求严格凸(\(f'' > 0\))。
-
很多人以为:学习率越大收敛越快。其实是:过大会发散,过小会停滞。因为更新幅度 = 学习率 × 梯度,梯度大时小步也走得远。数字反例:\(r(x) = x^2\),\(\eta = 1.1\) 时 \(x_k\) 绝对值越滚越大,参数震荡发散。
与下节的钩子(约 30 秒)¶
今天我们讲了优化的主力算法:一阶梯度下降、二阶牛顿法,以及带约束的拉格朗日乘子。所有这些都假设我们能精确算出梯度。
但是在深度学习里,模型有几百万参数,损失函数是几百层复合,单个梯度算起来代价不菲。下一节——概率与统计——我们会看到不确定性怎样进入优化:噪声怎样影响梯度、随机梯度下降 (SGD) 为什么要“随机”、Adam 又怎样在每个参数上自适应地调整学习率。带着这些连接,咱们下节见。