1. QAT使用说明

本文档主要介绍清微智能深度学习模型Finetune Lib的运行环境配置、工具的介绍、工具的使用方法以及工具的使用场景。

1.1. 简介

文件目录如下表:

目录

开源/封闭

说明

ts_qat_pytorch-2.0.x-py3-none-any.whl

开源

通过pip install在python的安装包路径下形成ts_qat_pytorch的库文件, 包含Finetune时所依赖的全部文件(详见ts_qat_pytorch介绍)

example/

开源

提供使用Knight-Finetune-Lib的一些demo

1.2. 准备工作

1.2.1. 环境配置

1.2.1.1. 基础环境配置

默认用户在服务器上配置了显卡和CUDA以及python3的相关与训练模型有关的环境, 查看显卡和CUDA的命令为

nvidia-smi

然后需要安装torch==2.1.0,torchvsion==0.16.0具体安装版本如下:

pip install torch==2.1.0 torchvision==0.16.0

安装完成后需要验证pytorch是否能够在gpu上面正常运行,验证方式如下图:

pipeline

图 cuda验证

如果是True的话就是pytorch能够在gpu上面正常运行,否则就需要检查服务器上显卡驱动和CUDA的版本是否安装正确。

1.2.1.2. 其他python环境的安装和配置

1.2.1.2.1. pip软件包的安装

确认python的安装环境中是否有安装pip,命令如下:

which pip

出现pip相应的安装路径,比如:miniconda3/envs/quant_tool/bin/pip,证明pip已安装。

如果pip并未安装,在终端里执行

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh

然后执行

bash Miniconda3-latest-Linux-x86_64.sh

自动安装此软件包内含pip安装包,无需另外安装。

1.2.1.2.2. 其他Python软件包的安装以及环境变量的配置
pip install ts_qat_pytorch-2.0.x-py3-none-any.whl

需要用户在联网的状态自动安装

如用户已安装上述依赖包,安装会自动跳过,直接安装 ts_qat_pytorch 软件包,如使用anaconda的环境安装后会在anaconda3/envs/${虚拟环境名称} /lib/python3.8/site-packages/ts_qat_pytorch里面,如使用其他python的环境请用户自行在python的安装路径中lib/python3.8/site-packages/ts_qat_pytorch中寻找。

1.3. Knight-Finetune-Lib介绍

1.3.1. 名词解释

Finetune:即微调,这个名词是从模型训练的领域中借鉴过来的,就是从一个训练好的模型中通过减小学习率进行进一步的调整,使模型精度有进一步的提升。在这里的Finetune有的地方也称作量化感知训练,即QAT(Quantization Aware Training)。

1.3.2. Knight-Finetune-Lib的应用场景

在使用量化工具进行模型量化时,精度不满足实际的需求,就需要使用Knight-Finetune-Lib进行Finetune训练,以达到实际的需求。

1.4. Knight-Finetune-Lib使用方法

1.4.1. 整体工作流程

用户提供浮点模型和训练数据,使用Knight-Finetune-Lib进行Finetune训练,在训练过程中插入量化和反量化的节点,得到带有QDQ的ONNX模型后,用ONNX量化工具进行模型量化:

使用QDQ的ONNX模型进行ONNX的量化,具体流程如下图:

pipeline

图 Knight-Finetune-Lib训练流程图

1.4.2. ts_qat_pytorch介绍

目录

说明

nn/

将浮点模型中浮点模块转化成量化模块

fake_quantize/

Knight-Finetune-Lib中模拟量化的实现

tools/

Knight-Finetune-Lib中对浮点模型的相关处理

utils/

调用Knight-Fi netune-Lib时需要的注册器、记录log信息和其他工具

custom_quantizer/

模型 量化时相关节点替换,同时也支持自定义的量化算法

onnx/

将插入fake节点的 pytorch的模型转成带有QDQ的ONNX,便于查看插入的 fake节点的位置,注意该模型不能进行ONNX的推理。

fuser_ method_mappings.py

conv、deconv、BN、linear的融合

observer/

量化使用的观测器

quantization/

和Finetune相关的一些依赖的函数文件

prep are_by_platform.py

根据不同的后端指定不同的量化方案

scheme.py

描述量化策略

custom _symbolic_opset.py

