llm-compressor 普通量化调用链分析

QuantizationModifier + oneshot("datafree") 完整调用链分析

示例调用: oneshot(model=model, recipe=QuantizationModifier(targets="Linear", scheme="W4A16", ignore=["lm_head"]), pipeline="datafree")


目录

  1. [第一阶段:oneshot 入口 → Session 初始化](#第一阶段:oneshot 入口 → Session 初始化)

  2. [第二阶段:Modifier.initialize → on_initialize](#第二阶段:Modifier.initialize → on_initialize)

  3. [第三阶段:scheme="W4A16" 的解析链路 🔑](#第三阶段:scheme="W4A16" 的解析链路 🔑)

  4. [第四阶段:apply_quantization_config → 将 scheme 挂载到模型层](#第四阶段:apply_quantization_config → 将 scheme 挂载到模型层)

  5. [第五阶段:on_start → 权重校准](#第五阶段:on_start → 权重校准)

  6. [第六阶段:Pipeline 推断 → "datafree"](#第六阶段:Pipeline 推断 → "datafree")

  7. 完整调用链路总结图

  8. 关键结论


第一阶段:oneshot 入口 → Session 初始化

复制代码
oneshot(model, recipe, pipeline)                                    # src/llmcompressor/entrypoints/oneshot.py:250
   └─ Oneshot(**local_args, **kwargs)                                # :413
        └─ one_shot()                                                # :414 → __call__():175
             └─ apply_recipe_modifiers()                             # :189
                  └─ session.initialize(recipe=self.recipe, ...)     # :226
                       └─ CompressionLifecycle.initialize()          # src/llmcompressor/core/lifecycle.py:73
                            │
                            ├─ Recipe.create_instance(recipe)        # recipe.py:95
                            │    └─ Recipe.from_modifiers(...)       # recipe.py:130 → :45
                            │         因为 recipe = QuantizationModifier(...) 已经是 Modifier 对象,
                            │         直接包装成 Recipe(modifiers=[QuantizationModifier])
                            │
                            └─ mod.initialize(state, **kwargs)       # 对每个 modifier 调用 lifecycle.initialize()

关键代码位置

步骤 文件 行号
oneshot() 函数 src/llmcompressor/entrypoints/oneshot.py L250-416
Oneshot.__call__() src/llmcompressor/entrypoints/oneshot.py L175-197
apply_recipe_modifiers() src/llmcompressor/entrypoints/oneshot.py L199-247
session.initialize() src/llmcompressor/core/session_functions.py -
Recipe.create_instance() src/llmcompressor/recipe/recipe.py L87-165
Recipe.from_modifiers() src/llmcompressor/recipe/recipe.py L44-85

第二阶段:Modifier.initialize → on_initialize

复制代码
Modifier.initialize(state, **kwargs)                                # src/llmcompressor/modifiers/modifier.py:61
   └─ self.on_initialize(state=state, **kwargs)                      # :79
        └─ QuantizationModifier.on_initialize()                      # src/llmcompressor/modifiers/quantization/quantization/base.py:50
             │
             ├─ QuantizationMixin.has_config(self)                   # 检查 scheme/kv_cache_scheme/config_groups 之一非空
             │
             └─ QuantizationMixin.initialize_quantization(state.model)  # base.py:65
                  │
                  ├─ reset_quantization_status(module)               # 重置所有匹配模块的量化状态
                  │                                                  # compressed-tensors/src/.../initialize.py
                  │
                  ├─ apply_quantization_config(model, self.resolved_config)  # 🔑 核心! 见第三、四阶段
                  │                                                  # compressed-tensors/src/.../apply.py:97
                  │
                  └─ model.apply(disable_quantization)               # 先禁用量化, 等 on_start 再启用

关键代码位置

步骤 文件 行号
Modifier.initialize() src/llmcompressor/modifiers/modifier.py L61-100
QuantizationModifier.on_initialize() src/llmcompressor/modifiers/quantization/quantization/base.py L50-67
initialize_quantization() src/llmcompressor/modifiers/quantization/quantization/mixin.py -
reset_quantization_status() compressed-tensors/src/.../lifecycle/initialize.py -

第三阶段:scheme="W4A16" 的解析链路 🔑

这是最核心的环节------"W4A16" 这个字符串如何一步步变成具体的量化参数。

3.1 入口: resolved_config

复制代码
# src/llmcompressor/modifiers/quantization/quantization/mixin.py:188
 @property
 def resolved_config(self):
     # lazy init: 只计算一次
     if self._resolved_config is None:
         self._resolved_config = self.resolve_quantization_config()
     return self._resolved_config

3.2 resolve_quantization_config()

复制代码
 # src/llmcompressor/modifiers/quantization/quantization/mixin.py:320
 def resolve_quantization_config(self) -> QuantizationConfig:
     """
     此时:
       self.scheme = "W4A16"        (字符串)
       self.targets = ["Linear"]
       self.config_groups = None    (未设置, 因为没有传 config_groups)
     """
 ​
     # Step 1: 检查是否为预设 scheme 名称
     is_preset_scheme("W4A16")               # quant_scheme.py:135
       └─ "W4A16".upper() = "W4A16" ∈ PRESET_SCHEMES → True!
 ​
     # Step 2: 将字符串 scheme 转换为 {"W4A16": targets} 字典
     scheme = {"W4A16": ["Linear"]}          # :350
 ​
     # Step 3: 遍历 scheme 中的每个 key
     for key in scheme.keys():
         is_preset_scheme("W4A16") → True    # :358
           └─ preset_name_to_scheme("W4A16", ["Linear"])  # :359 → quant_scheme.py:113

3.3 preset_name_to_scheme(): 查表获取量化参数

复制代码
# compressed-tensors-main/src/compressed_tensors/quantization/quant_scheme.py:113
 def preset_name_to_scheme(name: str, targets: list[str]) -> QuantizationScheme:
     name = name.upper()  # → "W4A16"
 ​
     if name not in PRESET_SCHEMES:
         raise KeyError(...)
 ​
     scheme_args = deepcopy(PRESET_SCHEMES[name])  # 深拷贝 W4A16 常量
     return QuantizationScheme(
         targets=targets,   # ["Linear"]
         **scheme_args,     # weights=QuantizationArgs(...)
     )

3.4 PRESET_SCHEMES["W4A16"] 的定义

复制代码
 # compressed-tensors-main/src/compressed_tensors/quantization/quant_scheme.py:286-295
 W4A16 = dict(
     weights=QuantizationArgs(
         num_bits=4,                           # 4-bit 量化
         type=QuantizationType.INT,            # 整数类型量化
         strategy=QuantizationStrategy.GROUP,  # group-wise 策略
         group_size=128,                       # 每 128 个元素一组, 共享 scale/zp
         symmetric=True,                       # 对称量化 (zero_point 固定为 0)
         dynamic=False,                        # 静态量化 (scale 预先计算, 不依赖输入)
     ),
 )
 # ⚠️ 注意: W4A16 只有 weights, 没有 input_activations 和 output_activations!
 # 这意味着只量化权重 (Weight 4-bit), 激活保持 FP16 (Activation 16-bit)

3.5 最终生成的 QuantizationConfig

复制代码
 # compressed-tensors-main/src/compressed_tensors/quantization/quant_config.py:94
 QuantizationConfig(
     config_groups={
         "group_0": QuantizationScheme(
             targets=["Linear"],                     # 目标: 所有 Linear 层
             weights=QuantizationArgs(               # 权重量化参数
                 num_bits=4,
                 type=QuantizationType.INT,
                 strategy=QuantizationStrategy.GROUP,
                 group_size=128,
                 symmetric=True,
                 dynamic=False,
             ),
             input_activations=None,                 # ← 不量化激活输入!
             output_activations=None,                # ← 不量化激活输出!
         ),
     },
     quantization_status=QuantizationStatus.INITIALIZED,
     ignore=["lm_head"],                             # ← lm_head 层不参与量化
     kv_cache_scheme=None,                           # ← KV Cache 不量化
 )

3.6 PRESET_SCHEMES 完整表格

预设名 权重 输入激活 输出激活 说明
W4A16 4-bit INT, GROUP, group_size=128, static None None 仅权重量化
W4A16_ASYM 4-bit INT, GROUP, group_size=128, asymmetric, static None None 非对称权重量化
W8A16 8-bit INT, CHANNEL, static None None 8-bit 权重量化
W8A8 / INT8 8-bit INT, CHANNEL, static 8-bit INT, TOKEN, dynamic None 权重+激活量化
W4A8 4-bit INT, GROUP, group_size=128, static 8-bit INT, TOKEN, dynamic None 4-bit权重+8-bit激活
W4AFP8 4-bit INT, GROUP, group_size=128, static 8-bit FLOAT, TOKEN, dynamic None 4-bit权重+FP8激活
FP8 8-bit FLOAT, TENSOR, static 8-bit FLOAT, TENSOR, static None FP8 权重+激活
FP8_DYNAMIC 8-bit FLOAT, CHANNEL, static 8-bit FLOAT, TOKEN, dynamic None FP8 动态激活
FP8_BLOCK 8-bit FLOAT, BLOCK(128,128), static 8-bit FLOAT, GROUP(128), dynamic None FP8 块量化
NVFP4A16 4-bit FLOAT, TENSOR_GROUP, group_size=16 None None NV FP4 权重量化
NVFP4 4-bit FLOAT, TENSOR_GROUP, group_size=16 4-bit FLOAT, dynamic None NV FP4 全量化
MXFP4A16 4-bit FLOAT, GROUP, group_size=32 None None MX FP4 权重量化
MXFP4 4-bit FLOAT, GROUP, group_size=32 4-bit FLOAT, dynamic None MX FP4 全量化
MXFP8A16 8-bit FLOAT, GROUP, group_size=32 None None MX FP8 权重量化
MXFP8 8-bit FLOAT, GROUP, group_size=32 8-bit FLOAT, dynamic None MX FP8 全量化

3.7 QuantizationArgs 各字段含义

字段 类型 说明
num_bits int 量化 bit 数 (4, 8)
type QuantizationType INT (整数量化) / FLOAT (浮点量化)
strategy QuantizationStrategy TENSOR / CHANNEL / GROUP / TOKEN / TENSOR_GROUP / BLOCK
group_size int GROUP 策略时的分组大小
symetric bool True=对称量化 (zero_point=0), False=非对称
dynamic bool/DynamicType 是否动态量化 (scale 在推理时从输入计算)
observer str 校准 observer 类型 (如 "minmax", "mse" 等)

关键代码位置

步骤 文件 行号
resolved_config property src/llmcompressor/modifiers/quantization/quantization/mixin.py L188
resolve_quantization_config() src/llmcompressor/modifiers/quantization/quantization/mixin.py L320
is_preset_scheme() compressed-tensors/src/.../quantization/quant_scheme.py L135
preset_name_to_scheme() compressed-tensors/src/.../quantization/quant_scheme.py L113
PRESET_SCHEMES compressed-tensors/src/.../quantization/quant_scheme.py L406-428
W4A16 定义 compressed-tensors/src/.../quantization/quant_scheme.py L286-295
QuantizationConfig compressed-tensors/src/.../quantization/quant_config.py L94-272

第四阶段:apply_quantization_config → 将 scheme 挂载到模型层

复制代码
 apply_quantization_config(model, config)                           # compressed-tensors/src/.../apply.py:97
   │
   ├─ 构建 target_to_scheme 映射                                    # :125-128
   │    {"Linear" → QuantizationScheme(W4A16)}
   │
   └─ for name, submodule in match_named_modules(                  # :131-147
   │       model,
   │       target_to_scheme={"Linear": scheme},
   │       ignore=["lm_head"]          # ← lm_head 被排除
   │   ):
   │     │  # 遍历模型中所有 Linear 层 (排除 lm_head)
   │     │  # 例如: model.layers.0.self_attn.q_proj
   │     │  #       model.layers.0.self_attn.k_proj
   │     │  #       model.layers.0.self_attn.v_proj
   │     │  #       model.layers.0.self_attn.o_proj
   │     │  #       model.layers.0.mlp.gate_proj
   │     │  #       model.layers.0.mlp.up_proj
   │     │  #       model.layers.0.mlp.down_proj
   │     │  #       ... (所有 decoder layer 的 Linear 子模块)
   │     │
   │     ├─ submodule.quantization_scheme = scheme               # 将 W4A16 scheme 挂到层的属性上
   │     │    # 之后可以通过 submodule.quantization_scheme 获取量化配置
   │     │
   │     ├─ submodule.quantization_status = QuantizationStatus.INITIALIZED
   │     │
   │     └─ initialize_module_for_quantization(submodule, config_)  # 初始化量化参数
   │          # compressed-tensors/src/.../lifecycle/initialize.py
   │          # - 创建 weight_scale, weight_zero_point 等参数 buffer
   │          # - 设置 observer (默认 "minmax")
   │          # - 注册 forward hook
   │          # - 所有参数初始化为空, 等 on_start 时填充

关键代码位置

步骤 文件 行号
apply_quantization_config() compressed-tensors/src/.../quantization/lifecycle/apply.py L97
match_named_modules() compressed-tensors/src/.../utils/ -
initialize_module_for_quantization() compressed-tensors/src/.../quantization/lifecycle/initialize.py -

第五阶段:on_start → 权重校准

注意: 在 session.initialize() 中传入了 start=-1, 这意味着 Modifier.initialize() 内部会立即触发 on_start。 因为 start=-1 < 0, 表示从初始化阶段就开始, 不需要等待 training step。

复制代码
 QuantizationModifier.on_start(state, event)                        # base.py:69
   │
   ├─ self.started_ = True                                          # 标记已开始
   │
   ├─ QuantizationMixin.start_calibration(state.model)              # base.py:75 → mixin.py:235
   │    │
   │    ├─ 对所有匹配的模块执行:                                    # :245-252
   │    │    ├─ _initialize_observers(module)                       # 初始化 weight observer
   │    │    │   # 根据 QuantizationArgs 创建 observer (默认 minmax)
   │    │    │   # observer 用于统计 weight 的 min/max 以计算 scale
   │    │    │
   │    │    └─ _initialize_hooks(module)                           # 初始化前向 hook
   │    │         # ⚠️ W4A16 只有 weight 量化, 无 input/output 量化
   │    │         # 所以 hooks 列表为空! 不需要在每次 forward 中记录激活值
   │    │
   │    └─ model.apply(enable_quantization)                         # :254 → 启用量化 forward
   │         # 将 quantization_status 从 INITIALIZED → CALIBRATION
   │
   ├─ named_modules = match_named_modules(model, resolved_targets, ignore)
   │
   ├─ for _, module in named_modules:                               # :84
   │    update_weight_global_scale(module)                          # :85 → calibration.py
   │    # 更新 weight 的全局 scale (用于 fused layer 等情况)
   │
   ├─ for module in model.modules():                                # :92
   │    update_fused_layer_weight_global_scales(module)             # :93 → utils.py
   │    # 对 Attention/MLP fused layers 更新 global scale
   │    # 这是 idempotent 操作, 可以运行多次
   │
   └─ for _, module in tqdm.tqdm(named_modules, "Calibrating weights"):  # :95
        update_weight_zp_scale(module)                              # :96 → calibration.py
        # 🔑 核心: 计算 weight scale 和 zero_point
        #
        # 1. 从 observer 读取 weight 的 min/max 统计值
        # 2. 根据 num_bits=4, symmetric=True 计算:
        #      qmin = 0, qmax = 2^4 - 1 = 15 (symmetric 只用到正半轴)
        #      或更常见的对称表示: qmin = -8, qmax = 7 (含符号位)
        #      scale = max(|min|, |max|) / (qmax - qmin) / 2
        # 3. zero_point = 0 (symmetric=True)
        # 4. 将计算好的 scale 和 zero_point 存入 module.weight_scale 和
        #    module.weight_zero_point buffer

量化后的 forward 流程

复制代码
 # 在 module.forward() 中, 权重经过 QDQ (Quantize-Dequantize):
 weight_q = torch.clamp(
     torch.round(weight / scale) + zero_point,  # 量化
     qmin, qmax
 )
 weight_dq = (weight_q - zero_point) * scale     # 反量化 (模拟量化精度损失)
 output = input @ weight_dq.T                     # 用反量化后的权重计算

关键代码位置

步骤 文件 行号
QuantizationModifier.on_start() src/llmcompressor/modifiers/quantization/quantization/base.py L69-96
start_calibration() src/llmcompressor/modifiers/quantization/quantization/mixin.py L235-255
update_weight_global_scale() src/llmcompressor/modifiers/quantization/calibration.py -
update_weight_zp_scale() src/llmcompressor/modifiers/quantization/calibration.py -
enable_quantization / disable_quantization compressed-tensors/src/.../quantization/lifecycle/initialize.py -

第六阶段:Pipeline 推断 → "datafree"

复制代码
 CalibrationPipeline.from_modifiers(modifiers, user="datafree")     # pipelines/registry.py:32
   │
   ├─ inferred = _infer_pipeline(modifiers)                         # :60
   │    └─ _modifier_requires_calibration(QuantizationModifier)      # :61
   │         │
   │         └─ config = modifier.resolve_quantization_config()
   │            config.requires_calibration_data()                  # quant_config.py:257
   │              │
   │              │  对于 W4A16:
   │              │    kv_cache_scheme = None       → 跳过 :258-259
   │              │    input_activations = None     → 跳过 :262-264
   │              │    output_activations = None    → 跳过 :265-267
   │              │
   │              └─ return False  ← 🔑 不需要校准数据!
   │
   ├─ inferred = "datafree"
   │
   ├─ user="datafree" == inferred="datafree" → 无警告                # :66-67
   │   如果 user 和 inferred 不一致, 会打 warning
   │
   └─ 返回 DataFreePipeline 实例
        DataFreePipeline 基本上是 no-op,
        因为权重校准已经在 on_start 中一次性完成, 不需要 forward 任何校准数据

requires_calibration_data() 的完整逻辑

复制代码
 # compressed-tensors-main/src/compressed_tensors/quantization/quant_config.py:257
 def requires_calibration_data(self):
     """
     判断量化配置是否需要外部校准数据 (即是否需要跑 forward pass 来收集激活值统计)
     """
     # 1. KV Cache 量化 → 需要校准数据
     if self.kv_cache_scheme is not None:
         return True
 ​
     # 2. 遍历所有 config_groups
     for _, scheme in self.config_groups.items():
         # 输入激活的静态量化或 LOCAL 动态量化 → 需要校准数据
         if scheme.input_activations is not None:
             if scheme.input_activations.dynamic in (False, DynamicType.LOCAL):
                 return True
 ​
         # 输出激活的静态量化 → 需要校准数据
         if scheme.output_activations is not None:
             if not scheme.output_activations.dynamic:
                 return True
 ​
     # 3. 没有任何激活量化 → 不需要校准数据 (datafree)
     return False

不同 scheme 对 pipeline 的影响

Scheme input_activations 需要校准数据? inferred pipeline 说明
W4A16 None ❌ No datafree 只量化权重, 无需校准数据
W8A16 None ❌ No datafree 只量化权重, 无需校准数据
W8A8 dynamic=True ❌ No datafree 动态激活, scale 实时计算
W4A8 dynamic=True ❌ No datafree 动态激活, scale 实时计算
FP8 dynamic=False ✅ Yes basic 静态激活, 需要先跑校准数据
FP8_DYNAMIC dynamic=True ❌ No datafree 动态激活, 无需校准

关键代码位置

步骤 文件 行号
CalibrationPipeline.from_modifiers() src/llmcompressor/pipelines/registry.py L32-70
_infer_pipeline() src/llmcompressor/pipelines/registry.py L60-64
_modifier_requires_calibration() src/llmcompressor/pipelines/registry.py L61
requires_calibration_data() compressed-tensors/src/.../quantization/quant_config.py L257-269

完整调用链路总结图

复制代码
 用户调用
   │
   │  oneshot(
   │      model=model,
   │      recipe=QuantizationModifier(
   │          targets="Linear",
   │          scheme="W4A16",
   │          ignore=["lm_head"],
   │      ),
   │      pipeline="datafree",
   │  )
   │
   ▼
 ┌──────────────────────────────────────────────────────────────────┐
 │ 1. Oneshot.__init__() + __call__()                               │
 │    ├─ parse_args() → model_args, dataset_args, recipe_args       │
 │    ├─ pre_process() → 加载模型和 tokenizer                        │
 │    └─ apply_recipe_modifiers()                                   │
 └───────────────────┬──────────────────────────────────────────────┘
                     │
                     ▼
 ┌──────────────────────────────────────────────────────────────────┐
 │ 2. Session.initialize(recipe=QuantizationModifier, start=-1)     │
 │    ├─ Recipe.create_instance(QuantizationModifier)               │
 │    │    └─ from_modifiers → Recipe(modifiers=[QuantizationModifier])
 │    │                                                             │
 │    └─ QuantizationModifier.on_initialize(state)                  │
 │         │                                                        │
 │         ├─ resolve_quantization_config()                         │
 │         │  ┌─────────────────────────────────────────────┐       │
 │         │  │ 3. scheme="W4A16" 解析 🔑                   │       │
 │         │  │                                             │       │
 │         │  │  "W4A16"                                    │       │
 │         │  │    │ is_preset_scheme() → True               │       │
 │         │  │    ▼                                        │       │
 │         │  │  PRESET_SCHEMES["W4A16"] = {                │       │
 │         │  │      weights: QuantizationArgs(             │       │
 │         │  │          num_bits=4,                        │       │
 │         │  │          type=INT,                          │       │
 │         │  │          strategy=GROUP,                    │       │
 │         │  │          group_size=128,                    │       │
 │         │  │          symmetric=True,                    │       │
 │         │  │          dynamic=False,                     │       │
 │         │  │      ),                                     │       │
 │         │  │  }                                           │       │
 │         │  │    ▼                                        │       │
 │         │  │  QuantizationConfig(                        │       │
 │         │  │      config_groups={                        │       │
 │         │  │          "group_0": QuantizationScheme(     │       │
 │         │  │              targets=["Linear"],            │       │
 │         │  │              weights=...,                   │       │
 │         │  │              input_activations=None,        │       │
 │         │  │              output_activations=None,       │       │
 │         │  │          )                                  │       │
 │         │  │      },                                     │       │
 │         │  │      ignore=["lm_head"],                    │       │
 │         │  │  )                                          │       │
 │         │  └─────────────────────────────────────────────┘       │
 │         │                                                        │
 │         └─ apply_quantization_config(model, config)              │
 │              ┌──────────────────────────────────────────┐        │
 │              │ 4. 挂载 scheme 到模型层                   │        │
 │              │                                          │        │
 │              │  match_named_modules(model,               │        │
 │              │      targets={"Linear": scheme},          │        │
 │              │      ignore=["lm_head"])                  │        │
 │              │    ↓                                     │        │
 │              │  对每个匹配的 Linear 层:                  │        │
 │              │    ├─ module.quantization_scheme = scheme │        │
 │              │    ├─ module.quantization_status =        │        │
 │              │    │       INITIALIZED                    │        │
 │              │    └─ initialize_module_for_quantization()│        │
 │              └──────────────────────────────────────────┘        │
 │                                                                  │
 │  (start=-1 < 0, 立即触发 on_start)                               │
 │    └─ QuantizationModifier.on_start(state)                      │
 │         ┌───────────────────────────────────────────┐            │
 │         │ 5. 权重校准 (一次性, 无数据依赖)            │            │
 │         │                                           │            │
 │         │  start_calibration(model):                │            │
 │         │    ├─ _initialize_observers(module)       │            │
 │         │    ├─ _initialize_hooks(module)  # 空!    │            │
 │         │    └─ enable_quantization(model)          │            │
 │         │                                           │            │
 │         │  for each Linear layer:                   │            │
 │         │    ├─ update_weight_global_scale(module)  │            │
 │         │    └─ update_weight_zp_scale(module)      │            │
 │         │        ① 从 observer 读 weight min/max    │            │
 │         │        ② 计算 scale = max(|min|,|max|)    │            │
 │         │                       / (2^(4-1)-1)       │            │
 │         │        ③ zero_point = 0 (symmetric)       │            │
 │         │        ④ 存入 weight_scale, weight_zp    │            │
 │         │                                           │            │
 │         │  on_end():                                 │            │
 │         │    ├─ _remove_hooks()                     │            │
 │         │    └─ model.apply(freeze_quantization)    │            │
 │         └───────────────────────────────────────────┘            │
 └──────────────────────────────────────────────────────────────────┘
                     │
                     ▼
 ┌──────────────────────────────────────────────────────────────────┐
 │ 6. CalibrationPipeline.from_modifiers(modifiers, user="datafree")│
 │    ├─ _infer_pipeline(modifiers)                                 │
 │    │    └─ config.requires_calibration_data()                    │
 │    │         ├─ kv_cache_scheme = None → skip                    │
 │    │         ├─ input_activations = None → skip                  │
 │    │         ├─ output_activations = None → skip                 │
 │    │         └─ return False → inferred = "datafree"             │
 │    │                                                             │
 │    └─ user="datafree" == inferred="datafree" → ✅ 无警告         │
 │                                                                  │
 │    DataFreePipeline(): 基本 no-op (权重校准已在 on_start 完成)   │
 │                                                                  │
 └──────────────────────────────────────────────────────────────────┘
                     │
                     ▼
     session.finalize() → on_finalize() → 保存模型
复制代码

关键结论

1. 为什么 W4A16 是 "datafree"?

  • W4A16input_activations=None, output_activations=None

  • 没有激活量化, 就不需要跑校准数据来统计激活值的 min/max

  • 权重的 scale 可以直接从权重本身的统计 (observer minmax) 一次性计算

  • QuantizationConfig.requires_calibration_data() 返回 False → pipeline 自动推断为 datafree

2. 不传 pipeline 或传 pipeline="datafree" 行为完全一致

  • pipeline 默认值是 "independent" (不是 "datafree")

  • _infer_pipeline() 的优先级更高:会检查 requires_calibration_data()

  • 对于 W4A16/W8A16 等单纯权重稀疏化的 scheme,一定被推断为 datafree

  • user 参数只是用来做一致性检查(如果用户指定了需要数据的 pipeline 但实际不需要,会打警告)

3. 量化只对 Linear 层生效 (targets="Linear")

  • match_named_modules(model, {"Linear": scheme}, ignore=["lm_head"]) 匹配所有 torch.nn.Linear

  • lm_head 在 ignore 列表中,不会被量化(因为 lm_head 量化通常会导致输出质量下降)

4. W4A16 的权重是静态量化 (dynamic=False)

  • 意味着 scale/zero_point 在 on_start 阶段一次性计算,推理时不再改变

  • 与动态量化 (dynamic=True) 不同,动态量化在每次 forward 都重新计算 scale

5. 对称量化 (symmetric=True) 意味着 zero_point=0

  • 量化公式简化为: q = clamp(round(w / scale), qmin, qmax)

  • 不需要存储/计算 zero_point,减少参数量和运算复杂度


相关文件索引

文件路径 说明
src/llmcompressor/entrypoints/oneshot.py oneshot 入口函数
src/llmcompressor/recipe/recipe.py Recipe 和 Recipe.create_instance
src/llmcompressor/modifiers/quantization/quantization/base.py QuantizationModifier
src/llmcompressor/modifiers/quantization/quantization/mixin.py QuantizationMixin (config 解析, calibration)
src/llmcompressor/modifiers/quantization/calibration.py update_weight_zp_scale 等校准函数
src/llmcompressor/pipelines/registry.py CalibrationPipeline.from_modifiers, pipeline 推断
compressed-tensors-main/src/compressed_tensors/quantization/quant_scheme.py QuantizationScheme, PRESET_SCHEMES
compressed-tensors-main/src/compressed_tensors/quantization/quant_config.py QuantizationConfig, requires_calibration_data
compressed-tensors-main/src/compressed_tensors/quantization/quant_args.py QuantizationArgs, QuantizationStrategy, DynamicType
compressed-tensors-main/src/compressed_tensors/quantization/lifecycle/apply.py apply_quantization_config
compressed-tensors-main/src/compressed_tensors/quantization/lifecycle/initialize.py initialize_module_for_quantization
相关推荐
Loo国昌7 小时前
从 Agent 编排到 Skill Runtime:企业 AI 工程化的下一层抽象
大数据·人工智能·后端·python·自然语言处理
小羊在睡觉8 小时前
力扣239. 滑动窗口最大值
数据结构·后端·算法·leetcode·go
编码者卢布8 小时前
【Azure Service Bus】Azure Service Bus Java SDK 中 Token 刷新异常的排查思路
java·python·azure
兰令水8 小时前
topcode【随机算法题】【2026.5.20打卡-java版本】
java·开发语言·算法
liuyunshengsir8 小时前
PyTorch 最小模型转 ONNX 完整样例
人工智能·pytorch·python
此生决int8 小时前
算法从入门到精通——前缀和
c++·算法·蓝桥杯
我星期八休息8 小时前
Linux系统编程—库制作与原理
linux·运维·服务器·数据结构·人工智能·python·散列表
Cloud_Shy6188 小时前
Python 数据分析基础入门:《Excel Python:飞速搞定数据分析与处理》学习笔记系列(第十二章 用户定义函数 上篇)
python·数据分析·excel·pandas
大大杰哥8 小时前
leetcode hot100(4)矩阵
算法·leetcode·矩阵