跳到正文
Hugging Face Blog·· 11 小时前精选AI 评分65

Hugging Face 提出 Transformers 模型集成契约 MIC

Transformers Model Integration Contracts

AI 导读

Hugging Face 发布 transformers-mic,提出模型集成契约(MIC)标准,用缩小后的 fixture 模型在 CPU 上运行可复现的用法示例并比对基线输出。

推荐理由

Hugging Face 公开了用缩小模型在 CPU 上跑集成测试的完整配方,读者可据此理解大模型仓库如何把回归挡在合入前。

正文 · AI 翻译

2026 年 7 月 30 日,Transformers 为 T5 启用了 PyTorch 的缩放点积注意力(SDPA)。副作用是,UMT5 的解码器可以关注未来的 token。在训练期间,它可以偷看它本应预测的答案。没有任何东西崩溃,这个 bug 在 main 上停留了将近两个月。

当我们后来重放那些提交时,一个在 CPU 上运行的小型 UMT5 模型在每一个提交上都标记了它。这篇文章讲的就是那个模型以及围绕它构建的测试。

为什么 bug 会进入 main

Transformers 支持超过 750 种模型类型,其测试套件规模庞大:main 上有 88,000 多个 CPU 测试,加上每日运行中 200,000 多个 GPU 测试。模型测试只是其中一部分:我们还测试流水线、训练、分布式执行、量化和注意力内核。

Transformers testing: 88,000+ CPU tests on main and 200,000+ GPU tests daily. Hardware includes CPUs, NVIDIA GPUs, AMD GPUs, Intel XPUs and Gaudi 3. PRs run selected tests.

集成测试会加载真实检查点,并在真实硬件上调用模型的 API。在每个 PR 上都运行所有这些意味着要让大量 GPU 全天忙碌,这不切实际。等到定时运行发现回归时,它可能已经进入 main 了。

我们的方法是缩小模型。我们构建一个 fixture:一个根据真实检查点配置生成的小模型,层数更少、更窄,但包含它拥有的每一种层,并且其 tokenizer 和 processor 文件保持不变。它发布一次,然后重复使用。我们在廉价的 CPU runner 上对它运行“快速集成测试”。在我们的 CPU 研究中,实验性的 UMT5 fixture 使用了 66 MB 权重;源检查点为 1,227 MB。

这也覆盖了非常大的模型:有些模型无法放入我们的标准 GPU runner,但它们的 fixture 可以在 CPU 上运行。

模型集成者已经在构建小型测试模型(Transformers 的 tiny-random-* 检查点)。我们想要一个通用的配方,以及超越加载模型和运行前向传播的检查。UMT5 的 bug 本来可以轻松通过前向传播。

Fixture 不会取代完整的集成测试,但在 PR 上它们给了我们在 bug 进入 main 之前抓住它们的机会。

引入模型集成契约

transformers-mic 是一个用于打包这些测试的拟议标准。模型集成契约(MIC)包含三个部分:

  • 一个 fixture:上面描述的缩小模型,发布一次并固定版本
  • 一个 使用路径:一个可运行的 Markdown 示例,展示人们用该模型做的事情,例如生成文本或运行一个训练步骤
  • 基线:运行该示例时记录的输出,由人工审核

如果在该 fixture 上运行使用路径仍然产生基线,则契约成立。

契约覆盖一个架构和一个使用路径,而不是单个检查点:兼容的检查点可以共享一个 fixture,同时各自保留自己的预期结果。我们将它们发布在 huggingface-mic 中。

例如,SmolLM 契约从“The capital of France is”等提示生成,并将其 token ID 与记录的答案进行比较。在加载模型和 tokenizer 后,生成代码简化为一个提示:

inputs = tokenizer("The capital of France is", return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=4, do_sample=False)
new_tokens = outputs[:, inputs["input_ids"].shape[1]:]
print(tokenizer.batch_decode(new_tokens, skip_special_tokens=True))

它还比较训练损失,检查梯度是否有限,并验证优化器步骤会改变权重。参见完整的 usage.md。

Hub 上的一个 fleet 数据集将每个 MIC 固定到一个冻结的修订版本,以及用于记录其基线的包版本。每次 CI 运行都会记录它使用的 fleet 修订版本,以便我们以后可以复现它。

在 PR 上,我们根据补丁更改的文件来选择 MIC。

UMT5 回归

我们在五个月的 Transformers 提交上重放了冻结的 MIC。小型 UMT5 fixture 从 2026 年 7 月 30 日 引入该回归起就标记了它,直到 9 月 28 日 修复。标签对数概率与审查过的基线相差 1.22,训练损失相差约 0.20。

一个细节很重要:契约使用的是 SDPA,即默认的注意力路径。只运行 eager 注意力变体会漏掉这个 bug。只有当 fixture 走与真实 checkpoint 相同的代码路径时,它才有帮助。

然后我们在 Transformers 的 CI 中于一个验证分支上回退了修复。检查以相同的差异失败,所选 T5 契约的 runner 步骤在 CPU 上耗时 13.4 秒,不含环境准备。

重放结果 和 CI 演示 包含测量数据和复现细节。

