tinygrad dtype:weak 提交、64 位整数拆字与低精度浮点模拟

作者:

在

结论:tinygrad 的 dtype 语义分两段:前端 Tensor 只构造 cast/bitcast 与 weak 常量,真正定宽发生在编译期——由 pm_commit_weak 推导输入宽度、pm_lower_weak 消除弱类型计算节点、末端 pm_cast_const 提交裸露常量;当某类型不在 renderer 支持集或列入 EMULATED_DTYPES 时,才由 pm_dtype_decomps 用两个 32 位字或位型重写来模拟。EMULATED_DTYPES 是运行上下文配置,不等于物理设备确实支持或不支持该 dtype。

从 API 到 UOp:三个阶段

前端阶段,DTypeMixin.commit_dtype() 利用 UOp 值域确定 weakint 的具体整数类型;cast() 产生数值转换,bitcast() 拒绝 weak dtype 并产生位重解释。两者都先构造 UOp,并非当场完成设备计算。弱类型提交阶段由 commit_weak_srcs()、cast_weak_srcs()、lower_weak_node() 根据消费者、显式 CAST 和表达式边界定宽,最终 pm_cast_const 处理仍裸露的常量;弱类型图不是可直接交给任意设备的 ABI。

降解插入点固定在 full_rewrite_to_sink():代码生成先整理 weak 类型和符号,再进行早期算子降解,随后将 pm_dtype_decomps 与弱常量提交一起执行,最后才进入后期降解和渲染。编译次序上,sym + indexing_simplify + pm_commit_weak 先达到定点;接着 pm_lower_weak + indexing_simplify 固定计算 dtype,特意不再组合 symbolic,以免 Invalid 门重新生成 weak 节点形成循环;dtype 模拟之后的最终重写再次提交新产生的 weak 常量,末端 pm_cast_const 处理剩余边。

阶段 函数/组件 行为和边界
前端 API commit_dtype() / cast() / bitcast() 确定 weakint 具体类型;产生数值转换或位重解释;均先构造 UOp
弱类型提交 commit_weak_srcs() / cast_weak_srcs() / lower_weak_node() 按消费者、显式 CAST、表达式边界定宽;pm_cast_const 末端提交裸常量
降解插入点 full_rewrite_to_sink() 先整理 weak 类型,再早期降解,随后执行 dtype 模拟与弱常量提交
选择模拟 do_dtype_decomps() / pm_dtype_decomps 仅在类型不受支持或在 EMULATED_DTYPES 时重写;uint64 归并到 long 降解族

64 位整数:两个 32 位字

宽整数降解由 l2i()、split_l2i() 和 pm_long_decomp 实现:用两个 32 位字完成转换、加减乘、比较、移位和逐位除法,内存定义扩大为两个字,索引/存储拆分。ALU 地址空间的 Variable 明确不支持此降解——这是宽整数模拟最容易踩的边界。

低精度浮点则由 f2f()、f2f_clamp()、f2f_load()、f2f_store() 通过位型重写 FP8/BF16/FP16 的载入、计算/转换与存回;模拟路径显式把非规格化数冲零,FP8 转换还涉及饱和及 FNUZ 非有限值约定。这些数值语义差异必须在逐算子数值测试中单独覆盖,不能只验证 API 层能否调用。

目标类型 降解入口 关键语义与限制
int64 / uint64 l2i() / split_l2i() / pm_long_decomp 两字实现转换、算术、比较、移位、逐位除法;ALU Variable 不支持
FP8 f2f() 家族 位型重写;涉及饱和与 FNUZ 非有限值约定
BF16 / FP16 f2f() 家族 位型重写载入/转换/存回;模拟路径非规格化数冲零
内存定义 f2f_load() / f2f_store() LOAD/STORE 存储格式重写;长整型缓冲扩为两个字

选择逻辑上,pm_dtype_decomps 仅收集 FP8、BF16、FP16、int64/uint64 等候选;当类型不在 renderer 支持集,或列入 EMULATED_DTYPES 时才重写。Renderer.supported_dtypes() 给出基础能力接口,具体 renderer 可以覆盖;do_dtype_decomps() 在处理完收集集后清空上下文,使后续编译遍历不把先前发现的类型当作当前结果。

weak 类型规则的逐函数前提

