Rust in Everything
基于 burn 0.22.1

训练一步

PyTorch 的优化器握着参数,loss.backward() 把梯度写到参数上,opt.step() 原地改参数。burn 的优化器不握参数:backward() 返回梯度,GradientsParams::from_grads 按 ParamId 把梯度和参数对上,optim.step(lr, model, grads) 拿走旧模型、交回新模型。参数的身份从「同一个 Python 对象」换成了「同一个 ParamId」,这一部分的大多数差别都从这里来。

  1. 一步:A1 的一整步逐行对照(最大误差 1.19e-7);优化器怎么靠 ParamId 找到参数;更新后旧模型的 clone() 留着旧值;梯度配错模型、不接 step 的返回值,两种静默的错误。
  2. 优化器状态:Adam 训练 10 步,默认 ε 不同(1e-8 对 1e-5)差到 3e-4,对齐后差 4.8e-7,剩下的差来自 burn 在 f32 里算偏差修正;状态按 ParamId 存,换了 id 的模型静默从头开始;梯度裁剪按参数而不是全局;学习率调度和几处默认值。
  3. 训练循环:同一个任务的 PyTorch 手写循环、burn 手写循环、burn Learner,前两者差 1.19e-7,后两者逐位相同;验证模式、指标的平均方式、checkpoint、训练完的模型。
flowchart TB
  loss["loss"] -->|"backward"| g["Gradients 按节点"]
  g -->|"from_grads 和模型"| gp["GradientsParams 按 ParamId"]
  gp --> st["optim.step lr model grads"]
  state["优化器状态 按 ParamId"] <--> st
  sched["调度器给 lr"] --> st
  st --> nm["新模型 ParamId 不变"]
  nm -.->|"下一步"| loss

burn 内部的优化器结构(Optimizer 和 ModuleOptimizer 两层、状态的类型擦除、记录格式)和 Learner 的组成见 burn 卷的优化器和 Learner 与数据。同一个模型训练到收敛、误差随步数怎么累积,见同一个小模型训练到收敛。

💬 关联讨论

发起讨论
加载中...