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

这个错误说明 MovingAverageMinMaxObserver 内部使用的 aminmax 操作在量化图上不支持。这是版本兼容性问题。

快速解决方案

方案1:使用更简单的 Observer(推荐)

from horizon_plugin_pytorch.quantization import FakeQuantize
from horizon_plugin_pytorch.quantization.observer import MinMaxObserver  # 不用 MovingAverage

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()
        
        # 使用 MinMaxObserver 而不是 MovingAverageMinMaxObserver
        self.shared_fake_quant = FakeQuantize(
            observer=MinMaxObserver
        )
        
    def forward(self, x):
        x1 = self.relu1(self.conv1(x))
        x2 = self.relu2(self.conv2(x))
        x3 = self.relu3(self.conv3(x))
        
        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)

方案2:不手动创建 FakeQuantize,改用标准 QAT 流程(更稳定)

根据官方文档,不要手动插入 FakeQuantize,而是通过 prepare_qat_fxqconfig_dict 控制:

import torch
import torch.nn as nn
import copy
from horizon_plugin_pytorch.quantization import prepare_qat_fx, convert_fx, set_fake_quantize, FakeQuantState
from horizon_plugin_pytorch.quantization.qconfig import default_qat_8bit_fake_quant_qconfig

class CatModule(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.relu = nn.ReLU()
        
    def forward(self, x):
        x1 = self.relu(self.conv1(x))
        x2 = self.relu(self.conv2(x))
        x3 = self.relu(self.conv3(x))
        return torch.cat([x1, x2, x3], dim=1)

model = CatModule()

# 关键:为所有分支设置同一个 qconfig 对象(注意是调用函数返回对象)
shared_qconfig = default_qat_8bit_fake_quant_qconfig()
model.conv1.qconfig = shared_qconfig
model.conv2.qconfig = shared_qconfig
model.conv3.qconfig = shared_qconfig
model.relu.qconfig = shared_qconfig

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

# calibration 状态
model.eval()
set_fake_quantize(model, FakeQuantState.CALIBRATION)

# 执行 calibration
with torch.no_grad():
    for data in calib_loader:  # 多批数据
        model(data)

# validation 状态
model.eval()
set_fake_quantize(model, FakeQuantState.VALIDATION)

# 转换
model = convert_fx(model)

方案3:如果上述都不可行,接受 rescale 开销,优化模型结构

根据 X5 高效模型设计指导,减少 cat 操作:

# 不推荐:多次 cat
x = torch.cat([a, b], dim=1)
x = torch.cat([x, c], dim=1)

# 推荐:一次性 cat
x = torch.cat([a, b, c], dim=1)

# 或者用 add 替代(如果业务允许)
x = a + b + c  # elementwise add 不需要 rescale

诊断信息

请运行以下代码,告诉我输出,方便进一步定位问题:

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__)}")

# 检查可用的 observer
from horizon_plugin_pytorch.quantization import observer
print(f"Available observers: {[x for x in dir(observer) if 'Observer' in x]}")

建议

根据 Marcelo6151 的回复,QAT 深度优化建议联系 FAE 支持。如果上述方案都无法解决,建议:

  1. 提供工具链版本和完整代码给 FAE
  2. 考虑使用 PTQ 方案(YAML 配置更简单)
  3. 参考社区已有案例:QAT 快速上手(fx mode)

先试试方案1(换 MinMaxObserver),有结果随时同步 :+1: