CUDA与TensorRT学习四:模型部署基础知识、模型部署的几大误区、模型量化、模型剪枝、层融合

文章目录

一、模型部署基础知识

1)FLOPS和TOPS定义介绍、计算公式

(1)基础定义
  • 学习目标
    ①理解FLOPS和TOPS是什么
    ②CPU/GPU中的计算FLOPS/TOPS的公式
    ③CUDA core和Tensor Core的区别

  • FLOPS定义
    一秒钟可以出来的浮动小数点运算的次数(衡量计算机硬件性能),表示计算机每秒可以执行的浮点数运算次数,衡量计算机性能标准
    在这里插入图片描述

  • TOPS定义
    一秒钟可以处理整形运算的次数
    在这里插入图片描述

  • HPC对比(CPU/GPU 单双精度对比)
    在这里插入图片描述

  • FLOPs:
    衡量模型大小的指标,表示模型中有多少个浮点运算
    在这里插入图片描述

(2)计算公式
  • FLOPS计算公式
FLOPS = 时钟频率 * core数量 * 每个时钟周期可以处理的FLOPS
  • 举例计算
    intel i7 Haswell架构 (8核 ,频率3.0 GHz,两个FMA,支持AVX-256指令集)
    那么双精度:
3.0 * 10^9Hz * 8 core * 16 FLOPS/clk = 0.38 TFLOPS 

16 FLOPS/clk:
2 FMA * 4个FP64的SIMD运算*2 乘加融合(乘法和加法是两个浮点运算) = 16   FLOPS/clk

单精度:

3.0 * 10^9Hz * 8 core * 32 FLOPS/clk = 0.76 TFLOPS

2 FMA * 8个FP64的SIMD运算*2 乘加融合(乘法和加法是两个浮点运算) = 32 FLOPS/clk
  • FMA 计算(加法和乘法融合计算,只需一个时钟周期就可以完成计算
    在这里插入图片描述

  • AVX-256指令集的SIMD操作 (一个指令集处理多个数据)
    在这里插入图片描述

(3)FLOPS在GPU试怎么运算?
  • 与cpu不同的地方
    1)没有AVX这种东西
    2)但是有大量的core来提高吞吐量
    3)有Tensor Core来优化矩阵运算
(4)Ampere SM的电子元件结构
  • 一个SM包括
    在这里插入图片描述
  • 每种精度在一个SM的吞吐量
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2)Roofline model

  • 学习目标
    ①理解什么叫做Roofline model、memory bound、compute bound
    ②理解各个layer的计算密度分类

  • Roofline model定义
    一个衡量计算机软件/硬件性能的一个分析模型
    在这里插入图片描述

  • Roofline model作用
    在这里插入图片描述

  • 关于模型的各种指标
    ①计算量:FLOPs
    ②计算峰值:FLOPS
    ③参数量:Byte,表示模型中所有的weights(主要在conv和FC中),衡量模型大小的标准
    ④访存量:Byte,表示模型中某一个算子,或者某一层layer需要与memory产生read/write的量,是分析模型计算效率的标准之一
    ⑤带宽:Byte/s,表示单位时间内可以传输数据量的多少,衡量计算机硬件memory性能的标准,就比如DDR3/DDR4/GDDR4
    在这里插入图片描述
    这里乘4是因为是FP32计算的,是4字节
    在这里插入图片描述

  • 带宽影响因素
    ①memory clock(GHz):表示单位时间内可以read/write的频率,一般以GHz为单位
    ②memory bus width(Bytes):可以同时读写的数据多少
    ③memory channel:表示通道数量,越多越好

  • 带宽计算举例
    在这里插入图片描述
    在这里插入图片描述

(1)Roofline model相关参数计算(计算密度计算)

①计算密度计算:
单位:FLOPs/Byte
作用:表示的是传送单位数据可以进行的浮点运算数(假如传数据很多耗时很长,但是只进行了一次计算,计算效率就很低),纵轴是计算量峰值,横轴是计算密度,斜率是峰值带宽,分为性能饱和和未饱和区间(性能未饱和区间:读写访存太多了,性能饱和区域:计算量太大了
在这里插入图片描述

  • 用3080 Ampere架构来做Roofline model性能分析
1)Core种类和数量
8704 CUDAT cores
272 Tensor cores
68 SMs
2)计算峰值
(FP32) 29.8 TFLOPS
(FP16) 119TFLOPS
(INT8) 238 TOPS
3)带宽
760.32GB/s
4)频率
1.7GHz