为torch.quantize_function 注册符号算子

convert_export.py

导出带有QDQ节点的ONNX模型的入口函数

1.4.3. Finetune自定义模型

1.4.3.1. Knight-Finetune-Lib的API接口

API接口

接口说明

输入参数说明

prepare_by_platform

根据不同 的后端类型 ,向传入的 model插入不 同的伪量化 节点,为后 续校准和伪 量化做准备

model:原始模型定义

backend:指定finetune后端,现阶段 支持TSQAT、Experimental的后端。

prepare _custom_config_dict:自定义配置信 息,具体如何配置详见代码中的注释

custo m_tracer:自定义tracer,可以缺省

enable_calibration

使能校准, 有益于下一 步的伪量化

mode l:插入fake_quantize节点后的模型

enable_quantization

使能伪量化

mode l:插入fake_quantize节点后的模型

enable_calibra tion_woquantization

校准过 程中不使用 伪量化节点

mode l:插入fake_quantize节点后的模型

qua ntizer_type:伪量化对象类型,取值 “weight_fake_quant” /“act_fake_quant”/“fake_quant”, 分别指定只校准权重、只校准激活、 同时校准权重和激活;默认第三种;

enable_calib ration_quantization

校准 过程中使用 伪量化节点

mode l:插入fake_quantize节点后的模型

save_checkpoint

保 存模型文件

model: QAT的模型

file_path:去除伪节 点的模型保存路径(含保存文件名) file_path_json:量化参数js on文件的保存路径(含保存文件名)

1.4.3.2. 使用步骤介绍

以下以resnet18为例,来看一下如何量化自己的模型,其中与模型训练相关的部分只需和浮点模型训练一致即可:

from ts_qat_pytorch.prepare_by_platform import prepare_by_platform, BackendType
from ts_qat_pytorch.utils.state import enable_calibration, enable_quantization, enable_calibration_woquantization, enable_calibration_quantization

# 首先,创建模型并加载预训练权重
model = models.__dict__["resnet18"](pretrained=True)
model.train()

# 然后,我们使用torch.fx来跟踪原始的模型,根据不同的后端插入不同的伪量化的节点,现阶段支持TSQAT、Experimental的后端
model = prepare_by_platform(model, BackendType.TSQAT)

# 在训练之前,为了使QAT在训练的scale更加稳定,我们推荐先使用一些校准数据进行scale的校准,然后再进行QAT的训练
model.eval()
enable_calibration(model)

# calibration loop
for i, batch in enumerate(data):
    # 做前向过程
    ...

model.train()
enable_quantization(model)
# 训练过程
for i, batch in enumerate(data):
    #做前向过程
    ...

    #做反向过程和梯度优化
    ...

1.4.4. Finetune Demo模型

此处Demo模型主要以mobilenet_v3_small图像分类网络为例,以下分别介绍finetune该类demo模型的相关参数及操作步骤,了解更多细节请结合本文档说明及示例源码。

1.4.4.1. 参数说明

参数

说明

默认值*

必选 /可选

参 数类型

-h 或是 --help

显示帮 助信息并退出

可选

--data

imagene t数据集的路径

必选

--model-zoo

指定mo del-zoo的名称

to rchvision

可选

str

-a 或是 --arch

模 型结构的名称

resnet18

可选

str

--teacher-arch

蒸馏时teac her模型结构名

resnet101

可选

str

-nc 或是 --num-classes

模型分 类的类别数量

1000

可选

int

-j 或是 --workers

数据加载 时开启的线程

4

可选

int

--epochs

运行的 epoch的总个数

90

可选

int

--start-epoch

手动指定从 哪个epoch开始

0

可选

int

-b或是 --batch-size

min i-batch的大小

256

可选

int

--lr或是 --learning-rate

学习率

0.1

可选

float

--momentum

动量

0.9

可选

float

--wd或是 --weight-decay

权重衰减

1e-4

可选

float

-p 或是 --print-freq

每隔多 少迭代次数屏 幕中打印一次

100

可选

int

--resume

最近保存 的模型的路径

‘ ’

可选

str

-e或是--evaluate

只在验 证集进行测试

可选

st ore_true

--pretrained

使能使 用预训练模型

可选

st ore_true

--world-size

分布式训 练节点的数量

-1

可选

int

--rank

分布式训练节 点进程的编号

-1

可选

int

--dist-url

设置用于分 布式训练的url

tcp:// 224.66.41 .62:23456

可选

str

--dist-backend

分布式的后端

nccl

可选

str

--seed

用于初始化 训练的种子点

None

可选

int

--gpu

指 定训练需要使 用的gpu的id号 ,如不指定使用 所有可用的gpu

None

可选

int

--multiproces sing-distributed

使能多进 程分布式训练

可选

st ore_true

--model-path

指定官 方的模型路径

None

可选

str

--teacher-path

指定teac her的模型路径

None

可选

str

--backend

量化的后端:

TSQ AT、Experimen tal共有两种可 选,具体参见 下面的注解。

TSQAT

可选

str

--optim

训练 需要的梯度优 化算法:目前 支持sgd/adam

sgd

可选

str

--not-qat

不进行qat

可选

st ore_true

l或是--log-level

日志的级别

0: debug

1: info

2: warning

3: error

1

可选

int

--profile

输 出每一层的精 度对比,便于 查找精度问题

可选

st ore_true

--distill-method

指 定蒸馏的方法

None

可选

str

--distill-alpha

蒸 馏的调节系数

0.95

可选

float

--temperature

蒸馏的温度

6

可选

float

--amp

使用torch .cuda.amp进行 混合精度训练

可选

st ore_true

--onnx-batch

导出 QDQ的ONNX模型 的batch-size

1

可选

int

--opset-version

导出QD Q的ONNX模型的 opset-version

18

可选

int

备注

1.如果要从预训练的模型进行finetune训练,需要--pretrained、--model-path、--resume三个参数任选其一,否则这三个参数就是可选的。

2.--lr、--optim、--wd这三个参数不要任意指定,要根据实际的训练策略来决定,比如,对于imagenet的mobilenet_v3_small和yolov5s网络我们推荐操作步骤展示的参数配置。

3.--world-size、--rank、--dist-url、--dist-backend、--multiprocessing-distributed这四个参数选项是与分布式训练相关的参数,具体如何使用可以参见https://github.com/pytorch/examples/tree/main/imagenet

4.对于backend的2种不同的后端的具体使用场景的几点说明:

backend

使用场景

应用范围

TSQAT

使用ONNX量化工 具进行导入量化参数的 方式进行模型量化使用

用于ONNX量 化工具导入量化参数

Experimental

实验性的后 端,不推荐用户使用。

进行实验性的验证

1.4.4.2. Demo操作步骤

以下的示例只针对单gpu训练。

步骤一:测试浮点模型

将example文件夹放到自定义目录下,直接执行以下命令:

运行结果:

* Acc@1 64.350 Acc@5 89.917
# 测试 yolov5_v3.0
cd example/yolov5_v3.0_example
python test.py –weights yolov5s.pt –data data/coco.yaml –device 1

运行结果:

Scanning labels /data/public_data/data_coco/labels/val2017.cache (4952 found, 0 missing, 48 empty, 0 duplicate, for 5000 images): 5000it [00:00, 11245.95it/s]
Class Images Targets P R mAP@.5 mAP@.5:.95: 100%|█████████████████████████████| 157/157 [01:14<00:00, 2.11it/s]
all 5e+03 3.63e+04 0.36 0.627 0.538 0.338

步骤二:通过Knight-Finetune-Lib获得更优的浮点模型

# Finetune mobilenet_v3_small
python example/imagenet_example/main.py -a mobilenet_v3_small -b 128 --data example/imagenet_example/data/imagenet/images –model-path example/imagenet_example/float_model/ mobilenet_v3_small_120.pth --gpu 0 -j 10 --lr 1e-4 --optim adam --wd 1e-5 --epochs 10 -nc 120

运行结果:

* Acc@1 62.667 Acc@5 89.433
# Finetune yolov5_v3.0
cd example/yolov5_v3.0_example
CUDA_VISIBLE_DEVICES='1,2,3,4,5,6,7' python train_qat.py --data data/coco.yaml --device 1,2,3,4,5,6,7 --epochs 10 --batch-size 49 --workers 6 --quantize --output_dir checkpoint_qat --hyp data/hyp.qat.yaml

运行结果:

