07_NVIDIA_ModelOpt-Recipe配方系统

07 · Recipe 配方系统详解

本文深入剖析 `modelopt/recipe/`(file:///workspace/modelopt/recipe/) 与 `modelopt_recipes/`(file:///workspace/modelopt_recipes/) 子系统。Recipe(配方)是 ModelOpt 提供的声明式配置层------通过 YAML 文件描述量化 / 蒸馏 / speculative decoding 的完整配置,避免手写 Python 代码。


目录

  1. [总览:Recipe 系统定位与价值](#总览:Recipe 系统定位与价值)
  2. [modelopt/recipe/config.py --- Pydantic Schema](#modelopt/recipe/config.py — Pydantic Schema)
  3. [modelopt/recipe/loader.py --- 加载器](#modelopt/recipe/loader.py — 加载器)
  4. [modelopt/recipe/presets.py --- 预设管理](#modelopt/recipe/presets.py — 预设管理)
  5. [modelopt_recipes/ --- 内置配方库](#modelopt_recipes/ — 内置配方库)
  6. 本篇使用指南
  7. 本篇效果对比

1. 总览:Recipe 系统定位与价值

1.1 为什么需要 Recipe?

直接使用 `mtq.quantize()`(file:///workspace/modelopt/torch/quantization/) Python API 需要:

  • 手写 quant_cfg 列表(含每个 module 的 quantizer 描述)
  • 手写 algorithm 字段
  • 手写校准参数

对于复杂模型(如 Llama-3.1-405B),完整 quant_cfg 可能有数百行。Recipe 系统通过 YAML + Pydantic schema + $import 机制 把这些配置抽象为可复用、可组合、可版本化的「配方」文件。

1.2 Recipe 的两种存储方式

方式 结构 适用类型 overrides 支持
单文件 一个 .yaml,含 metadata + (quantize / eagle / dflash / medusa) PTQ + Speculative ✅ 支持 dotlist
目录 metadata.yml + quantize.yml(两个文件) 仅 PTQ ❌ 不支持

1.3 RecipeType 四类

`config.py`(file:///workspace/modelopt/recipe/config.py) 定义枚举:

python 复制代码
class RecipeType(str, Enum):
    PTQ = "ptq"
    SPECULATIVE_EAGLE = "speculative_eagle"
    SPECULATIVE_DFLASH = "speculative_dflash"
    SPECULATIVE_MEDUSA = "speculative_medusa"
    # QAT = "qat"  # Not implemented yet

配图 1:Recipe 加载流程图

#mermaid-svg-DbllNkCL6qZSLqwZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DbllNkCL6qZSLqwZ .error-icon{fill:#552222;}#mermaid-svg-DbllNkCL6qZSLqwZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DbllNkCL6qZSLqwZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DbllNkCL6qZSLqwZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DbllNkCL6qZSLqwZ .marker.cross{stroke:#333333;}#mermaid-svg-DbllNkCL6qZSLqwZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DbllNkCL6qZSLqwZ p{margin:0;}#mermaid-svg-DbllNkCL6qZSLqwZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ .cluster-label text{fill:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ .cluster-label span{color:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ .cluster-label span p{background-color:transparent;}#mermaid-svg-DbllNkCL6qZSLqwZ .label text,#mermaid-svg-DbllNkCL6qZSLqwZ span{fill:#333;color:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ .node rect,#mermaid-svg-DbllNkCL6qZSLqwZ .node circle,#mermaid-svg-DbllNkCL6qZSLqwZ .node ellipse,#mermaid-svg-DbllNkCL6qZSLqwZ .node polygon,#mermaid-svg-DbllNkCL6qZSLqwZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DbllNkCL6qZSLqwZ .rough-node .label text,#mermaid-svg-DbllNkCL6qZSLqwZ .node .label text,#mermaid-svg-DbllNkCL6qZSLqwZ .image-shape .label,#mermaid-svg-DbllNkCL6qZSLqwZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-DbllNkCL6qZSLqwZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DbllNkCL6qZSLqwZ .rough-node .label,#mermaid-svg-DbllNkCL6qZSLqwZ .node .label,#mermaid-svg-DbllNkCL6qZSLqwZ .image-shape .label,#mermaid-svg-DbllNkCL6qZSLqwZ .icon-shape .label{text-align:center;}#mermaid-svg-DbllNkCL6qZSLqwZ .node.clickable{cursor:pointer;}#mermaid-svg-DbllNkCL6qZSLqwZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DbllNkCL6qZSLqwZ .arrowheadPath{fill:#333333;}#mermaid-svg-DbllNkCL6qZSLqwZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DbllNkCL6qZSLqwZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DbllNkCL6qZSLqwZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DbllNkCL6qZSLqwZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DbllNkCL6qZSLqwZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DbllNkCL6qZSLqwZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DbllNkCL6qZSLqwZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DbllNkCL6qZSLqwZ .cluster text{fill:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ .cluster span{color:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DbllNkCL6qZSLqwZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DbllNkCL6qZSLqwZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-DbllNkCL6qZSLqwZ .icon-shape,#mermaid-svg-DbllNkCL6qZSLqwZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DbllNkCL6qZSLqwZ .icon-shape p,#mermaid-svg-DbllNkCL6qZSLqwZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DbllNkCL6qZSLqwZ .icon-shape .label rect,#mermaid-svg-DbllNkCL6qZSLqwZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DbllNkCL6qZSLqwZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DbllNkCL6qZSLqwZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DbllNkCL6qZSLqwZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 单文件
目录


User

recipe_path + overrides
load_recipe

loader.py
_resolve_recipe_path

内置库优先 → 文件系统
文件 or 目录?
_load_recipe_from_file
_load_recipe_from_dir

仅 PTQ
_peek_recipe_type

读 metadata.recipe_type

不解析 $import
RECIPE_TYPE_TO_CLASS

映射到 schema 类
_REQUIRED_SECTION_PER_RECIPE_TYPE

检查必需 section
load_config

含 $import 解析
Pydantic schema 实例
有 overrides?
_apply_dotlist

OmegaConf.merge
schema_class.model_validate
ModelOptRecipeBase 实例
传给 mtq.quantize / mts.convert
load_config metadata.yml
load_config quantize.yml

QuantizeConfig

说明 :加载流程的核心是「先 peek recipe_type 决定 schema → 再 load_config 解析 i m p o r t → 可选应用 d o t l i s t o v e r r i d e s → 最终 P y d a n t i c 校验」。 ' p e e k r e c i p e t y p e ' 不解析 ' import → 可选应用 dotlist overrides → 最终 Pydantic 校验」。`_peek_recipe_type` 不解析 ` import→可选应用dotlistoverrides→最终Pydantic校验」。'peekrecipetype'不解析'import` 是为了避免在不知道 schema 时的循环依赖。


2. modelopt/recipe/config.py --- Pydantic Schema

2.1 文件概览

`config.py`(file:///workspace/modelopt/recipe/config.py) 定义所有 recipe 相关的 Pydantic 模型,是整个系统的「数据契约」。

2.2 核心类层次

复制代码
ModeloptBaseConfig (from opt.config)
    └── ModelOptRecipeBase
        ├── metadata: RecipeMetadataConfig
        │   ├── recipe_type: RecipeType
        │   └── description: str
        │
        ├── ModelOptPTQRecipe
        │   └── quantize: QuantizeConfig (来自 quantization.config)
        │
        └── ModelOptSpeculativeRecipeBase
            ├── model: SpecModelArgs
            ├── data: SpecDataArgs
            ├── training: SpecTrainingArgs
            │
            ├── ModelOptEagleRecipe
            │   └── eagle: EagleConfig
            ├── ModelOptDFlashRecipe
            │   └── dflash: DFlashConfig
            └── ModelOptMedusaRecipe
                └── medusa: MedusaConfig

2.3 RecipeMetadataConfig

python 复制代码
class RecipeMetadataConfig(ModeloptBaseConfig):
    recipe_type: RecipeType = Field(title="Recipe type")
    description: str = ModeloptField(default="Model optimization recipe.")

强制要求 :每个 recipe 必须有 metadata section,且 metadata.recipe_type 必填。这避免了「缺少 metadata 时静默回退到默认 PTQ」的陷阱(见 `config.py` 第 90-95 行(file:///workspace/modelopt/recipe/config.py#L90-L95) 注释)。

2.4 ModelOptPTQRecipe

python 复制代码
class ModelOptPTQRecipe(ModelOptRecipeBase):
    quantize: QuantizeConfig = Field(...)

PTQ recipe 必须含 quantize section(类型为 `QuantizeConfig`(file:///workspace/modelopt/torch/quantization/config.py),见 02 量化子系统(file:///workspace/ReadCode/02_量化子系统_quantization.md))。

2.5 Speculative Recipe 系列

`ModelOptSpeculativeRecipeBase`(file:///workspace/modelopt/recipe/config.py) 是 speculative recipe 的基类。与 PTQ 不同,speculative 是训练时优化,所以 recipe 包含三组训练相关字段:

字段 类型 用途
model SpecModelArgs HF 模型路径等
data SpecDataArgs 训练数据配置(含 mode: online/offline/streaming)
training SpecTrainingArgs HF TrainingArguments 扩展

三个子类 ModelOptEagleRecipe / ModelOptDFlashRecipe / ModelOptMedusaRecipe 分别加 eagle / dflash / medusa 字段。

关键 model_validator
python 复制代码
@model_validator(mode="after")
def _derive_eagle_offline(self) -> ModelOptEagleRecipe:
    self.eagle.eagle_offline = self.data.mode != "online"
    return self

eagle_offline 不是用户直接设置,而是由 data.mode 自动推导------offline 模式使用预先 dump 的 hidden states,online 模式实时跑 base model。dflash 同理。

2.6 RECIPE_TYPE_TO_CLASS 映射

python 复制代码
RECIPE_TYPE_TO_CLASS: dict[RecipeType, type[ModelOptRecipeBase]] = {
    RecipeType.PTQ: ModelOptPTQRecipe,
    RecipeType.SPECULATIVE_EAGLE: ModelOptEagleRecipe,
    RecipeType.SPECULATIVE_DFLASH: ModelOptDFlashRecipe,
    RecipeType.SPECULATIVE_MEDUSA: ModelOptMedusaRecipe,
}

这是 single source of truth ------loader.py 通过此映射把 metadata.recipe_type 转为具体的 Pydantic schema 类。新增 recipe 类型只需在此添加映射。


3. modelopt/recipe/loader.py --- 加载器

3.1 主入口 load_recipe()

`load_recipe()`(file:///workspace/modelopt/recipe/loader.py) 的完整签名:

python 复制代码
def load_recipe(
    recipe_path: str | Path | Traversable,
    overrides: list[str] | None = None,
) -> ModelOptRecipeBase:

支持三种路径:

  • 内置库路径 (如 "configs/ptq/presets/model/nvfp4"):自动加 .yml / .yaml 后缀探测
  • 绝对路径:直接使用
  • 相对路径:先查内置库,再查文件系统

3.2 路径解析 _resolve_recipe_path

python 复制代码
def _resolve_recipe_path(recipe_path):
    if isinstance(recipe_path, (str, Path)) and not absolute:
        # 先查内置库
        for suffix in ["", ".yml", ".yaml"]:
            candidate = BUILTIN_RECIPES_LIB.joinpath(rp_str + suffix)
            if candidate.is_file() or candidate.is_dir():
                return candidate
        # 再查文件系统
        for suffix in ["", ".yml", ".yaml"]:
            fs_candidate = Path(rp_str + suffix)
            if fs_candidate.is_file() or fs_candidate.is_dir():
                return fs_candidate
    return recipe_path

3.3 _peek_recipe_type --- 不解析 $import 的预读

python 复制代码
def _peek_recipe_type(recipe_file):
    raw = yaml.safe_load(recipe_file.read_text())
    return RecipeType(raw["metadata"]["recipe_type"])

为什么需要 peek? 因为 $import 解析需要知道目标列表的元素 schema(如 quant_cfg 列表的元素是 QuantizerCfgEntry),而要确定 schema 必须先知道 recipe_type。所以分两步:先 peek recipe_type 决定 schema,再用 schema 解析 $import

3.4 单文件加载 _load_recipe_from_file

python 复制代码
def _load_recipe_from_file(recipe_file, overrides=None):
    rtype = _peek_recipe_type(recipe_file)
    schema_class = RECIPE_TYPE_TO_CLASS[rtype]

    # 检查必需 section(如 PTQ 必须有 quantize)
    required_section = _REQUIRED_SECTION_PER_RECIPE_TYPE.get(rtype)
    if required_section:
        raw = yaml.safe_load(recipe_file.read_text())
        if required_section not in raw:
            raise ValueError(f"... recipe must contain {required_section!r}.")

    if overrides:
        # 先 load_config(含 $import),再 model_dump,应用 dotlist,最后 re-validate
        recipe = load_config(recipe_file, schema_type=schema_class)
        data = recipe.model_dump()
        data = _apply_dotlist(data, overrides)
        return schema_class.model_validate(data)

    return load_config(recipe_file, schema_type=schema_class)

3.5 dotlist overrides _apply_dotlist

python 复制代码
def _apply_dotlist(data: dict, overrides: list[str]) -> dict:
    for entry in overrides:
        if "=" not in entry:
            raise ValueError(f"Invalid override (missing '='): {entry!r}")
    merged = OmegaConf.merge(
        OmegaConf.create(data),
        OmegaConf.from_dotlist(list(overrides)),
    )
    return OmegaConf.to_container(merged, resolve=False)

使用 OmegaConf 实现 key.path=value 风格的覆盖。关键点 :overrides 必须在 $import 解析后应用,否则 import 进来的列表会被整体覆盖而非合并。

3.6 目录加载 _load_recipe_from_dir

python 复制代码
def _load_recipe_from_dir(recipe_dir):
    metadata = load_config(_find_recipe_section_file(recipe_dir, "metadata"),
                           schema_type=RecipeMetadataConfig)
    if metadata.recipe_type == RecipeType.PTQ:
        quantize_cfg = load_config(_find_recipe_section_file(recipe_dir, "quantize"),
                                   schema_type=QuantizeConfig)
        return ModelOptPTQRecipe(metadata=metadata, quantize=quantize_cfg)
    raise ValueError(f"Unsupported recipe type: {metadata.recipe_type!r}")

注意:目录格式仅支持 PTQ,且不支持 overrides。Speculative recipe 必须用单文件格式。

3.7 $import 机制

$import 是 recipe 的核心复用机制。一个完整 NVFP4 recipe(`modelopt_recipes/configs/ptq/presets/model/nvfp4.yaml`(file:///workspace/modelopt_recipes/configs/ptq/presets/model/nvfp4.yaml)):

yaml 复制代码
imports:
  base_disable_all: configs/ptq/units/base_disable_all
  w4a4_nvfp4_nvfp4: configs/ptq/units/w4a4_nvfp4_nvfp4
  default_disabled_quantizers: configs/ptq/units/default_disabled_quantizers

algorithm: max
quant_cfg:
  - $import: base_disable_all
  - $import: w4a4_nvfp4_nvfp4
  - $import: default_disabled_quantizers

$import: base_disable_all 引用 imports 中声明的 configs/ptq/units/base_disable_all,加载时被替换为该文件的内容。typed-list 支持让 $import 知道目标列表的元素 schema 是 QuantizerCfgEntry

配图 2:Recipe 加载时序图

_apply_dotlist schema_class load_config _peek_recipe_type _resolve_recipe_path load_recipe User _apply_dotlist schema_class load_config _peek_recipe_type _resolve_recipe_path load_recipe User #mermaid-svg-7TnszK3js0Qd3iG1{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7TnszK3js0Qd3iG1 .error-icon{fill:#552222;}#mermaid-svg-7TnszK3js0Qd3iG1 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7TnszK3js0Qd3iG1 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7TnszK3js0Qd3iG1 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7TnszK3js0Qd3iG1 .marker.cross{stroke:#333333;}#mermaid-svg-7TnszK3js0Qd3iG1 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7TnszK3js0Qd3iG1 p{margin:0;}#mermaid-svg-7TnszK3js0Qd3iG1 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7TnszK3js0Qd3iG1 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7TnszK3js0Qd3iG1 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-7TnszK3js0Qd3iG1 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-7TnszK3js0Qd3iG1 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-7TnszK3js0Qd3iG1 .sequenceNumber{fill:white;}#mermaid-svg-7TnszK3js0Qd3iG1 #sequencenumber{fill:#333;}#mermaid-svg-7TnszK3js0Qd3iG1 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-7TnszK3js0Qd3iG1 .messageText{fill:#333;stroke:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7TnszK3js0Qd3iG1 .labelText,#mermaid-svg-7TnszK3js0Qd3iG1 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .loopText,#mermaid-svg-7TnszK3js0Qd3iG1 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7TnszK3js0Qd3iG1 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-7TnszK3js0Qd3iG1 .noteText,#mermaid-svg-7TnszK3js0Qd3iG1 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-7TnszK3js0Qd3iG1 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7TnszK3js0Qd3iG1 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7TnszK3js0Qd3iG1 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7TnszK3js0Qd3iG1 .actorPopupMenu{position:absolute;}#mermaid-svg-7TnszK3js0Qd3iG1 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-7TnszK3js0Qd3iG1 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7TnszK3js0Qd3iG1 .actor-man circle,#mermaid-svg-7TnszK3js0Qd3iG1 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-7TnszK3js0Qd3iG1 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} load_recipe("nvfp4", overrides="algorithm=mse") resolve path <builtin>/configs/ptq/presets/model/nvfp4.yaml peek recipe_type yaml.safe_load RecipeType.PTQ RECIPE_TYPE_TO_CLASSPTQ = ModelOptPTQRecipe load_config(file, ModelOptPTQRecipe) 解析 imports / $import typed-list 解析 ModelOptPTQRecipe 实例 有 overrides recipe.model_dump() → dict OmegaConf.merge(dotlist) model_validate(merged_dict) 最终 validated recipe ModelOptPTQRecipe

说明 :注意 dotlist overrides 的特殊流程------先 load_config 得到 schema 实例,model_dump 转回 dict,应用 dotlist,再 model_validate 重新校验。这确保 overrides 也通过 schema 验证。


4. modelopt/recipe/presets.py --- 预设管理

`presets.py`(file:///workspace/modelopt/recipe/presets.py) 提供预设 recipe 的快捷访问。它把常用的内置 recipe 路径暴露为 Python 常量,便于在代码中引用:

python 复制代码
from modelopt.recipe.presets import PTQ_PRESETS
# PTQ_PRESETS["nvfp4"] → "<builtin>/configs/ptq/presets/model/nvfp4"

5. modelopt_recipes/ --- 内置配方库

`modelopt_recipes/`(file:///workspace/modelopt_recipes/) 是随 ModelOpt 安装包分发的内置配方库,组织如下:

复制代码
modelopt_recipes/
├── configs/                  # 配置原语
│   ├── numerics/            # 10+ 数值格式预设
│   └── ptq/
│       ├── presets/
│       │   ├── model/       # 30+ 模型级 PTQ 预设
│       │   ├── kv/          # 7 种 KV cache 预设
│       │   └── diffusers/   # 4 种扩散模型预设
│       └── units/            # 15+ 单元配置
├── general/                  # 组合配方
│   ├── ptq/                 # 20+ 端到端 PTQ 配方
│   ├── speculative_decoding/ # 3 种 speculative 配方
│   └── distillation/        # DMD2 配方
└── huggingface/             # 按厂商/模型组织
    ├── gemma/
    ├── gemma4/
    ├── mpt/
    ├── nvidia/
    │   └── Nemotron-3-Nano-4B/
    │   └── Nemotron-3-Super-120B-A12B/
    │   └── Nemotron-3-Ultra-550B-A55B/
    ├── nemotron_vl/
    ├── phi4mm/
    ├── qwen3_5/
    ├── qwen3_5_moe/
    ├── step3p5/
    └── vit/

5.1 numerics/ --- 数值格式预设

10+ 种数值格式预设,定义量化器的基础属性:

预设 文件 说明
fp8 `fp8.yaml`(file:///workspace/modelopt_recipes/configs/numerics/fp8.yaml) FP8 E4M3
int8 `int8.yaml`(file:///workspace/modelopt_recipes/configs/numerics/int8.yaml) INT8 per-tensor
int8_per_channel `int8_per_channel.yaml`(file:///workspace/modelopt_recipes/configs/numerics/int8_per_channel.yaml) INT8 per-channel
int4_per_block `int4_per_block.yaml`(file:///workspace/modelopt_recipes/configs/numerics/int4_per_block.yaml) INT4 per-block (block size 32)
mxfp4 `mxfp4.yaml`(file:///workspace/modelopt_recipes/configs/numerics/mxfp4.yaml) MXFP4 (E2M1)
mxfp6 `mxfp6.yaml`(file:///workspace/modelopt_recipes/configs/numerics/mxfp6.yaml) MXFP6 (E3M2 / E2M3)
mxfp8 `mxfp8.yaml`(file:///workspace/modelopt_recipes/configs/numerics/mxfp8.yaml) MXFP8 (E4M3)
mxint8 `mxint8.yaml`(file:///workspace/modelopt_recipes/configs/numerics/mxint8.yaml) MXINT8
nvfp4 `nvfp4.yaml`(file:///workspace/modelopt_recipes/configs/numerics/nvfp4.yaml) NVFP4 (E2M1 + per-block scale)
nvfp4_bs32 `nvfp4_bs32.yaml`(file:///workspace/modelopt_recipes/configs/numerics/nvfp4_bs32.yaml) NVFP4 with block size 32
nvfp4_four_over_six `nvfp4_four_over_six.yaml`(file:///workspace/modelopt_recipes/configs/numerics/nvfp4_four_over_six.yaml) NVFP4 4/6 模式
nvfp4_static `nvfp4_static.yaml`(file:///workspace/modelopt_recipes/configs/numerics/nvfp4_static.yaml) NVFP4 静态量化

例如 `nvfp4.yaml`(file:///workspace/modelopt_recipes/configs/numerics/nvfp4.yaml):

yaml 复制代码
# modelopt-schema: modelopt.torch.quantization.config.QuantizerAttributeConfig
num_bits: e2m1
block_sizes:
  -1: 16
  type: dynamic
  scale_bits: e4m3

5.2 ptq/presets/model/ --- 模型级 PTQ 预设

30+ 种端到端 PTQ 配方,覆盖主流量化方案:

类别 示例 说明
FP8 系列 fp8.yaml / fp8_per_channel_per_token.yaml / fp8_2d_blockwise_weight_only.yaml H100/H200 通用
INT8 系列 int8.yaml / int8_smoothquant.yaml / int8_weight_only.yaml 兼容性最广
INT4 AWQ int4_awq.yaml LLM 主流 W4A16
MXFP4/6/8 mxfp4.yaml / mxfp6.yaml / mxfp8.yaml Blackwell MX 系列
NVFP4 系列 nvfp4.yaml / nvfp4_awq_lite.yaml / nvfp4_awq_clip.yaml / nvfp4_awq_full.yaml / nvfp4_svdquant.yaml / nvfp4_experts_only.yaml / nvfp4_mlp_only.yaml / nvfp4_omlp_only.yaml / nvfp4_fp8_mha.yaml / nvfp4_four_over_six.yaml Blackwell 主推
W4A8 混合 w4a8_awq_beta.yaml / w4a8_mxfp4_fp8.yaml / w4a8_nvfp4_fp8.yaml 权重 4-bit + 激活 8-bit
W4A16 w4a16_nvfp4.yaml 权重 4-bit + 激活 FP16
MoE 特化 mamba_moe_fp8_aggressive.yaml / mamba_moe_nvfp4_conservative.yaml Mamba + MoE 模型

5.3 ptq/presets/kv/ --- KV cache 量化预设

7 种 KV cache 量化方案,可叠加在任意模型级预设上:

预设 说明
kv_fp8.yaml KV cache FP8
kv_fp8_affine.yaml FP8 + affine 量化
kv_fp8_cast.yaml FP8 cast(直接截断)
kv_nvfp4.yaml KV cache NVFP4
kv_nvfp4_affine.yaml NVFP4 + affine
kv_nvfp4_cast.yaml NVFP4 cast
kv_nvfp4_rotate.yaml NVFP4 + Hadamard rotation

5.4 ptq/presets/diffusers/ --- 扩散模型预设

预设 说明
fp8.yaml SDXL / SD3 FP8
int8.yaml SDXL INT8
nvfp4.yaml SDXL NVFP4
nvfp4_fp8_mha.yaml NVFP4 + FP8 attention(Blackwell 优化)

5.5 ptq/units/ --- 单元配置

15+ 个原子单元,每个单元定义一组模块的量化策略,可被模型级预设通过 $import 复用:

单元 用途
base_disable_all.yaml 关闭所有量化(基础)
default_disabled_quantizers.yaml 默认禁用某些 quantizer
attention_qkv_fp8.yaml attention QKV 用 FP8
kv_fp8.yaml / kv_fp8_affine.yaml / kv_fp8_cast.yaml KV cache FP8 变体
kv_nvfp4*.yaml (4 个) KV cache NVFP4 变体
w4_nvfp4.yaml 权重 NVFP4
w4a4_nvfp4_nvfp4.yaml W4A4 NVFP4
w4a4_nvfp4_nvfp4_four_over_six.yaml W4A4 NVFP4 4/6
w8a8_fp8_fp8.yaml W8A8 FP8
experts_nvfp4.yaml / block_sparse_moe_nvfp4.yaml MoE 专家 NVFP4
mamba_moe_disabled_quantizers.yaml Mamba MoE 禁用项

5.6 general/ptq/ --- 组合配方

20+ 端到端组合配方,命名规则 <weight_format>-kv_<kv_format>

配方 说明
fp8_default-kv_fp8.yaml FP8 权重 + FP8 KV
fp8_default-kv_fp8_cast.yaml FP8 权重 + FP8 cast KV
nvfp4_default-kv_fp8.yaml NVFP4 权重 + FP8 KV
nvfp4_default-kv_fp8_cast.yaml NVFP4 权重 + FP8 cast KV
nvfp4_default-kv_none-gptq.yaml NVFP4 权重 + GPTQ 校准
nvfp4_default-kv_nvfp4_cast.yaml NVFP4 权重 + NVFP4 cast KV
nvfp4_experts_only-kv_fp8.yaml NVFP4 仅专家 + FP8 KV
nvfp4_experts_only-kv_fp8_layerwise.yaml NVFP4 仅专家 + 逐层校准
nvfp4_mlp_only-kv_fp8.yaml NVFP4 仅 MLP + FP8 KV
nvfp4_weight_only-kv_fp16.yaml NVFP4 仅权重 + FP16 KV
... 等 20 个

5.7 general/speculative_decoding/ --- Speculative 配方

配方 说明
eagle3.yaml EAGLE3 训练 + 部署
dflash.yaml DFlash 分布式 EAGLE
domino.yaml Domino(DFlash 变体)

5.8 general/distillation/ --- DMD2 配方

配方 说明
dmd2_qwen_image.yaml Qwen-Image DMD2 蒸馏

5.9 huggingface/ --- 厂商特化配方

按厂商/模型组织,覆盖:

厂商 模型 配方
Google Gemma / Gemma4 / DiffusionGemma W4A8 AWQ + FP8 KV
MosaicML MPT W4A8 AWQ + FP8 KV
NVIDIA Nemotron-3-Nano-4B / Super-120B-A12B / Ultra-550B-A55B / Nemotron VL NVFP4 max/mse/4o6 变体
Microsoft Phi4MM NVFP4 + FP8 KV
Qwen Qwen3.5 / Qwen3.5 MoE W4A16 NVFP4 + FP8 attention
StepFun Step3.5-Flash NVFP4 MLP-only
OpenAI ViT FP8

配图 3:Recipe 文件组织树状图

#mermaid-svg-sDv7Z8WfGphJA7ve{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sDv7Z8WfGphJA7ve .error-icon{fill:#552222;}#mermaid-svg-sDv7Z8WfGphJA7ve .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sDv7Z8WfGphJA7ve .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sDv7Z8WfGphJA7ve .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sDv7Z8WfGphJA7ve .marker.cross{stroke:#333333;}#mermaid-svg-sDv7Z8WfGphJA7ve svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sDv7Z8WfGphJA7ve p{margin:0;}#mermaid-svg-sDv7Z8WfGphJA7ve .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve .cluster-label text{fill:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve .cluster-label span{color:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve .cluster-label span p{background-color:transparent;}#mermaid-svg-sDv7Z8WfGphJA7ve .label text,#mermaid-svg-sDv7Z8WfGphJA7ve span{fill:#333;color:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve .node rect,#mermaid-svg-sDv7Z8WfGphJA7ve .node circle,#mermaid-svg-sDv7Z8WfGphJA7ve .node ellipse,#mermaid-svg-sDv7Z8WfGphJA7ve .node polygon,#mermaid-svg-sDv7Z8WfGphJA7ve .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sDv7Z8WfGphJA7ve .rough-node .label text,#mermaid-svg-sDv7Z8WfGphJA7ve .node .label text,#mermaid-svg-sDv7Z8WfGphJA7ve .image-shape .label,#mermaid-svg-sDv7Z8WfGphJA7ve .icon-shape .label{text-anchor:middle;}#mermaid-svg-sDv7Z8WfGphJA7ve .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sDv7Z8WfGphJA7ve .rough-node .label,#mermaid-svg-sDv7Z8WfGphJA7ve .node .label,#mermaid-svg-sDv7Z8WfGphJA7ve .image-shape .label,#mermaid-svg-sDv7Z8WfGphJA7ve .icon-shape .label{text-align:center;}#mermaid-svg-sDv7Z8WfGphJA7ve .node.clickable{cursor:pointer;}#mermaid-svg-sDv7Z8WfGphJA7ve .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sDv7Z8WfGphJA7ve .arrowheadPath{fill:#333333;}#mermaid-svg-sDv7Z8WfGphJA7ve .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sDv7Z8WfGphJA7ve .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sDv7Z8WfGphJA7ve .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sDv7Z8WfGphJA7ve .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sDv7Z8WfGphJA7ve .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sDv7Z8WfGphJA7ve .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sDv7Z8WfGphJA7ve .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sDv7Z8WfGphJA7ve .cluster text{fill:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve .cluster span{color:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sDv7Z8WfGphJA7ve .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sDv7Z8WfGphJA7ve rect.text{fill:none;stroke-width:0;}#mermaid-svg-sDv7Z8WfGphJA7ve .icon-shape,#mermaid-svg-sDv7Z8WfGphJA7ve .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sDv7Z8WfGphJA7ve .icon-shape p,#mermaid-svg-sDv7Z8WfGphJA7ve .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sDv7Z8WfGphJA7ve .icon-shape .label rect,#mermaid-svg-sDv7Z8WfGphJA7ve .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sDv7Z8WfGphJA7ve .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sDv7Z8WfGphJA7ve .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sDv7Z8WfGphJA7ve :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} modelopt_recipes/
configs/
numerics/

10+ 数值格式
ptq/
presets/
model/

30+ 模型级预设
kv/

7 种 KV 预设
diffusers/

4 种扩散预设
units/

15+ 原子单元
general/
ptq/

20+ 组合配方
speculative_decoding/

eagle3 / dflash / domino
distillation/

dmd2_qwen_image
huggingface/
gemma / gemma4 / mpt
nvidia

Nemotron-3-Nano/Super/Ultra
nemotron_vl / phi4mm
qwen3_5 / qwen3_5_moe
step3p5 / vit / diffusion_gemma

说明 :组织遵循「原语 → 单元 → 预设 → 组合 → 厂商特化」的层次,每层都可通过 $import 复用下层。general/ptq/ 的组合配方命名 <weight>-kv_<kv> 清晰表达双维度配置。


6. 本篇使用指南

6.1 案例 1:使用内置 PTQ 配方量化 Llama

python 复制代码
import torch
from transformers import AutoModelForCausalLM
import modelopt.torch.quantization as mtq
from modelopt.recipe import load_recipe

# 加载模型
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B-Instruct",
                                              torch_dtype=torch.bfloat16,
                                              device_map="auto")

# 加载 NVFP4 内置配方
recipe = load_recipe("configs/ptq/presets/model/nvfp4")

# 量化
mtq.quantize(model, quant_cfg=recipe.quantize, calibration_data=calib_loader)

# 导出
from modelopt.torch.export import export_hf_checkpoint
export_hf_checkpoint(model, export_dir="./llama_nvfp4")

6.2 案例 2:自定义 Recipe(dotlist overrides)

bash 复制代码
# 命令行覆盖:把 NVFP4 配方的 algorithm 改为 mse,并设置 NNCF tablet
python -c "
from modelopt.recipe import load_recipe
recipe = load_recipe(
    'configs/ptq/presets/model/nvfp4',
    overrides=[
        'algorithm=mse',
        'quantize.calibration_data/calib_seq_len=2048',
    ],
)
print(recipe)
"

注意 :overrides 是 dotlist 风格,路径用 . 分隔。值会被 yaml.safe_load 解析(如 true → bool,2048 → int)。

6.3 案例 3:创建目录格式配方

bash 复制代码
mkdir my_recipe/
cat > my_recipe/metadata.yml <<EOF
recipe_type: ptq
description: My custom PTQ recipe
EOF

cat > my_recipe/quantize.yml <<EOF
algorithm: max
quant_cfg:
  - quantizer: "*"
    num_bits: "fp8"
    method: "dynamic"
EOF

加载:

python 复制代码
from modelopt.recipe import load_recipe
recipe = load_recipe("my_recipe/")  # 注意结尾的 /

6.4 案例 4:Speculative Decoding 配方(eagle3)

python 复制代码
from modelopt.recipe import load_recipe
recipe = load_recipe("general/speculative_decoding/eagle3")

# recipe 是 ModelOptEagleRecipe 实例
print(recipe.metadata.recipe_type)  # RecipeType.SPECULATIVE_EAGLE
print(recipe.eagle)                  # EagleConfig
print(recipe.training)               # SpecTrainingArgs

# 用 mts.convert 应用
import modelopt.torch.speculative as mts
model = mts.convert(model, mode=("eagle", recipe.eagle))
# 然后用 HuggingFace Trainer 训练(recipe.training 提供参数)

6.5 案例 5:组合 KV cache 量化

python 复制代码
# 加载权重预设 + KV 预设的组合
recipe = load_recipe("general/ptq/nvfp4_default-kv_fp8_cast")
# 等价于:NVFP4 权重 + FP8 cast KV cache

7. 本篇效果对比

表 1:不同 numerics 预设的精度 / 性能对比

预设 位宽 加速比(H100/H200) 加速比(Blackwell) 内存压缩 典型精度损失 适用硬件
int8 W8A8 1.5--2× 1.5× < 0.5% 所有 GPU
int8_per_channel W8A8 (per-channel) 1.6--2× 1.6× < 0.3% 所有 GPU
int4_per_block W4A16 (bs=32) 2--3× 2.5--3.5× < 1.5% 所有 GPU
fp8 W8A8 (E4M3) 1.5--2× 1.6--2.2× < 0.3% H100+ / Blackwell
mxfp8 W8A8 (per-block scale) 1.6--2.2× 1.7--2.3× < 0.2% Blackwell
mxfp4 W4A4 (E2M1) 2.5--3.5× 2.8--3.8× < 1.0% Blackwell
mxfp6 W6A6 2--2.5× 2.2--2.8× 5.3× < 0.5% Blackwell
mxint8 W8A8 (INT) 1.5--2× 1.6--2.2× < 0.5% Blackwell
nvfp4 W4A4 (E2M1 + FP8 scale) 3--4× 3.5--4.5× < 1.0% Blackwell
nvfp4_bs32 W4A4 (bs=32) 3--4× 3.5--4.5× < 1.2% Blackwell
nvfp4_four_over_six W4A4 (4/6 模式) 3--4× 3.5--4.5× < 0.8% Blackwell
nvfp4_static W4A4 (静态) 3--4× 3.5--4.5× < 1.5% Blackwell

表 2:KV cache 量化策略对比

策略 KV 位宽 显存压缩 精度损失 推理影响 推荐场景
kv_fp16 (默认) FP16 0% 短上下文、精度敏感
kv_fp8 FP8 E4M3 < 0.3% 略快 通用
kv_fp8_affine FP8 + affine < 0.5% 略快 数值范围大的场景
kv_fp8_cast FP8 直接截断 < 1.0% 最快 速度优先
kv_nvfp4 NVFP4 (E2M1 + scale) < 2.0% 中等 长上下文 + Blackwell
kv_nvfp4_affine NVFP4 + affine < 2.5% 中等 数值范围大
kv_nvfp4_cast NVFP4 直接截断 < 3.0% 较快 速度优先
kv_nvfp4_rotate NVFP4 + Hadamard < 1.5% 较慢(rotation 开销) 精度敏感的长上下文

表 3:组合配方 vs 单元配方(开发效率 vs 灵活性)

维度 单元配方(units/) 模型级预设(presets/model/) 组合配方(general/ptq/)
抽象级别 单个 quantizer 一组模块的量化策略 完整端到端配置
可复用性 高(被多预设 import) 中(被组合配方 import) 低(直接使用)
灵活性 最高 较低(固定组合)
使用门槛 需理解 $import 直接用,可选覆盖 直接用
典型场景 自定义新预设 单一权重格式 权重 + KV 双维度配置
示例 kv_fp8.yaml nvfp4.yaml nvfp4_default-kv_fp8_cast.yaml

表 4:Recipe 系统价值对比

维度 Recipe (YAML) 直接 Python API
可读性 高(声明式) 中(命令式)
可版本化 强(YAML 文件) 弱(散落在代码中)
可复用 强($import 弱(需手写函数)
校验 强(Pydantic schema) 弱(运行时报错)
覆盖能力 dotlist overrides 直接修改 dict
学习曲线 中(需学 schema) 低(Python 字典)
CI/CD 集成 强(YAML + dotlist) 中(需写脚本)
典型场景 生产部署、多模型批量化 实验研究、快速迭代

下一篇08 测试与示例(file:///workspace/ReadCode/08_测试与示例.md)

相关推荐
韦胖漫谈IT2 小时前
Apple M3 Max 与 Apple M5 Max 对比:本地算力的新旧王者之争
网络·人工智能·macos·transformer
treesforest3 小时前
做内容平台,IP地址精准定位和IP高精度定位查询怎么帮我们提升用户留存
网络·网络协议·tcp/ip
happyprince3 小时前
08_NVIDIA_ModelOpt-测试与示例
modelopt
电商API_180079052473 小时前
电商ERP 自动同步订单功能实现拆解与技术手段
服务器·前端·网络·爬虫
云计算-Security3 小时前
分组交换的可靠性来自哪里?
网络·智能路由器
ward RINL3 小时前
# GPT-5.6-sol vs GPT-5.5 新题实测:非弹性碰撞物理题和稳定路由算法
网络·gpt·算法
wang_shu_mo_ran4 小时前
网络编程(二):UDP数据报在客户端与服务端之间的传输
网络·网络协议·udp
humors2214 小时前
【转帖】关于防范AI编程工具Claude Code安全后门隐患的风险提示
网络·安全·ai编程
永久鳕4 小时前
WebSocket 连接成功但行情不更新,应该先查哪几个状态?
网络·websocket·网络协议