模型如何被缩小

最初的配方很简单:把维度变小,保留更少的层。这对混合架构来说还不够。如果两层都使用滑动注意力,而全注意力层消失了,保留两层也没有用。

现在的配方有四个步骤:

  1. 缩小配置。 从真实 checkpoint 出发,减小隐藏维度、注意力头数和深度。保留不同的层类型,包括滑动注意力和全注意力的混合,或稠密层和 MoE 层的混合。某些架构需要额外规则来保持其组件兼容。我们还会查看模型自身的 Transformers 测试:test_modeling_<model>.py 中的 ModelTester 已经手动选择了一个小配置,因此对于我们的通用规则无法按名称识别的任何宽度,我们采用它的尺寸。
  2. 保持预处理不变。 保留词表、特殊 token 和输入维度,并逐字节复制 tokenizer 和 processor 文件。加载和预处理正是我们想要测试的一部分。
  3. 构建并验证权重。 尝试带种子的随机权重,并更改输入以检查模型是否有响应。如果没有响应,尝试在契约的小批量示例上训练它。重新加载保存的模型,并检查输出、损失和梯度是否有限。拒绝失败的构建。
  4. 冻结并记录。 保存接受的权重,并在已知良好的 Transformers 构建上测量可重复的输出。审查每个受支持平台和精度的基线,然后发布一个固定快照。CI 复用它;它不会为每个 PR 重建 fixture。

我们还保留原始权重文件格式。否则我们会跳过用户加载真实 checkpoint 时运行的转换代码。完整配方 有更多细节。

Llama 4 Scout 缩小报告 展示了这在大模型上的效果。1086 亿参数变成 4470 万。视觉栈从 34 层降到 2 层,语言栈从 48 层降到 4 层,保留已检查的层类型和 MoE 路由风格。

用智能体构建 MIC

我们的 CLI,tmic,创建契约并构建 fixture。对于新模型,LLM 起草用法代码和清单,CPU 和 GPU 运行测量候选基线。LLM 起草;它不批准。更改的期望需要人工审查。

要在你的机器上尝试,请用你的源 checkpoint 代替 org/model:

pip install "transformers-mic[runtime]" "hf-doc-builder @ git+https://github.com/huggingface/doc-builder.git"
hf auth login
tmic run org/model --local-only --fixtures-only --no-history --bill-to ''

它会起草合同、构建 fixture 并在你的机器上记录其基线,请你审阅每一步,并在上传任何内容之前停止。对于新模型,草稿来自通过 Inference Providers 的 LLM,费用计入你自己的账户(--bill-to '')。CLI 文档涵盖了各个步骤。

我们使用 agent 跨模型系列构建 MIC。当它们遇到边缘情况时,我们借助模型专家的帮助修复配方本身,而不是修复单个 fixture。已发布的模型和剩余的缺口见覆盖空间。

随机权重与过拟合

使用随机权重时,我们的 Whisper fixture 对音频变化几乎没有反应。它能运行,但这使它成为音频路径的糟糕测试。

因此我们用几个音调与“red”和“green”等词配对来训练它。我们并不是在教它语音识别,只是让音频变化在其输出中可见。在我们的权重初始化研究中,随机 Whisper fixture 捕获了 24 个注入故障中的 18 个。过拟合 fixture 捕获了全部 24 个。

这给了我们两种构建权重的方式:

  • 从随机权重和固定种子开始。
  • 在几个示例上过拟合,例如“The capital of France is”=>“Paris”。

Whisper 的结果并不能确定哪种更好。那些是合成故障,我们还没有发现仅由过拟合版本捕获的真实回归。两个版本都漏掉了一个由真实 Whisper checkpoint 暴露的辅助解码 bug。

因此,当随机权重通过检查时,我们保留它们;当需要更好的灵敏度或可读答案时,我们使用过拟合。训练只需几秒钟,但它是多一个可能无法收敛的步骤,也是多一件需要维护的事情。对比包含两者的结果。

未解决的问题

截至 2026 年 11 月 1 日,Transformers CI 中的 MIC 任务会报告失败,但不会阻止 PR。它是否应该阻止取决于我们尚未测量的事情:

  • 它在 PR 上(而不仅仅是在重放中)能捕获多少真实 bug?
  • 它多久会让我们去追查误报?
  • 基线审查需要多少工作量?

我们也不知道有多少 bug(比如 Whisper 辅助解码那个)只在真实权重下才会出现,或者过拟合是否能捕获随机权重漏掉的真实 bug。

覆盖范围仍然不完整,无论是跨模型系列还是人们使用的 API。当回归漏过时,我们可以添加缺失的使用路径,并在损坏和修复版本上重放它。我们将保留现有测试,直到它们的覆盖范围被纳入考虑。

最后,我们希望将原始 Hub 模型页面链接到它们的 MIC,这样使用 checkpoint 的开发者或 agent 就可以从在该 checkpoint、其环境和预期输出上测试过的示例开始。

想帮忙?从覆盖空间中选一个未覆盖的模型,尝试tmic 工作流,并贡献一个使用路径或审查生成的合同。

来源:Hugging Face Blog · huggingface.co