mcpField
I
import-model

import-model

github.com/modular开发2071.4k 次安装3 天前更新
代码仓库

关于 import-model

指导开发者将 Hugging Face 模型移植到 MAX ModuleV3 的工作流,涵盖检查配置与权重、选择参考架构、实现差异,并在服务模型前验证输出。

主要功能

  1. 01检查 Hugging Face 配置和权重
  2. 02识别原生架构及移植障碍
  3. 03比较模型并选择参考架构
  4. 04生成 ModuleV3 移植骨架
  5. 05实现架构差异并验证输出

适用场景

  1. 01评估模型是否需要移植到 MAX
  2. 02基于参考架构规划 ModuleV3 实现
  3. 03对照 Hugging Face 输出验证移植结果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/modular/skills --skill import-model

安装后在 Claude Code 中输入/import-model确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.gitattributes
.gitignore
pixi.toml
README.md
references/
distributed-transformer.md
divergences.md
implement-graph.md
layer-by-layer-debugging.md
map-to-max.md
max-vs-port-isolation.md
native-arch-check.md
pitfalls-config.md
pitfalls-graph.md
pitfalls-serving.md
pitfalls-weights.md
pitfalls.md
plan-and-veto.md
read-config-json.md
read-modeling-code.md
recognize-walls.md
rename-weights.md
rewrite-donor-docstrings.md
serve-and-iterate.md
state-dict-audit.md
template.md
tests-and-ci.md
validation-tiers.md
scripts/
__init__.py
check_port.py
check_walls.py

详细介绍

将模型导入 MAX

输入: Hugging Face 模型 ID($ARGUMENTS)。

将 references/template.md 复制一份,在各个阶段推进时跟踪此移植工作。其中的文件引用是相对于此技能根目录的路径,因此复制到其他位置后仍然有效。

将模型移植到 MAX,意味着编写一个 ModuleV3 模型,使其执行与 Hugging Face transformers 中的 modeling_<type>.py 相同的计算。然后,使用发布的权重编译模型,并验证输出是否匹配。ModuleV3 是 MAX 的模型 API。层是 max.experimental.nn 中 Module 的子类,包含对 Tensor 值进行处理的 forward()。算子来自 max.experimental.functional(导入为 F)。流水线会在 F.lazy() 下构建模块,并使用 compile(weights=...) 编译。单 GPU、张量并行和专家并行模型都使用 ModuleV3。多 GPU 模型通过 DeviceMesh 分片。

工作流分为决定与规划、实现和验证三个阶段。第 1 阶段是阅读和规划。第 2 阶段是移植:在模块中实现每个存在差异的子层。第 3 阶段是验证,仅在实现完成后进行。守卫(会中止工作流的前置条件)用于控制活动之间的转换。它们本身不是步骤。

反模式: 运行 scaffold.py,调整 arch.py,并启动服务,而 <slug>.py 仍实现供体模型(llama3_modulev3、olmo3 等)。由于 <slug>.py 仍运行供体架构,logit 验证会在该移植上失败。只有在满足 implement-graph.md 的完成标准后,才能运行验证脚本。

每个阶段都链接到包含详细信息的参考文档。只阅读当前活动对应的参考文档,不要一开始就全部阅读。

环境: 通过已安装 MAX 的 pixi 环境运行所有命令(pixi run python …、pixi run max serve …)。请在包含 pixi.toml 的技能根目录中运行命令,不要使用 shell PATH 中的裸 python 或 max:

cd <path-to-skill>
pixi install
pixi run python scripts/inspect_hf.py <HF_MODEL_ID>
# Or: pixi run test-scripts   # smoke-test all scripts (no GPU)

默认环境可安装在 Linux(x86-64 和 ARM64)及搭载 Apple 芯片的 macOS 上,无需 CUDA。其 PyTorch 会在 CPU 或 Apple 芯片 GPU 上运行 HF 参考模型。在 NVIDIA 主机上,pixi run -e cuda … 会使用 CUDA PyTorch 运行相同的命令,因此 HF 参考模型也会在 GPU 上运行。

辅助脚本位于此技能的 scripts/ 目录中(请将它们复制或 vendoring 到你的仓库中)。所有辅助脚本也可通过统一分发器调用,其参数名称和退出代码相同:

pixi run python scripts/import_model.py inspect <HF_MODEL_ID>
pixi run python scripts/import_model.py list-archs --donors
pixi run python scripts/import_model.py scaffold <HF_MODEL_ID> --start-from olmo3 --output-dir ./
pixi run python scripts/import_model.py list-archs --match LlamaForCausalLM
pixi run python scripts/import_model.py check-walls <HF_MODEL_ID>
pixi run python scripts/import_model.py list-keys <HF_MODEL_ID> --summary
pixi run python scripts/import_model.py gates <HF_MODEL_ID> --port-dir <port_dir>
pixi run python scripts/import_model.py compare <HF_MODEL_ID> --port 8000

移植目录布局:

  • <port_dir>:包含 arch.py 和 __init__.py 中 ARCHITECTURES 的 slug 文件夹(通常为 <output_dir>/<slug>,末尾不带斜杠)。将此路径传给 --custom-architectures 和 run_oss_gates.py --port-dir。

MAX 会通过将 dirname(<port_dir>) 添加到 sys.path,并将 basename(<port_dir>) 作为模块导入,来解析 --custom-architectures <port_dir>。传入父目录会导入错误的模块名(例如,你的 slug 所在目录为 custom-arch)。

如果编辑时遇到导入或 API 错误,请从已安装 MAX 软件包中 max/pipelines/architectures/<donor>/ 下的供体架构复制导入语句。请参阅 pitfalls-config.md § Import and config API traps。


阶段 1:决定与规划

守卫:该架构是否已在 MAX 中注册? 编写任何代码之前,请检查 MAX 是否已注册模型 config.json::architectures[0] 中的架构类。如果 pixi run python scripts/list_native_archs.py --match <Class> 返回一个 slug,请运行 pixi run max serve --model-path <HF_MODEL_ID> 并停止。无需移植。完整流程请参阅: native-arch-check.md。

读取 config.json

获取配置并读取每个字段:

pixi run python -c "from transformers import AutoConfig; \
  print(AutoConfig.from_pretrained('<HF_MODEL_ID>', trust_remote_code=True))"

也可以使用辅助脚本:它会从 Hub 获取原始的 config.json,运行原生架构检查,并打印映射到 MAX API 的每个键:

pixi run python scripts/inspect_hf.py <HF_MODEL_ID>

然后列出 safetensors 元数据(键、形状和数据类型,不下载权重):

pixi run python scripts/list_checkpoint_keys.py <HF_MODEL_ID> --summary

摘要会统计张量和数据类型的数量。在编写权重适配器前,再运行一次,不带 --summary,以列出键名。

inspect_hf.py 表格中的每一行都会将一个 config.json 键映射到 pipeline_config.model.huggingface_config(architectures 和 torch_dtype 则映射到 arch.py 中的 SupportedArchitecture)。选定一个供体后,使用 --start-from <donor_slug> 重新运行:它会标出供体配置来源中从未提及的每个键。这些键就是你需要实现的配置差异,包括配置字段及使用该字段的模块代码;但如果没有模型代码读取它们(bos_token_id、initializer_range),则无需实现。字段含义和常见差异见:read-config-json.md。

在确定移植方案前,先检查是否存在阻碍:

pixi run python scripts/check_walls.py <HF_MODEL_ID>

退出码为 0 → 继续。退出码为 1 → 查阅 recognize-walls.md。退出码为 2 → 先停止,直到解决阻碍或将其排除在范围之外。

阅读模型卡

打开 https://huggingface.co/<HF_MODEL_ID> 并阅读模型卡,重点关注:

  • 论文或博客文章。 浏览其中的架构部分。作者会在该部分列出他们的修改(QK-norm、MLA、滑动窗口注意力、MoE 路由)。
  • 模型卡中提到的“技巧”。 “我们引入”“不同于以往模型”和“这是首个……”等表述都意味着存在差异。若现在忽略这些内容,实施时就会引入 bug。

如果模型卡表明该模型属于某个已知系列(Llama、Mistral、Qwen、Gemma),下方的供体比较环节会从该系列中最接近且已完成移植的变体开始。

某些模型卡信号需要检查是否存在阻碍:自定义 CUDA 内核、没有公开参考实现的自定义注意力、仅发布 FP8/FP4 权重、ALiBi,以及循环或状态空间层。如果模型卡提及其中任何一项,请先阅读 recognize-walls.md,再继续。有些模型仅凭公开的 MAX 接口无法移植。

提出计划并接受否决

编写任何代码之前,先用一小段文字说明默认方案,然后等待用户确认或否决。根据目前已阅读的内容,说明分发方式、供体、量化变体、验证深度和硬件目标。如果模型需要 ModuleV3 尚不具备的组件(层、分布式原语、量化路径),请指出该组件,并说明你会将其添加到 max.experimental.nn,还是需要用户决定。不要提出宽泛的问题。先说明默认方案,让用户提出异议。

