YOLOv3量化
YOLOv3 Int8量化
YOLOv3 Pytorch版本代码梳理
选用Pytorch版本YOLOv3代码链接:https://github.com/bubbliiiing/yolo3-pytorch/tree/bilibili
YOLOv3-Pytorch
- img:存放detect图片。
- logs:存放权值文件。
- model_data:存放各种数据集的类别信息。
- nets:网络模型结构文件夹:
- __init__.py
- darknet.py:定义残差结构,并按照卷积,BN,LeakyReLU,残差封装darknet53
- yolo_training.py:
- YOLOLoss:
- 整合损失
- 获得网络的预测结果后, 将预测结果进行解码,判断预测结果和真实值的重合程度,如果重合程度过大则忽略,因为这些特征点属于预测比较准确的特征点,作为负样本不合适。
- 计算损失
- 计算IOU
- weights_init:初始化权重
- YOLOLoss:
- yolo.py:
- conv2d:组合卷积,BN和relu到这个模块中
- make_last_layers:七个卷积,前五个用于提取特征,后两个用于获得yolo网络的预测结果
- YoloBody:定义backbone,加载权重文件,得到模型输出tensor,计算yolo_head的输出通道数,对于VOC数据集是75,输出三个不同尺寸的yolo_head
- utils:
- __init__.py
- callback.py:画损失的时候会用到。
- dataloader:读取数据集,并进行数据增强。
- utils_bbox.py:DecodeBox:
- 解码网络预测结果,调整先验框。利用预测结果对先验框进行调整,首先调整先验框的中心,从先验框中心向右下角偏移,再调整先验框的宽高。
- 非极大值抑制。
- utils_fit.py:反向传播,记录损失值。
- utils_map.py:计算map,画图。
- utils.py:
- 图像转换
- resize
- 获得类,先验框,学习率。
- VOCdevkit:数据集,数据集中的train,val,test都在,根据txt进行区分,整个voc2007数据集是完整的。
- get_map.py: 输出map值
- kmeans_for_anchors.py:获取最适合的anchors。
- predict.py:进行预测,可以预测图片,视频和文件夹。
- summary.py:该部分代码用于看网络结构。
Int8量化
量化是一种减少模型大小和加速推理过程的技术,它通过将浮点数转换为整数
来实现。在模型推理过程中,将可转换的operator,从float32转成int8,压缩参数,提升速度,降低内存占用,提升模型的推理速度,但是精度会有一定的下降。
根据量化数据表示的原始数据范围是否均匀,可以将量化分为线性量化和非线性量化。非线性量化的通用硬件加速比较困难,而且实现更加复杂,因此线性量化更加常用。线性量化中,根据浮点值的零点
是否映射
到量化值的零点
,可以将量化分为对称量化(Symmetric)
和非对称量化(Asymmetric)
。
量化粒度:
- Per channel:一个tensor里的所有value按照同一种方式去scale和offset;
- Per tensor:粒度更细。对于tensor的某一个维度(通常是channel的维度)上的值按照一种方式去scale和offset,也就是一个tensor里有多种不同的scale和offset的方式(组成一个vector),如此以来,在量化的时候相比per tensor的方式会引入更少的错误。
Pytorch支持的两种量化模式:
- Eager Mode Quantization:一种beta测试量化模式,
需要手动指定量化和去量化发生的位置,只支持模块,不支持函数
。 - FX Graph Mode Quantization:
- 相对更高级的量化方式,
不用手动设定各种配置,添加了对函数的支持
。 使用的时候对模型进行一个trace追踪,但不能在任意模型中使用,有些模型无法追踪
。- FX是PyTorch的一个功能,可以将模型转换为一个Graph图表示,然后对图进行变换和量化。
- 这种方式通常比Eager mode更高效,因为它可以将多个操作融合在一起,减少运算时间,并且优化内存使用。
- 相对更高级的量化方式,
具体量化方式,可以分为两类,训练后量化和量化感知训练:
- 训练后量化:Post training Quantization
- 量化感知训练:Quantization aware training
训练后量化:Post training Quantization
- 接对已训练完成的模型进行量化,无需复杂的fine-tuning或训练过程,因此训练后量化的开销较小。
- 训练后量化无需或只需要一小部分数据驱动量化,因此能很好地应用于数据敏感的场景。但是训练后量化的模型精度下降可能要高于量化感知训练。
- 训练后量化,又分为静态量化和动态量化。
- 静态量化:Post Training Static Quantization:weight和activation都提前量化好,有calibration阶段。
- 静态量化中
离线计算好模型权重和激活的量化参数,推理的时候不再调整直接使用
。 - 对激活值量化需要获取激活值的分布信息。
- 因此,静态量化中需要提供一定的数据来推理网络,收集网络的激活值信息,确定相关的量化参数。
- 静态量化中
- 动态量化:Post Training Dynamic Quantization:weight提前量化好,activation在inference过程中收集data range,从而确定scale无calibration阶段(一般用在含有LSTM GRU RNN的NLP类模型)
- 在动态量化中,激活值相关的量化参数是在推理阶段实时计算的。
虽然效果更好,但是会给推理带来额外的开销
。因为很多nlp模型都是有一个范围在的,需要根据实际情况去动态训练。
- 在动态量化中,激活值相关的量化参数是在推理阶段实时计算的。
- 静态量化:Post Training Static Quantization:weight和activation都提前量化好,有calibration阶段。
静态量化和动态量化所支持的操作符:
量化感知训练:Quantization aware training
在训练好的模型上插入伪量化算子
。- 对数值
量化然后反量化
,模拟量化产生的误差
。 - 然后在训练数据集更新权重并调整对应的量化参数,或者直接将量化参数作为可学习的参数在反向传播中更新。
- 整个计算过程使用浮点数计算,但是最后会得到一个量化后的模型。
Eager Mode Quantization
Eager mode 量化之前需要做的准备:
- 将输出重量化(因此需要额外参数)的操作从函数式转换为模块形式(例如,使用torch.nn.ReLU而不是torch.nn.function .relu)。
- 注意附加子模块的设置。
- 静态量化和量化感知训练需要指定激活被量化和去量化的位置。
- 使用FloatFunctional将需要特殊处理量化的张量操作包装到模块中。例如像add和cat这样的操作,它们需要特殊处理来确定输出量化参数。!
- Fuse模块:将操作/模块组合成一个模块,以获得更高的精度和性能。目前支持:[Conv, Relu], [Conv, BatchNorm], [Conv, BatchNorm, Relu], [Linear, Relu]
Post training Dynamic Quatization
- 最简单的量化方式。
- 权重是提前量化的。
- 推理过程中的激活是动态量化的:因为模型执行时间主要从内存加载权重而不是计算矩阵乘法,多用于nlp,rnn,lstm和transformer。
1 |
|
调用代码:
- 定义一个模型
- 创建模型实例
- 利用torch api创建量化模型,指定模型动态量化的数据项。
- 运行量化后的模型。
1 |
|
Post Training Static Quantization
- ptsq中权重和激活都会提前量化。
- Pytorch会将权重和激活融合在一起,做算子融合,如何可能得话,这样会一定程度的优化模型。
- 因为激活也要提前量化,需要有代表性的数据集校准,以确定激活的最佳量化参数。
- 当内存带宽和计算节省都很重要时,通常使用训练后静态量化,CNN是典型的用例。
1 |
|
代码流程:
- 定义一个包含量化和反量化的模型。
- 创建模型实例。
- 模型设置为eval模式,否则无法进行静态量化。
- 模型附加一个全局的qconfig,包含类型相关信息,包含一定的量化配置。例如指定对称非对称,MinMax等。
- 设置可以进行融合的层,常用的包括
conv + relu
和conv + batchnorm + relu
。 - 创建静态量化准备模型,这个
prepared model会在校准期间观察激活的张量
。 - 用少量的代表性数据集,校准prepared model模型,以确定激活。
- 将prepared model转换为quantized model。
- 量化权重
- 计算和存储scale,bias,与激活张量一起使用。并取代键运算符。
代码示例:
1 |
|
量化感知训练
量化感知训练:在训练过程中,对量化的影响进行建模,也就是模型知道自己要被量化了,学习量化过程中的参数。
- 在训练过程中:参数同样是以float32进行训练。
- fake_quant模块可以模拟int8量化的结果。
- 在模型转换之后,尽可能的将激活和权重融合到一层,与静态量化相比,可以产生更高的精度,通常与CNN一起使用。
1 |
|
量化感知训练流程:(前5步和静态量化训练一样)
- 定义一个包含量化和反量化的模型。
- 创建模型实例。
- 模型设置为eval模式,否则无法进行静态量化。
- 模型附加一个全局的qconfig,包含类型相关信息,包含一定的量化配置。例如指定对称非对称,MinMax等。
- 设置可以进行融合的层,常用的包括
conv + relu
和conv + batchnorm + relu
。 - 生成一个prepared模型,将插入observers and fake_quants,需要将模型设置为训练逻辑.train()。这样在校准期间可以观察权重和激活张量。
- 运行训练循环,进行模型训练。
- 将prepared模型设置为eval模式。
- 进行模型转换。
代码:
1 |
|
FX Graph Mode Quantization
FX类型的参数配置主要通过qconfig_mapping (prepare_fx函数的一个参数)完成。
代码示例:
1 |
|
YOLOv3模型量化
FX mode的训练后量化
1 |
|
QAT
1 |
|
项目源码:https://github.com/cauccliu/YOLOv3Quant
参考列表:
- https://pytorch.org/docs/2.0/quantization.html#prototype-fx-graph-mode-quantization
- https://zhuanlan.zhihu.com/p/675552307
- https://blog.csdn.net/magic_ll/article/details/132167012
- https://github.com/qiaofengsheng/yolo-v3-DarkNet53-MobileNet-V2/tree/main
- https://github.com/bubbliiiing/yolo3-pytorch/tree/bilibili
- https://zhuanlan.zhihu.com/p/299108528
YOLOv3量化
https://cauccliu.github.io/2024/05/07/YOLOv3量化/