07 · Recipe 配方系统详解
本文深入剖析 `modelopt/recipe/`(file:///workspace/modelopt/recipe/) 与 `modelopt_recipes/`(file:///workspace/modelopt_recipes/) 子系统。Recipe(配方)是 ModelOpt 提供的声明式配置层------通过 YAML 文件描述量化 / 蒸馏 / speculative decoding 的完整配置,避免手写 Python 代码。
目录
- [总览:Recipe 系统定位与价值](#总览:Recipe 系统定位与价值)
- [modelopt/recipe/config.py --- Pydantic Schema](#modelopt/recipe/config.py — Pydantic Schema)
- [modelopt/recipe/loader.py --- 加载器](#modelopt/recipe/loader.py — 加载器)
- [modelopt/recipe/presets.py --- 预设管理](#modelopt/recipe/presets.py — 预设管理)
- [modelopt_recipes/ --- 内置配方库](#modelopt_recipes/ — 内置配方库)
- 本篇使用指南
- 本篇效果对比
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/ --- 厂商特化配方
按厂商/模型组织,覆盖:
| 厂商 | 模型 | 配方 |
|---|---|---|
| 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× | 4× | < 0.5% | 所有 GPU |
int8_per_channel |
W8A8 (per-channel) | 1.6--2× | 1.6× | 4× | < 0.3% | 所有 GPU |
int4_per_block |
W4A16 (bs=32) | 2--3× | 2.5--3.5× | 8× | < 1.5% | 所有 GPU |
fp8 |
W8A8 (E4M3) | 1.5--2× | 1.6--2.2× | 2× | < 0.3% | H100+ / Blackwell |
mxfp8 |
W8A8 (per-block scale) | 1.6--2.2× | 1.7--2.3× | 2× | < 0.2% | Blackwell |
mxfp4 |
W4A4 (E2M1) | 2.5--3.5× | 2.8--3.8× | 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× | 4× | < 0.5% | Blackwell |
nvfp4 |
W4A4 (E2M1 + FP8 scale) | 3--4× | 3.5--4.5× | 8× | < 1.0% | Blackwell |
nvfp4_bs32 |
W4A4 (bs=32) | 3--4× | 3.5--4.5× | 8× | < 1.2% | Blackwell |
nvfp4_four_over_six |
W4A4 (4/6 模式) | 3--4× | 3.5--4.5× | 8× | < 0.8% | Blackwell |
nvfp4_static |
W4A4 (静态) | 3--4× | 3.5--4.5× | 8× | < 1.5% | Blackwell |
表 2:KV cache 量化策略对比
| 策略 | KV 位宽 | 显存压缩 | 精度损失 | 推理影响 | 推荐场景 |
|---|---|---|---|---|---|
kv_fp16 (默认) |
FP16 | 1× | 0% | 无 | 短上下文、精度敏感 |
kv_fp8 |
FP8 E4M3 | 2× | < 0.3% | 略快 | 通用 |
kv_fp8_affine |
FP8 + affine | 2× | < 0.5% | 略快 | 数值范围大的场景 |
kv_fp8_cast |
FP8 直接截断 | 2× | < 1.0% | 最快 | 速度优先 |
kv_nvfp4 |
NVFP4 (E2M1 + scale) | 4× | < 2.0% | 中等 | 长上下文 + Blackwell |
kv_nvfp4_affine |
NVFP4 + affine | 4× | < 2.5% | 中等 | 数值范围大 |
kv_nvfp4_cast |
NVFP4 直接截断 | 4× | < 3.0% | 较快 | 速度优先 |
kv_nvfp4_rotate |
NVFP4 + Hadamard | 4× | < 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)