自动求导与训练
candle 的训练支持比 PyTorch 薄得多:反向模式、一阶导数、两个优化器(没有动量的 SGD 和 AdamW),没有调度器、没有梯度裁剪。这一卷的主轴是推理,这一部分只讲从 PyTorch 过来、写训练代码时要改的习惯。算出来的数和 PyTorch 对得上:训练主线的 MLP(A3),四组梯度最大差 4.47e-8,100 步 AdamW 后的参数最大差 2.98e-7。
不同的地方集中在「状态放在哪」。PyTorch 把要不要梯度(requires_grad)、梯度(.grad)、图都挂在张量上,用一个全局开关(torch.no_grad())决定记不记图。candle 用类型 Var 标出参数,梯度放在 backward() 返回的 GradStore 里,记不记图只看输入里有没有 Var。
- Var 与梯度:
requires_grad=True对Var;.grad对grads.get(&t);普通张量也拿得到梯度,中间结果拿不到;backward可以跑两次,不累加;非标量、整数、「非叶子参数」三种 PyTorch 报错在 candle 里各变成什么。 - 没有 no_grad:加载的预训练权重不是
Var,推理本来就不记图;忘了no_grad的 PyTorch 前向峰值内存多 0.93 GB;训练中做评估、留参数快照、冻结参数的写法;融合算子没有反向。 - 训练一步:手写训练循环;优化器默认值;AdamW 和 PyTorch 逐步对 100 步,差只来自 f32 舍入;在 burn 卷的两个 Adam 设置上重跑,差比 burn 小一个量级,原因是偏差修正因子在 f64 里算;顺带发现
conv1d的卷积核梯度在 0.11.0 上是错的。
flowchart TB var["Var 参数"] --> fwd["前向 记 Op"] plain["普通张量"] --> fwd plain --> nog["前向 不记图"] fwd --> loss["loss"] loss --> bw["backward"] bw --> gs["GradStore"] gs --> opt["SGD 或 AdamW"] opt -->|"Var set"| var
candle 内部怎么记图、backward 怎么走、优化器怎么写回,见 candle 卷的自动微分。和 burn 的做法对照,见 burn 那一卷的自动求导。
💬 关联讨论
发起讨论加载中...