结论:tinygrad 的优化器是训练期参数更新器,不是车端规划器或控制器;把它接进车端推理链没有意义。有两个事实最容易被忽略。第一,zero_grad() 是把每个参数的 .grad 设为 None,不是对梯度缓冲填零,下一轮 backward() 才重新生成梯度。第二,step() 的执行包含参数、动量/矩和偏置幂三组状态的同批 realize,只序列化权重而遗漏优化器状态,不能无损续训。此外 FUSE_OPTIM 与 TRAINING 默认都是 0,它们是 tinygrad 的上下文/构建配置,不是车辆安全授权。以下为固定快照的静态分析,未运行完整优化器矩阵或实车测试,本地没有模型实体。
公共生命周期
Optimizer.__init__() 拒绝负学习率,只把 is_param 张量作为可更新参数并按对象去重,非参数进入 buffers;无可更新参数会断言。device 默认取第一个参数的设备,OPTIM_DTYPE 默认 float32,学习率 dtype 至少为 float32。_new_optim_param() 为动量/矩状态创建零张量:普通模式逐参数创建,设备为 tuple 时使用 zeros_like,融合模式只创建一条展平状态,长度由 pos_params 决定。
调度与执行上,schedule_step() 要求 TRAINING=1:融合模式拼接参数与梯度、执行一次 _step() 再按原形状拆回,普通模式逐参数更新;它调用 assign() 排定状态和参数写入,返回额外状态、参数和 buffer 的实现列表,梯度缺失则通过 unwrap() 报错。step() 把 schedule_step() 返回的张量交给 Tensor.realize();_apply_update() 将更新量搬到参数设备并从 detach() 后的参数中减去。由于 schedule_step() 已有 assign 副作用,不应视为只读计划 API。
| 入口 | 实现及外部契约 |
|---|---|
Optimizer.__init__() |
拒绝负学习率;仅 is_param 张量可更新并按对象去重;OPTIM_DTYPE 默认 float32。 |
_new_optim_param() |
创建零状态张量;融合模式只建一条展平状态,长度由 pos_params 决定。 |
zero_grad() |
把 .grad 设为 None,不是填零;下轮反传重新生成。 |
schedule_step() |
要求 TRAINING=1;融合拼接后一次 _step() 再拆回;有 assign 副作用。 |
step() / _apply_update() |
前者把张量交给 realize();后者在参数设备上从 detach() 参数减去更新量。 |
OptimizerGroup |
汇集多优化器的参数/buffer/排定更新;无跨组参数去重,也未调用基类构造器。 |
优化器族与状态布局
优化器族大致分为 LARS 家族与 LAMB 家族。SGD() 是 LARS(tcoef=0, pre_wd=True) 的包装;LARS._step() 可按参数/梯度范数计算 trust ratio,支持两种动量与 Nesterov,权重衰减和学习率在 classic 分支的作用次序不同。Muon() 复用 LARS 更新主干,先对梯度应用 Newton-Schulz,再做学习率及后置权重衰减,并明确拒绝 fused=True。
| 优化器 | 实现要点 | 边界 |
|---|---|---|
SGD() |
LARS(tcoef=0, pre_wd=True) 包装 |
复用 LARS 主干与权重衰减次序。 |
LARS._step() |
按参数/梯度范数算 trust ratio;两种动量与 Nesterov | 权重衰减与学习率次序在 classic 分支不同。 |
Muon() |
先 Newton-Schulz 再学习率与后置权重衰减 | 拒绝 fused=True;形状与数值稳定性不能由接口名保证。 |
Adam() |
包装 LAMB(adam=True),trust ratio 固定为 1 |
不加权重衰减。 |
AdamW() |
同 Adam 包装 |
默认衰减为 0.01。 |
LAMB._step() |
更新幂状态与一、二阶矩,做偏置修正与 eps 分母稳定,可选算 trust ratio |
梯度与状态设备不同则先搬至状态设备;更新量 shard_like(t) 在参数设备应用。 |
状态布局的关键是 OPTIM_DTYPE 默认 float32、FUSE_OPTIM 默认关闭;融合时会把参数和梯度展平拼接,切换融合配置或设备布局不能直接复用旧状态形状。学习率 dtype 至少为 float32。
状态机与调用顺序
典型训练调用为:loss.backward() 前先 zero_grad(),随后 loss.backward()、step()。step() 的执行包含参数、动量/矩和偏置幂的实现;仅序列化权重而遗漏优化器状态,不能无损续训。FUSE_OPTIM 默认 0、TRAINING 默认 0,这两个开关是 tinygrad 的上下文/构建配置,不是车辆安全授权。OptimizerGroup 的交叉参数重叠、状态文件版本兼容、多设备搬运以及异常发生在部分 assign() 之后的恢复语义,均应列入训练插件测试矩阵。
| 开关 / 状态 | 默认值 | 含义 |
|---|---|---|
OPTIM_DTYPE |
float32 |
优化器状态张量的默认 dtype。 |
FUSE_OPTIM |
0(关闭) | 融合时参数与梯度展平拼接为单条状态。 |
TRAINING |
0(关闭) | schedule_step() 要求其为 1;是构建/上下文配置,非安全授权。 |
| 优化器状态集合 | — | 参数 + 动量/矩 + 偏置幂,step() 时同批 realize。 |
ONNX 与车端关系
OnnxRunner._init_from_graph() 通过图中训练域节点设置 is_training,OnnxRunner.__call__() 在该标志下设置 Context(TRAINING=...)。ONNX 的 Adam() 借用 TinyAdam,但把外部 V/H 及学习率装入临时优化器,并依据步数初始化偏置幂——这属于 ONNX 训练域功能,不表明 openpilot 车端执行在线学习。
车端一侧,openpilot 的 compile_model() 在构建时把 ONNX 编译为捕获的模型工件;运行期 ModelState.run() 调用 run_warp/run_model 并解析输出。当前本地源码未见该路径实例化 tinygrad.nn.optim 或调用 step();由于缺少模型实体,只能确认可见源码的调用边界,不能断言模型图内部的全部节点。
硬件与插件重构建议
把优化器、梯度、训练域 ONNX 和权重写入归入离线训练/构建插件;车端推理插件只接受已验证、版本绑定、只读的模型工件,不要给训练插件 CAN 发送、panda 安全模式或控制消息发布权限。模型工件契约应记录 ONNX/opset、tinygrad 版本、dtype、输入输出 shape、目标设备、权重哈希和参考数值;优化器状态另行版本化,fused、参数顺序和设备分片都需一致。硬件替换只接管相机帧、时间戳、缓冲拷贝/映射和推理执行端,保持 modelV2 等输出 schema、延迟预算和健康信号稳定,不可通过更换优化器绕开感知、规划、车型协议与 panda 固件安全门。
常见问题
zero_grad() 是把梯度清零吗?
不是。它把每个参数的 .grad 设为 None,而不是对已有梯度缓冲填零;下一轮 backward() 会重新生成梯度。
只保存权重就能无损续训吗?
不能。step() 的执行包含参数、动量/矩和偏置幂三组状态的同批 realize;只序列化权重而遗漏优化器状态,无法无损续训,优化器状态需要另行版本化保存。
tinygrad 优化器与 openpilot 车端推理是什么关系?
没有直接关系。优化器是训练期参数更新器;openpilot 在构建时把 ONNX 编译为捕获的模型工件,运行期 ModelState.run() 只运行该工件,当前可见源码未见车端实例化 tinygrad.nn.optim 或调用 step()。
FUSE_OPTIM 或 TRAINING 打开会影响车辆安全吗?
不应这样理解。这两个开关默认都是 0,是 tinygrad 的上下文/构建配置,不是车辆安全授权;训练数值测试也不等于整车安全验证。
延伸阅读
- tinygrad NN 层状态与 shape 契约 —— 承接参数与状态张量的形状与版本管理。
- 端侧推理工具链快速上手 —— 对照模型工件契约与目标设备绑定。
- tinygrad 数据集与 torch 前端入口边界 —— 承接训练数据与模型构建的边界。
- modeld 构建工件与 warp 契约 —— 对照构建期编译与运行期推理的分工。
- tinygrad 的 torch 私有 use1 与 aten 别名设备 —— 承接前端算子与设备映射的边界。
参考资料
- 项目 02 ——
openpilot-research/TINYGRAD_OPTIMIZER_TRAINING_STATE_INFERENCE_BOUNDARY_DEEP_DIVE.md(取用了优化器族与状态表、zero_grad置 None、三组状态同批 realize、ONNX 训练域与车端推理边界)。
说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。
更新记录
首次发布 2026-10-11 最近核对:2026-10-11