计算峰值曲线图(计算密度峰值 = 横轴 = 纵轴/斜率 = 硬件峰值/带宽)
在这里插入图片描述
得出关系表
在这里插入图片描述

(2)卷积分析conv核函数算子的各个参数对计算密度的影响FP32(kernel size、Output size、channel size、group convolution、tensor reshape、FC)

核函数kernel size对计算密度的影响:

  • 参数解释
M: 卷积核输出特征图的H高和W宽。不同的时候可以用Mh和Mw表示
K:卷积核大小

在这里插入图片描述
在这里插入图片描述

可以看到kernel size也就是卷积核大小逐步变化

  • 总结
    1x1 conv虽然减少计算量,但是计算密度很低。随着kernel size增大,计算密度增长率逐渐下降

②Output size对计算密度的影响
在这里插入图片描述

  • 总结
    1x1 conv虽然减少计算量,但是计算密度很低。随着Output size增大,计算密度增长率逐渐下降

③channel size对计算密度的影响
在这里插入图片描述

  • 总结
    随着channel size增大,计算密度增长率逐渐下降

④group convolution对计算密度影响
在这里插入图片描述

  • 总结
    group conv对计算密度的影响,depthwise虽然降低了计算量,但是计算密度也下降很多

⑤tensor reshape的影响
在这里插入图片描述
在这里插入图片描述

  • 总结
    reshape多,那计算密度就降低,reshape不参与计算
    ⑥FC对计算密度的影响
    在这里插入图片描述

  • 总结
    FC计算密度低在于有大量的访存

(3)对整个模型进行Roofline model分析

在这里插入图片描述

①用3080 RTX Ampere架构去看各个模型的计算密度(都没有达到计算密度的饱和)
在这里插入图片描述

②如果把模型部署在jetson上

  • jetson Xavier AGX Volta架构配置
1)Core种类和数量
512 CUDAT cores
64 Tensor cores
8 SMs
2)计算峰值
(FP32) 1.4 TFLOPS
(FP16) 11 TFLOPS
(INT8) 22 TOPS
3)带宽
137GB/s
4)频率
900MHz

画出roofline的图
在这里插入图片描述

在这里插入图片描述
这个jetson架构比较老,可以看出来理论上这个几个模型的计算量都可以跑满

(4)实际发现理论值的硬件峰值、带宽还是有不少差距

在这里插入图片描述

  • 方法
    自己根据benchmark去写几个计算密度的核函数来找到部署架构的真实值(跑数据拷贝,填充数据到多少,密度就不变了)

二、模型部署的几大误区

  • 学习目的
    理解部署模型中优化的过程中容易踩的坑

1)FLOPs不能衡量模型性能(不能完全衡量)

  • 原因
    ①FLOPs只是模型计算大小的单位
    ②还要考虑访存量(访存量大,计算密度就比较小)
    ③考虑与计算无关的DNN部分(reshape、shortcut、nchw2nhwc等等)
    ④DNN以外的部分(前处理、后处理这些)

2)不能完全依靠tensorRT

  • 原因
    tensorRT可以对模型做适当的优化,是存在上限的

  • 举例
    ①计算密度低的1x1 conv和depthwise conv计算密度怎么优化还是很差,tensorRT不会重构
    GPU无法优化的地方回到CPU执行
    方法:手动修改代码实现部分,例如用C++写一个kernel核函数,让部分cpu执行转移到GPU执行(比如DNN的后处理,但是没必要放CPU里面执行,融合到DNN后端部分;前处理也可以放到GPU里面跑)
    ③有些冗长计算,TensorRT可以为了优化额外添加一些多余操作
    <1>比如类似于添加reformatter这种
    <2>直接修改代码实现部分
    存在TensorRT尚未支持的算子
    方法:自己写plugin
    ⑤TensorRT不一定会分配Tensor Core
    原因:因为TensorRT kernel auto tuning会选择最适合的kernel

3)CUDA Core和Tensor Core的使用

  • 原因
    TensorRT不一定会分配Tensor Core
    在这里插入图片描述

4)不能忽视前处理/后处理的overhead

在这里插入图片描述

5)对使用TensorRT得到的推理引擎做benchmark和profiling

在这里插入图片描述