完整指南和示例段落见: plan-and-veto.md。

如果估算的权重字节数无法放入一块 GPU,请先阅读 distributed-transformer.md,再选择 --start-from:分发方式比单独的注意力系列更重要。

与其他 MAX 架构进行比较

你要选择最适合复制的 ModuleV3 架构。“最适合”是指在以下方面匹配:

  • 注意力形态(dense、GQA 或 MLA)
  • MLP 形态(门控或非门控、dense 或路由)
  • 头部布局(共享或不共享、单个 Linear 或多步)
  • 分布形态

列出已安装的 MAX 中包含的 ModuleV3 架构(不要硬编码 slug 列表):

pixi run python scripts/list_native_archs.py --donors

HF 信号到 donor slug 的启发式提示见 map-to-max.md。简要版本:

你的模型从以下架构开始
类似 Llama 3(GQA、RoPE、SwiGLU MLP)llama3_modulev3
QK-norm、混合滑动窗口和全注意力olmo3
类似 Gemma(1 + weight RMSNorm、双重 norm)gemma3_modulev3
类似 Phi(融合 qkv_proj 和 gate_up_proj)phi3_modulev3
类似 Granite(MuP 标量)granite_modulev3
MoE(稀疏专家、top-k 路由)gpt_oss_modulev3
MLA(潜在 KV)、单 GPUdeepseekV2_modulev3
MLA + MoE、多 GPU(TP、DP + EP)deepseekV3_modulev3
混合注意力和状态空间层nemotron_h_modulev3
视觉语言(使用 --full-copy 搭建脚手架)gemma3multimodal_modulev3、kimik2_5_modulev3

打开所选架构的目录,阅读其模型文件(即 model.py 在 _instantiate_module() 中实例化的模块,例如 olmo3/olmo3.py 或 llama3_modulev3/llama3.py)及其 layers/。你要回答一个问题:移植时哪些模块会改变,哪些模块保持不变?

现在阅读对应的 Hugging Face 建模文件:

pixi run python -c "from transformers.models.<model_type> import modeling_<model_type>; \
  print(modeling_<model_type>.__file__)"

阅读 __init__、注意力 forward、MLP forward、block 类和最终 head。将它们与 MAX 中的对应实现逐一比较。参考 read-modeling-code.md 了解各部分需要检查的内容。在开始服务之前,立即对照 divergences.md 中的症状表检查 RoPE 布局、norm 公式和激活函数:名为 rotate_half 的函数仍可能旋转相邻元素对(ERNIE 4.5),而 donor 的默认实现读取的是错误的元素对。

此项活动的输出:一份差异清单,每个 HF 与 donor MAX 架构之间的实际差异占一行(注意力、MLP/MoE、block 连接、head、RoPE、掩码)。你要在第 2 阶段实现其中的每一项。结构性差异不超过 3 项 → donor 选择不错。差异很多 → 换一个更接近的 donor,或计划重写整个模块。不要带着空的或“看起来像 Llama”的差异清单进入验证阶段。


第 2 阶段:实现

搭建文件结构

scaffold.py 只会写入骨架,不会实现你的模型。

pixi run python scripts/scaffold.py <HF_MODEL_ID> --start-from <donor_slug> --output-dir <output_dir>

该脚本会从 Hub 的 config.json 中读取 architectures[0],以供 arch.py::name 使用,然后将继承所选 ModuleV3 架构的骨架写入 <output_dir>/<slug>/。slug 默认为仓库名称,包含模型规模后缀 (ernie_4_5_0_3b_pt)。传入 --slug,可使用架构系列名称作为包名。生成的类为 <Short>Model 和 <Short>Config(Ernie4_5Model),名称可能与 Hugging Face 自带的类重复,因此并排查看时请注明它们各自所属的类。

  • arch.py:注册框架,逐字保留 donor 设置的所有 SupportedArchitecture 关键字(memory_planner=、batching=、reasoning_parser= 等),包括已配置的规划器,例如 PagedMemoryPlanner.with_activation_reservation(...)。脚手架会写入 name=、仓库 ID、编码、权重格式,以及该移植版本自己的类和适配器(请核对 name=、编码和 memory_planner=)。 如果 donor 未声明规划器,则省略该字段并附上 TODO。脚手架无法追溯到导入来源的值会标记为 TODO 并发出警告。
  • model_config.py:donor 配置子类,带有 from_donor() 钩子,用于处理 donor 不读取的字段(实现期间必须重新接线)
  • model.py:pipeline 模型框架。_create_model_config() 会将 donor 的配置重新指定为你的配置类型,而 _instantiate_module() 会构建你的根模块,并按照 donor 的放置方式将其放到设备或网格上。它继承 donor 的批处理器,因此无需 batch_processor.py 也能继续处理输入。
  • weight_adapters.py:委托给 donor 的重命名逻辑(必须针对你的检查点重写)
  • <slug>.py:donor 模块(实现期间必须编辑,使其与 HF 一致)

