现在位置: 首页 > AI 数学基础 > 正文

手动实现链式法则

构造复合函数,手动逐层计算局部梯度并相乘,再用 sympy 验证。

学完本案例你将理解:反向传播的核心就是链式法则——每一层只算自己的局部梯度,最终梯度是各层梯度的乘积。


生活引入

多米诺骨牌的生产线

一个工厂有三道工序:原料 → 半成品 A → 半成品 B → 成品。你想知道「原料多用 1 公斤,最终成品多几个?」

你不需要从头推导整个流程的公式。每道工序只算自己的「局部比例」:半成品 A 增产 1 个 → 半成品 B 多几个?半成品 B 多 1 个 → 成品多几个?三个比例相乘就是答案。

这就是链式法则——每层只关心自己,最终影响 = 各层影响的乘积。


直观理解

构造一个三层复合函数:

x
u = g(x)
x^2+1
v = f(u)
3*sin(u)
y = h(v)
v^2
\[ \frac{dy}{dx} = \underbrace{\frac{dy}{dv}}_{h'(v)} \cdot \underbrace{\frac{dv}{du}}_{f'(u)} \cdot \underbrace{\frac{du}{dx}}_{g'(x)} \]

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}")
=======================================================
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 方法二