Class      Images     Targets           P           R      mAP@.5  mAP@.5:.95: 100%|█████████████████████████████| 103/103 [02:16<00:00,  1.32s/it]
 all       5e+03    3.63e+04       0.356       0.608       0.519       0.302

备注

1.由于训练时做了数据的重新排布,所以现在只训练一个epoch时,得到的Acc@1和Acc@5和上面给出的结果有一些差别,这个差别是合理的。 2.如果采用多卡训练时,产生的模型的state_dict会产生’module.’的前缀,如果后续使用量化工具量化时,需要做处理,方式如下:

state_dict = checkpoint['state_dict']
model_dict = model.state_dict()
if 'module.' in list(state_dict.keys())[0] and 'module.' not in list(model_dict.keys())[0]:
for k in list(state_dict.keys()):
        state_dict[k[7:]] = state_dict.pop(k)

备注

1.关于训练epoch的数量,对于imagenet的分类的网络可以先训练一个epoch,看是否满足需求,如果不满足需求,需要继续finetune,最多不超过10个epochs。 2.关于上述demo模型屏幕打印信息的一些说明:

pipeline

Epoch[0]表示第0个epoch;[0/2503],0表示第0个batch,2503表示一共2503个batch;Time 12.614(12.614),12.614表示一个batch的执行时间,括号内的是平均时间;

Data 6.371(6.371),6.371表示一个batch的数据的加载时间,括号内的是平均时间;Loss 1.1625e+00(1.1625e+00), 1.1625e+00表示一个batch的loss值,括号内的是平均loss值,Acc@1 71.48(71.48),71.28表示一个batch的top1精度, 括号内的是平均top1精度;

Acc@5 89.26(89.26),89.26表示一个batch的top5精度,括号内的是平均top5精度。

1.4.4.3. 关于QAT文件的相关说明

模型保存方式

参考 example/imagenet_example/main.py 中的 save_checkpoint 函数,该函数会将模型自动保存;convert_export函数,该函数会自动把带量化参数的QDQ的ONNX模型自动保存。import该函数如下:

from ts_qat_pytorch.utils.utils import save_checkpoint
from ts_qat_pytorch.convert_export import convert_export
1.4.4.3.1. 保存文件的相关说明

save_checkpoint函数会保存两类文件:带伪节点的QAT训练模型权重和带有qdq节点的ONNX浮点模型。 带伪节点的QAT训练模型:用来继续进行QAT训练; convert_export函数生成带QDQ(Quantize-DQuantize)节点的ONNX模型,可使用ONNX量化工具对其进行量化。 对于imagenet_example来说,会在 example/imagenet_example/checkpoint 路径下生成如下表所列文件;

文件名

说明

模型名_checkpoint.pth

当前epoch生成的模型文件

模型名_model_best.pth

已训练epoch中精度最高的模型文件

模型 名_onnx_quantization.onnx

当前epoch生成的QDQ的ONNX模型文件

模型名_ bestonnx_quantization.onnx

已 训练epoch中精度最高的QDQ的ONNX模型文件

1.5. Knight-Finetune-Lib适用的算子规格表

序 号

Pytorch算子名称

是 否支持

1

torch.nn.Conv2d

torch.nn.Conv1d

支持

2

torch.nn.ConvTranspose2d

torch.nn.ConvTranspose1d

支持

3

torch.nn.Linear

torch.nn.functional.linear

支持

4

torch.nn.MaxPool2d

torch.nn.functional.max_pool2d

torch.nn.MaxPool1d

torch.nn.functional.max_pool1d

支持

5

torch.nn.AdaptiveAvgPool2d

torch.nn.functional.adaptive_avg_pool2d

torch.nn.AdaptiveAvgPool1d

torch.nn.functional.adaptive_avg_pool1d

支持

6

torch.nn.BatchNorm2d

torch.nn.BatchNorm1d

支持

7

torch.nn.ReLU

torch.nn.functional.relu

torch.relu

支持

8

torch.nn.PReLU

torch.nn.functional.prelu

torch.prelu

支持

9

torch.nn.Upsample

torch.nn.functional.interpolate

支持

10

torch.nn.AvgPool2d

torch.nn.functional.avg_pool2d

torch.nn.AvgPool1d

torch.nn.functional.avg_pool1d

支持

11