搭建脚手架后,<slug>.py 仍会执行 donor 的数学运算。在模块实现完成前,不要提供服务。

脚手架会使用 ruff format 格式化移植代码,并将 donor 中对 huggingface_config.rope_theta 的读取改写为 get_rope_theta(huggingface_config);该函数可读取 Transformers 4 和 Transformers 5 中的值。使用此技能早期版本搭建脚手架的移植代码,仍可能在 model.py 中读取 huggingface_config.rope_theta,并导致 check_port.py 报错:AttributeError: ... has no attribute 'rope_theta'。请重新搭建脚手架,或手动进行相同修改,并从 max.pipelines.lib.pipeline_variants.utils 导入 get_rope_theta。

复制 donor 代码时,donor 的文档字符串和代码注释会一并保留。 默认情况下,脚手架会为生成的文件写入新的文档字符串。--full-copy 模式会保留 donor 的文本,手动复制或通过子类化再编辑的任何 donor 文件也一样。重命名类不会修改那些描述文件声称用途的文本。这些文件开头的文档字符串仍会描述 donor,并声称具备你的移植版本可能并不具备的行为(单 GPU 支持、QK 归一化、注意力后归一化等)。重写这些文档字符串是实现过程中的必做步骤。请参阅 rewrite-donor-docstrings.md,了解每个模块文档字符串必须遵循的模式。其中还包含你必须在宣布实现完成前运行的审查清单。

实现模块

第 1 阶段生成了配置映射和差异列表。实现阶段会将它们转化为代码。

完整清单、工作顺序、ModuleV3 API 范围、反模式和完成标准: implement-graph.md。

按以下顺序:

  1. model_config.py:供体的配置会读取它已知的键。对于 Phase 1 / inspect_hf.py 中每个其他 config.json 键,都要在移植版配置中声明一个字段,并在 from_donor() 中设置该字段;model.py::_create_model_config() 会使用供体的完整配置调用它。确认 construct_kv_params() 中的头数和 head_dim 与 HF 一致。流水线会根据你的配置中的 construct_kv_params() 为 KV 缓存分配空间,但 from_donor() 会从供体配置复制 kv_params,而模块读取的是这份副本。如果你覆盖了 construct_kv_params()、get_head_dim() 或 get_num_layers(),也要在 from_donor() 中根据你的覆盖实现设置 kv_params,确保缓存与模块一致。
  2. weight_adapters.py:将检查点的 safetensor 键映射到根模块通过 parameters 返回的参数名称,包括根模块的包装器前缀(olmo3 中为 language_model.)。先运行 list_checkpoint_keys.py。参见 rename-weights.md。接入 state-dict-audit.md 中的覆盖率审计:compile() 会拒绝缺失或形状不匹配的参数,审计则会捕获未被任何参数使用的检查点张量。
  3. <slug>.py:针对差异列表中的每一项,编辑或替换供体模块,使 MAX forward() 与 HF forward() 保持一致:
    • Attention(Q/K/V、RoPE、mask、GQA、softcap,……)
    • MLP 或 MoE(激活函数、路由、共享专家,……)
    • Decoder block(归一化顺序和残差连接,不能与 Llama 互换)
    • 最终归一化和 LM head(权重绑定、logit 缩放、softcap)
  4. arch.py:确认 name= 与 architectures[0] 匹配,且 default_encoding 与 Hub 的 torch_dtype 匹配。保留脚手架生成的 memory_planner=(从供体复制而来)。没有它,MAX 不会为 KV 缓存预留激活内存,也会跳过 max_batch_size 推断。如果脚手架留下了 memory_planner TODO,说明供体没有设置它。上线服务前解决此问题:KV 缓存移植版需要设置 memory_planner=PagedMemoryPlanner,只有自行进行内存估算的架构(diffusion、embedding)才应保持未设置。脚手架还会保留供体的 batching=。只有移植版的批处理方式与供体不同时才修改它。
  5. model.py:_instantiate_module() 会构造你的根模块并调用 .to(self.devices[0]),或者在多 GPU 移植版中于 default_device(mesh) 内构建模块。仅当 HF 以不同方式包装骨干网络(VL、多模态)时才进一步编辑。