三、模型量化(模型的压缩方式)

  • 学习目的
    ①什么叫做量化
    ②PTQ和QAT的区别
    ③calibration的种类
    ④Per-tensor量化与Per-layer量化
    ⑤量化技巧
    ⑥掉精度需要做的事(控制精度在2%是比较好的)
    ⑦量化与融合优化以及多余算子,去除多余算子

  • 进十年模型变化和硬件发展(DNN模型几乎以每年10倍的FLOPs在增长)
    在这里插入图片描述
    但是相对比来说硬件的发展速度很慢,还需要对应的编译器,有了基本的编译器后,还需要编译器的优化(tensorRT 3.x~8.x)
    一系列目的都是为了在现有的硬件基础上减少模型计算量、增大模型计算密度等等,所以针对这些需求,就有了“量化”、”剪枝“等优化方法

  • 量化目的
    在这里插入图片描述
    量化指减少模型中计算精度从而减少模型整体计算量的一种方法,计算精度可以分为FP32、FP16、FP8、INT8、INT32等等这些

1)mapping-and-shift(法一:根据缩放比获得偏移量、)

  • 量化针对的是
    ①activation value:每一层的激活值
    ②weight:权重

  • 一般的建议
    一般来说会对conv或者linear这些计算密集型算子进行量化

  • 过程
    在这里插入图片描述

  • 量化会出现的问题
    用256种数据去表现FP32可能出现的数据,有可能会造成表现力下降,需要合理设计dynamic range
    在这里插入图片描述

  • 量化基本原理
    映射和偏移
    ①方法一:根据缩放比获得偏移量
    在这里插入图片描述

  • 使用举例
    在这里插入图片描述

  • 量化公式及公式反推x
    在这里插入图片描述

在这里插入图片描述

(1)NVIDIA默认的mapping就是对称量化(特点就是快)

根据R和Q的dynamic range的选择以及mapping的方式,我们可以分为,对称映射symmetric quantization以及非对称映射asymmetric quantization

  • 对称映射快的原因(就可以把z的过程去掉)
    在这里插入图片描述

2)quantization-granularity 量化粒度及量化方案的选择原因

  • 介绍
    指的是对于一个Tensor,以多大的粒度去共享scale和z,或者dynamic range
  • 介绍图
    在这里插入图片描述
    ①per-tensor quantization:一个tensor共享dynamic range
    优点:1)低延迟:一个tensor共享同一个量化参数
    缺点:1)高错误率:一个scale很难覆盖所有的FP32的dynamic range

②per-channel quantization:一个layer共享dynamic range
优点:1)低错误率:每一个channel都有自己的scale量化系数来体现这个channel中的数据的dynamic range
缺点:1)高延迟:需要用vector来存储每一个channel的scale

③per-element quantization:一个element共享自己dynamic range

  • 学习目的
    ①理解量化粒度是什么
    ②如何正确选择量化粒度
    ③量化力度与精度/计算量/计算效率的关系

  • 量化方案的选择
    ①对于activation values,选择per-tensor量化
    ②对于weights,选择per-channel量化
    1)BN计算和线性计算的融合(BN folding:BN设计初衷是per-channel的,若权重weight用per-tensor的话,会掉精度)
    2)depthwise convolution(它kernel的channel size是1,每一个kernel针对输入的对应channel做卷积,所以每一个channel的参数可能差别比较大,如果用per-tensor的话容易掉精度严重
    在这里插入图片描述
    在这里插入图片描述
    可以看到per-tensor后掉精度很高

3)calibration-algorithm三个校准算法比较、校准数据集和batch size的关系

  • 前提条件
    对于一个训练好的模型,权重是固定的,所以可以通过一次计算就可以得到每一层的量化参数

  • calibration校准的定义
    对于activation value激活值是根据输入的改变而改变的,所以需要通过类似于统计的方式去寻找对于不同类型的输入的不同的dynamic range。这个过程叫校准

  • 评价
    量化粒度一样,不同校准算法的选择很大程度影响精度
    纵轴:出现次数
    横轴:激活值
    在这里插入图片描述

  • 学习目标
    ①理解calibration作用
    ②理解不同calibration algorithm算法的不同点,以及什么时候用哪种算法
    ③calibration和batch size的关系

  • 数据集的考量
    ①针对不同的输入,各层的输入激活值都有不同的分布和取值。大数据集的差别比较大。我们需要通过训练数据集中的一部分数据来尝试表征整个数据集
    ②这个小数据集就是calibration dataset,一般往往很小,但需要尽量有整体的表征

  • 校准的流程思路
    ①一般哦都是模型训练后进行校准,所以都是与PTQ搭配使用

  • 整体校准流程
    1)在calibration dataset中做一次FP32的推理
    2)以histogram的形式去统计每一层的floating point的分布
    ①注意,因为激活值是per-tensor quantization
    ②寻找能够表征当前层的floating point分布的scale
    ③这里会有几种不同的算法:
    常见的如下:

