Files
maths-cs-ai-compendium-zh/chapter 03: calculus/05. optimisation.md
T
flykhan 2536c937e3 feat: 完整中文翻译 maths-cs-ai-compendium(数学·计算机科学·AI 知识大全)
翻译自英文原版 maths-cs-ai-compendium,共 20 章全部完成。

第01章 向量 | 第02章 矩阵 | 第03章 微积分
第04章 统计学 | 第05章 概率论 | 第06章 机器学习
第07章 计算语言学 | 第08章 计算机视觉 | 第09章 音频与语音
第10章 多模态学习 | 第11章 自主系统 | 第12章 图神经网络
第13章 计算与操作系统 | 第14章 数据结构与算法
第15章 生产级软件工程 | 第16章 SIMD与GPU编程
第17章 AI推理 | 第18章 ML系统设计
第19章 应用人工智能 | 第20章 前沿人工智能

翻译说明:
- 所有数学公式 $...$ / $$...$$、代码块、图片引用完整保留
- mkdocs.yml 配置中文导航 + language: zh
- README.md 已翻译为中文(兼 docs/index.md)
- docs/ 目录包含指向各章文件的 symlink
- 约 29,000 行中文内容,排除 .cache/ 构建缓存
2026-05-03 10:23:20 +08:00

146 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 优化
*优化是模型训练的数学核心——寻找使损失函数最小的参数。本文涵盖驻点、凸性、梯度下降、牛顿法、带拉格朗日乘数的约束优化,以及驱动现代深度学习的主流优化器(SGD、Adam)。*
- 训练神经网络、拟合回归线、调优超参数:几乎所有机器学习算法的核心都是一个**优化**问题。
- 我们有一个函数(损失函数、代价函数、目标函数),希望找到使其尽可能小(或大)的输入。
- 在优化之前,我们需要理解函数的**零点**(或根)。$f(x)$ 的零点是指满足 $f(x) = 0$ 的 $x$ 值。从图形上看,这些点就是与 x 轴的交点。
- 例如,$f(x) = x^2 - 3x + 2 = (x-1)(x-2)$ 的零点在 $x = 1$ 和 $x = 2$ 处。在两个零点之间,函数为负($f(1.5) = -0.25$);在零点之外,函数为正。零点将数轴分割成若干个区域,在每个区域中函数保持相同符号。
- 零点的**重数**是指对应因式出现的次数。
- 在单零点(重数为 1)处,图像穿过 x 轴。在二重零点(重数为 2)处,图像接触 x 轴但反弹回去而不穿过,在该点处看起来是"平坦"的。
- 寻找零点之所以重要,是因为导数 $f'(x)$ 的零点正是 $f(x)$ 的**驻点**——即极大值或极小值的候选点。
- 在极大值或极小值处,切线是水平的(斜率为 0),因此 $f'(x) = 0$。
![驻点:当导数为零时,函数出现波峰、波谷或鞍点](../images/critical_points.svg)
- 但并非每个驻点都是极大值或极小值。$f'(x) = 0$ 的点也可能是**拐点**(如 $f(x) = x^3$ 在 $x = 0$ 处),函数在该点暂时变平但并未改变方向。
- **二阶导数检验**可以解决这个问题。在驻点 $x = c$(即 $f'(c) = 0$)处:
- 若 $f''(c) > 0$:曲线向下凸(碗状),因此 $c$ 是**局部极小值**。
- 若 $f''(c) < 0$:曲线向上凸(山丘状),因此 $c$ 是**局部极大值**。
- 若 $f''(c) = 0$:检验无效,需要使用更高阶导数或其他方法。
- 例如,$f(x) = x^3 - 3x$。导数为 $f'(x) = 3x^2 - 3 = 3(x-1)(x+1)$,因此驻点在 $x = -1$ 和 $x = 1$ 处。二阶导数为 $f''(x) = 6x$。在 $x = -1$ 处:$f''(-1) = -6 < 0$(局部极大值)。在 $x = 1$ 处:$f''(1) = 6 > 0$(局部极小值)。
- 如果连接函数图像上任意两点的线段位于图像之上(或与之重合),则该函数是**凸的**。可以想象成一个碗形,处处向上弯曲。数学上,若对所有 $x$ 有 $f''(x) \geq 0$,则 $f$ 是凸函数。
![凸函数具有唯一的全局最小值;非凸函数可能有多个局部最小值](../images/convex_nonconvex.svg)
- 凸性的强大之处在于凸函数有一个卓越的性质:每个局部极小值同时也是**全局最小值**。不存在会让人陷入的欺骗性局部低谷。如果你把一个球滚入凸碗中,它总是会到达底部。
- 若 $-f$ 是凸的,则函数是**凹的**(向下弯曲)。函数从凹性过渡到凸性的点称为**拐点**,出现在 $f''(x) = 0$ 处。
- **牛顿法**利用切线寻找函数的零点(进而也可用于寻找其导数的驻点)。从初始猜测 $x_0$ 出发,迭代更新:
$$x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}$$
![牛顿法:沿切线方向逼近根的更好近似值](../images/newtons_method.svg)
- 其思想是:在 $x_n$ 处画出切线,找到它与 x 轴的交点,该交点即为 $x_{n+1}$。对于性质良好且初始点选取恰当的函数,牛顿法收敛非常快(二次收敛,即每步正确位数大致翻倍)。
- 例如,求 $\sqrt{5}$(即 $f(x) = x^2 - 5$ 的零点):$f'(x) = 2x$,因此 $x_{n+1} = x_n - \frac{x_n^2 - 5}{2x_n}$。从 $x_0 = 2$ 开始:$x_1 = 2.25$$x_2 = 2.2361\ldots$,已精确到小数点后四位。
- 如果初始猜测离根太远、根附近 $f'(x) = 0$,或函数在附近有拐点,牛顿法可能会失败。此外,它还需要计算导数,这可能代价高昂。
- 对于优化(寻找极小值而非零点),我们将牛顿法应用于 $f'(x) = 0$,得到更新公式:
$$x_{n+1} = x_n - \frac{f'(x_n)}{f''(x_n)}$$
- 在多维情形下,这变为 $\mathbf{x}_{n+1} = \mathbf{x}_n - H^{-1} \nabla f(\mathbf{x}_n)$,其中 $H$ 是 Hessian 矩阵。这正是上一节中二阶泰勒近似的实际应用:将函数近似为二次型,跳到该二次型的极小值点,然后重复。
- **拉格朗日乘数**用于求解**约束优化**:在约束条件 $g(x, y) = c$ 下求 $f(x, y)$ 的最优值。我们不是在 $\mathbb{R}^n$ 中全域搜索,而是限制在约束条件成立的集合(一条曲线或曲面)上。
- 关键见解是几何层面的:在约束最优解处,$f$ 的梯度必须与 $g$ 的梯度平行。如果它们不平行,我们可以沿着约束条件朝某个方向移动,从而继续改进 $f$ 的值,这意味着还没有达到最优。
- 我们引入一个新变量 $\lambda$(拉格朗日乘数),定义**拉格朗日函数**:
$$\mathcal{L}(x, y, \lambda) = f(x, y) - \lambda(g(x, y) - c)$$
- 令所有偏导数为零,得到一个方程组,其解即为约束最优解:
$$\frac{\partial \mathcal{L}}{\partial x} = 0, \quad \frac{\partial \mathcal{L}}{\partial y} = 0, \quad \frac{\partial \mathcal{L}}{\partial \lambda} = 0$$
![拉格朗日乘数:在最优解处,f 和 g 的梯度平行](../images/lagrange_multiplier.svg)
- 例如,在 $x^2 + y^2 = 1$ 的约束下最大化 $f(x,y) = x^2 y$。拉格朗日函数为 $\mathcal{L} = x^2 y - \lambda(x^2 + y^2 - 1)$。求偏导:
$$2xy - 2\lambda x = 0, \quad x^2 - 2\lambda y = 0, \quad x^2 + y^2 = 1$$
- 由第一个方程(假设 $x \neq 0$):$\lambda = y$。代入第二个方程:$x^2 = 2y^2$。结合约束条件:$2y^2 + y^2 = 1$,得 $y = \frac{1}{\sqrt{3}}$。最大值为 $f = \frac{2}{3\sqrt{3}}$。
- 对于不等式约束($g(x,y) \leq c$ 而非 $= c$),**Karush-Kuhn-TuckerKKT)条件**推广了拉格朗日乘数法。约束要么是激活的(有效约束,按等式处理),要么是非激活的(解在内部,约束无关紧要)。
- 在实践中,我们很少手工进行优化。以下是主要的算法家族:
- **一阶方法**(仅使用梯度):梯度下降、随机梯度下降(SGD)、Adam。这些方法每步计算成本低,但收敛可能较慢,尤其是在病态问题上。
- **二阶方法**(使用梯度和 Hessian 矩阵):牛顿法收敛快,但计算和求逆 Hessian 矩阵代价高昂(对于 $n$ 个参数为 $O(n^3)$)。**拟牛顿法**(如 BFGS 和 L-BFGS)仅利用梯度信息近似 Hessian 矩阵,比一阶方法收敛更快,又无需承担完全的二阶方法计算成本。
- **共轭梯度法**:适用于大型稀疏系统,仅需矩阵-向量乘积,无需存储完整的 Hessian 矩阵。
- **高斯-牛顿法**和**莱文贝格-马夸尔特法**:专门用于最小二乘问题(在回归中常见),通过 Jacobian 矩阵近似 Hessian 矩阵。
- **自然梯度下降**:利用 Fisher 信息矩阵考虑参数空间的几何结构,对概率模型可能更有效。
- 优化器的选择取决于具体问题。对于深度学习,一阶方法(尤其是 Adam)占主导地位,因为参数量巨大(数百万到数十亿),计算 Hessian 矩阵不切实际。对于目标函数光滑的小规模问题,二阶方法可能快得多。
## 编程练习(在 CoLab 或 notebook 中完成)
1. 实现牛顿法求 $\sqrt{7}$(即 $f(x) = x^2 - 7$ 的零点)。观察其快速收敛。
```python
import jax.numpy as jnp
f = lambda x: x**2 - 7
df = lambda x: 2*x
x = 3.0 # 初始猜测
for i in range(6):
x = x - f(x) / df(x)
print(f"step {i+1}: x = {x:.10f} (error: {abs(x - jnp.sqrt(7.0)):.2e})")
```
2. 使用梯度下降最小化 $f(x, y) = (x - 3)^2 + (y + 1)^2$。最小值在 $(3, -1)$ 处。尝试不同的学习率。
```python
import jax
import jax.numpy as jnp
def f(params):
x, y = params
return (x - 3)**2 + (y + 1)**2
grad_f = jax.grad(f)
params = jnp.array([0.0, 0.0])
lr = 0.1
for i in range(20):
g = grad_f(params)
params = params - lr * g
if i % 5 == 0 or i == 19:
print(f"step {i:2d}: ({params[0]:.4f}, {params[1]:.4f}) loss={f(params):.6f}")
```
3. 数值求解约束优化问题。在 $x + y = 10$ 的约束下最大化 $f(x,y) = xy$,通过参数化 $y = 10 - x$ 并求单变量函数的最优值。
```python
import jax
import jax.numpy as jnp
# 代入约束条件:y = 10 - x,所以 f = x(10 - x) = 10x - x²
f = lambda x: x * (10 - x)
df = jax.grad(f)
# 梯度上升(我们要求最大值,所以加上梯度)
x = 1.0
lr = 0.1
for i in range(20):
x = x + lr * df(x)
print(f"x={x:.4f}, y={10-x:.4f}, f={f(x):.4f}") # 应为 x=5, y=5, f=25
```