编辑时阅读 HF 的 modeling_<type>.py,不要等验证失败后再读。只有在 HF 与供体一致时才继承供体。差异列表指出不同之处时,重写相应模块。

以下各项全部勾选后,才算实现完成:implement-graph.md 中的每一项,尤其是:

  • 每项差异都有对应的代码更改。
  • 权重编译时没有孤立键。
  • 你已运行 rewrite-donor-docstrings.md 中的脚手架注释审计,并将每项匹配结果分类为 OK、Wrong 或 Stale。

声明实现完成前运行审计。max serve 和 compare_layers.py 不会读取文档字符串,因此后续步骤无法发现审计遗漏的供体声明。

快速 grep 示例(完整分类规则见 rewrite-donor-docstrings.md):

grep -rniE 'qwen|llama|mistral|cohere|gemma|phi|deepseek|olmo|granite|qwen3|mixtral|single-GPU|single GPU|RMSNorm|QK-norm' <port_dir>/

在子类模式的移植版中,大多数匹配项都是供体导入和脚手架生成的血缘信息行。这些内容是准确的。请阅读匹配项中的文档字符串和注释。 实现完成消息必须明确说明已完成审计 (例如:"docstrings 已按 rewrite-donor-docstrings.md 中的模式重写,且 rg 返回 N 处匹配,均为合理的 血缘引用")。没有这项说明,请勿报告实现完成。

预检(Hub 配置 + 架构注册,在首次启动服务前运行):

pixi run python scripts/run_oss_gates.py <HF_MODEL_ID> --port-dir <port_dir>

防护:本地冒烟测试门槛(Phase 3 前必须通过)。 max serve 会先编译整个模型,再响应请求,因此参数名称或形状有误时,需要等完整编译完成才能发现。先运行端口检查。它会像 max serve 一样导入端口,在不编译的情况下,通过 F.lazy() 构建根模块,并列出适配后的检查点未填充的所有参数、所有形状或 dtype 不匹配项,以及所有没有参数读取的张量:

pixi run python scripts/check_port.py <HF_MODEL_ID> --port-dir <port_dir>

如果 compile() 会失败,该命令会以状态码 1 退出。它会读取真实检查点,因此首次运行时会下载权重。每次检查前都要格式化并检查端口,因为你的编辑会添加脚手架未格式化的代码:

pixi run ruff format <port_dir>
pixi run ruff check <port_dir>

ruff check 不得报告任何错误。run_oss_gates.py 会检查墙面、检查点元数据,以及 arch.py 的名称和编码。它不能替代本检查。权重格式预检请参阅 serve-and-iterate.md。


Phase 3:验证

检查是否能生成连贯文本

前提条件: 模块实现已完成。实现期间不要启动服务来“看看会怎样”。应先修复配置、适配器和模块。

先对 HF 参考模型进行健全性检查。 在使用 MAX 之前,先按照模型卡指定的提示词模板单独运行 HF。如果 HF 本身生成的是乱码,那么参考模型就有问题,与其进行比较会发现一些无法通过修改端口解决的不匹配。

然后启动服务:

pixi run max serve --model-path <HF_MODEL_ID> --custom-architectures <port_dir>

max serve 会为 KV 缓存预留设备内存的 --device-memory-utilization 比例(默认值为 0.9)。如果启动时分配失败(内存不足,或缓冲区大于设备允许的大小),请降低该比例,例如使用 --device-memory-utilization 0.6。如果 HF 参考模型与服务运行在同一台机器上,也应降低该比例,因为两者会争用内存:否则,float32 参考模型可能会溢出到磁盘,导致每次比较耗时数分钟。

通过 /v1/chat/completions 探测经过指令微调的模型,该接口会应用其聊天模板;通过 /v1/completions 和纯提示词探测基座模型。PrefixLM 需要使用模型卡中展示的提示词格式。对于回答前会进行推理的模型(默认会生成 <think> 块),请在两端都关闭推理:MAX 使用 chat_template_kwargs,HF 的 apply_chat_template() 使用相同的关键字(enable_thinking=False),否则比较内容只会涵盖推理文本。在 HF 侧对经过聊天模板处理的文本进行分词时,请传入 add_special_tokens=False,因为模板已经添加了这些特殊标记。根据结果采取下一步操作:

  • 服务在加载期间崩溃 → 修复配置和适配器。
  • 服务成功启动但返回乱码 → 开始排查差异。
  • 服务返回看似合理的文本 → 使用 max_tokens=64+ 运行,然后通过验证门槛。即使端口缺少某个增量,也仍可能生成流畅的回答。

