【X5】请问量化时如何避免_hz_cat_1_rescale_1这类操作的产生

错误分析

MovingAverageMinMaxObservercalibration 完成前 确实没有 scale 属性,这是正常的。scale 是在 calibration 过程中通过统计数据计算出来的。

出现这个错误说明 calibration 流程没有正确执行


完整的 QAT 流程(含 calibration 状态设置)

根据官方文档 QAT 快速上手(fx mode),正确的流程是:

import torch
import torch.nn as nn
import copy
from horizon_plugin_pytorch.quantization import (
    prepare_qat_fx,
    convert_fx,
    set_fake_quantize,
    FakeQuantState,
    FakeQuantize,
)
from horizon_plugin_pytorch.quantization.observer import MovingAverageMinMaxObserver
from horizon_plugin_pytorch.quantization.qconfig import default_qat_8bit_fake_quant_qconfig

class SharedCatModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(32, 32, 3, padding=1)
        self.conv2 = nn.Conv2d(32, 32, 3, padding=1)
        self.conv3 = nn.Conv2d(32, 32, 3, padding=1)
        self.relu1 = nn.ReLU()
        self.relu2 = nn.ReLU()
        self.relu3 = nn.ReLU()
        
        # 创建共享的 FakeQuantize 模块
        self.shared_fake_quant = FakeQuantize(
            observer=MovingAverageMinMaxObserver
        )
        
    def forward(self, x):
        x1 = self.relu1(self.conv1(x))
        x2 = self.relu2(self.conv2(x))
        x3 = self.relu3(self.conv3(x))
        
        # 所有输入通过同一个 FakeQuantize 模块
        x1_q = self.shared_fake_quant(x1)
        x2_q = self.shared_fake_quant(x2)
        x3_q = self.shared_fake_quant(x3)
        
        return torch.cat([x1_q, x2_q, x3_q], dim=1)

# ========== 完整流程 ==========

# 1. 创建模型
model = SharedCatModule()

# 2. prepare_qat_fx
model = prepare_qat_fx(copy.deepcopy(model))

# 3. 【关键】设置 calibration 状态
model.eval()
set_fake_quantize(model, FakeQuantState.CALIBRATION)

# 4. 执行 calibration(需要多批数据)
calib_loader = [...]  # 你的校准数据集
with torch.no_grad():
    for data in calib_loader:
        model(data)

# 5. 【关键】切换到 validation 状态后才能访问 scale
model.eval()
set_fake_quantize(model, FakeQuantState.VALIDATION)

# 6. 现在可以检查 scale 了
def check_quant_params(model):
    for name, module in model.named_modules():
        if isinstance(module, FakeQuantize):
            if hasattr(module, 'scale') and module.scale is not None:
                print(f"{name}: scale={module.scale}")

check_quant_params(model)

# 7. 转换
model = convert_fx(model)

# 8. 性能验证
from horizon_plugin_pytorch import quantization as hq
hq.perf_model(
    model,
    [torch.rand(1, 32, 64, 64)],
    opt=2,
    layer_details=True,
    out_dir="./perf_check"
)

关键点总结

步骤 说明
:white_check_mark: set_fake_quantize(model, FakeQuantState.CALIBRATION) calibration 前必须设置,否则 observer 不更新统计量
:white_check_mark: model.eval() calibration 和 validation 都需要 eval 模式
:white_check_mark: set_fake_quantize(model, FakeQuantState.VALIDATION) calibration 后才能访问 scale
:white_check_mark: 多批 calibration 数据 单批数据可能导致统计量不准确

如果仍有问题

请运行以下诊断代码,告诉我输出:

import horizon_plugin_pytorch
print(f"Plugin version: {horizon_plugin_pytorch.__version__}")

from horizon_plugin_pytorch.quantization import FakeQuantize
import inspect
print(f"FakeQuantize signature: {inspect.signature(FakeQuantize.__init__)}")

from horizon_plugin_pytorch.quantization.qconfig import default_qat_8bit_fake_quant_qconfig
qconfig = default_qat_8bit_fake_quant_qconfig()
print(f"QConfig type: {type(qconfig)}")

备选方案:如果共享 FakeQuantize 仍不可行

如果上述方案因版本问题无法使用,建议:

  1. 联系 FAE 支持(如 Marcelo6151 所说,QAT 深度优化需要官方支持)
  2. 尝试 PTQ 方案,在 YAML 配置中控制量化参数
  3. 接受 rescale 开销,通过其他优化(如减少 cat 次数、调整模型结构)来弥补性能损失

参考资源:

请先确认你的工具链版本,我们再针对性调整代码 :+1: