模型
PyTorch 的模型是一个 nn.Module 子类的实例:在 __init__ 里把层赋给属性,__setattr__ 把它们登记成子模块和参数,之后 parameters()、.to()、state_dict()、train() / eval() 都靠这份运行期登记表工作。burn 的模型是一个 #[derive(Module)] 的结构体:派生宏在编译期按字段生成遍历代码,没有登记表;构造参数单独写成一个 Config;训练和推理的切换返回一个新的模型值。
这一部分沿训练主线的前半段走,每页一个 PyTorch 习惯:
- 定义模型:
nn.Module+__init__对#[derive(Module)]结构体 +XxxConfig::init(&device);Linear权重[out, in]对[in, out];普通 Python 列表不登记参数,Vec<Linear>却是子模块;没有nn.Sequential,HashMap装不了子模块。 - 参数与遍历:
named_parameters()对一个十几行的ModuleVisitor,路径名两边一样;BatchNorm 的运行统计在 burn 里算进num_params;冻结参数requires_grad_(False)对no_grad()或按路径的set_require_grad_group;原地改参数值时怎样保住ParamId和梯度。 - 训练和推理模式:
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 过来要改的写法。
💬 关联讨论
发起讨论加载中...