完整的 HF 参考模型健全性检查、编码器/嵌入模型 slug 服务流程,以及修复-测试循环规范: serve-and-iterate.md。

一致性失败(调用 debug-model)

服务可以启动,但输出不正确:乱码、索引 K 处的贪心选择错误、logit 与错误 argmax 的余弦相似度较高,或文本连贯地生成了 N 个 token 后开始偏离。发生这种情况时,停止添加标量输出探针,并加载 debug-model 技能。

该技能用于处理能够加载并运行的模型所产生的错误输出。其工作流要求完成以下步骤:

  1. 在相同提示词和检查点上进行 HF 健全性检查
  2. 逐层运行 HF 与 MAX 张量转储比较器(而不是靠 F.print 肉眼检查)
  3. 通过并行调查 Agent 在重新编译前进行数值验证
  4. 如果转储结果一致但生成文本不一致,则对服务与管线进行二分排查

使用 import-model 搭建初始框架并设置检查门槛。使用 debug-model 本身来排查偏差。

快速 logit 探测(仅限前 5 分钟)

在构建转储工具之前,先运行快速健全性检查:

pixi run python scripts/compare_layers.py <HF_MODEL_ID> \
  --port 8000 \
  --prompt "The capital of France is"

需要在同一端口上运行 pixi run max serve,并指定 --custom-architectures <port_dir>。该探测会读取 logprobs,而重叠调度器会拒绝此请求。MAX 默认启用该调度器,除非 arch.py 设置了 supports_overlap_scheduler=False;因此,如果 arch.py 保持默认设置,请在 serve 命令中添加 --no-enable-overlap-scheduler --force。此脚本会打印仅 HF 的逐层统计,并比较提示词处的 top-1 logprob。标志详情请参阅 layer-by-layer-debugging.md。

如果 logprob 不一致或输出是乱码,请切换到 debug-model。不要只靠手动输出探针反复迭代。比较器定位出故障层后,divergences.md 中的症状目录仍然适用。

与 Hugging Face 对照

使用预训练权重端到端运行模型,然后在相同提示词上以贪心采样运行 HF。在 MAX 端,使用与模型支持的权重编码匹配的数据类型(大多数模型以 bfloat16 发布)。如果可行,HF 端使用 float32:bfloat16 参考本身会引入舍入误差,而正确的 bfloat16 移植版本也可能在几个 token 内与其产生偏差。

在输出首次不同时,查看 HF 的两个最高 logprob。如果它们相差约 0.1 nat 以内,那么模型在此处不分胜负,任一 token 都是正确的。如果前几个 token 就出现偏差,且 HF 有明显更优的选择,通常意味着分词器或聊天模板不匹配、数据类型与发布的权重不匹配,或 MAX 采样值非零。

当输出一致,或首次差异出现在平局处时,该移植版本就算完成了 贪心文本 部分。其他完成标准取决于规划阶段所选的验证深度。选择一个等级,从冒烟测试到 logit 一致性。

完整的 HF 对比流程、偏差分类和验证等级表,请参阅:validation-tiers.md。


常见陷阱

将 pitfalls.md 用作索引:找到症状后,加载对应类别的文件(配置、权重、模块或服务);文档字符串专项审查请参阅 rewrite-donor-docstrings.md。最常见的陷阱:

  • 为脚手架提供服务。 在模块实现 <slug>.py 中的所有差异之前,不要提供服务或进行验证,因为脚手架生成的模块仍在运行供体的计算逻辑。
  • 重命名后供体文档字符串仍未修改。 在复制的供体文件中(使用 --full-copy 或手动复制),类名会被重命名,但文档字符串和注释仍描述供体。请重写它们,并在宣布实现完成前运行审计 grep。

测试与 CI

为移植后的模型添加 pytest 测试时,应尽量减少每个文件的编译次数。通过模块级 fixture 编译一次,并在 @pytest.mark.parametrize 用例之间复用。对于必须编译不同模块的文件,使用 Bazel shard_count 并行运行,以保持文件完整。完整模式和示例请参阅:tests-and-ci.md。

评论

支持 Markdown