深度学习模型剪枝、量化和TensorRT推理

深度学习模型剪枝、量化和TensorRT推理

模型剪枝算法

        Rethinking the Value of Network Pruning这篇文献主要介绍了以下几种剪枝算法,并在github上开源了代码,在ImageNet和cifar两个数据集上进行了测试,论文也验证了对比了对剪枝模型进行fine tune和根据剪枝后的网络结构从头训练网络的准确率,在作者提供的准确率中,一般情况下,对于分类网络,从头训练的准确率比剪枝后fine tune后的准确率高。

预定义网络结构剪枝

剪枝方法 参考文献 github 剪枝原理
L1-norm based Filter Pruning Pruning Filters for Efficient ConvNets l1-norm-pruning 在每一个卷积层,根据卷积核的权重值的L1 norm大小,修剪掉相应百分比的通道数。
ThiNet ThiNet: A Filter Level Pruning Method for Deep Neural Network Compression https://github.com/Roll920/ThiNet 剪枝时,不根据当前层进行剪枝,而是修剪去对下一卷积层激活值影响最小的权重值。
Regression based Feature Reconstruction Channel Pruning for Accelerating Very Deep Neural Networks https://github.com/yihui-he/channel-pruning 根据LASSO回归算法选出有代表性的卷积层通道,减枝去掉冗余通道,使用最小二乘法重建剩余通道。

自动网络结构剪枝

剪枝方法 参考文献 github 剪枝原理
Network Slimming (1) Learning Efficient Convolutional Networks through Network Slimming
(2) SlimYOLOv3: Narrower, Faster and Better for Real-Time UAV Applications
(1) network-slimming
(2) https://github.com/PengyiZhang/SlimYOLOv3
在剪枝时,对BN层的gamma参数进行惩罚进行稀疏训练,剪枝时选择稀疏训练后BN层gamma值较大的参数进行保留
Sparse Structure Selection Data-Driven Sparse Structure Selection for Deep Neural Networks https://github.com/TuSimple/sparse-structure-selection 除了对通道进行稀疏训练,还可以对残差模块进行稀疏训练。
  • 稀疏训练代码
def updateBN():
    for m in model.modules():
        if isinstance(m, nn.BatchNorm2d):
            m.weight.grad.data.add_(args.s*torch.sign(m.weight.data))
  • 注意:剪枝时对残差模块通道的剪枝策略需要考虑,方案有不剪枝(减去的参数较少)或者根据残差模块的某一层进行剪枝,也有对所有残差通道的mask进行或运算。剪枝后的效果如下图所示,在剪枝时必须保证shortcut连接的两个卷积层通道数相等。
  • 使用network slimming算法时,每个卷积层都必须剩下至少1个通道。
    在这里插入图片描述

TensorRT int8量化算法

参考连接:8-bit Inference with TensorRT

量化概述

  • 目标:将fp32的卷积神经网络转换为int8而不会造成明显的精度损失;
  • 原因:int8方法具有更高的吞吐量和更低的内存需求;
  • 挑战:int8的精度和动态范围明显低于fp32;
  动态范围 最小精度
fp32 -3.4 x 1038 ~ +3.4 x 1038 1.4 x 10-45
fp16 -65504 ~ +65504 5.96 x 10-8
int8 -128 ~ +127 1
  • 解决方案:在将训练的模型权重量化为int8时以及在int8计算激活时,最大限度地减少信息损失;
  • 结果:在TensorRT中实现了int8方法,并且不需要任何额外的fine tune或重训练。
  • 问题:
    为什么要量化而不使用int8直接训练?
    模型训练是需要反向传播和梯度下降的,训练时的超参一般都是浮点型,如学习率等,int8类型无法进行训练。

线性量化

公式:
Tensor Values = fp32 scale factor * int8 array

根据量化公式仅需求fp32 scale factor即可进行int8量化,那么如何求fp32 scale factor?
在这里插入图片描述

        从上图中可以看出,有两种int8量化方法,一种是非饱和映射(左),另一种是饱和映射(右)。经过验证,非饱和映射会造成严重的准确率损失,原因是由于卷积层计算的正负分布很不均匀,如果按照对称非饱和映射(原意是为了尽可能多地保留原信息)的话,那么+max那边有一块区域就浪费了,也就是说scale到int8后,int8的动态范围就更小了,举个极限的例子就是量化后正的样本没有,负的全部扎堆在一个很小的值附近,这样会造成严重的精度损失。饱和映射方法是先找一个阈值T,将低于最低阈值的值全部都饱和映射到-127上,如右上图的左边的三个红色的点。

如何选择量化阈值?

1. 标定步骤:

  • 在标定数据集上进行fp32推理。
  • 对每一个卷积层:
    • 收集激活的直方图;
    • 生成具有不同饱和阈值的量化分布;
    • 选择使KL发散最小化的阈值。
  • 一般来说,整个标定过程需要几分钟的时间

2. 标定数据集选择:

  • 有代表性
  • 多样化
  • 理想情况下是验证数据集的子集
  • 1000+样例

深度学习模型转TensorRT

【1】 深度学习模型PyTorch训练并转ONNX与TensorRT部署
【2】 darknet YOLOv4模型转ONNX转TensorRT部署
【3】 yolov5 PyTorch模型转TensorRT
【4】 CenterFace模型转TensorRT
【5】 RetinaFace MXNet模型转ONNX转TensorRT

猜你喜欢

转载自blog.csdn.net/linghu8812/article/details/109585506