<1>Minmax calibration
<2>Entropy calibration
<3>Percentile calibration
  • 三种校准算法的比较和适用方面:
    1)Minmax calibration:如果floating point的分布比较离线,各个区间的分布都比较均匀,minmax是不错选择,但是如果像上图这个有些数据分布在2.0,会让dynamic range变得非常系数,不适合用minmax
    2)Entropy calibration:通过计算KL散度(相对熵,用来衡量两个概率分布之间的差异),寻找一种threashold(阈值),能够最小化量化钱的FP32的浮点数分布于INT8的量化后整形分布(目前TensorRT默认使用Entropy calibration,一般来讲哦那个Entropy calibration精度可以比较好
    3)Percentile calibration:表示的是FP32中占据99.99%的浮点数参与量化。这样可以避免个别特殊点(误差)参与量化,导致量化出现问题

  • 如何选择calibration algorithm
    weight的calibration ,选用minmax(weight权重比较多变,权重信息比较重要,尽可能让他信息不遗漏)
    ②activation的calibration,选用entropy或者percentile(激活值可能由于输入不同,数据分布导致的误差可能会比较大)
    在这里插入图片描述
    右图表示精度高概率,可以看到用minmax的话,精度掉就比较严重

  • calibration dataset校准数据集和batch size的关系
    填充直方图的时候,若batchsize大于当前histogram可以表示的最大值的时候,TensorRT会直接平方当前hitogram的最大值,来扩大存储空间
    在这里插入图片描述
    1)若最后一个batch的浮点数很大,histogram会呈现很突兀的高峰
    在这里插入图片描述
    在这里插入图片描述

calibration的batch size越大越好,但不是绝对的

2)若每一个batch size的数据分布很均匀,histogram会呈现规则的钟形(或者近似钟形),白哦纤维各个柱子的高度大致相等,整体形状较为平滑对称
3)batchsize=1的精度要比16/32等的要低

4)PTQ-and-quantizatin-analy:优缺点、流程、sensitive analysis原理和具体使用工具(敏感度分析)

  • PTQ定义
    PTQ:Post-Training Quantization,训练后量化

  • 使用思路
    一般是对于训练好的模型,通过calibration算法等获取dynamic range来进行量化。但量化普遍上会产生精度下降。
    在这里插入图片描述

  • 学习目标
    ①理解PTQ和QAT的区别(所处阶段不一样)
    ②PTQ的优缺点
    ③layer-wise sensitive analysis

  • PTQ特点
    不会更新权重,容易产生误差,精度下降可能会比较明显
    ②也叫做隐式量化(implicit quantization),并不显示的对算子添加量化节点(Q/DQ)
    ③trtexec在选择参数进行fp16或者int8指定的时候,使用的就是PTQ(int8的时候需要指定校准数据集)
    靠近输出和输出这两个地方尽量不要做int8量化,这里涉及权重比较少,这时候做scale的话不能满足fp32的权重分布,量化精度会下降严重
    在这里插入图片描述

  • 优缺点
    1)优点:
    ①方便使用,不需要训练,可以在部署设备上直接跑

