Rust in Everything
基于 burn 0.22.1

模型

PyTorch 的模型是一个 nn.Module 子类的实例:在 __init__ 里把层赋给属性,__setattr__ 把它们登记成子模块和参数,之后 parameters()、.to()、state_dict()、train() / eval() 都靠这份运行期登记表工作。burn 的模型是一个 #[derive(Module)] 的结构体:派生宏在编译期按字段生成遍历代码,没有登记表;构造参数单独写成一个 Config;训练和推理的切换返回一个新的模型值。

这一部分沿训练主线的前半段走,每页一个 PyTorch 习惯:

  1. 定义模型:nn.Module + __init__ 对 #[derive(Module)] 结构体 + XxxConfig::init(&device);Linear 权重 [out, in] 对 [in, out];普通 Python 列表不登记参数,Vec<Linear> 却是子模块;没有 nn.Sequential,HashMap 装不了子模块。
  2. 参数与遍历:named_parameters() 对一个十几行的 ModuleVisitor,路径名两边一样;BatchNorm 的运行统计在 burn 里算进 num_params;冻结参数 requires_grad_(False) 对 no_grad() 或按路径的 set_require_grad_group;原地改参数值时怎样保住 ParamId 和梯度。
  3. 训练和推理模式:model.eval() 只翻一个标志、原地生效;burn 的 valid() 返回去掉 autodiff 的副本,dropout 和 BatchNorm 还要求输入在 autodiff 设备上;BatchNorm 的运行方差用有偏估计,和 PyTorch 差 n/(n-1) 倍。
flowchart TB
  cfg["MlpConfig"] -->|"init device"| m["Mlp 结构体"]
  m --> vis["visit 遍历参数"]
  m --> fwd["forward 方法"]
  m -->|"valid"| v["推理副本"]
  v -->|"train"| m
  vis --> pid["按 ParamId 认参数"]

三页都用主线里的两层 MLP(4→8→3),权重和 A1 相同。#[derive(Module)] 生成了什么、Param 的懒初始化、train / valid 在参数上做了什么,见 burn 卷的 Module 派生;这一部分只讲从 PyTorch 过来要改的写法。

💬 关联讨论

发起讨论
加载中...