手写自动微分引擎:从数值到符号的可执行求导实践

1. 这不是数学课,而是一本写给实践者的微分计算手记

“Derivatives: A Computational Approach — Part one”这个标题乍看像教材副标题,但如果你正坐在终端前调试一个梯度爆炸的神经网络、在量化策略里反复校验delta对冲的灵敏度、或只是想搞懂Excel里那个叫 SERIESUM 的函数到底在算什么——那你点进来就对了。这不是讲ε-δ语言的分析学复习班,也不是堆砌LaTeX公式的理论推导集;它是一份我用Python、NumPy、SymPy和手写纸草稿本反复验证过的 可执行微分实践指南 。核心关键词很直白: 数值微分、符号微分、自动微分、差分步长选择、截断误差与舍入误差的博弈、Jacobian矩阵的实际组装逻辑 。它适合三类人:刚学完高数但一写代码就卡在“怎么把∂f/∂x变成能跑的数字”的理工科学生;需要快速验证金融衍生品希腊字母(Gamma、Vega)敏感性的量化初学者;以及那些不满足于调用 torch.autograd 却想看清反向传播底层齿轮如何咬合的算法工程师。整篇内容不预设你记得链式法则的证明,但默认你会写 for 循环、能看懂 x += h x -= h 的区别,并且愿意为0.0001的精度多花3分钟调参。Part one只做一件事:把“求导”从黑板上的箭头符号,变成你键盘上敲得出、屏幕上看得见、生产环境里压得住的确定性操作。

2. 为什么非得绕开教科书?三种求导路径的本质差异与选型逻辑

2.1 手动求导:最古老也最容易翻车的方式

手动求导就是拿出纸笔,对目标函数f(x)进行代数化简,写出解析表达式f′(x),再代入数值计算。比如f(x)=sin(x²),手动推得f′(x)=2x·cos(x²)。这方法在考试中高效,在代码里却脆弱得像薄冰。我去年帮一个期权定价团队重构波动率曲面拟合模块时,发现他们沿用十年的手动导数公式里藏着一个被忽略的边界条件:当输入x趋近于0时,cos(x²)的泰勒展开前三项足够,但第四项在高频重采样下会累积出0.8%的gamma偏差。问题不在于数学错误,而在于 手动推导无法随函数结构变化动态更新 ——当你把sin(x²)换成更复杂的随机微分方程解时,重新推导成本指数级上升。更致命的是,它完全无法处理隐式定义的函数,比如由迭代过程生成的f(x):先执行100次牛顿法求根,再取结果的平方。这种函数连解析形式都没有,手动求导直接失效。

2.2 数值微分:用“试探”代替“推演”,但代价是精度陷阱

数值微分的核心思想极朴素:用割线斜率逼近切线斜率。最常用的是中心差分公式:
f′(x) ≈ [f(x+h) − f(x−h)] / (2h)
这里h是步长,通常取1e-5或1e-8。但“通常”二字背后是血泪教训。去年我调试一个热传导仿真模型时,发现温度梯度计算结果在网格细化后剧烈震荡。排查三天才发现:当网格尺寸Δx降到1e-6量级时,我仍用h=1e-8计算导数,导致f(x+h)和f(x−h)在浮点精度下完全相等(IEEE 754双精度有效位约15~16位),分子变成0,整个梯度崩为NaN。这就是 舍入误差主导区 ——h太小,函数值差异被浮点噪声淹没;h太大, 截断误差 (泰勒展开截断带来的系统性偏差)又开始作祟。实际测试表明,对大多数工程函数,最优h≈√ε·|x|,其中ε是机器精度(约2.2e-16)。这意味着x=1时h取1e-8合理,但x=1e-10时h必须缩到1e-13,否则精度灾难必然发生。数值微分真正的价值不在单点计算,而在它 无需函数可导性假设 ——你可以对任何能输入输出的“黑盒”程序求导,哪怕内部是调用Fortran子程序或查表插值。

2.3 符号微分与自动微分:确定性的终极解法

符号微分(Symbolic Differentiation)用计算机代数系统(如SymPy)对表达式树进行规则化简,输出另一个表达式。它给出精确的解析解,但面临 表达式膨胀 (Expression Swell)问题:对f(x)=sin(cos(tan(x)))求导,符号结果可能长达数百字符,包含大量冗余三角恒等式,计算效率反而低于数值法。而自动微分(Automatic Differentiation, AD)走的是第三条路:它不求数学表达式,而是将函数分解为基本运算(+、−、×、÷、sin、log等)的有向无环图(DAG),然后按链式法则逐节点传播导数。关键在于,AD在 运行时 (而非编译时)构建计算图,因此能处理含分支、循环、内存分配的任意程序。PyTorch的 autograd 和JAX的 grad 都是AD实现。但Part one不直接上框架——我要带你手写一个微型AD引擎,因为只有亲手拆解 y = x * x 如何分解为 u=x, v=x, y=u*v ,再计算 dy/du=v, dy/dv=u, dx/dx=1 ,你才能真正理解为什么反向传播比数值微分快三个数量级,又比符号微分节省90%内存。

3. 实操核心:从零构建一个支持标量与向量的微型自动微分引擎

3.1 数据结构设计:Value类封装值与梯度的共生关系

自动微分的根基是 计算图节点 。我们不造轮子,用Python类 Value 承载一切:

class Value:
    def
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值