2)缺点:
①精度下降:PTQ没有QAT这种微调的过程,所以权重不会更新来吸收误差
②量化不可控:(量化模型,精度改变可能会从Tensor core转为Cuda core上

<1>TensorRT会权衡量化后所产生的新添的计算或者访存,是否用INT8还是FP16
<2>TensorRT中的kernel autotuning会选择核函数来做FP16/INT8的计算,来查看是否在CUDAcore上跑还是在Tensor core上跑
<3>有可能FP16是在Tensor core上,但转为INT8之后就在CUDA core上了

③曾融合问题:

<1>量化后有可能出现之前可以融合的曾,不能融合了
<2>量化会添加reformatter这种更改tensor的格式的算子,如果本来融合的两个算子间添加了这个就不能被融合了
<3>比如有些算子支持int8,但某些不支持。之前可以融合的,但因为精度不同不能融合了
  • PTQ问题排查
    如果int8量化后速度反而比FP16/FP32要慢,可以从PTQ的缺点2和3去分析和排查原因

  • PTQ流程
    ①calibration data:准备校准集,大概全部数据的10%,1000章的小数据集
    ②把数据集放到预训练的模型上,统计好每一层layer的信息
    ③对每一层计算,计算每一层量化的scale
    ④把这些scale尽量量化,得到一个量化后的模型

  • 量化中的sensitive analysis(敏感度分析)
    1)sensitive analysis在论文里面是layer-wise sensitive analysis
    2)以精度分析的角度去弥补PTQ的精度下降,可以进行layer-wise的量化分析(参照下图,对这个模型各层进行量化分析,寻找影响精度的层)
    在这里插入图片描述
    右图可以看到对所有层都做量化后精度是72,现在去找每个层的精度/敏感度
    ①如果不做block0depthwise的精度量化,量化精度从72涨到了74.5左右
    ②可以看到改了每个层,影响的精度有多少
    3)最终的模型推理引擎是FP16+INT8精度的
    在这里插入图片描述

  • 学习使用Polygrapy(做TensorRT量化必须掌握,主要是命令行cli操作)
    1)能做的事情:

(1)onnxruntime与TensorRT engine的layer-wise的精度分析
(2)输出每一层layer的权重histogram
(3)截取影响整个网络中对精度影响最大的子网,并用onnx-surgeon单独拿出来

在这里插入图片描述
2)怎么看量化后的conv或者gemm是放在Tensor core还是CUDA core上计算呢?
①使用dlprof:右上角的tensor core 的efficiency和使用tensor core计算的百分比是多少,不支持Jetson系列的Profile
②使用nsight system:可以从核函数的名字去猜整个核函数有没有用tensor core
③使用trtexec
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5)QAT-and-layer-fusion

  • QAT定义
    QAT:Quantization-Aware Training,训练时量化

  • 使用思路
    QAT拿来弥补精度下降,在学习过程中通过Fine-tuning权重来适应这种误差,实现精度下降的最小化。所以一般来说,QAT的精度会高于PTQ。但并不绝对。

  • QAT特点
    ①在学习过程中更新Fine-tuning权重,来适应精度这种误差

  • QAT流程
    ①先拿到一个预训练的模型,添加QDQ节点(就是量化和反量化节点)
    ②结合QDQ节点来微调,不断更新权重
    ③存储scale,把这些scale量化,得到一个量化后的模型

  • 学习目标
    ①理解什么是QAT
    ②理解什么是Q/DQ
    ③理解Q/DQ与算子的融合是如何做的

  • 加入Q/DQ节点示意
    在这里插入图片描述

(1)Q/DQ是什么
  • 定义解释
    也叫做fake quantization node,用来模拟fp32向int8量化的scale和shift(zero-point)信息,以及int8向fp32的反量化的scale和shift(zero-point)

  • Q/DQ节点作用
    通过对Q和DQ node里面存储的信息对fp32或者int8进行线性变化

  • Q/DQ的计算参数和公式
    在这里插入图片描述

clip在右下角表示截取的操作

  • DQ+FP32精度的OP可以拼成一个int8精度的OP
    在这里插入图片描述
    由于这里是对称化计算,所以这里的z为0,也就是位移shift为零
    在这里插入图片描述
(2)可量化层
  • 可量化层介绍
    DQ+FP32精度op+Q的融合,可以称这个op或者layer为quantizable layer,翻译为可量化层
