Build QConfig
Definition and Principle
Definition of QConfig
The qconfig refers to quantization configuration, which is a key set of parameters in the quantization process of deep learning models. The quantization mode of the model is determined by qconfig, which needs to be set for the model before preparing the qat / calibration model.
Due to historical reasons, there are different definitions and usages of qconfig in the Plugin. Earlier versions of qconfig will be deprecated in the near future, and we only recommend that you use the qconfig usage described in this document.
A qconfig object can set three keywords: input, weight, and output, representing the quantization configuration of the operator's input, weight, and output respectively. When preparing model, these configurations determine whether to insert FakeQuantize or FakeCast nodes at the corresponding positions. None means no nodes will be inserted.
Definition of FakeQuantize
FakeQuantize is a fake quantization node that performs quantization and dequantization operations on the input. Inserting fake quantization can simulate the errors caused by quantization in the forward pass of a floating-point model. The horizon_plugin_pytorch supports three types of fake quantization: FakeQuantize, PACTFakeQuantize, and _LearnableFakeQuantize. We recommend using the statistic-based FakeQuantize. The document won't introduce PACTFakeQuantize and _LearnableFakeQuantize. If required, please read the papers before using them.
You can call the with_args method of FakeQuantize to get a constructor and use it to construct qconfig as shown in the previous section. The parameters of with_args include parameters supported by FakeQuantize and observer, theoretically allowing configuration of all parameters declared in the __init__ method of the FakeQuantize and observer classes. However, to avoid unnecessary details, we recommend you to configure the observer-related parameters only.
Different observers have different parameters. Below are examples of constructing FakeQuantize with common used observers. For the specific usage of other observers, see the calibration section.
Definition of FakeCast
FakeCast is a fake conversion node that converts the input to float32 data type. If the data type is float16, it also simulates the truncation error caused by converting value to float16. This node is mainly used to mark operators that require floating-point computation.
The method of using FakeCast to construct qconfig is similar to FakeQuantize, but it only has one parameter.
Construct QConfig
There are two methods for you to choose from when constructing Qconfig:
-
(Recommended) Use the
get_qconfiginterface to construct a QConfig. Compared with directly instantiating a QConfig object, this interface is simpler and easier to use, and can meet the requirements of most scenarios. -
Construct the QConfig object directly as introduced above. This method is flexible, allowing the configuration of any configurable parameter, but requires deep understanding of QConfig.
Set qconfig via QconfigSetter
QconfigSetter automatically sets qconfig according to the specified rules based on the model's computation graph, and it is our most recommended method for setting qconfig. The use of QconfigSetter depends on the graph mode of the prepare process, with the usage as follows:
Template Description
The templates you can configure are as follows:
-
ModuleNameTemplate(required, needs to cover all quantized operators): Specify dtype configuration or quantization threshold through module name. -
ConvDtypeTemplate(required): Specify the input and weight dtype of Conv-type operators. -
MatmulDtypeTemplate(required): Specify the input dtype of Matmul operators. -
SensitivityTemplate(optional): Configure the top-n operators to high precision according to sensitivity. -
LoadFromFileTemplate: Load the qconfig.pt file, which is used to reproduce previous quantization configurations. At this time, enable_optimize must be False; otherwise, the correctness of the configuration results cannot be guaranteed, and there may be CPU operators during deployment.
These templates take effect in the order of configuration, and the configuration of the previous template can be overwritten by the subsequent one.
Detailed Explanation of ModuleNameTemplate
-
The module name can be an operator name or a prefix. When different module names in a ModuleNameTemplate have an overriding relationship, the longer name has higher priority. For example:
-
The threshold of the operator can be specified (provided that there is a corresponding pseudo-quantization node in the operator). At this time, the calculation method of the quantization scale is
scale = threshold / -qdtype.min. For example: -
By default, dtype and threshold are configured on the output of the operator. You can configure the input or weight by specifying the key. When the operator has multiple inputs, None can be used as a placeholder. For example:
Scenario Examples
-
All int8:
-
Feature int16, weight int8:
-
Gemm operators with double int8, other operators with fp16:
-
Gemm operators with double int8, other operators with int16, and high-sensitivity gemm configured as int16:
Description of Default Optimization Passes
In addition to the templates you can configure, QconfigSetter also integrates a series of optimization and legalization templates, which are explained in this section.
-
CanonicalizeTemplate: Legalize dtype configuration according to operator types. The current default rules are:-
Gemm-type operators do not support float inputs(include weight).
-
Interpolation-type operators: By default, int8 is used (although the interpolation operators on the current nash-e/m/p/h platform support fp16 and int16, their performance is poor, so the template still uses int8 by default. If the interpolation operator needs to use other dtypes, please use
ModulaNameTemplate (..., freeze=True)to configure the output of its previous operator to the required dtype). -
Special operators such as DPP and RPP only support int8.
-
General rules for other operators: The input dtype and output dtype of an operator cannot have both qint and float.
-
-
EqualizeInOutScaleTemplate: For relu, relu6, concat, and stack operators, the scale should be counted after the operator; otherwise, there may be a loss in precision or performance. To this end:-
Configure the output dtype of the previous operator as float32.
-
When exporting hbir for relu, concat, and stack operators, insert pseudo-quantization at the input, and reuse the output scale for the scale.
-
-
FuseConvAddTemplate: The hardware supports the fusion of conv + add. To this end:-
Configure the output dtype of conv as float32.
-
Configure the corresponding input dtype of add as float32.
-
-
GridHighPrecisionTemplate: According to experience, the grid calculation process of grid sample with qint8 is not precise enough, so the relevant operators are automatically configured to high precision. -
InternalQuantsTemplate: In the scenario of segmented model deployment, QuantStub will be inserted at the segmentation points to record the dtype and scale here. The dtype configuration of such QuantStub must be consistent with the input. -
OutputHighPrecisionTemplate: When a Gemm-type operator is used as the model output, configure it to output with high precision. -
PropagateTemplate: For operators split into subgraphs for implementation, there are empirical configurations. For example, the small internal operators of LayerNorm and Softmax should use high precision. -
SimpleIntPassTemplate: For performance optimization, for computation graphs such as op0->op1->op2, if the following conditions are met at the same time, modify the output type of op1 to int:-
op2 requires int input.
-
op0 can output int.
-
op1 currently outputs float16 and belongs to the following types:
-
cat, stack.
-
mul_scalar.
-
Lookup table operators without precision risks (that is, operators that use lookup table implementation by default on fp16).
-
-
-
SimplifyTemplate: Delete redundant quantization node configurations (modify the corresponding dtype to None).
