错误分析
MovingAverageMinMaxObserver 在 calibration 完成前 确实没有 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"
)
关键点总结
| 步骤 | 说明 |
|---|---|
set_fake_quantize(model, FakeQuantState.CALIBRATION) |
calibration 前必须设置,否则 observer 不更新统计量 |
model.eval() |
calibration 和 validation 都需要 eval 模式 |
set_fake_quantize(model, FakeQuantState.VALIDATION) |
calibration 后才能访问 scale |
| 单批数据可能导致统计量不准确 |
如果仍有问题
请运行以下诊断代码,告诉我输出:
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 仍不可行
如果上述方案因版本问题无法使用,建议:
- 联系 FAE 支持(如 Marcelo6151 所说,QAT 深度优化需要官方支持)
- 尝试 PTQ 方案,在 YAML 配置中控制量化参数
- 接受 rescale 开销,通过其他优化(如减少 cat 次数、调整模型结构)来弥补性能损失
参考资源:
请先确认你的工具链版本,我们再针对性调整代码 ![]()