quantization(x') = Sx' * (1/(Sw * Sx)) * Wq * Xq

在这里插入图片描述

  • 备注
    ①可量化层的输入和输出都是int8
    ②计算的主体也是int8,可以节省带宽的同时,提高计算效率

  • DQ+FP32精度op+Q
    这里的op一般指代conv或linear
    在这里插入图片描述

  • 算子融合
    ①conv和Relu融合成为ConvRelu算子
    ②DQ和fp32精度的conv组合,融合成一个int8精度的conv
    ③fp32精度输出的conv和后面的Q也可以融合在一起,输出一个int8精度的activation value

在这里插入图片描述

融合成:QConvRelu和QConv
在这里插入图片描述

  • 备注
    新生成的QConvRelu以及Qconv是int8精度的计算,速度很快并且TensorRT会很大几率分配tensor core执行这个计算。
  • pytorch官方支持对已训练好的模型自动添加Q/DQ节地,详细参考
    在这里插入图片描述
    安装步骤文档
    在这里插入图片描述
(3)TensorRT对包含Q/DQ节点的onnx模型使用很多图优化,从而提高计算效率
  • 主要分为
    1)Q/DQ fusion层融合
    说明:通过层融合,将Q/DQ中的线性计算与conv或者linear这种线性计算融合在一起,实现int8计算
    ①conv和DQ的融合
    ②conv与Q/DQ的融合
    ③conv+DQ+SigmOid+Mul的融合
    ④conv+BN+ReLU+DQ的融合
    ⑤ShotCut+DQ的融合
    在这里插入图片描述

2)Q/DQ Propagation传播 (将尽量多的计算换成int8的)
说明:将Q节点尽量往前挪,将DQ节点尽量往后挪,让网络中的int8计算的部分变得更长
举例说明
在这里插入图片描述
好处:
①int8 计算相比浮点计算通常具有更高的计算效率。通过将更多的计算转换为 int8 类型,可以利用硬件(如特定的加速器)对整数运算的优化,从而加快模型的推理速度;
②int8 数据类型占用的内存空间比浮点数据类型小得多。将更多的计算转换为 int8 类型可以减少内存占用,从而更有效地利用内存带宽。减少数据在内存中的传输量,提高内存访问的效率

(5)部署过程中应该按照什么样子的流程进行QAQ
  • 流程
    1)先进行PTQ
    ①从多种calibration策略选取最佳的算法
    ②查看精度是否满足,不满足则继续下一步
    2)进行partial-quantization(对每一层进行敏感度分析)
    ①用layer-wise的sensitive analysis分析每一层的精度损失
    ②尝试fp16+int8的组合
    ③fp16放在敏感层(网络入口和出口),int8放在计算密集处(网络中间),polygraph去分析得出
    ④查看精度是否满足,不满足则继续下一步
    注意,这里也要看计算效率是否得到满足
    3)进行QAT来通过学习权重来适应误差
    在这里插入图片描述

  • 总体评价
    量化后精度下降控制在相对精度损失<=2%是最好的

  • 流程图
    在这里插入图片描述

(4)QAT的学习过程
  • 目的:主要是训练weight来学习误差
  • 作用:通过训练来学习最好的scale来表示dynamic range

四、模型剪枝(相对于量化另外一种模型压缩方式)

  • 学习目的
    ①理解什么是模型剪枝
    ②模型剪枝的分类
    ③各类剪枝的利弊

  • 为什么需要模型剪枝?
    因为学习的过程会产生过参数化,导致会产生一些意义不是很大的权重,或者值为0的权重(ReLU)。对于这些权重所参与的计算是占用计算资源且没有作用的。我们要想办法找到这些权重,并让硬件去skip掉这些权重参与的计算

  • 大概流程
    ①把一些没用的权重归零,也就是图片里面的白色方框
    ②把不是零的权重压缩,也就是图片的绿色部分,还有生成一些索引,表示哪些权重是归零的
    ③把没归零的权重和激活值计算,那么就可以省去归零权重的计算
    在这里插入图片描述

在这里插入图片描述

  • 正式流程
    ①获取一个已经训练好的初始模型
    ②对这个模型进行剪枝
1)通过训练的方式让DNN去学习哪些权重是可以归零的
2)通过自定义一些规则,手动有规律(先切分成1x4的矩阵,每四个权重中选两个权重归零)

在这里插入图片描述

③对剪枝后的模型进行fine-tuning
在这里插入图片描述

④获得一个压缩的模型
备注如果这个阶段对模型压缩不满足,还可以回到第②步

  • 备注
    ①模型剪枝是可以配合量化一起进行的
    在这里插入图片描述

0)量化和剪枝的比较

①量化:通过改变权重和激活值的表现形式从而让内存占用变小和计算变快
②剪枝:直接删除模型中没有意义的,或者意义比较小的权重,来让推理计算量减少的过程(让某些权重归零)

在这里插入图片描述

1)pruning granularity

(1)模型剪枝分类

