跳到内容

第 10 卷 / 第 11 章 / 第 1 课

11.1 极限、导数与链式法则:描述局部变化 ​

模型参数微调后,预测值会变多少?一条连续的位置曲线,在某一时刻的速度又是多少?这两类问题都要从函数在某点附近的变化开始,再判断局部近似能用多远。

本课目标 ​

  • 用极限解释导数,而不只记求导规则;
  • 区分连续、可导和数值上“看起来平滑”;
  • 使用乘积法则与链式法则拆解复合函数;
  • 理解有限差分、符号求导和自动微分的边界。

1. 极限处理“无限接近” ​

当 x 接近 a 时,若 f(x) 接近 L,写作:

limx→af(x)=L.

极限关注附近的行为,不要求 f(a) 一定存在,也不要求 f(a)=L。它允许我们严谨地讨论瞬时速度:不能真的取“零秒内的位移除以零秒”,但可以观察时间间隔趋近于零时平均速度的极限。

例如 f(x)=(x2−1)/(x−1) 在 x=1 无定义,但附近等于 x+1,故极限为 2。有限极限的精确定义是:对每个 ε>0,都能找到 δ>0,使 0<|x−a|<δ 时有 |f(x)−L|<ε。本例取 δ=ε 即可;定义中特意排除了点 a。

函数在 a 处连续,需要同时满足:

  1. f(a) 有定义;
  2. limx→af(x) 存在;
  3. 两者相等。

离散计算机只能采样有限个点。图像看起来连续,不代表数学上已经证明连续;采样也可能错过尖点、间断或高频振荡。

2. 导数是局部线性近似 ​

导数定义为差商的极限:

f′(x)=limh→0f(x+h)−f(x)h.

几何上,它是切线斜率;建模上,它给出小扰动的一阶近似:

f(x+Δx)≈f(x)+f′(x)Δx.

这里必须假设函数在该点可导。更精确地,近似的余项除以 |Δx| 后趋于零;这并不保证任意有限步长都误差很小。对 f(x)=x2,展开为 x2+2xΔx+(Δx)2,余项就是被一阶模型舍去的 (Δx)2。

常用规则包括:

ddxxn=nxn−1,ddxex=ex,ddxsin⁡x=cos⁡x.

更一般地,cex 的导数仍是自身;不能把 ex 误说成唯一满足这一性质的函数。

幂函数规则应在函数和右侧表达式有定义处使用。整数 n≥1 时适用于所有实数;常数 x0=1 的导数直接为零,不必在 x=0 硬算 0x−1。三角函数求导默认角度使用弧度。

可导蕴含连续,连续不蕴含可导。例如 |x| 在零点连续,但左右导数分别为 −1 和 1。ReLU 在零点也不可导,软件框架会选定一个次梯度约定;这是一项实现选择,不会让该点在经典意义下突然可导。

3. 复合系统需要链式法则 ​

若 g 在 x 可导,f 在 g(x) 可导,且 y=f(g(x)),则:

dydx=f′(g(x))g′(x).

例如:

y=(3x+1)2,

外层平方的导数是 2(3x+1),内层线性函数的导数是 3,所以:

y′=6(3x+1).

程序常由多层函数复合而成。神经网络可用计算图表示,前向传播计算节点值,反向传播从输出向输入反复应用链式法则。它的关键优势不是“会求一个导数”,而是可以复用中间结果,高效计算一个标量输出对大量参数的梯度。

把上例写成两个中间节点,可以手工检查一次反传。bar_v 表示输出对 v 的导数;重复使用同一变量的两条路径要相加:

python
x = 2.0
v = 3 * x + 1
y = v * v
bar_y = 1.0
bar_v = bar_y * (v + v)  # Both inputs of the product depend on v.
bar_x = bar_v * 3
print(y, bar_x)  # 49.0 42.0

这里用 Python 3 直接写局部导数,尚未实现通用自动微分器。框架还要保存所需中间值、管理计算图并处理不支持的操作。

还应掌握乘积法则:

(fg)′=f′g+fg′.

把乘积误写成 f′g′ 是最常见的机械错误之一。

4. 多元函数、偏导与梯度 ​

对 f(x1,…,xn),偏导数只让一个变量变化,其余暂时固定:

∂f∂xi.

所有偏导数组成梯度:

∇f(x)=[∂f/∂x1⋮∂f/∂xn].

对可微函数,方向单位向量 u 上的方向导数为:

Duf=∇fTu.

梯度给出局部增长最快的方向,负梯度则是局部下降最快的方向。这里的“最快”依赖欧氏范数;改变空间度量,最陡方向的定义也会改变。

当梯度为零时,所有方向的一阶方向导数都为零,没有唯一的最快方向。仅有各偏导也不足以保证可微:取 f(x,y)=xy/(x2+y2)(原点另定义为 0),两个坐标方向的偏导都是 0,但沿 y=x 接近原点时函数值为 1/2,连连续都不满足。

5. 有限差分是近似,不是自动微分 ​

中心差分公式为:

f′(x)≈f(x+h)−f(x−h)2h.
python
from math import isfinite

def f(x: float) -> float:
    return x**3 - 2 * x

def central_difference(x: float, h: float) -> float:
    if not isfinite(h) or h <= 0:
        raise ValueError("h must be positive and finite")
    return (f(x + h) - f(x - h)) / (2 * h)

x = 1.5
exact = 3 * x**2 - 2
for h in [1e-1, 1e-3, 1e-5, 1e-8, 1e-12, 1e-20]:
    estimate = central_difference(x, h)
    print(f"{h:.0e} {estimate:.8f} {abs(estimate - exact):.3e}")

h 变小时,截断误差起初下降;但过小时,f(x+h) 与 f(x-h) 非常接近,浮点舍入和消减误差开始主导。因此“让 h 尽可能小”不是可靠策略。

对这个三次多项式,精确算术下的中心差分正好是 f′(x)+h2,所以截断误差为 h2;一般二阶误差结论需要足够光滑,例如附近三阶导数有界。这里真值为 4.75。在通常的 binary64 Python 环境中,h=1e-20 已小到 x+h == x-h == x,差分返回零,误差反而变成 4.75。其他步长的末位输出可能随环境变化。

三种求导方式要分清:

方法结果典型用途
符号求导操作表达式,得到新公式代数推导、简化
有限差分用函数值近似导数验证梯度、黑盒函数
自动微分对基本运算应用链式法则训练模型、可微程序

自动微分按基本运算的导数传播链式法则,不依赖有限差分步长。它仍进行浮点计算,不能保证所有问题都得到机器精度级的最终导数误差;溢出、消减、病态运算和不可导点约定都会影响结果。框架行为可核对 PyTorch 自动微分说明,尤其要检查实际参与计算的分支与运算。

常见误区 ​

  • 导数就是函数值除以输入:导数是局部增量之比的极限。
  • 连续就一定有平滑斜率:尖点处可以连续但不可导。
  • 梯度是全局最佳方向:它只描述当前位置附近的一阶变化。
  • 数值差分的 h 越小越准:截断误差与舍入误差之间存在权衡。

练习 ​

  1. 用导数定义推导 f(x)=x2 的导数。
  2. 对 f(x)=sin⁡(x2) 使用链式法则求导。
  3. 计算 f(x,y)=x2+3xy+y2 的梯度。
  4. 运行中心差分示例,找出当前环境中误差最小的大致 h。

小结 ​

极限让“无限接近”可被严格讨论,导数给出函数的局部线性模型,链式法则把复杂复合拆成局部导数的乘积。自动微分把这套规则系统化,但不会替你判断函数是否适合求导、不可导点应怎样处理。

下一课研究另一半微积分:局部变化如何累积成总量,以及计算机怎样近似算出解析积分。

Built with VitePress | Software Systems Atlas