weak 类型是这套降解里最容易被误读的部分。commit_weak_consts() 与 derived_dtypes() 对已有具体 dtype 的广播算子求操作数共同类型及结果类型,再提交裸常量——但两者任一仍为 weak 时返回 None,不会强行选一个设备宽度。cast_weak_srcs() 与 pm_commit_weak 为显式 CAST 的 weak 表达式提供计算宽度下界,因此 float32 表达式再 cast 到 float16 不意味着内部计算可降到 float16,需保留范围允许的更宽 dtype。

absorb_weak_src() 与 lower_weak_node() 吸收可重推导的 weak CAST,并给无法再推导的算子/常量定宽;这里从浮点经 weakint CAST 是数值转换,不能当纯注释删掉,且 WHERE 条件不参与分支宽度统一。pm_lower_weak 处理小缓冲的 gated long index、连续 weak 类型转换和 ALU 变量参数,索引缩窄只在缓冲最大元素数落入 int32 时适用。pm_uncast_const 在消费者类型推导完全不变时去掉常量上的强类型 CAST;pm_cast_const 最后提交仍裸露的常量边,其中 Invalid 不按普通常量提交。

与 openpilot 集成的边界

ModelState.pack_inputs() 的帧与辅助输入分别使用 uint8 和 float32 缓冲视图,这里必须先保持 dtype、shape、偏移和设备拷贝一致;后端内部低精度降解发生在编译阶段,不能拿它替代输入缓冲 ABI 检查。构建期 compile_model() 捕获并编译模型/warp 的 TinyJit 产物,实际节点是否包含某个被模拟 dtype,需要检查相应 LFS 模型图及编译产物。

源码证据层面,本机补跑 test_dtype_weak.py 得 46 项 OK,含 1 项预期失败 test_changed_rows——预期失败明确表明部分弱标量提升矩阵尚未达到测试期待,不能把整套弱类型语义视为已完全收敛。后端小样例中,int64 两元素加法在普通及 EMULATED_DTYPES="long" 上均得到 [1099511627788, 18],强制模拟 BF16 后转回浮点得到 [1.5, -2.0]。自制硬件后端若声明支持新 dtype,应有逐算子数值、字节布局、端序、非有限值、饱和、非规格化数、跨设备复制与尾延迟证据。

常见问题

EMULATED_DTYPES 设了,是否说明设备真的不支持该类型?

不等价。源文档明确 EMULATED_DTYPES 是运行上下文配置,不等于物理设备确实支持或不支持某 dtype。是否重写还取决于类型是否在 renderer 支持集内:pm_dtype_decomps 只有当类型不在支持集或列入 EMULATED_DTYPES 时才重写。

float32 表达式再 cast 到 float16,内部计算会降到 float16 吗?

不一定。源文档指出 cast_weak_srcs()/pm_commit_weak 只是为显式 CAST 提供计算宽度下界,float32 表达式再 cast 到 float16 不意味着内部计算可降到 float16,需保留范围允许的更宽 dtype,否则会丢失中间结果精度。

64 位整数模拟在所有场景都能用吗?

不是。宽整数降解用两个 32 位字实现,但源文档明确 ALU 地址空间的 Variable 不支持此降解;索引缩窄也只在缓冲最大元素数落入 int32 时才适用。超出这些边界时需要另行处理。

测试通过是否代表 dtype 语义已经收敛?

不代表。test_dtype_weak.py 的 46 项 OK 中含 1 项预期失败 test_changed_rows,源文档据此说明部分弱标量提升矩阵尚未达到测试期待。此外 test_dtype_alu.py 的定向运行因环境缺少 hypothesis 在导入阶段即停止,64 位除法/移位、FP8 特殊值和具体 GPU renderer 未经本轮动态验证。

延伸阅读

参考资料

  • 项目 02 —— openpilot-research/TINYGRAD_DTYPE_UOP_LOWERING_EMULATION_DEEP_DIVE.md(取用了前端 API、weak 类型规则、宽整数与低精度浮点降解、编译次序及与 openpilot 集成的边界)。
  • 项目 02 —— openpilot-research/TINYGRAD_DTYPE_PROMOTION_STORAGE_CONTRACT_DEEP_DIVE.md(仅用于确认基础 dtype 提升与存储契约的上下文)。

说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

更新记录

首次发布 2026-10-11 最近核对:2026-10-11

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注