# 离线量化 离线量化又称为训练后量化,仅需要使用少量校准数据,确定最佳的量化参数降低量化误差。这种方法需要的数据量较少,但量化模型精度相比在线量化稍逊。 ## 使用方法 离线量化的基本流程可以分为以下三步: 1. 选择量化配置 2. 采样收集量化信息 3. 转换量化模型 ## 接口介绍 ### 1. 量化配置相关概念以及接口: `Observer`:用于统计OP输入或输出,并计算出量化相关的统计量,比如scale、zero_point等。每个离线量化算法对应一个Observer,现已有的Observer包含: - `AVGObserver`:收集目标Tensor的平均值作为量化scale - `MSEObserver`:收集最大绝对值并通过最小化MSE误差,收集量化scale - `EMDObserver`:收集最大绝对值并通过最小化EMD误差,收集量化scale - `HistObserver`:将张量值收集到直方图中,并根据百分比计算量化scale - `KLObserver`:以最小化浮点值分布与量化浮点值分布之间的 Kullback-Leibler散度计算量化scale - `AbsMaxChannelWiseWeightObserver`:根据目标权重的通道维度,收集最大绝对值作为量化scale - `MSEChannelWiseWeightObserver`:根据目标权重的通道维度,收集最大绝对值并通过最小化MSE误差,收集量化scale `Quanter`:对OP的输入或输出执行量化或模拟操作操作,同时还可以对输入Tensor的数值进行统计分析。每个量化训练算法对应一个Quanter,现已有的Quanter包含: - `PACTQuanter` - `WeightLSQplusQuanter`: - `ActLSQplusQuanter` `QuantConfig`:在执行量化操作之前,首先要配置量化相关的信息,主要是指定每层的各个输入使用什么Observer或Quanter。可通过以下调用方法,根据需求添加每层的量化配置信息: | **QuantConfig接口** | **传入参数及其含义** | **注意事项** | |-----------------------------|-----------------------------------------|-----------------------------------------| | add_layer_config | `layer`: 指定模型的某一层或某些层的list

`activation`: 用于量化激活以上指定layer的`Observer`或`Quanter`

`weight`: 用于量化权重以上指定layer的`Observer`或`Quanter` | 此方法是最高优的要求,这些层的量化方式将按照这里的要求,而不是按照其他配置进行量化 | add_name_config | `layer_name`: 指定模型的某一层的名字或某些层的名字的list

`activation`: 用于量化激活以上指定layer的`Observer`或`Quanter`

`weight`: 用于量化权重以上指定layer的`Observer`或`Quanter` | 此方法的优先级仅此于add_layer_config | add_type_config | `layer_type`:指定需要量化的layer类型,可以为单个layer类型,或一个layer类型的list,layer类型必须为paddle.nn.Layer的子类

`activation`: 用于量化激活以上指定layer的`Observer`或`Quanter`

`weight`: 用于量化权重以上指定layer的`Observer`或`Quanter` | 此方法的优先级此于add_name_config,指定需要量化的layer类型,如nn.Linear, 量化时将对所有nn.Linear进行量化,并指定weight和activation的quanter类型 | add_qat_layer_mapping | `source`:被量化的layer

`target`:量化的layer | source和target必须为paddle.nn.Layer的子类;当指定需要量化的layer类型,如果在框架中没有实现该层量化时,需要指定该layer的量化层,比如ColumnParallelLinear对应PaddleSlim中实现的QuantizedColumnParallelLinear ### 2. PTQ接口介绍: | **PTQ接口** | **传入参数及其含义** | **介绍** | |-----------------------------|-----------------------------------------|-----------------------------------------| | quantize | `model`:需要被量化的模型
`inplace`:inplace=True时,该模型会被inplace的量化;inplace=False时,不改变原模型,并且会return一个量化的模型 | 对模型需要量化的层插入observers以采样到需要的量化信息 | convert | `model`:需要被转化的量化模型
`inplace`:inplace=True时,该模型会被inplace的量化;inplace=False时,不改变原模型,并且会return一个量化的模型 | 将模型转化成onnx形式,进行此步骤之后才能对量化模型进行验证、导出成静态图等 ## 使用示例 ```python import paddle import paddleslim from paddle.vision.models import mobilenet_v1 from paddle.quantization import QuantConfig from paddle.quantization import PTQ from paddleslim.quant.observers import HistObserver, KLObserver, EMDObserver, MSEObserver, AVGObserver, MSEChannelWiseWeightObserver, AbsMaxChannelWiseWeightObserver # create the model model = mobilenet_v1() # define QuantConfig q_config = QuantConfig(activation=None, weight=None) # define act_quanter and weight_quanter act_quanter = MSEObserver() weight_quanter = MSEObserver() # map ColumnParallelLinear to QuantizedColumnParallelLinear q_config.add_qat_layer_mapping(ColumnParallelLinear, QuantizedColumnParallelLinear) # map RowParallelLinear to QuantizedRowParallelLinear q_config.add_qat_layer_mapping(RowParallelLinear, QuantizedRowParallelLinear) # for each layer if type in [paddle.nn.Linear, ColumnParallelLinear, RowParallelLinear] # make them quantizable q_config.add_type_config( [paddle.nn.Linear, ColumnParallelLinear, RowParallelLinear], activation=activation, weight=weight, ) ptq = PTQ(q_config) model = ptq.quantize(model, inplace=True) # ptq sample ptq_step = 100 for step, data in enumerate(dataloader): pred = model(data) if step == ptq_step: break # convert to quant model that can evaluate and export model = ptq.convert(model, inplace=True) ```