尧图精选

TorchTitan-NPU CPU UT Review 指南:基于正向功能单元的测试覆盖审查方法

🕒 发布时间:2026/9/18 7:45:27 📁 来源:尧图网络
TorchTitan-NPU CPU UT Review 指南基于正向功能单元的测试覆盖审查方法【免费下载链接】torchtitan-npuAscend Extension for torchtitan项目地址: https://gitcode.com/cann/torchtitan-npu导读本文围绕.agents/skills/developer-tests-review/references/ut-review.md定义的 CPU 单元测试更新与审查规则系统介绍 TorchTitan-NPU 仓库如何从正向功能单元出发判断一条 CPU 单元测试是否真正覆盖了 PR 修改的生产路径。你将掌握一套可执行的审查工作流确定审查范围、独立写出正向功能、读取已有测试、逐条套用规则、判定复用/调整/新增/检查无效并最终输出带状态和合入前置条件的覆盖表同时理解路径等价性、独立 expected、producer/consumer 连接、状态隔离与低价值 UT 判定等核心原则在真实仓库中的落地方式。本文是developer-tests-reviewskill 的组成部分与 format-review.md测试格式、st-review.mdNPU 系统测试、low-value-ut-principles.md低价值 UT 判定配合使用。适用范围与边界本文只审查CPU 上可观察的模块行为、组件连接、路径等价性和独立预期明确不审查测试框架本身也不负责验证真实 NPU 训练。配套 skill 定义了两个 workflow更新测试修改测试代码、执行相关检查并按规则迭代到通过review 测试只读代码并输出报告不修改或执行测试。两者使用同一套规则但修改权限和执行权限不同。审查范围限定为本仓torchtitan_npu/、tests/、.ci/和.gitcode/中参与产品运行或测试执行的内容若 PR 仅修改 torchao、torchft 等第三方仓库且不影响本仓适配接口、注册/配置或训练调用路径则结论为不适用。关键边界UT 和 ST 不是同一条覆盖链路。UT 审查 CPU 可观察行为ST 只审查真实 NPU 集成测试是否进入 PR 改变的训练路径且不把 CPU UT、CPU oracle 或单元测试计入 ST 覆盖。Workflow六步审查流程1. 确定审查范围先记录以下事实基线版本、PR 版本生产源码、已有测试、测试入口和固定依赖将改动区分为生产逻辑、测试代码、测试基础设施和文档。测试基础设施runner、fixture 工具、golden 读取器只作为入口事实读取不把其本身当作产品行为来生成 UT。审查前应确认固定的 TorchTitan commit从requirements.txt和 CI 脚本确认沿本仓patches、override、模型或算子与上游 trainer、model 和 consumer 的真实调用链核对。2. 独立写出正向功能在读取 PR 测试断言之前从生产代码和用户/训练入口写出正向功能正常输入或配置 → 实际生产路径 → CPU 可观察结果 → expected 来源只有不同的用户结果、训练结果或受支持运行方式才拆成不同正向功能配置、工厂、辅助函数、生产分支和 consumer 通常是同一行中的检查点不应据此拆分测试。3. 读取已有测试对每个正向功能记录测试文件、测试入口、准备过程、真实生产调用、直接断言、expected 来源和隔离方式。固定上游测试只能支持固定版本中未修改的通用机制本仓新增的模型、配置、override 和实际选中路径仍要核对本仓测试。4. 按正向功能执行规则对每个正向功能逐条应用下文 Rules 中适用的规则。规则适用性由生产代码路径决定不因为某条规则暂时没有对应测试就跳过如果一个测试同时混合多个正向结果先判断是否应拆分而不是按断言数量拆分。5. 决定复用或更新判定条件复用已有测试进入目标生产路径且有独立结果检查调整测试能进入路径但缺少实际启用、真实输入表示、consumer 接收、最终结果或隔离新增没有直接证据检查无效预期值同源、模拟掉目标行为或断言与声明无关6. 汇总并输出每个正向功能写入覆盖表状态只使用已覆盖、部分覆盖、未覆盖、检查无效、不适用。有缺口时给出准确测试路径、稳定测试名称、最小准备、真实调用、具体断言和 expected 来源。更新workflow 继续修改并执行reviewworkflow 只提交报告。Rules核心审查规则详解1. 模块职责配置和 override测试必须从真实配置、registry 或override.imports入口进入目标实现。只导入模块、直接调用工厂或手动构造目标对象不能证明真实配置选择了该实现。本仓 override 机制位于 torchtitan_npu/override/README.mdoverride.imports中的每个条目必须是完整的module.function路径一个条目只启用对应的工厂函数不会启用同一模块中的其他 override。模型和共享组件模型测试必须从真实 registry/config 进入被修改的主要前向路径并断言该路径产生的 CPU 可观察结果共享组件测试必须使用其实际调用者提供的输入表示不能只测试孤立 helper。算子 wrapper 和 autograd算子测试必须检查 wrapper 的生产参数、输入输出 shape/dtype、CPU 可观察输出和受影响的梯度若 PR 改变 backward 或 saved activation必须直接比较相关输入、score、metadata 或参数梯度。patch 和替换patch 测试必须从真实导入或 apply 入口确认目标上游符号已被替换并确认实际使用位置收到替换后的对象。只断言 patch 函数被调用不能证明替换后的行为。metadata、数据和并行必须确认生产者生成的对象被实际 consumer 接收并检查本次修改涉及的 shape、dtype、boundary、route row 或 placement。CPU 测试不能把真实 NPU/HCCL 结果当作已验证但必须保护 CPU 可观察的契约。compile必须从真实入口确认目标 backend、选项或图替换实际生效并断言编译后仍得到声明的 CPU 结果。只检查配置字段存在不算 compile 路径覆盖。checkpoint 和状态映射必须断言本次修改涉及的具体 key、tensor、dtype、placement 或恢复后的状态不能只比较 key 数量、文件存在或保存函数返回成功。固定上游版本复用上游测试或说明 patch 兼容性时从 PR 版本的依赖文件和 CI 脚本确认实际固定的 TorchTitan 版本报告写明上游符号、测试路径和版本。多种实现的精确选择同一目标存在golden、cann、workaround或其他实现时测试必须确认一条override.imports只启用请求的工厂不隐式启用同模块的其他实现带参数的配置条目要检查解析后的具体参数。自动生效的兼容 patch修改torchtitan_npu/patches/下随包导入生效的 patch 时测试必须从本仓包导入或apply入口确认替换已经安装再检查该 patch 负责的最小行为。共享实现和新模型修改共享 attention、normalization、RoPE、MoE 或 decoder 时先保护共享实现的输出、形状和类型新增模型或新的生产入口时至少一条 CPU UT 必须使用真实注册配置构建小模型并进入主要前向路径。只检查注册表名称或配置构造成功不足以覆盖模型路径。2. 正向入口和实际启用从正常入口开始测试应从用户实际使用的入口开始至少走到 CPU 能观察的承诺结果。导入成功、构造成功、注册成功、有限值或不抛异常只有在这就是接口完整结果时才足够。检查目标确实启用配置、注册、替换实现、补丁、编译或回退路径可能静默绕过新代码时测试必须检查实际选中的对象、替换后的配置、传入参数或最终调用。对 override-refactor优先从真实Trainer.Config.override.imports和工厂入口构建检查目标配置或对象被替换。检查最终结果断言只覆盖能够区分本次正确行为与错误行为所需的输出、形状、类型、参数、状态、放置或持久化值。多个断言可以共同证明一个正向结果不按断言数量拆测试也不遍历与 PR 无关的整个对象。3. 生产者、consumer 和参数传递这一组规则强调谁把什么交给谁的契约检查使用真实生产者输出测试应使用真实生产者输出或使用已由生产者规则验证过的 fixture——两端分别有测试不能自动证明中间字段、形状或语义一致连接生产者和 consumer连接发生变化时测试至少要让 consumer 直接接收真实生产者输出或让 fixture 按明确的生产者输出规则生成并检查该规则或增加一条薄测试证明生产者输出成为 consumer 输入明确谁把什么交给谁当张量、mask、metadata、config、placement 或 callable 从组件 A 交给组件 B 且参与本次结果时测试必须断言 B 实际收到的具体值或对象。报告要写明双方和对象参数和边界PR 改变参数顺序、默认值、可选值、shape、dtype、边界或 placement 时测试必须使用能区分旧行为和新行为的输入并在 consumer 处或最终结果处断言该参数实际生效数据、tokenizer 和 dataloader至少一条测试必须使用真实生产者输出报告记录与改动有关的 padding、positions、labels 或 packed boundary 字段预期值不能由同一待测转换同时生成并行、DeviceMesh 和 DTensor必须明确 mesh 形状、rank、placement 和并行数值并检查 CPU 能看到的路由或 metadata 结果。真实通信、NPU 放置和跨 rank 梯度不由 CPU UT 证明新增并行组合前必须写出该交叉条件会进入哪条不同生产路径写不出时不新增组合测试。4. 路径等价性触发条件score、scale、mask、clamp、activation、dtype、quantization、bias、route row、permute/unpermute、collective、saved activation 或 backward 路径发生变化或者 PR 声称数学等价只优化性能时必须执行本组规则。写出旧路径、新路径和等价条件测试设计必须先写出旧路径、新路径、两者应相等的条件以及有意变化的预期。不要把都能运行或训练 loss 相近当作路径等价条件。使用独立 expected旧路径和新路径必须分别与独立 dense/reference expected 比较。可接受来源包括手算小例子、独立 PyTorch 实现、固定且注明版本的上游实现、数学性质和保存/加载往返不能复制待测算法生成 expected也不能直接录制待审代码输出作为 golden。比较 forward 和 backward路径等价测试必须比较受影响的 forward 输出、输入梯度、score 或 metadata 梯度以及参数梯度。只比较最终 loss或只比较 forward不足以保护改变了 backward 或 saved activation 的 PR。比较路由对应关系路由变化测试必须比较 routed rows、expert ids/counts、score 对齐以及 permute/unpermute mapping。只比较输出 shape 或 expert 数量不能证明 token 与 score、expert 和 row 的对应关系保持。collective 的 CPU 契约涉及 AllToAll 的 CPU 契约必须使用真实 2-rank Gloo collective 检查 rank 间的排列、聚合和返回结果fake permutation 只能证明局部排列逻辑不能证明 collective 契约。等价性结论的边界本组规则只判断测试是否提供了等价路径的证据不判断生产代码本身是否数学正确。保持等价的路径没有独立 expected 时状态只能为部分覆盖或未覆盖不能给出可以合入。若 PR 有意改变 dtype、量化或其他语义应比较新的独立预期不要求与旧路径相等。Router-score 的具体契约对无 bias 的 dense expert若生产路径把 score 从hidden W2.T之后移动到之前测试必须明确比较post (hidden W2.T) * score与pre (hidden * score) W2.T的独立结果。只有 score 是每个 routed row 的标量、W2无 bias、两条路径使用相同 dtype 语义且 routed input 与 score 逐行对应不变时才有代数等价依据activation、量化、额外 clamp 或 row reorder 位于 score 与W2之间时必须重新证明。Router-score 的 fixture 和梯度等价测试应使用固定 float64 输入、W1/W2/W3、交错 expert ids、非均匀 scores/counts并让 input、scores 和权重参与固定 scalar loss 或 upstream gradient。dense reference 必须分别产生 post/pre 的输出以及 input、score、W1/W2/W3梯度Local 或 AllToAll 候选各自与 reference 比较候选互比只能作为补充。Router-score 的对齐和 collective涉及路由重排时测试必须独立计算 row map并断言 routed input、routed score、expert ids/counts、permute indices 和最终 unpermute/combine 对齐。AllToAll 路径要使用 2-rank Gloo 真实 collective 检查 rank-local split/gather 和跨 rank 梯度归属。5. 独立 expected 和断言质量expected 必须来自手算、独立实现、固定上游、数学性质或保存/加载往返不能由待测路径、同一 helper 或同一生产对象生成。断言必须能够让一个具体错误实现失败——只断言不抛异常、有限值、对象非空、调用次数或 key 数量不能支持名称中声称的数值、路由、替换或恢复结果。当生产代码把结果交给后续模块时测试必须断言后续模块接收到的具体值或最终使用结果。仓库中的典型正面示例是 tests/unit_tests/ops/triton/gdn/test_gdn_validation.pytest_gdn_l2_normalize_matches_float64_oracle用独立 float64 oracle 计算 inverse 和 normalized 期望值test_gdn_l2_normalize_cpu_gradient_matches_oracle让 input 和 inverse 参与固定 scalar loss 后用 float64 重算 autograd 梯度并逐值比较正是独立 expected forward/backward 都验证的落地形态。6. Fake、Stub 和 SpyFake、Stub 和 Spy 可以隔离 NPU、进程、外部服务或昂贵操作但不能替代正在声明验证的计算、目标选择、参数传递或张量放置。模拟 tokenizer、数据集、模型、算子或 process group 时名称和 fixture 说明必须写清模拟支持的输入范围。调用次数只有在路由本身就是结果时才有意义。真实 NPU 结论边界CPU fake、模拟进程组或模拟 NPU 算子不能证明真实 NPU kernel、HCCL、跨 rank 梯度或完整训练结果这些属于 ST 或其他专门测试的范围不把它们误记为 CPU UT 缺陷或 UT 已证明。仓库中的具体实现见 tests/unit_tests/conftest.py_fake_cann_ops()构造一个cann_ops_transformer调用记录器把每次调用追加到ct.calls作为(fn_name, args, kwargs)install()将其注入sys.modules和torch.ops.cann_ops_transformer命名空间。CPU 测试由此获得 NPU 边界 seam但 conftest 注释明确写道CANN op surface is untestable on CPU——记录器本身不证明 NPU kernel 行为只保证 CPU 侧可导入与可观察调用。7. 状态隔离测试必须恢复其修改的 RNG、环境变量、registry、monkeypatch、process group、临时文件、单例、钩子和 import cache。随机输入使用局部 generator 或可恢复的 RNG 范围测试不得依赖另一条测试先执行也不得依赖未声明的网络、设备或外部初始化。格式审查规则将静态可见的恢复缺口记录为隔离风险不运行测试猜测它是否污染后续测试。8. 测试最小性和复用对每条现有或拟议测试问删除它以后哪项正向功能会失去直接检查能指出独立结果则保留否则标记为重复或无需新增。一个测试无法用单一条件和结果命名时检查它是否混合了不同准备、不同调用或不同最终结果。固定上游测试可以复用未修改的通用行为但不能替代本仓新增模型、配置、override 或实际选中路径的测试。9. 测试框架边界测试入口和结果处理修改 pytest 入口、CI 脚本、测试发现或结果处理时只静态读取配置和 shell 控制流程检查目标路径没有被排除、pytest 非零退出没有被吞掉、跳过和超时没有被改写不要把 runner 自身的可用性测试当作产品 UT测试辅助函数名称声称校验时代码必须存在明确失败条件只做数据转换的辅助函数不能被报告为审查结论golden 读取器、报告渲染器和测试工具只做入口事实审查非运行文件文档、skill、审查规则、报告渲染、HTML、邮件和其他不参与产品运行或测试执行的修改直接标为不适用。10. 低价值 UT 原则本节只用于判断一条 CPU unit test 是否值得长期保留与功能覆盖审查解耦。仓库中的完整版本见 docs/developer_guides/low-value-ut-principles.md核心判定包括先判断删除后失去什么删除后若仍有另一条测试保护相同的用户可观察行为、受支持边界或数值语义通常是重复的只能说代码被执行了对象存在或没有抛异常通常不足以证明长期价值私有不等于低价值判断私有防御性分支不能只看函数名是否带下划线需确认其未被公开导出、只拒绝非法输入、不产生业务结果且正常生产配置已保证该条件反之私有函数若实现数值变换或状态映射仍可能是高价值测试对象防御性校验只保留不可替代的约束像 GDN_validate_inputs()这样的校验不应为每个 dtype、shape、device 和错误组合建立长期拒绝矩阵配置测试不要复写 Python 实现不应把partial类型、函数名、keywords字典、内部 tuple、对象 identity 或当前常量排列当成稳定契约性能机制不能用字段存在代替结果host cache、减少.item()同步、缓存 metadata 等实现机制只断言seq_len_host、n_cmp_blocks_host等字段存在通常是低价值 implementation test退化数据会制造低价值测试全零、完全对称或线性参数的 fixture 会使不同公式得到相同结果应改成能真正区分实现的最小数据。关于 GDN 校验仓库现状是 test_gdn_validation.py 对_validate_inputs保留了少量参数化拒绝用例token length 非 64 倍数、dtype 非 bf16/fp16、reset shape 错误、非有限 scale其余重心放在 L2 normalize 的 dtype 保持、float64 oracle 数值对照和前向/反向梯度验证——这与校验不建拒绝矩阵、数值语义用独立 oracle的原则一致。处置候选测试只允许四种结果保留为有独立价值的产品 UT、缩小为最小边界测试、迁移到 tooling/benchmark/static check、或删除且处置记录必须写明删除后失去的证据和替代证据。输出UT 覆盖表审查最终输出为覆盖表按 report-output.md 的格式要求部分覆盖行必须突出显示浅红或浅黄背景正向功能单元生产路径测试实际准备、调用和断言expected 来源状态合入前置条件每项正向功能一行应观察结果具体准备、调用和断言不能只写测试名称独立来源五种状态之一路径名称最小准备真实调用具体断言为什么足够合入前置条件要写准确测试路径、稳定测试名称、最小准备、真实调用、具体断言和 expected 来源以及为什么这一条足够不需要继续增加组合。报告还需遵守统一术语见 terminology.md例如写override.imports选择了哪个工厂并替换了哪个配置而不是约定或连接review测试固定写明测试执行未执行仅静态审查。与其他审查文件的分工文件职责ut-review.mdCPU UT 正向功能覆盖、路径等价、独立 expectedst-review.md真实 NPU 集成测试是否进入 PR 改变的训练路径format-review.md文件位置、pytest 收集、命名、结构、隔离low-value-ut-principles.md一条 UT 是否值得长期保留三者结论互不替代格式问题不能代替正向功能未覆盖CPU UT 结论不能计入 ST 覆盖低价值判定不取代功能覆盖审查。【免费下载链接】torchtitan-npuAscend Extension for torchtitan项目地址: https://gitcode.com/cann/torchtitan-npu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →