旧版 Qconfig

注解

自工具链 OE3.5.0 版本开始,我们支持了新版 qconfig 模板,新版 qconfig 将模板配置和回退逻辑统一到了同一套流程中,在适配平台能力、提升量化配置效率和支持典型高精度场景方面,都比旧版方式更适合当前使用,建议您尽快完成迁移升级。

本章节中,我们为您保留介绍使用旧版 Qconfig 的一些使用原理性介绍,便于您进行理解。

QConfig 的定义

qconfig(Quantization Configuration)指的是量化配置,是深度学习模型量化过程中的关键参数集合,模型的量化方式由 qconfig 决定,在准备 qat / calibration 模型之前,需要先给模型设置 qconfig。

注意

因历史原因,Plugin 中有不同 qconfig 的定义和用法,早期版本的 qconfig 将在不久的将来被废弃,我们只推荐您使用此文档中介绍的 qconfig 用法。

一个 qconfig 对象可以设置 input / weight / output 三个关键字,分别表示算子输入/权重/输出的量化配置,prepare 模型时会根据这些配置决定是否要在对应位置插入 FakeQuantize / FakeCast 节点,None 表示不插入任何节点。

import torch
from horizon_plugin_pytorch.quantization.qconfig import QConfig
from horizon_plugin_pytorch.quantization.fake_quantize import FakeQuantize
from horizon_plugin_pytorch.quantization.fake_cast import FakeCast
from horizon_plugin_pytorch.quantization.observer_v2 import MinMaxObserver
from horizon_plugin_pytorch.dtype import qint8

qconfig = QConfig(
    input=None,
    weight=FakeQuantize.with_args(
        observer=MinMaxObserver,
        dtype=qint8,
        qscheme=torch.per_channel_symmetric,
        ch_axis=0,
    ),
    output=FakeCast.with_args(dtype=torch.float16),
    # activation=xxx 早期用法,作用与 output 关键字一致,当前仍兼容,但建议您使用 output 关键字。
)

FakeQuantize 的定义

FakeQuantize 是伪量化节点,会对输入进行量化反量化操作,插入伪量化可以在浮点模型的前向中模拟量化产生的误差。horizon_plugin_pytorch 支持 FakeQuantize / PACTFakeQuantize / _LearnableFakeQuantize 三种伪量化,我们只推荐您使用基于统计的 FakeQuantize,可以满足绝大部分需求。标准流程不对 PACTFakeQuantize 和_LearnableFakeQuantize 两种方法做详细说明,如果一定有需求,请在阅读相关论文后再使用。

# 基于统计的方法
from horizon_plugin_pytorch.quantization.fake_quantize import FakeQuantize
# https://arxiv.org/pdf/1805.06085
from horizon_plugin_pytorch.quantization.pact_fake_quantize import PACTFakeQuantize
# https://arxiv.org/pdf/1902.08153
from horizon_plugin_pytorch.quantization._learnable_fake_quantize import _LearnableFakeQuantize

可以调用 FakeQuantize 的 with_args 方法得到构造器,并按上一节的代码示例用它构造 qconfig。with_args 的参数包括 FakeQuantize 和 observer 支持配置的参数,理论上可以配置所有 FakeQuantize 和 observer 类 __init__ 方法声明中的参数,但为了屏蔽无关紧要的细节,我们只推荐您配置 observer 相关参数。

不同 observer 的参数不同,下面列出常用 observer 构造 FakeQuantize 的例子,其他 observer 的具体用法见校准章节。

import torch
from horizon_plugin_pytorch.quantization.qconfig import QConfig
from horizon_plugin_pytorch.quantization.fake_quantize import FakeQuantize
from horizon_plugin_pytorch.quantization.observer_v2 import MinMaxObserver, FixedScaleObserver, HistogramObserver
from horizon_plugin_pytorch.dtype import qint8

# MinMaxObserver 的 __init__ 方法包含很多参数,with_args 方法可以控制这些参数。
# 我们只推荐您设置 fq_constructor_1 示例中的几个参数。
# def __init__(
#     self,
#     averaging_constant: float = 0.01,
#     ch_axis: int = -1,
#     dtype: Union[torch.dtype, QuantDType] = qint8,
#     qscheme: torch.qscheme = torch.per_tensor_symmetric,
#     quant_min: int = None,
#     quant_max: int = None,
#     is_sync_quantize: bool = False,
#     factory_kwargs: Dict = None,
# ) -> None:

fq_constructor_1 = FakeQuantize.with_args(
    observer=MinMaxObserver,   # 适用于 qat 阶段的 input / output / weight 和 calibration 阶段的 weight。
    averaging_constant=0.01,   # calibration 后进行 qat 时,可将 input / output 的 averaging_constant 置为 0 以固定 scale。
    dtype=qint8,  # 量化类型,考虑算子的支持情况进行设置。
    qscheme=torch.per_channel_symmetric,  # 只有 weight 支持 per channel 量化。
    ch_axis=0,  # per channel 量化时指定 channel。
)

# 同理,您也可以查看 FixedScaleObserver 和 HistogramObserver 的 __init__ 方法了解有哪些可以设置的参数。
fq_constructor_2 = FakeQuantize.with_args(
    observer=FixedScaleObserver,  # 固定 scale,无论何种情况都不会变。
    dtype=qint8,  # 量化类型,考虑算子的支持情况进行设置。
    scale=INPUT_ABS_MAX / 128,  # 设定的 scale 值,一般设为绝对值最大值除以量化类型最大值。
)

fq_constructor_3 = FakeQuantize.with_args(
    observer=HistogramObserver,   # 适用于 calibration 阶段的 input / output。
    dtype=qint8,  # 量化类型,考虑算子的支持情况进行设置。
)

qconfig = QConfig(
    weight=fq_constructor_x,
    ...
)

FakeCast 的定义

FakeCast 是伪转换节点,会将输入转换为 float32 类型,如果数据类型是 float16,那么还会在中间模拟转 float16 产生的截断误差,此节点主要用于标志需要浮点计算的算子。

使用 FakeCast 构造 qconfig 的方法与 FakeQuantize 类似,但只有 dtype 一个参数。

import torch
from horizon_plugin_pytorch.quantization.qconfig import QConfig
from horizon_plugin_pytorch.quantization.fake_cast import FakeCast

qconfig = QConfig(
    input=FakeCast.with_args(dtype=torch.float16), # 考虑算子的支持情况进行设置。
    ...
)