目录
前言
自动驾驶之心推出的 《CUDA与TensorRT部署实战课程》,链接。记录下个人学习笔记,仅供自己参考
本次课程我们来学习课程第四章—TensorRT 模型部署优化,一起来了解量化的一些基本概念和基本原理
课程大纲可以看下面的思维导图
0. 简述
本小节目标:理解什么叫做量化,PTQ 和 QAT 的区别,calibration 的种类,Per-tensor 量化与 Per-layer 量化,量化的一些技巧,掉精度时需要做的事情,量化与融合优化以及多余算子
这节课程给大家讲解第四章节第三小节—量化,量化在模型部署中属于比较重要的环节,因此我们这里会分几节课程来跟大家依次讲解关于量化的一些比较细致的地方。
本次课程主要跟大家讲解量化的一些基本概念和专业术语的解释,我们会跟大家解释什么叫做量化以及 PTQ 和 QAT 的区别,calibration 的种类有哪些如何去选择,量化粒度又该如何选择是 per-tensor 方式去量化还是 per-layer 的方式去量化呢,量化中存在哪些技巧呢,量化激活函数如何选择,敏感层分析该如何做呢?当量化后的模型精度损失严重时我们需要做哪些事情来减少量化后精度的损失呢?QAT 量化时融合优化怎么做以及多余算子该如何减少呢?
这些都是我们在量化这个小节中要去解决的问题,下面我们正式开始量化的学习
1. 近10年模型的变化与硬件的发展
首先我们先看几个背景知识,来看看近 10 年模型的变化与硬件的发展趋势,先看看模型的变化趋势如下图所示:
从上图中我们能看到 DNN 模型的大小几乎在以每年 10 倍的 FLOPs 在增长,相反硬件的性能却以仅每年 0.74 倍 FLOP/s 的速度增长,如下图所示:
从上面的图中可以看出相比于模型的发展,硬件的发展速度很慢,而且即便硬件有了还需要有相对应的编译器,有了基本的编译器后还需要有编译器的优化(TensorRT 3.x~10.x 的演变),还需要有一套其他的 SDK,比如 onnx-graphsurgeon、polygraphy 等等
比如 Vision Transformer 虽然在 2020 年左右兴起了,但是真正在硬件上达到如同现在的 CNN 的优化效果可能还需要 8~10 年时间
因此大家一般会考虑如何在现有的硬件基础上减少模型计算量、增大模型计算密度,所以针对这些需求就有了量化(quantization)、剪枝(pruning)等等这些优化方法
2. 模型量化回顾
我们先来回顾下模型量化的一些数据格式,存储 FP32 需要 4 个字节,但存储 INT8 只需要一个字节,因为训练的时候,我们想训练到非常细节的部分,所以我们使用 FP32,当然现在也有将 FP32 和 FP16 结合的 Mixed-precision Training 混合精度训练。但是如果我们在部署的时候只用 8 个 bit 就把 FP32 的数据给表现出来,那么计算量以及能耗消耗不就更好?模型量化就是做这个的
3. 什么是量化
模型量化是通过减少模型中计算精度从而减少模型整体的计算量的一种方法,计算精度可以分为 FP32、FP16、FP8、INT8、INT32、TF32 这些
量化主要针对的是
- activation value:激活值
- weight:权重值
所以一般来说我们在讲量化时主要是针对 conv 或者 linear 这些计算密集型算子进行量化
上图展示了量化和反量化的整个过程,首先我们的数据一般是以浮点数的方式进行存储的,经过量化变成 INT8 以整数方式进行存储,最后反量化成 FP32 还原成之前的精度
4. 量化会出现什么问题
那我们思考下量化会出现什么问题呢?上面说的经过量化和反量化过程中恢复的数据还能和之前的数据一样吗?我们先来看不同精度下的动态范围(dynamic range),如下图所示:
如果说我们仅仅用 INT8 的 256 种数据去表示 FP32 的所有可能出现的数据,有可能会造成表现力下降,如下图所示:
最上面的绿色的图我们可以理解为权重的分布图,可以看到它的分布近似于正态分布,它的精度是 FP32,我们找到它的最大值和最小值后将它映射到 INT8 的空间,即中间的图所展示的。由于 INT8 只有 256 个数据,所以其中的每一个数据都会用来表示 FP32 一片空间内的数据,很多 FP32 的数据会共享到 INT8 中的一个值,再反量化回 FP32 时可能会发现其中的数据不再是非常连续的,而是断开的,即最下面的图所展示的
所以如何能够比较完美的用这 256 个数据去最大限度的表现 FP32 的原始数据分布,是量化的一个很大挑战。换句话说,就是如何合理的设计这个 dynamic range 是量化的重点
5. 量化的基本原理:映射和偏移
在讲量化原理之前我们先来看一个简单的例子:
R
:
{
x
∣
x
∈
[
−
100
,
0
]
,
x
∈
Z
}
Q
:
{
y
∣
y
∈
[
0
,
20
]
,
y
∈
Z
}
R{:}\{x|x\in[-100,0],x\in Z\}\\Q{:}\{y|y\in[0,20],y\in Z\}
R:{x∣x∈[−100,0],x∈Z}Q:{y∣y∈[0,20],y∈Z}
倘若我们想把 R 中的数据用 Q 来表示,如何做呢?
方法一:
我们可以先根据 R 和 Q 中 x 和 y 可以取的最大值和最小值,计算得到一个缩放比(ratio):
r
a
t
i
o
=
(
R
m
a
x
−
R
m
i
n
)
(
Q
m
a
x
−
Q
m
i
n
)
ratio=\frac{(R_{max}-R_{min})}{(Q_{max}-Q_{min})}
ratio=(Qmax−Qmin)(Rmax−Rmin)
以及缩放后的 R 要在 Q 的范围中显示所需要的偏移量(distance):
d
i
s
t
a
n
c
e
=
Q
m
i
n
−
R
m
i
n
r
a
t
i
o
distance=Q_{min}-\frac{R_{min}}{ratio}
distance=Qmin−ratioRmin
最终,通过 ratio 和 distance 得到
x
x
x 和
y
y
y 的关系:
y
=
x
r
a
t
i
o
+
d
i
s
t
a
n
c
e
y=\frac{x}{ratio}+distance
y=ratiox+distance
我们根据上面的方法一来计算缩放比 ratio 和偏移量 distance 如下所示:
r
a
t
i
o
=
(
R
m
a
x
−
R
m
i
n
)
(
Q
m
a
x
−
Q
m
i
n
)
=
100
20
=
5
d
i
s
t
a
n
c
e
=
0
−
−
100
5
=
20
\begin{aligned}&ratio=\frac{(R_{max}-R_{min})}{(Q_{max}-Q_{min})}=\frac{100}{20}=5\\&distance=0 -\frac{-100}{5}=20\end{aligned}
ratio=(Qmax−Qmin)(Rmax−Rmin)=20100=5distance=0−5−100=20
其中缩放比 ratio 等于 5,而偏移量 distance 等于 20,对于 ratio 和 distance 我们可以理解为 Q 中每一个元素可以代表 R 中每 5 个元素,并且偏移量是 20
那我们来思考一个问题,如果说可以通过公式 y = x r a t i o + d i s t a n c e y=\frac{x}{ratio}+distance y=ratiox+distance 将 R 中的数据映射到 Q 中的话,那么我们按照 x = ( y − d i s t a n c e ) ∗ r a t i o x = (y-distance)*ratio x=(y−distance)∗ratio 公式反着计算是不是可以通过 Q 中的数据得到 R 呢?
我们将
y
y
y 取不同值时
x
x
x 的取值简单罗列一下,如下所示:
y
=
0
,
x
=
−
100
y
=
1
,
x
=
−
95
y
=
2
,
x
=
−
90
y
=
3
,
x
=
−
85
y
=
4
,
x
=
−
80
.
.
.
y=0,x=-100\\y=1,x=-95\\y=2,x=-90\\y=3,x=-85\\y=4,x=-80\\...
y=0,x=−100y=1,x=−95y=2,x=−90y=3,x=−85y=4,x=−80...
我们之前有讲过量化映射之后数据有可能是不连续的,有些数据可能会有丢失,从上面的取值我们就可以发现这个问题,相比于原本 R 中的 101 个数据,如今我们只能够得到 R 中的 21 个数据,比如说 -96,-93,-81 这种不能被 ratio 整除的数据是无法得到的
那么我们思考下上面这种计算缩放比和偏移量的方法是否可行?如果不可行,那么问题出现在哪里呢?该如何解决呢?
我们来看几个案例分析下,R 中的数据分布可能存在多种情况,下面我们简单列举了几种:
example1:R 中的数据分布不均匀,随机出现在 -100 到 0 中,如下图所示:
example2:R 中的数据呈现高斯分布,主要集中在 -80 到 20 中,如下图所示:
example3:R 中的数据呈现高斯分布,主要集中在 -65 到 -45 中,如下图所示:
example4:R 中的数据呈现高斯分布,主要集中在 -30 到 -15 中,如下图所示:
很明显,虽然上述的 4 个 example 中数据都呈现在 -100 到 0 中,但是由于数据的分布形式不同,如果我们统一都用一种 ratio 和 distance 的话会有很大的误差
我们接着来分析下这几种情况下的误差:
example1:R 中的数据分布不均匀,随机出现在 -100 到 0 中
这个时候因为数据分布不均匀,所以将 -100 到 0 均分为 20 个部分映射到 Q 中是可以接受的,误差也会比较小
example2:R 中的数据呈现高斯分布,主要集中在 -80 到 20 中
这个时候 R 中的数据分布是属于正态分布,所以数据主要集中在靠拢中间的部分,靠近边缘的数据出现的概率比较低,如果依然等分为 20 个部分的话,靠近中间的数据会出现比较大的误差。
example3:R 中的数据呈现高斯分布,主要集中在 -65 到 -45 中
这个时候 R 中的数据分布是属于正态分布,所以数据主要集中在靠拢中间的部分,但是由于方差比较大,所以接近两侧的数据几乎没有,如果按照 20 个部分分配的话,Q 中 0~5,15~20 所代表的数字没有意义。
example4:R 中的数据呈现高斯分布,主要集中在 -30 到 -15 中
这个时候 R 中的数据分布是属于正态分布,所以数据主要集中在靠拢中间的部分,但是由于方差比较大,以及均值有所偏移,所以 R 中 -100 到 -30 这段区域几乎没有,将这段区域映射到 Q 中是没有意义的
所以为了能够让 R 到 Q 的映射合理,以及将 Q 中的数据还原为 R 时误差能够控制到最小,我们需要根据 R 中的数据分布合理的设计这个 ratio 和 distance,如下图所示:
6. 量化的基本原理:基本术语
6.1 量化和反量化
目前为止我们所做的事情其实就是所谓的量化,我们稍微把一些概念和术语给整理一下:
-
R 是一组 FP32 的数据,能够表现的数据种类有很多,大约是 2 32 2^{32} 232 种(4 亿),范围是: − 1.2 ∗ 1 0 − 38 ∼ 3.4 ∗ 1 0 38 -1.2 * 10^{-38}\sim3.4 * 10^{38} −1.2∗10−38∼3.4∗1038
-
Q 是一组 INT8 的数据,只能够表现 2 8 2^8 28 种数据(256),范围是 -128~128 或 0~255
-
R 到 Q 的映射的缩放因子 scale 的计算公式为: s c a l e = ( R m a x − R m i n ) ( Q m a x − Q m i n ) \mathrm{scale} = \frac{(R_{max}-R_{min})}{(Q_{max}-Q_{min})} scale=(Qmax−Qmin)(Rmax−Rmin)
-
R 缩放之后映射到 Q 时,所需要的偏移量 z 为: z = Q m i n − R m i n r a t i o z=Q_{min}-\frac{R_{min}}{ratio} z=Qmin−ratioRmin
-
R 中每一个元素转移到 Q 的过程称为量化(Quantization),公式是: Q i = R i s c a l e + z Q_{i}=\frac{R_{i}}{scale}+z Qi=scaleRi+z
-
Q 空间中一个元素转换回 R 空间的过程称为反量化(Dequantization),公式是: R i = ( Q i − z ) ∗ s c a l e R_{i}=(Q_{i}-z)*scale Ri=(Qi−z)∗scale
6.2 对称量化和非对称量化
根据 R 和 Q 的动态范围(dynamic range)的选择以及映射(mapping)的方式我们可以将量化分为对称量化(symmetric quantization)和非对称量化(asymmetric quantization)
Note:对称量化的另一个叫法是 Scale Quantization,非对称量化的另一个叫法是 Affine Quantization,这两个称呼是比较早期的,大家在读论文遇到时可以注意一下
对称量化中量化前后的数据分布是以 0 为界限对齐的,所以不会有偏移量(z/shift)的存在,这个可以让量化过程的计算简单。NVIDIA 默认的 mapping 就是对称量化,因为快!
6.3 量化粒度
量化中还有一个非常重要的概念:量化粒度(Quantization Granularity),它指的是对于一个 tensor 以多大的粒度去共享 scale 和 z 或者 dynamic range,常见的量化粒度主要有以下几种:
- per-tensor quantization:一个 tensor 中所有的 element 共享同一个 dynamic range
- per-channel quantization:一个 tensor 中每一个 channel 都有一个自己的 dynamic range
- per-element quantization(element-wise quantization):一个 tensor 中每一个 element 都有一个自己的 dynamic range
下图更加形象的对比展示了这几种不同的量化粒度:
不同的量化粒度的选择会很大程度影响模型的性能和精度!这个我们下节课再详细跟大家介绍
6.4 校准
量化中另外一个非常重要的概念叫校准(Calibration),对于一个训练好的模型权重是固定的,所以通过一次计算就可以得到每一层的量化参数。但是 activation value(激活值)是根据输入的改变而改变的,所以需要通过类似于统计的方式去寻找对于不同类型的输入的不同的 dynamic range,这个过程叫做校准
对于某一个 tensor 的 histogram,不同的校准算法所截取的范围不同
跟量化粒度一样,不同的校准算法的选择会很大程度影响精度,具体细节我们留在下下节课讲
6.5 PTQ和QAT
根据量化的时机,一般我们会把量化分为
- PTQ(Post-Training Quantization),训练后量化
- QAT(Quantization-Aware Training),训练时量化
PTQ 一般是指对于训练好的模型,通过 calibration 算法来获取 dynamic range 来进行量化。但量化普遍上会产生精度下降,所以 QAT 为了弥补精度下降,在学习过程中通过 Fine-tuning 权重来适应这种误差,实现精度下降的最小化。所以一般来讲,QAT 的精度会高于 PTQ,但并不绝对。
PTQ 和 QAT 我们会分两节课来讲解,具体细节我们留在下下下节课讲解
7. 其他:有关量化学习的激活函数
最后一个题外话,我们来看下有关量化的激活函数,量化学习是一个 Fine-tuning 的过程,那么选取什么样子的激活函数会更好呢?我们可以结合量化的特性去思考,我们希望整个学习过程让权重或者激活值控制在某个区域范围内,所以我们需要实现某种 Clipping,这里推荐两个激活函数:
- PACT(Paramertized Clipping Activation Function)
- ReLU6
大家可能对 ReLU6 比较熟悉,其公式如下:
R
e
L
U
6
=
min
(
6
,
max
(
0
,
x
)
)
ReLU6=\min(6,\max(0,x))
ReLU6=min(6,max(0,x))
大家不清楚的可以回顾下 MobileNetV2 这篇 paper,而对于 PACT 的介绍推荐大家阅读一下 IBM 的论文 PACT,这里就不展开讲了,其公式如下:
y
=
P
A
C
T
(
x
)
=
0.5
(
∣
x
∣
−
∣
x
−
α
∣
+
α
)
=
{
0
,
x
∈
(
−
∞
,
0
)
x
,
x
∈
[
0
,
α
)
α
,
x
∈
[
α
,
+
∞
)
y=PACT(x)=0.5(|x|-|x-\alpha|+\alpha)=\begin{cases}0,&x\in(-\infty,0)\\x,&x\in[0,\alpha)\\\alpha,&x\in[\alpha,+\infty)\end{cases}
y=PACT(x)=0.5(∣x∣−∣x−α∣+α)=⎩
⎨
⎧0,x,α,x∈(−∞,0)x∈[0,α)x∈[α,+∞)
总结
本次课程我们主要学习了模型量化的一些背景知识介绍,我们学习了量化是什么,量化出现的问题,以及量化的基本原理(映射和偏移)。随后我们简单了解了下量化的一些基本术语包括量化和反量化,对称量化和反对称量化,最后我们分享了后续量化课程要学习的内容包括量化粒度、校准、PTQ 和 QAT。
OK,以上就是量化第 1 部分有关映射和偏移的全部内容了,下节我们来学习量化粒度,敬请期待
标签:distance,20,shift,mapping,TensorRT,量化,数据,我们,ratio From: https://blog.csdn.net/qq_40672115/article/details/139717214