torch.nn.functional.LeakyReLU

torch.nn.functional.leaky_relu

支持

12

torch.nn.Tanh

torch.nn.functional.tanh

torch.tanh

支持

13

torch.nn.Sigmoid

torch.nn.functional.sigmoid

torch.sigmoid

支持

14

torch.nn.ReLU6

torch.nn.functional.relu6

支持

15

torch.nn.ELU

torch.nn.functional.elu

支持

16

torch.nn.SELU

torch.nn.functional.selu

torch.selu

支持

17

torch.flatten(必须指定dims)

支持

18

torch.nn.Softmax

torch.nn.functional.softmax

torch.softmax

支持

19

torch.nn.RNN

不支持

20

torch.nn.LSTM

不支持

21

torch.nn.GRU

不支持

22

torch.cat

支持

23

torch.split

支持

24

torch.Tensor.repeat

支持

25

torch.add, operator.add

支持

26

torch.mul, operator.mul

支持

27

torch.abs

支持

28

torch.sqrt

支持

29

torch.exp

支持

30

torch.pow

支持

31

torch.log

支持

32

torch.sin

支持

33

torch.cos

支持

34

[:, :, :, :]

支持

35

torch.transpose

torch.Tensor.transpose

支持

36

torch.Tensor.view

支持

37

torch.squeeze

torch.Tensor.squeeze

支持

38

torch.unsqueeze

torch.Tensor.unsqueeze

支持

39

torch.nn.GLU

torch.nn.functional.glu

支持

40

torch.stack

支持

41

torch.chunk

支持

42

torch.mean

支持

43

torch.sub, operator.sub

支持

44

torch.min

支持

45

torch.max

支持

46

torch.nn.PixelShuffle

torch.nn.functional.pixel_shuffle

支持

47

torch.nn.LayerNorm

torch.nn.functional.layer_norm

支持

48

torch.nn.Hardswish

torch.nn.functional.hardswish

支持

49

torch.nn.Hardsigmoid

torch.nn.functional.hardsigmoid

支持

50

torch.clamp

支持

51

torch.argmax

torch.Tensor.argmax

支持

52

torch.nn.Embedding

支持

53

torch.nn.SiLU

torch.nn.functional.silu

支持

54

torchvision.ops.RoIPool

支持

55

torch.matmul

支持

56

torch.nn.GELU

torch.nn.functional.gelu

支持

57

torch.nn.PixelUnshuffle

torch.nn.functional.pixel_unshuffle

支持

58

torch.tile

torch.Tensor.tile

支持

59

torch.Tensor.to

支持

60

torch.permute

torch.Tensor.permute

支持

61

torch.reshape

torch.Tensor.reshape

支持

62

torch.roll

支持

备注

对于LSTM、GRU、RNN QAT不插入fake节点,因此对于循环结构的网络QAT没有任何效果。**

1.6. FAQ

【问题1】动态控制流的trace问题

【问题解析】因为trace模型是用torch.fx跟踪的,现在torch.fx无法trace到动态控制流

【验证过程】

pipeline

【问题2】静态控制流的trace问题

【问题解析】因为trace模型是用torch.fx跟踪的,现在torch.fx无法直接trace到静态控制流,但是可以修改

【验证过程】

pipeline

将原始的MyModule分成上图的两个模型,就可以trace到

【问题3】Tensor构造函数(比如:torch.zeros, torch.ones,torch.rand,torch.randn,torch.sparse_coo_tensor)和assert无法进行跟踪

【解决方法】

1.对于确定性的Tensor构造函数(比如zeros,ones)可以使用torch.ones_like,torch.zeros_like来代替这样就可以被跟踪到;

2.对于不确定性的Tensor构造函数(比如rand,randn)可以用torch.fx.wrap对torch.randn进行装饰,例如:

pipeline

3.forward函数中删除assert;

【问题4】对于图像领域的检测网络,需要首先做前后处理的剥离,因为前处理和后处理往往无法trace

【解决方法】
将网络部分单独提取出来,只trace网络的部分,qat的部分也只针对网络部分进行,以业内使用最多的yolov5为例:

原始网络为

pipeline

改成

pipeline

分别进行跟踪

【问题5】自定义CustomTracer(比如使用leaf_module)

【解决方法】

pipeline