①根据剪枝的方法按照一定规律是否可以分为:
1)结构化剪枝:每四个删除几个、根据layer或channel(layer剪枝精度下降比较大)
2)非结构化剪枝:随机删除
②也可以按照剪枝的粒度与强度分为:
1)粗粒度剪枝:跟结构化差不多
2)细粒度剪枝:

(2)粗粒度剪枝(Coarse Grain Pruning)
  • 定义介绍
    这里包括channel / Kernel Pruning,是结构化剪枝(Structured pruning)
    在这里插入图片描述

  • 做法介绍
    直接把某些卷积核给去掉

  • 方法介绍
    通过L1Norm寻找权重中影响度比较低的卷积核

  • 优势
    不依赖于硬件,可以在任何硬件上跑并且获得性能的提升

  • 劣势
    ①由于剪枝粒度大(卷积核级别的),所以有掉精度的风险
    ②不同DNN的层影响程度是不一样的
    剪枝之后有可能反而不适合硬件加速(比如Tensor Core的使用条件是channel是8或者16的倍数)

(3)Fine Grain Pruning(细粒度剪枝)
  • 介绍
    主要是对权重的各个元素本身进行分析剪枝
  • 分类
    结构化剪枝(主流):
    在这里插入图片描述
    在这里插入图片描述

非结构化剪枝:
在这里插入图片描述
在这里插入图片描述

  • 优势
    ①相对比粗粒度剪枝,精度的影响并不是很大

  • 劣势
    ①需要特殊的硬件的支持(Tensor Core可以支持sparse,需要支持sparse计算的硬件)
    ②需要用额外的memory来存储哪些index是可以保留计算的
    ③memory的访问不是非常效率(跳着访问)
    ④支持sparse计算的硬件内部会做一些针对sparse的tensor的重编,这个会比较耗时(重编:要计算哪些要参与计算,哪些不参与计算)

2)channel level pruning

  • 学习目标
    ①理解channel-level pruning的算法
    ②理解如何使用L1-Norm来让权重稀疏
(1)L1和L2的regularization
  • 算法重点
    ①算法侧重点是关注conv和linear这样的op
    把不同conv或linear这样的channel提取出channel scaling factors(表现权重重要性的缩放因子),scaling factors越大,说明这个channel在整个模型的特征提取重要性越大
    ③利用剪枝把scaling factor比较小的channel层删去,得到压缩的网络compact network
    在这里插入图片描述

  • 算法找出scaling factor比较小的channel方法
    使用L1-regularization的训练可以让权重趋向于零这一特点,找到conv中不是很重要的channel,实现channel-level的pruning

  • 思考:为什么L1-regularization可以让权重趋向于零?
    1)数学原理:在模型损失函数中加入L1正则化项后,新的损失函数变为原始损失函数与正则化项之和。当对新损失函数求导并令其导数为零时,由于L1正则化项中权重的绝对值在求导后在零点处不可导,且在零点两侧导数不同,这就使得权重更容易向零靠近(L1正则化项时权重向量中各权重绝对值之和)
    2)稀疏性引导:L1正则化会使模型倾向于选择更少的非零权重,也就是让一些权重变为零,所以在训练过程中权重会逐渐趋向于零
    3)特征选择:当权重趋向于零时,意味着对应的特征对模型的贡献较小或不重要。L1正则化通过让部分权重趋近于零,自动实现了对特征的选择,去除哪些对预测结果影响不大的特征,提高模型的泛化能力和解释性

  • L1和L2的regularization
    在这里插入图片描述
    L1目的:让W1或W2为零的时候就是最优解
    L2目的:让整个权重大小变小是最优解,但是不是变为零

(2)BN中的scaling factor
  • BN作用
    BN一般都是放在conv之后的,对conv的输出进行normalization,整个计算是channel-wise的,所以每一个channel都有自己的BN参数(均值、方差、缩放因子、偏移因子)
  • 进阶作用
    如果BN之后发现某一个channel的scaling很小,或者为零,是不是可以认为这个channel做参与的计算没有非常大强度的改变/提取特征,是不是那么重要
    在这里插入图片描述
    在这里插入图片描述
(3)channel-wise pruning结合BN、L1-Norm对模型的权重计算以及重要度排序
  • 原理
    在channel-wise pruning中,同样使用L1-norm作为惩罚项添加到损失函数loss中,但是L1-norm的参数不再是每一个权重,参数改变成了BN中对于conv中每一个channel的scaling factors。从而在学习的过程中让scaling factor趋向于零,并最终变为零(负的scaling factor会变大,整的scaling factor会变小)

  • 总结步骤
    对于scaling factor不是很大的channel,在剪枝pruning的时候可以把这些channel直接剪枝掉,但同时也需要把这些channel所对应的input/output的计算也skip掉。最终得到一个紧凑版本的网络。通过不断尝试剪枝粒度,找到最好的剪纸百分比(就是把百分之25%排前面比较小的权重删除)

在这里插入图片描述

  • 后续步骤
    ①刚剪枝完的网络,由于权重信息很多都没了,需要fine-tuning来提高精度(需要使用mask
    ②刚剪枝完的channel size可能会让计算密度变低(64ch通过75% pruning后变成16ch)
    在这里插入图片描述
    在这里插入图片描述
(4)channel-level pruning中的超参和技巧
  • 超参
    λ 代表损失函数loss中L1-Norm这个penalty所占的比重,λ 越大整个模型就会越趋近稀疏
    在这里插入图片描述

在这里插入图片描述
可以看到剪枝到70%,模型的偏差就不能容忍了,就算是微调后也不行

在这里插入图片描述

  • pruning的经验
    ①剪枝pruning后的channel尽量控制在64的倍数
    最大化tensor core的使用
    ③对哪些层layer可以大力度的剪枝pruning需要进行sensitive analysis
    ④要记住DNN中那些层是敏感层

3)sparse tensor core

  • 学习目标
    ①理解NVIDIA是如何使用sparse tensor core来处理带有稀疏性的矩阵乘法

  • 介绍在Ampere架构下的A100,Jetson AGX Orin(结构化的细粒度剪枝)
    在这里插入图片描述

  • 举例Dence Tensor core(FP16)和Sparse Tensor core对于计算 A(M,K) * B(K,N) = C(M,N)的过程
    ①可以看到Dence Tensor core在右边需要两个cycle才能完成
    在这里插入图片描述

sparse Tensor core对于右边只需要一个cycle就可以完成计算
在这里插入图片描述

  • 一些sparse的缺点
    ①需要压缩权重
    ②需要存储这些多余的表示哪些权重不需要计算的index,把输入的激活值重构
    ③如果模型不是很大,那么多余的操作延迟会很大,加速不是很可观
    在这里插入图片描述
    纵轴是加速比,参与计算的参数越来越多,那达到的加速比越来越多

五、补充知识点

1)激活函数

  • 激活函数作用
    ①让权重或者激活值控制在某个区域范围内

  • 为什么要控制权重和激活函数在某个范围内?
    ①若权重过大,神经网络可能会过度拟合训练数据,在出现新数据的时候表现不佳
    过大权重也可能会导致梯度爆炸或者消失问题,使得网络的训练变得不稳定(梯度爆炸:反向传播算法中,用于更新神经网络权重的梯度有时候会会变得很大,导致权重的更新幅度异常剧烈)
    ③某些激活函数在输入值过大或过小会出现数值不稳定情况,例如sigmoid在输入值过大或过小,梯度会变得非常小,导致训练缓慢
    ④一些激活函数在特定范围有更好的性能,例如ReLU在正区间有线性特性,计算速度快,并且可以避免梯度小时问题

  • 这里推荐两个激活函数
    ①PACT
    ②ReLU6
    在这里插入图片描述

2)channel-wise和layer-wise

1)channel-wise
含义:指的是在通道维度上进行操作或分析。以卷积神经网络为例,对图像的处理是基于不同的通道分别进行的,如RGB图像的红、绿、蓝三个通道,在channel-wise操作中会对每个通道独立计算,考虑的是通道内的信息整合与处理。
应用:在图像风格迁移中,可通过对不同通道的特征进行调整来改变图像风格。在一些轻量化模型设计中,会采用channel-wise的卷积操作来减少计算量,同时保留重要的通道信息。

2)layer-wise
①含义:是指在层的维度上进行相关操作或分析,关注的是模型中不同层之间的关系和特性。每一层都有其特定的功能和作用,如提取不同层次的特征,layer-wise的操作会涉及到这些层的处理、连接或优化等
②应用:在模型的训练过程中,采用layer-wise的学习率调整策略,根据不同层的特点设置不同的学习率。在模型压缩时,通过分析各层的冗余信息,进行layer-wise的剪枝操作,去除对模型性能影响较小的层或层内的连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值