目录

量化(不是那个量化啊喂!)

模型的量化配置写在文件里,计算却发生在一个个层上。这篇文章沿着两者之间的路径,梳理 HF 模型中的真实配置、SGLang 与 vLLM 的解析流程,以及普通层和融合层的匹配方式。这里的“量化”指模型数值量化。

核查日期:2026-10-08。源码基于 SGLang 730f1f3 (opens new window) 与 vLLM e1a5fc4 (opens new window)。下文的实现细节以这两个版本为准;同一格式在不同框架、后端和版本中的支持范围可能不同。

# 1. HF 上的量化描述长什么样

常见的入口是 config.json 中的 quantization_config,其字段由导出工具和量化格式决定。HF 托管这些文件,并不要求所有方法共用一套字段。有些模型则把描述放在独立的 quantize_config.json、quant_config.json 或 hf_quant_config.json 中。

先区分三个概念:

概念 例子 决定什么
数值方案/算法 FP8、INT4、AWQ、GPTQ、NVFP4 如何表示数值、如何生成量化权重
文件格式/schema fp8、awq、gptq、compressed-tensors、ModelOpt 用哪些字段描述方案、如何存储权重和 scale
层匹配规则 排除列表、targets、quantized_layers 哪个层使用哪个方案

FP8 可以由原生 fp8、compressed-tensors 或 ModelOpt 的格式描述;使用 AWQ 算法生成的权重,也可能采用 compressed-tensors schema。因此,选择解析器需要看实际文件,而不能只看模型名字中的“FP8/AWQ”。

下面选取七个真实案例,覆盖全局配置、排除列表、按类型或正则分组、按完整层名配置,以及 bitsandbytes。它们代表几种常见写法,并未穷举所有格式。JSON 均为原文件的字段节选,省略了模型结构或部分量化字段,不能直接作为完整配置使用。

# 1.1 原生 FP8:DeepSeek-V3

来源:DeepSeek-V3/config.json (opens new window),节选其 quantization_config:

{
  "quant_method": "fp8",
  "fmt": "e4m3",
  "activation_scheme": "dynamic",
  "weight_block_size": [128, 128]
}
1
2
3
4
5
6
字段 含义
quant_method 标识格式,供框架定位 FP8 配置类
fmt FP8 数值格式:E4M3 表示 4 位指数、3 位尾数
activation_scheme 激活的量化 scale 在运行时计算;static 则通常使用预先标定的 scale
weight_block_size 权重每个 128×128 block 共用一个 scale;这不是激活 block 大小

这份配置没有逐层列出量化目标,框架会根据支持的层类型选择 FP8 方法。其他 FP8 文件可能提供 ignored_layers 或 modules_to_not_convert 排除列表,具体匹配规则仍由解析器决定。另一个容易忽略的细节是:两框架的 Fp8Config.from_config() 都没有把 fmt 作为可切换任意 FP8 格式的通用选项。

# 1.2 AWQ:全局 INT4 参数与排除列表

来源:Qwen2.5-7B-Instruct-AWQ/config.json (opens new window),节选:

{
  "quant_method": "awq",
  "bits": 4,
  "group_size": 128,
  "zero_point": true,
  "version": "gemm",
  "modules_to_not_convert": null
}
1
2
3
4
5
6
7
8
字段 含义
bits 权重量化为 4 bit;不表示激活也为 4 bit
group_size 沿权重量化分组维度,每组 128 个元素共享量化参数
zero_point 使用零点,支持非对称量化
version 导出工具标记的权重/执行布局版本,案例为 GEMM;框架也可能选择兼容的 Marlin 方法
modules_to_not_convert 不量化的模块;案例为 null,表示未提供显式排除列表

AWQConfig.from_config() 主要读取 bit 数、group 大小、零点和排除列表。文件中的 version 不等于最终一定调用某个同名 kernel。

# 1.3 GPTQ:推理参数与量化时元数据共存

来源:Qwen2.5-7B-Instruct-GPTQ-Int4/config.json (opens new window),节选:

{
  "quant_method": "gptq",
  "bits": 4,
  "group_size": 128,
  "sym": true,
  "desc_act": false,
  "damp_percent": 0.01,
  "true_sequential": true
}
1
2
3
4
5
6
7
8
9
字段或字段组 含义
bits、group_size、sym 权重 bit 数、分组大小和是否对称量化
desc_act 是否按激活重要性重排量化顺序(activation order);会影响 g_idx 等加载/执行处理
damp_percent GPTQ 量化时,对 Hessian 近似施加的阻尼比例
true_sequential 量化同一 block 内的模块时,后续模块使用前面模块量化后的结果
batch_size、dataset、tokenizer、pad_token_id 校准数据和校准批处理信息
cache_block_outputs、model_seqlen 量化期间的 block 输出缓存及序列长度设置
block_name_to_quantize、module_name_preceding_first_block、modules_in_block_to_quantize 量化工具定位 block、前置模块及 block 内目标模块的信息;案例均为空
use_exllama、exllama_config、max_input_length、use_cuda_fp16 导出工具/原始运行库的执行设置;不能据此断定 SGLang/vLLM 使用 ExLlama

加载已量化权重时,推理配置类读取所需字段,不会重新执行 GPTQ 校准。扩展 GPTQ 文件还可能提供 lm_head 和 dynamic;后者允许按正则覆盖部分层的 bit 数、分组参数,或排除模块。第 3 节会展开这些匹配规则。

# 1.4 compressed-tensors:按层类型配置 FP8

来源:RedHatAI/Meta-Llama-3.1-8B-Instruct-FP8/config.json (opens new window),节选:

{
  "quant_method": "compressed-tensors",
  "format": "naive-quantized",
  "ignore": ["lm_head"],
  "config_groups": {
    "group_0": {
      "targets": ["Linear"],
      "weights": {"num_bits": 8, "type": "float", "strategy": "tensor"}
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11

原文件将权重和输入激活都设为静态、对称、per-tensor FP8,输出激活和 KV cache 方案为空。targets: ["Linear"] 是这份配置的关键:它按模块类型选择层,因此不需要逐项列出完整层名。

字段 含义
config_groups 多组“目标层 + 量化方案”;组名是标识,不是层路径
targets 正向目标:可以是模块类型名、完整层名或以 re: 开头的正则
ignore 排除规则;先判断排除,再选择正向方案
weights/input_activations/output_activations 分别描述权重、输入和输出激活;为空表示未声明对应量化
num_bits、type、symmetric bit 数、整数/浮点类型、对称性
strategy scale 粒度,例如 tensor、channel、group、block、tensor_group
dynamic scale 是否运行时生成;权重通常为 false;部分方案使用 "local" 表示局部动态 scale
group_size/block_structure group 元素数或二维 block 形状,仅对相应粒度有意义
format 权重的压缩/存储格式,可在全局或各组声明
quantization_status 导出状态;案例为已压缩的 checkpoint,不是让推理框架重新校准的命令
observer/observer_kwargs 导出时估计量化范围的方法与参数
scale_dtype/zp_dtype scale 和零点的存储类型(若格式声明)
kv_cache_scheme KV cache 的量化描述,独立于 Linear 权重量化
sparsity_config/transform_config 可选的稀疏/变换描述;不是所有 compressed-tensors 文件都会提供

compressed-tensors 是能装下多个数值方案的 schema,而不是一个固定的“8 bit 算法”。

# 1.5 compressed-tensors:按正则分组的混合方案

来源:RedHatAI/GLM-5.2-NVFP4-FP8/config.json (opens new window),只节选路由字段:

{
  "quant_method": "compressed-tensors",
  "format": "mixed-precision",
  "config_groups": {
    "group_0": {"targets": ["re:.*self_attn\\..*"], "format": "float-quantized"},
    "group_1": {"targets": ["re:.*mlp\\..*"], "format": "nvfp4-pack-quantized"}
  }
}
1
2
3
4
5
6
7
8

第一组声明 attention 使用 block FP8 权重(128×128),激活按 128 个元素一组动态量化到 FP8;第二组声明 MLP 使用 NVFP4,权重和激活采用 tensor_group、group size 16,scale 类型为 E4M3。排除列表另外保留 router、部分 indexer 投影和 LM head 等。

JSON 中的 \\ 解码成正则中的 \,所以 \. 匹配路径中的字面量点。re: 后面是正则表达式,不是通配符;解析器使用 re.match,是否匹配任意前缀由表达式中的 .* 决定。

同一 schema 可以通过不同分组描述多种执行方案。不过,文件能表达一种方案,不等于框架一定能运行它;模型架构、量化参数和 kernel 支持仍需分别验证。

# 1.6 ModelOpt:独立文件与完整层名映射

来源:nvidia/Qwen3.5-397B-A17B-NVFP4-V2/hf_quant_config.json (opens new window),节选:

{
  "quantization": {
    "quant_algo": "MIXED_PRECISION",
    "kv_cache_quant_algo": "FP8",
    "quantized_layers": {
      "model.language_model.layers.0.linear_attn.out_proj": {"quant_algo": "FP8"},
      "model.language_model.layers.0.mlp.experts": {"quant_algo": "NVFP4", "group_size": 16}
    }
  }
}
1
2
3
4
5
6
7
8
9
10
字段 含义
producer 导出工具的名称和版本;在原文件顶层,此处省略
quantization 独立 ModelOpt 文件的配置外壳;另有内嵌于 HF 配置的扁平形式
quant_algo 全局算法;MIXED_PRECISION 表示继续查每层条目;普通 ModelOpt 文件也可统一指定 FP8/NVFP4
quantized_layers 完整层名到该层算法/参数的映射,区别于 compressed-tensors 的 target 分组
层内 group_size 该层方案的分组大小;此处 NVFP4 为 16
kv_cache_quant_algo KV cache 方案;不随某个 Linear 层的算法自动推导
exclude_modules 部分 ModelOpt 文件使用的排除列表;不出现在上述节选中

框架将 ModelOpt 元数据识别为 modelopt、modelopt_fp4 或 modelopt_mixed 等内部方法,再交给对应类解析。因此“入口读取一个 quant_method 字符串”只概括常规情况,ModelOpt 还涉及外壳展开和算法识别。

# 1.7 bitsandbytes:NF4 与计算 dtype 分开声明

来源:unsloth/llama-3-8b-Instruct-bnb-4bit/config.json (opens new window),节选:

{
  "quant_method": "bitsandbytes",
  "load_in_4bit": true,
  "bnb_4bit_quant_type": "nf4",
  "bnb_4bit_compute_dtype": "bfloat16",
  "bnb_4bit_quant_storage": "uint8",
  "bnb_4bit_use_double_quant": true
}
1
2
3
4
5
6
7
8

load_in_4bit/load_in_8bit 选择加载路径;NF4 是权重编码,compute_dtype 是计算时类型,quant_storage 是打包容器类型,三者不能混同。use_double_quant 表示进一步压缩量化统计量。原文件中的 _load_in_* 是序列化的内部状态,和公开的 load_in_* 同时存在。

llm_int8_skip_modules 提供跳过模块的信息;llm_int8_threshold 是 INT8 outlier 阈值;CPU offload 与保留 FP16 权重由 llm_int8_enable_fp32_cpu_offload/llm_int8_has_fp16_weight 描述。4 bit 文件带这些字段不表示推理过程中都启用 INT8 功能。

# 1.8 几个容易混淆的数值字段

字段或术语 作用与边界
权重 bit 数与激活 bit 数 两者分别描述存储的权重和运行时输入。AWQ/GPTQ 的 bits: 4 通常只指权重;compressed-tensors 则在 weights、input_activations 中分别声明。W4A16 表示 4 bit 权重配合 16 bit 激活
group_size 一维量化分组的元素数,不是层数、专家数或 batch。本文 AWQ/GPTQ Linear 的分组沿输入特征维进行,同一输出通道内每组共用 scale 等参数;compressed-tensors 的具体分组轴还取决于张量类型和 strategy,不能只看这个数字
weight_block_size/block_structure 二维 block 形状。前者是原生 FP8 的权重字段,后者放在 compressed-tensors 的相应张量描述中。对于按 [输出特征, 输入特征] 理解的 Linear 权重,[128, 128] 表示两个轴各 128 个元素共用 scale;实际存储可能经过转置或打包
scale 与 zero-point scale 将编码值映射到实际数值范围,zero-point 用来表示零值位置。常见整数重建形式为 scale × (编码值 − zero-point);浮点量化的编码与缩放方式不同。对称方案通常不需要非零零点。scale 文件名、是否保存倒数以及张量形状由格式决定
静态/动态 scale 静态激活 scale 通常在离线校准时生成,随 checkpoint 保存;动态激活 scale 在推理时根据当前输入计算。权重的静态 scale 随量化权重加载。dynamic 要结合所在张量描述理解,不能直接推断整模型都在运行时重新量化
tensor/tensor_group tensor 通常让一个张量共用 scale;NVFP4 的 tensor_group 同时包含局部分组 scale 和张量级缩放信息,不能等同于普通 INT4 的单层 group scale
desc_act/actorder/g_idx 前两者描述量化顺序或分组重排策略;g_idx 是 GPTQ 权重所需的分组索引信息,帮助加载/执行方法对应每行输入特征与 scale 组。它不是模型层编号,也不用于 prefix 匹配

true_sequential 是 GPTQ 生成权重时的处理顺序;GPTQ 扩展字段 dynamic 则是逐层规则表。它们和 compressed-tensors 张量内的 dynamic scale 标志不是同一种配置。

# 2. SGLang 与 vLLM 怎样读取、解析和执行

两框架采用相近的职责划分:配置类解释自己的格式,模型代码提供层及其完整路径,执行方法管理权重和计算。这里的 from_config() 属于各量化配置类,而不是每个 Linear 或 Attention 层。

# 2.1 SGLang

HF config.json / compression_config / 独立 ModelOpt 文件 / 用户指定方法
                                  ↓
ModelConfig:识别 quant_method,必要时展开 ModelOpt 元数据并选择覆盖方法
                                  ↓
quantization 注册表:找到 QuantizationConfig 类
                                  ↓
model_loader.get_quant_config():优先使用 HF 内嵌配置
       没有可用内嵌配置 → 按该类 get_config_filenames() 查独立 JSON
                                  ↓
该类 from_config() → quant_config
                                  ↓
注入模型 packed_modules_mapping,并按模型 mapper 转换配置中的层名
                                  ↓
模型逐层构造:传入 quant_config 与完整 prefix
                                  ↓
quant_config.get_quant_method(layer, prefix)
                                  ↓
层保存 quant_method → create_weights() → 加载/后处理权重
                                  ↓
Linear.forward() → quant_method.apply(layer, input, bias)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

内嵌配置通常优先;ModelOpt mixed 如果缺少逐层映射或所需 KV 元数据,会回到独立文件路径补齐。选择量化类时还可能发生方法覆盖,例如选择兼容的 Marlin 实现。来源:ModelConfig 识别 (opens new window)、配置文件加载 (opens new window)、模型映射注入 (opens new window)。

# 2.2 vLLM

HF 配置(含 text_config / compression_config 的兼容入口)+ 用户参数
                                  ↓
ModelConfig._verify_quantization():确定方法、调用 override、检查冲突
                                  ↓
quantization 注册表:找到 QuantizationConfig 类
                                  ↓
model_loader.get_quant_config():优先内嵌配置,否则查独立 JSON
                 ModelOpt mixed 缺 quantized_layers → 查独立文件
                                  ↓
该类 from_config() → quant_config
                                  ↓
模型量化初始化:应用 HF→vLLM mapper,并传入 packed_modules_mapping
                                  ↓
模型逐层构造:传入 quant_config 与完整 prefix
                                  ↓
quant_config.get_quant_method(layer, prefix)
                                  ↓
层保存 quant_method → create_weights() → 加载/后处理权重
                                  ↓
Linear.forward() → quant_method.apply(layer, input, bias)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

文件名由具体类提供,不是扫描任意 JSON 猜字段。常规独立文件路径遇到零个或多个候选配置会报错;特定方法也有默认配置、用户 override 或在线量化分支。新版模型可通过 SupportsQuant 接口设置映射,旧模型由 configure_quant_config() 兼容注入。来源:方法识别与覆盖 (opens new window)、配置读取 (opens new window)、映射注入 (opens new window)。

以上 forward → apply 是 Linear 的典型路径。Attention 的量化方法可能主要负责 KV scale;MoE 会结合路由器和专用 runner,不能把所有层都理解成同一个 Linear 调用签名。

# 3. 如何匹配到具体层

# 3.1 layer 和 prefix 分别提供什么信息

layer 给出 Python 层类型及其形状等属性;prefix 给出模型中的具体位置,例如 model.layers.0.mlp.down_proj。它是层路径,通常对应 checkpoint 参数名去掉 .weight/.bias 等参数后缀的部分。

prefix 由模型构造代码逐层拼接:

model
  └─ layers.0
       └─ mlp
            └─ down_proj
完整 prefix = model.layers.0.mlp.down_proj
1
2
3
4
5

模型代码使用 add_prefix()、maybe_prefix() 或字符串拼接,把父路径传给子模块。PyTorch 不会通过 self.down_proj = ... 自动为量化匹配生成这个值。一个层的 DAG 展示名如 L0.mlp.down 也不能直接替代它。实际路径还受模型结构、多模态文本塔、封装层和融合命名影响。来源:SGLang DeepSeek 构造 (opens new window)、vLLM DeepSeek 构造 (opens new window)。

# 3.2 普通层:不同格式使用不同匹配规则

格式 SGLang vLLM
原生 FP8 支持的 Linear/MoE 默认量化,排除按点分隔模块路径判断,可匹配父路径/连续路径段 支持的层默认量化,FP8 排除 helper 默认按完整路径相等判断
AWQ 支持的层默认量化;普通 AWQ 排除按字符串包含判断 支持的层默认量化;AWQ 调用允许 substring 的 helper,并考虑融合映射
GPTQ 扩展 基础方案 + dynamic 逐层正则 override,-: 排除、+: 覆盖;按配置顺序取首个命中 auto_gptq 等兼容类处理基础方案、dynamic 以及 block 内目标信息;具体分支取决于所选后端
compressed-tensors ignore + config_groups.targets 选择 scheme 同样由 ignore + targets 选择 scheme
ModelOpt mixed 在 quantized_layers 中查层路径,未配置的普通 Linear 保持未量化 同样逐层查表,未配置的普通 Linear 保持未量化
bitsandbytes skip helper 检查路径 component 和累计父路径 同样使用专门的 BNB skip helper

因此不能把所有列表都当成 regex,也不能把所有名字都理解为完整路径精确匹配。上表列的是核查版本的典型分支;AWQ/GPTQ 的 Marlin、MoE 等分支还会做额外的类型、shape 和硬件检查。源码入口:SGLang FP8 (opens new window)、SGLang AWQ (opens new window)、SGLang GPTQ (opens new window)、vLLM FP8 (opens new window)、vLLM AWQ (opens new window)、vLLM AutoGPTQ (opens new window)。

compressed-tensors 的普通匹配过程尤其值得展开:

  1. from_config() 将每组的字段解析为 QuantizationArgs,形成 target → scheme 映射。
  2. get_quant_method() 先判断层类型,再检查 ignore。
  3. 正向匹配依次尝试层路径的精确/正则匹配、模块类名匹配、融合 component 匹配。类型名匹配使用包含关系,所以 Linear 可以匹配 RowParallelLinear 等框架类名。
  4. 取命中的 target 所属方案,再根据 bit 数、数值类型、scale 粒度、激活配置和 format 选择执行 scheme。

在普通正向路径上,两者都不是“完全没匹配就默认不量化”:如果存在非空 target 表,而普通 Linear 无法匹配,会抛 ValueError。被显式忽略、没有权重量化方案等情况才会返回未量化方法。已匹配但方案或设备不支持也可能报错。

SGLang 的 compressed-tensors 排除 helper 额外接受点分隔路径后缀,如 self_attn.kv_b_proj;vLLM 此版本主要是精确/正则。这个后缀兼容不能直接套用到普通正向 find_matched_target()。源码:SGLang 匹配 helper (opens new window)、vLLM 匹配 helper (opens new window)。

# 3.3 融合层:执行名称与 checkpoint 名称不一定一对一

模型可以把多个 Linear 合成一个执行层,但 checkpoint 的配置和权重仍按原始模块命名。模型提供 packed_modules_mapping 将两者关联:

执行层名 checkpoint 中的 component 名 说明
gate_up_proj gate_proj、up_proj 合并 MLP 的两个投影
qkv_proj q_proj、k_proj、v_proj 合并普通 attention 的 Q/K/V 投影
SGLang fused_qkv_a_proj_with_mqa q_a_proj、kv_a_proj_with_mqa DeepSeek-V3 MLA 的低秩投影融合
vLLM fused_qkv_a_proj q_a_proj、kv_a_proj_with_mqa 此版本使用不同的融合名称,component 相同

例如执行层路径是 model.layers.0.mlp.gate_up_proj,量化配置可以仍然写 model.layers.0.mlp.gate_proj 和 model.layers.0.mlp.up_proj。匹配器保留父路径,将最后的投影名展开为两个 component,再检查原始名称。这个映射由模型/加载器提供,不要求每个 HF 文件自己携带它。实际权重加载还需要把 component 的权重和 scale 放入融合参数的相应 shard;单有匹配映射并不完成权重融合。

各格式对融合一致性的检查范围不同:

路径 真正检查的内容 不能据此推断的内容
原生 FP8 排除 helper 对已识别的融合映射,检查各 component 的 skip 状态;部分 skip、部分量化会报错 不等于检查各 component 的所有参数和 scale 完全相同
compressed-tensors ignore 展开 component 后,检查是否全部忽略或全部不忽略;不一致会报错 报错文案说 scheme 不同,但这里实际比较的是 ignore 布尔值
compressed-tensors 正向 _match_fused_layer() 要求全部 component 都能命中某个 target,然后返回第一个 component 的 target 此 helper 没有逐项比较 scheme 对象;component 分别命中不同组不代表一定被拒绝;直接路径/类型命中还会先于此分支返回
ModelOpt mixed 查表 对已找到的 component 收集 quant_algo;出现两种以上算法会报错 缺少某个 component 条目不一定报错;只找到一种算法也可返回;这里也不比较每个 component 的完整参数
SGLang 普通 AWQ 排除 对执行层 prefix 做 substring 检查 此分支没有自动展开 component,不能保证只排除原始 gate_proj 就按预期处理 gate_up_proj

还有两个细节:vLLM FP8 helper 会先尊重直接写出的融合层排除名;SGLang FP8 helper 在没有模型映射时有 QKV/gate-up 的 fallback,但其他融合投影需要正确映射。上面的具体行为不应泛化成“所有格式都保证融合 component 使用相同配置”。来源:SGLang FP8 helper (opens new window)、vLLM FP8 helper (opens new window)、SGLang ModelOpt mixed (opens new window)、vLLM ModelOpt mixed (opens new window)。

# 3.4 LM head、MoE、路径转换等特殊 case

LM head。 ParallelLMHead 常属于 embedding 继承体系,因此配置类需要单独判断,不能默认被普通 LinearBase 分支覆盖。SGLang compressed-tensors 此版本仅在完整层名/正则等显式指向 head 时选择量化,targets: ["Linear"] 不自动量化它;未命中返回默认 embedding 执行。vLLM 会尝试普通 scheme 匹配,但捕获 ValueError 并回退;同样不能推断“所有报错都严格拒绝 head”。AWQ/GPTQ 的部分实现还有 lm_head 开关。来源:SGLang head 匹配 (opens new window)、vLLM head 分支 (opens new window)。

MoE 专家打包。 checkpoint 可以为每个专家保存 experts.0.gate_proj 等权重,执行端却使用一个批量专家模块(SGLang FusedMoE、vLLM RoutedExperts),内部再打包为 gate/up 与 down 参数。因此会走专门的 MoE scheme/method 及专家权重映射,不能直接靠普通 Linear 的 prefix 规则覆盖。ModelOpt mixed 还允许通过父模块下的子条目推断算法;此版本的这类 prefix fallback 取首个相关条目,未在这里验证所有专家采用同一方案。实际是否支持还取决于 MoE kernel 和导出布局。

HF 名称与框架名称不同。 多模态模型可能有 language_model.model.layers.*、model.language_model.layers.* 等不同路径。模型提供的 hf_to_sglang_mapper/hf_to_vllm_mapper 会转换支持方法中的排除项、targets 或逐层字典;ModelOpt mixed 另有若干显式候选 prefix。它们不是自动猜测任意路径的通用机制。漏配 mapper 可能导致未匹配报错,也可能在允许 fallback 的格式中退回未量化,需要具体检查。

正则的顺序与锚点。 重叠 targets 或 GPTQ dynamic 规则需要关注首个命中;re.match 从开头开始匹配,表达式末尾不写 $ 也可能命中更长的子路径。排除一个父模块是否覆盖子模块,依赖 helper 的语义,不能仅凭字符串外观判断。

# 4. 代码如何组织:保持配置独立、Layer 接口统一

两框架在职责上相近,目录细节不同:

职责 SGLang vLLM
方法识别、检查用户参数 configs/model_config.py config/model.py 等配置模块
方法名→配置类注册 layers/quantization/__init__.py model_executor/layers/quantization/__init__.py
配置公共接口 layers/quantization/base_config.py model_executor/layers/quantization/base_config.py
读取独立文件 model_loader/weight_utils.py model_executor/model_loader/weight_utils.py
各格式解析和分派 fp8.py、awq/、gptq/、compressed_tensors/、modelopt_quant.py 等 fp8.py、awq.py、auto_gptq.py、compressed_tensors/、modelopt.py 等
模型层路径与融合映射 models/*.py 与加载器 model_executor/models/*.py 与加载器
可复用执行层 layers/linear.py、MoE/Attention 层 model_executor/layers/linear.py、MoE/Attention 层

每个具体配置类实现自己的 from_config(),将文件中的字段转换为内部属性、target 表或子配置。随后,get_quant_method(layer, prefix) 判断该层是否适用、是否需要排除,并选择执行方法。compressed-tensors 还会选择细分 scheme;ModelOpt mixed 可以由同一个配置对象为不同层返回不同方法。

代码中的名字 指代什么
quant_config 解析后的配置对象,保存模型所用格式、参数和匹配规则;可以在多层之间共享
JSON 的 quant_method 方法标识字符串,如 "fp8";供加载入口选择配置类
Layer 的 quant_method 配置类为当前层返回的执行对象;名称相同,但它不是 JSON 字符串
scheme compressed-tensors 等实现中的具体数值方案/执行策略,由权重和激活参数选择;可由 method 再委托它建立参数和计算
prefix 当前层的完整模块路径,如 model.layers.0.mlp.down_proj;model.layers.0.mlp.down_proj.weight 则是该层的一个参数名

同样需要区分配置字段和执行实现:fmt 描述数值格式,version 标记导出版本/布局,format 描述压缩存储。最终使用哪一个 kernel,还取决于解析后的方案、设备、shape 和所选后端。

Layer 的典型接口仍然很小,下面是职责示意,不是要求两个框架逐字一致:

# 层构造阶段
method = quant_config.get_quant_method(self, prefix)
self.quant_method = method or default_method
self.quant_method.create_weights(layer=self, **weight_args)

# 权重加载完成后,由加载流程调用后处理
self.quant_method.process_weights_after_loading(self)

# Linear 的 forward
output = self.quant_method.apply(self, input, bias)
1
2
3
4
5
6
7
8
9
10

执行方法负责建立权重、scale、zero-point、g_idx 等参数,配合 loader 加载分片,再进行转置、重排、repack 或其他 kernel 所需处理;apply() 调用实际计算实现。解析 JSON、匹配层、加载参数、调用 kernel 是相连但不同的职责。 来源:SGLang 配置接口 (opens new window)、vLLM 配置接口 (opens new window)、SGLang Linear (opens new window)、vLLM Linear (opens new window)。

仿真框架也可以沿用这套职责划分:加载入口负责路由,各 QuantizationConfig 独立完成解析和匹配,模型传入符合真实实现的 prefix 与融合映射,Layer 继续通过 get_quant_method() 和 apply() 工作。新增格式时,补充对应的配置类和执行方法即可,不需要让每个 Layer 都理解所有 HF schema。

上次更新: 2026/10/17, 14:40:14
最近更新
01
怦然心动(节选)
10-17
02
好久不“见”
10-06
03
我想我们都在往前走
09-14
更多文章>