A04 · 第 3 章 · 第二编 计算图与梯度
计算图
把复合张量函数表示为有向无环计算图,按拓扑序执行前向,以局部 Jacobian 组织 JVP 与 reverse-mode VJP,处理分支梯度累加、广播形状、缓存重计算和数值梯度核验。
报告页面错误本章目标
- 把复合标量或张量函数拆为有向无环节点,并按拓扑序计算前向值和形状。
- 定义局部 Jacobian,区分前向模式 JVP 与反向模式 VJP 的输入输出方向。
- 在共享变量和分支汇合处累加所有下游路径贡献,而不是覆盖梯度。
- 推导仿射、逐元素、广播和归约运算的 VJP 形状。
- 权衡中间值缓存与重计算,并用中心有限差分和方向导数核验实现。
本页目录
计算图记录值如何依赖
计算图把一次函数求值拆成基本运算节点。输入、参数和常量是源节点,运算输出是中间节点,边表示某输出读取了哪个输入。只要一次执行中的依赖没有回到自身,图就是有向无环图;循环程序可按实际步数展开成有限 DAG,共享参数则由多个展开节点共同引用。
图节点不仅要记录数值,还要记录数据类型、张量形状、设备、生成它的运算和输入引用。两条边连着相同维度并不保证语义相同,批次轴、特征轴和时间轴必须明确。原地修改会破坏“节点值由父节点唯一决定”的假设;若反向需要修改前的值,就必须保存版本或禁止覆盖。
前向执行使用拓扑序:每个节点只在全部父节点完成后求值。一个 DAG 可以有多个合法拓扑序,只要无副作用,最终数学结果应一致;浮点加法次序可能造成微小差异,因此复现实验还要固定归约实现和精度。
令 ,节点为 、、。合法拓扑顺序可以是 ,前向依次得到 。 未完成前不能求 ,但常量 与乘法 的准备次序可交换。
图中每个局部操作都容易复算:乘法、加法和平方。把复合式直接展开为 数学上等价,计算图却显式保留了中间值五和依赖边,供反向局部规则与缓存策略使用。
局部 Jacobian 是节点接口
若节点 ,其中 ,局部 Jacobian 为
自动微分通常不显式构造这个矩阵,而只实现它与向量的乘积。前向模式传播输入方向 ,计算 Jacobian–向量积 ,回答输入沿 微扰时输出如何变化。反向模式接收输出余切或上游向量 ,计算向量–Jacobian 积 。
当输入参数很多、输出是一个标量损失时,反向模式一次 VJP 就得到全部参数梯度;若输入维度很小而输出很多,前向模式可能更合适。二者都是链式法则的组织方式,不是数值近似。显式完整 Jacobian 需要按输入或输出方向多次乘积,成本可能很高。
reverse-mode 沿逆拓扑序累积伴随量
对标量损失 ,给每个节点 定义伴随量 ,其形状与 相同。先执行前向并保存所需中间值,再令 。逆拓扑处理节点 ,对每个输入执行
这里的加等号不可省略。一个节点可流向多个下游操作,总导数是所有路径贡献之和;每条下游边完成自己的 VJP,再在共享节点汇合。若把后到贡献覆盖先到贡献,分支图的梯度会系统性错误。
令 ,在 时前向得 。从加法反向得到 。平方分支向 贡献 ,立方分支贡献 。
因此 ,与直接求导 一致。若两个分支各自把 grad[x] 赋值,最后只会留下四或十二。正确实现先把伴随缓冲初始化为零,对所有出边贡献做原子或确定性归约。
对前一例 ,逆向从 得 ,加法给 ,乘法给 。局部规则只读取其输入和上游伴随,不需重新展开整条复合式。
张量 VJP 要同时核对数学轴与形状
批量仿射层设 、、,前向
其中 沿批次轴广播。若上游梯度 ,则
最后一式对广播轴求和,不能把 原样交给形状为 的偏置。类似地,前向按某轴求和,反向就沿该轴广播;前向广播,反向就沿扩展轴归约。转置、切片、拼接和重复索引都有对应的形状逆操作,共享索引处仍需累加。
设批量 、输入维 、隐藏宽度 。 形状为 , 为 , 为 ,所以 与 都为 。若标量损失给出 为 ,ReLU 局部规则产生 ,仍为 。
随后 为 , 为 , 对四行求和后为 。形状全部闭合只是必要条件;若把批次和特征轴同时转置,仍可能得到可乘但语义错误的矩阵,所以还需小数值例核对。
JVP 与 VJP 不应被口头混淆
对于复合 ,前向模式从 开始,依次算 、;反向模式从输出余切 开始,依次算 、再乘 。二者遍历方向相反,但都不需要形成完整 Jacobian。
梯度是标量输出对输入的特殊 VJP,种子为一。若输出是向量而没有给出上游向量,“对输入求梯度”并不完整;需要指定某个标量化、某个输出分量或 VJP 种子。很多张量自动微分接口要求非标量输出显式提供 grad_outputs,正是为了确定这个余切。
基本节点的 VJP 要与前向约定成对
加法把上游梯度传给两个输入;若输入经广播,传回前要沿广播轴求和。逐元素乘法 分别返回 与 。指数返回 ,对数返回 ,因此前向定义域和零值处理也属于导数接口。
逐元素 ReLU 在正区间导数为一、负区间为零,在零点不可微;实现通常固定选择某个次梯度。最大归约遇到并列最大值时,可把梯度给第一个、平均分配或按其他冻结规则,数值梯度检查必须知道该约定。排序、取整、离散采样等节点一般没有普通路径导数,若使用直通估计或连续松弛,应明确它是另一个估计器而非精确链式法则。
reshape 只改变视图形状,VJP 把上游恢复原形状;转置执行逆置换;切片反向把梯度散射回原位置,未选位置为零;同一索引重复出现时要相加。均值归约除广播外还需除以被平均元素数,求和归约则不除。把均值误写成求和会让梯度随批量大小成比例变化,进而改变有效学习率。
参数共享和批次归约形成更大的分支图
同一个权重矩阵可在多个时间步、空间位置或样本上使用。计算图中这些是多条以同一参数为源的边,参数梯度必须汇总全部使用位置。循环网络展开十步并不复制十套参数;反向经过十个时间节点后,把十项贡献累加到同一缓冲。卷积核在所有位置共享也是同一原则,只是局部 VJP 由高效算子完成。
批损失若定义为样本损失均值,单样本贡献带 ;若定义为总和则不带。梯度累积跨多个小批时,要决定累积的是各批均值之和、按样本数加权的全局均值,还是刻意放大的总和。最后一个批次较小时,简单平均各批均值会给它过高权重。数学损失、并行归约和优化器步长必须使用同一尺度约定。
截断边与自定义操作改变可微程序
停止梯度操作前向返回原值,反向却返回零,相当于主动删除依赖边。它可用于固定目标、交替优化或避免某分支更新,但不能被当成普通恒等函数;图可视化和公式都应标出截断。误放一次停止梯度会让损失仍正常变化而某组参数永远没有梯度。
自定义操作需要提供与真实前向一致的 VJP,并处理保存值、广播、复数约定、不可导点和高阶导数需求。若反向偷偷使用前向没有定义的信息,数值检查可能在少量样本上碰巧通过,仍会在边界失效。先用小张量参考实现与自动组合结果比较,再替换为融合内核更稳妥。
编译器可做常量折叠、公共子表达式消除和算子融合,只要保持值、别名和导数语义。融合能减少中间张量与内存流量,却可能改变浮点归约次序。优化前后应在设定容差内比较前向、VJP 和关键随机状态,而不是只比较训练最终精度。
令 ,在 处
输入方向 的 JVP 为 ,表示沿该微扰第一输出一阶增加、第二输出不变。输出余切 的 VJP 为 。两者都用同一局部 Jacobian,却处在不同空间、回答不同问题。
缓存与重计算交换内存和算力
许多 VJP 需要前向值:乘法反向要另一输入,sigmoid 反向可用输出,ReLU 需要符号掩码,归一化需要统计量。全部缓存能使反向快速,却让激活内存随深度和批量增长。全部重算节省内存,但重复计算和输入读取可能昂贵。
梯度检查点保存少数边界激活,反向到某段时从最近检查点重跑前向,再释放局部值。检查点选择要平衡峰值内存、重算次数和通信。含随机失活、随机增强或采样的段落重算时必须恢复相同随机状态;含可变外部状态或原地写入的操作要特别谨慎,否则重算图不再等于原前向。
网络依次有四个昂贵模块 。全缓存保存四段输出;若内存不足,可只保存输入、 输出和 损失。反向处理后两段前,先从 输出重算 ;处理前两段时再从输入重算 。
这样减少长期驻留激活,但部分前向计算执行两次。若 含随机掩码,检查点还要保存对应随机生成器状态;仅保存全局种子而其他操作已消耗随机数,未必能重现同一掩码。核对时比较重算前向损失与原损失应完全符合设定容差。
数值梯度检查只验证局部实现
对单个参数坐标 ,中心有限差分为
它的截断误差随 下降,但 太小会遭遇浮点抵消。应在双精度、小而确定的数据上,根据参数尺度尝试一段 ,比较绝对误差与相对误差
ReLU 在零、最大值平局、裁剪边界等不可导点会让左右差分不一致,应避开或按实现约定做单侧核对。随机操作必须固定,训练态归一化统计和状态更新应暂停。大模型可抽查坐标,或用随机方向 比较有限差分方向导数与 。
数值检查通过说明当前输入附近的反向实现与前向函数一致,不证明损失定义正确、数据无泄漏或训练可泛化。它是局部导数测试,不是训练验收。
练习
查看提示
查看解答
查看提示
查看解答
查看提示
查看解答
查看提示
查看解答
查看提示
查看解答
查看提示
查看解答
关系与资源
- 链式法则 提供局部导数组合的数学基础。
- 图算法方法 支持拓扑排序与逆序遍历。
- 感知机与多层感知器 提供典型仿射非线性计算图。
- 反向传播 把 VJP 应用于共享参数的标量损失。
- 参数初始化与梯度流 分析深图中的前向与反向尺度。
- 神经网络与反向传播综合复习 将图核验纳入训练审计。
Deep Learning
Ian Goodfellow, Yoshua Bengio, Aaron Courville
适合作为反向传播和优化章节的完整参考。
打开官方来源