模型量化(2):Paddle 模型的静态量化和动态量化
转自AI Studio,原文链接:模型量化(2):Paddle 模型的静态量化和动态量化 - 飞桨AI Studio1. 引入前文简单介绍了一下模型量化的基本原理和简单实例本次就继续前文内容,结合深度学习模型压缩的工具库 PaddleSlim介绍一下如何使用 PaddleSlim 对 Paddle 模型进行动态量化和静态量化2. 参考资料Github:PaddlePaddle/PaddleSlim
转自AI Studio,原文链接:模型量化(2):Paddle 模型的静态量化和动态量化 - 飞桨AI Studio
1. 引入
-
前文简单介绍了一下模型量化的基本原理和简单实例
-
本次就继续前文内容,结合深度学习模型压缩的工具库 PaddleSlim
-
介绍一下如何使用 PaddleSlim 对 Paddle 模型进行动态量化和静态量化
2. 参考资料
-
Github:PaddlePaddle/PaddleSlim
3. PaddleSlim
3.1 介绍
-
PaddleSlim 是 Paddle 官方开发的一个专注于深度学习模型压缩的工具库
-
提供剪裁、量化、蒸馏、和模型结构搜索等模型压缩策略,帮助用户快速实现模型的小型化
3.2 功能
-
PaddleSlim 支持以下功能,也支持自定义量化、裁剪等功能
Quantization Pruning NAS Distilling QAT SensitivityPruner *Simulate Anneal based NAS *FSP PACT FPGMFilterPruner *Reinforcement Learning based NAS *DML PTQ-Static L1NormFilterPruner **DARTS *DK for YOLOv3 PTQ-Dynamic L2NormFilterPruner **PC-DARTS Embedding Quant *SlimFilterPruner **Once-for-All *OptSlimFilterPruner *Hardware-aware Search - * 表示仅支持静态图
- ** 表示仅支持动态图
3.3 效果
-
PaddleSlim 在典型视觉和自然语言处理任务上做了模型压缩
-
并且测试了 Nvidia GPU、ARM 等设备上的加速情况,这里展示部分模型的压缩效果
-
详细信息可以参考官方文档中 CV 和 NLP 模型压缩方案
-
YOLOv3: 在移动端 SD855 上加速 3.55 倍
-
PP-OCR: 体积由 8.9M 减少到 2.9M, 在 SD855 上加速 1.27 倍
-
BERT: 模型参数由 110M 减少到 80M,精度提升的情况下,Tesla T4 GPU FP16 计算加速 1.47 倍
-
3.3 安装
- 使用 pip 命令可以快速安装 PaddleSlim
In [ ]
!pip install paddleslim
4. 模型量化
4.1 量化方法
-
PaddleSlim主要包含三种量化方法:
-
量化训练 (Quant Aware Training, QAT):量化训练让模型感知量化运算对模型精度带来的影响,通过 finetune 训练降低量化误差。
-
动态离线量化 (Post Training Quantization Dynamic, PTQ Dynamic):动态离线量化仅将模型中特定算子的权重从FP32类型映射成 INT8/16 类型。
-
静态离线量化 (Post Training Quantization Static, PTQ Static):静态离线量化使用少量无标签校准数据,采用 KL 散度等方法计算量化比例因子。
-
4.2 方法选择
-
下图展示了如何根据需要选择模型量化方法
4.3 方法对比
-
下表综合对比了模型量化方法的使用条件、易用性、精度损失和预期收益
-
下表综合对比了模型量化方法的API接口、功能和经典适用场景
量化方法 API接口 功能 经典适用场景 在线量化 (QAT) 动态图:paddleslim.QAT 静态图:paddleslim.quant.quant_aware 通过 Finetune 训练将模型量化误差降到最小 对量化敏感的场景、模型,例如目标检测、分割、OCR 等 静态离线量化 (PTQ Static) paddleslim.quant.quant_post_static 通过少量校准数据得到量化模型 对量化不敏感的场景,例如图像分类任务 动态离线量化 (PTQ Dynamic) paddleslim.quant.quant_post_dynamic 仅量化模型的可学习权重 模型体积大、访存开销大的模型,例如 BERT 模型 Embedding量化(Quant Embedding) paddleslim.quant.quant_embedding 仅量化模型的 Embedding 参数 任何包含 Embedding 层的模型
4.4 更多详情
- 更多详细的信息可以参考 PaddleSlim 的模型量化文档
5. 量化实践
5.1 案例介绍
-
模型选择:PaddleClas 提供的基于 ImageNet 预训练的 MobileNet v1 图像分类模型
-
量化方法:本次介绍两种训练后量化方法,即动态量化和静态量化
5.2 下载模型
- 使用 PaddleClas 提供的模型下载地址下载 MobileNet v1 预训练模型并解压
In [ ]
# 下载模型文件
!wget -P models https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/inference/MobileNetV1_infer.tar
# 解压缩模型文件
!cd models && tar -xf MobileNetV1_infer.tar
5.3 动态量化
-
介绍:
-
动态离线量化,将模型中特定 OP 的权重从 FP32 类型量化成 INT8/16 类型
-
量化前需要有训练好的预测模型,可以根据需要将模型转化为 INT8 或 INT16 类型
-
目前只支持反量化预测方式,主要可以减小模型大小,对特定加载权重费时的模型可以起到一定加速效果
-
权重量化成 INT16 类型,模型精度不受影响,模型大小为原始的 1/2。
-
权重量化成 INT8 类型,模型精度会受到影响,模型大小为原始的 1/4。
-
-
使用:
-
准备预测模型:先保存好FP32的预测模型,用于量化压缩
-
产出量化模型:使用 PaddleSlim 调用动态离线量化离线量化接口,产出量化模型
-
-
实践:
-
动态量化是模型量化中相对简单的一种,无需额外数据,一般只需要调用量化工具相对应的 API 接口即可
-
在 PaddleSlim 中,只需要调用 paddleslim.quant.quant_post_dynamic 这个接口即可实现模型的动态量化
-
有一点需要注意的是,使用上述接口是需要处于 Paddle 的静态图模式之下,否则无法正常运行
-
具体的动态量化实例代码如下:
-
In [ ]
import paddle
import paddleslim
# 开启静态图模式
paddle.enable_static()
# 模型的路径和文件名称
model_dir = "models/MobileNetV1_infer"
model_filename = 'inference.pdmodel'
params_filename = 'inference.pdiparams'
model_dir_quant_dynamic = "models/MobileNetV1_infer_quant_dynamic"
# 动态量化
paddleslim.quant.quant_post_dynamic(
model_dir=model_dir, # 输入模型路径
model_filename=model_filename, # 输入模型计算图文件名称
params_filename=params_filename, # 输入模型参数文件名称
save_model_dir=model_dir_quant_dynamic, # 输出模型路径
save_model_filename=model_filename, # 输出模型计算图名称
save_params_filename=params_filename, # 输出模型参数文件名称
weight_bits=8, # 量化比特数 8/16 对应 INT8/16 类型
)
5.4 静态量化
-
介绍:
-
静态离线量化是基于采样数据,采用 KL 散度等方法计算量化比例因子的方法
-
相比量化训练,静态离线量化不需要重新训练,可以快速得到量化模型
-
静态离线量化的目标是求取量化比例因子,主要有两种方法:
-
非饱和量化方法(No Saturation):非饱和量化方法计算 FP32 类型 Tensor 中绝对值的最大值 abs_max,将其映射为 127,则量化比例因子等于 abs_max/127
-
饱和量化方法(Saturation):饱和量化方法使用 KL 散度计算一个合适的阈值 T(0 < T < mab_max),将其映射为 127,则量化比例因子等于 T/127
-
-
一般而言,对于待量化 OP 的权重 Tensor,采用非饱和量化方法,对于待量化 OP 的激活 Tensor(包括输入和输出),采用饱和量化方法
-
-
使用:
-
加载预训练的 FP32 模型,配置 Reader
-
读取样本数据,执行模型的前向推理,保存待量化 OP 激活 Tensor 的数值
-
基于激活 Tensor 的采样数据,使用饱和量化方法计算它的量化比例因子
-
模型权重 Tensor 数据一直保持不变,使用非饱和方法计算它每个通道的绝对值最大值,作为每个通道的量化比例因子
-
将 FP32 模型转成 INT8 模型,进行保存
-
-
实践:
-
相比动态量化,静态量化会复杂一些,需要一些额外的无标签校准数据
-
这里采用 ImageNet 的验证集中的少量图像作为校准数据
-
静态量化时,需要首先构造一个校准数据读取器(Reader)
-
然后调用 PaddleSlim 的 paddleslim.quant.quant_post_static 接口进行静态量化
-
当然静态量化也需要处于 Paddle 的静态图模式之下才可以正常运行
-
还有一点需要注意的是,PaddleSlim 静态量化后的模型并不是可以最终在 CPU 上部署的模型
-
需要通过 Paddle 官方提供的转换脚本 save_quant_model.py 对产出的量化模型进行转换和优化操作
-
具体的静态量化实例代码如下:
-
5.4.1 解压数据集
- 解压 ImageNet 验证集数据
In [ ]
# 解压数据集
!mkdir ~/data/ILSVRC2012
!tar -xf ~/data/data68594/ILSVRC2012_img_val.tar -C ~/data/ILSVRC2012
5.4.2 模型静态量化
- 读取校准数据 -> 构建读取器 -> 静态量化
In [ ]
import os
import paddle
import paddleslim
import numpy as np
import paddle.vision.transforms as T
from PIL import Image
# 开启静态图模式
paddle.enable_static()
# 模型的路径和文件名称
model_dir = "models/MobileNetV1_infer"
model_filename = 'inference.pdmodel'
params_filename = 'inference.pdiparams'
model_dir_quant_static = "models/MobileNetV1_infer_quant_static"
# 数据预处理
'''
缩放 -> 中心裁切 -> 类型转换 -> 转置 -> 归一化 -> 添加维度
'''
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
val_transforms = T.Compose(
[
T.Resize(256, interpolation="bilinear"),
T.CenterCrop(224),
lambda x: np.asarray(x, dtype='float32').transpose(2, 0, 1) / 255.0,
T.Normalize(mean, std),
lambda x: x[None, ...]
]
)
# 校准数据读取
'''
读取图像 -> 预处理 -> 组成数据字典
'''
img_dir = 'data/ILSVRC2012'
img_num = 32
datas = iter([
val_transforms(
Image.open(os.path.join(img_dir, img)).convert('RGB')
) for img in os.listdir(img_dir)[:img_num]
])
# 静态量化
paddleslim.quant.quant_post_static(
executor=paddle.static.Executor(), # Paddle 静态图执行器
model_dir=model_dir, # 输入模型路径
model_filename=model_filename, # 输入模型计算图文件名称
params_filename=params_filename, # 输入模型参数文件名称
quantize_model_path=model_dir_quant_static, # 输出模型路径
save_model_filename=model_filename, # 输出模型计算图文件名称
save_params_filename=params_filename, # 输出模型参数文件名称
batch_generator=None, # 数据批次生成器,需传入一个可调用对象,返回一个 Generator
sample_generator=lambda:datas, # 数据采样生成器,需传入一个可调用对象,返回一个 Generator
data_loader=None, # Paddle DataLoader
batch_size=32, # 数据批次大小
batch_nums=1, # 数据批次数量,默认为使用全部数据
weight_bits=8, # 参数量化比特数 8/16 对应 INT8/16 类型
activation_bits=8, # 激活值量化比特数 8/16 对应 INT8/16 类型
weight_quantize_type='channel_wise_abs_max', # 参数量化方法,目前支持 'range_abs_max', 'moving_average_abs_max' 和 'abs_max'
activation_quantize_type='range_abs_max', # 激活值量化方法,目前支持 'range_abs_max', 'moving_average_abs_max' 和 'abs_max'
algo='KL', # 校准方法,目前支持 'KL', 'hist', 'mse', 'avg', 'abs_max'
)
5.4.3 模型转换
- 执行转换脚本,转换导出最终的部署模型
In [ ]
# 执行转换脚本
!python save_quant_model.py \
--quant_model_path "models/MobileNetV1_infer_quant_static" \
--quant_model_filename "inference.pdmodel" \
--quant_params_filename "inference.pdiparams" \
--int8_model_save_path "models/MobileNetV1_infer_quant_static/quantized_model" \
--save_model_filename "inference.pdmodel" \
--save_params_filename "inference.pdiparams"
6. 模型部署
6.1 文件大小
-
两种量化方式产生的模型文件大小对比如下表:
模型 计算图文件 参数文件 原始模型 414.7KB 16.2MB 动态量化 454.0KB 7.2MB 静态量化 221.4KB 16.1MB -
因为 Paddle 框架和模型储存格式的缘故,静态量化的模型参数仍以 Float32 格式储存,所以模型参数文件大小并没有缩小
-
而动态量化产生的模型参数使用了 Int8 格式储存,故文件大小缩减至原模型的一半左右
6.2 部署框架
-
动态量化:目前只有 PaddleLite 仅支持反量化预测方式,server 端预测(PaddleInference)不支持加载该量化模型
-
静态量化:使用 PaddleLite 或者 PaddleInference 加载量化模型进行预测推理
6.3 部署参考资料
-
端侧部署:PaddleLite 量化部署
-
服务器部署:Intel CPU 量化部署
6.4 部署实践
-
用 PaddleSlim 生成的量化模型,在 AIStuido 并不是很好部署,所以这里就不演示了
-
一堆奇奇怪怪的坑,要不就是结果不对,要不就是加载不了,也不知道哪里错了,可能是技术不行吧,算了摆烂不搞了
7. 尾巴
-
这当然部署 PaddleSlim 的全部,PaddleSlim 还有很多功能,本次只是介绍了其中比较简单的两种模型量化的方法使用
-
有关 PaddleSlim 量化训练和其他功能的使用介绍,之后应该会慢慢分享的
更多推荐
所有评论(0)