手动实现链式法则
构造复合函数,手动逐层计算局部梯度并相乘,再用 sympy 验证。
学完本案例你将理解:反向传播的核心就是链式法则——每一层只算自己的局部梯度,最终梯度是各层梯度的乘积。
生活引入
多米诺骨牌的生产线
一个工厂有三道工序:原料 → 半成品 A → 半成品 B → 成品。你想知道「原料多用 1 公斤,最终成品多几个?」
你不需要从头推导整个流程的公式。每道工序只算自己的「局部比例」:半成品 A 增产 1 个 → 半成品 B 多几个?半成品 B 多 1 个 → 成品多几个?三个比例相乘就是答案。
这就是链式法则——每层只关心自己,最终影响 = 各层影响的乘积。
直观理解
构造一个三层复合函数:
x
u = g(x)
x^2+1
x^2+1
v = f(u)
3*sin(u)
3*sin(u)
y = h(v)
v^2
v^2
Python 动手实践
实例
import sympy as sp
import numpy as np
def g(x): return x ** 2 + 1
def f(u): return 3 * np.sin(u)
def g_prime(x): return 2 * x
def f_prime(u): return 3 * np.cos(u)
x0 = 1.5
# ---- 手动链式法则 ----
u0 = g(x0)
dy_du = f_prime(u0) # 第2层局部梯度
du_dx = g_prime(x0) # 第1层局部梯度
manual_grad = dy_du * du_dx
print("=" * 55)
print("RUNOOB 手动链式法则")
print(f"x0 = {x0}, u = g(x0) = {u0:.4f}")
print(f"dy/du = 3*cos(u) = {dy_du:.4f}")
print(f"du/dx = 2*x0 = {du_dx:.4f}")
print(f"链式相乘: dy/dx = {manual_grad:.4f}")
# ---- sympy 自动求导(标准答案) ----
x = sp.Symbol('x')
y_expr = 3 * sp.sin(x**2 + 1)
auto_grad = float(sp.diff(y_expr, x).subs(x, x0))
print(f"\nRUNOOB sympy 自动求导 = {auto_grad:.4f}")
print(f"两种方法一致: {np.isclose(manual_grad, auto_grad)}")
# ---- 拓展:三层复合 ----
def h(v): return v ** 2
def h_prime(v): return 2 * v
v0 = f(u0)
dy_dv = h_prime(v0)
grad_3layer = dy_dv * dy_du * du_dx
print(f"\nRUNOOB 三层梯度传递:")
print(f" 第3层: {dy_dv:.4f} x 第2层: {dy_du:.4f} x 第1层: {du_dx:.4f} = {grad_3layer:.4f}")
import numpy as np
def g(x): return x ** 2 + 1
def f(u): return 3 * np.sin(u)
def g_prime(x): return 2 * x
def f_prime(u): return 3 * np.cos(u)
x0 = 1.5
# ---- 手动链式法则 ----
u0 = g(x0)
dy_du = f_prime(u0) # 第2层局部梯度
du_dx = g_prime(x0) # 第1层局部梯度
manual_grad = dy_du * du_dx
print("=" * 55)
print("RUNOOB 手动链式法则")
print(f"x0 = {x0}, u = g(x0) = {u0:.4f}")
print(f"dy/du = 3*cos(u) = {dy_du:.4f}")
print(f"du/dx = 2*x0 = {du_dx:.4f}")
print(f"链式相乘: dy/dx = {manual_grad:.4f}")
# ---- sympy 自动求导(标准答案) ----
x = sp.Symbol('x')
y_expr = 3 * sp.sin(x**2 + 1)
auto_grad = float(sp.diff(y_expr, x).subs(x, x0))
print(f"\nRUNOOB sympy 自动求导 = {auto_grad:.4f}")
print(f"两种方法一致: {np.isclose(manual_grad, auto_grad)}")
# ---- 拓展:三层复合 ----
def h(v): return v ** 2
def h_prime(v): return 2 * v
v0 = f(u0)
dy_dv = h_prime(v0)
grad_3layer = dy_dv * dy_du * du_dx
print(f"\nRUNOOB 三层梯度传递:")
print(f" 第3层: {dy_dv:.4f} x 第2层: {dy_du:.4f} x 第1层: {du_dx:.4f} = {grad_3layer:.4f}")
======================================================= RUNOOB 手动链式法则 x0 = 1.5, u = g(x0) = 3.2500 dy/du = 3*cos(u) = -2.9838 du/dx = 2*x0 = 3.0000 链式相乘: dy/dx = -8.9514 RUNOOB sympy 自动求导 = -8.9514 两种方法一致: True RUNOOB 三层梯度传递: 第3层: 6.5000 x 第2层: -2.9838 x 第1层: 3.0000 = -58.1841
AI 中的应用场景
| 场景 | 与链式法则的关系 |
|---|---|
| 反向传播 | 神经网络每层只计算自己的局部梯度,然后传给上一层 |
| PyTorch autograd | 自动追踪每个操作构建计算图,反向时自动应用链式法则 |
| 梯度检查 | 手动实现反向传播后,用数值梯度验证——就是本案的方法一 vs 方法二 |
