天天看點

一文搞懂模型量化算法

  • 1,模型量化概述
    • 1.1,模型量化優點
    • 1.2,模型量化的方案
      • 1.2.1,PTQ 了解
    • 1.3,量化的分類
      • 1.3.1,線性量化概述
  • 2,量化算術
    • 2.1,定點和浮點
    • 2.2,量化浮點
    • 2.2,量化算術
  • 3,量化方法的改進
    • 3.1,浮點數動态範圍選擇
    • 3.2,最大最小值(MinMax)
    • 3.3,滑動平均最大最小值(MovingAverageMinMax)
    • 3.4,KL 距離采樣方法(Kullback–Leibler divergence)
    • 3.5,總結
  • 4,量化實戰經驗
  • 參考資料
本文為對目前線性量化優點、原理、方法和實戰内容的總結,主要參考 神經網絡量化簡介 并加以自己的了解和總結,适合初學者閱讀和自身複習用。(正經标題:3-模型量化(低精度)算法總結)。

1,模型量化概述

1.1,模型量化優點

模型量化是指将神經網絡的浮點算法轉換為定點。量化有一些相似的術語,低精度(Low precision)可能是常見的。

  • 低精度模型表示模型權重數值格式為

    FP16

    (半精度浮點)或者

    INT8

    (8位的定點整數),但是目前低精度往往就指代

    INT8

  • 正常精度模型則一般表示模型權重數值格式為

    FP32

    (32位浮點,單精度)。
  • 混合精度(Mixed precision)則在模型中同時使用

    FP32

    FP16

    的權重數值格式。

    FP16

    減少了一半的記憶體大小,但有些參數或操作符必須采用

    FP32

    格式才能保持準确度。

模型量化有以下好處:

參考 TensorFlow 模型優化:模型量化-張益新
  • 減小模型大小:如

    int8

    量化可減少

    75%

    的模型大小,

    int8

    量化模型大小一般為

    32

    位浮點模型大小的

    1/4

    • 減少存儲空間:在端側存儲空間不足時更具備意義。
    • 減少記憶體占用:更小的模型當然就意味着不需要更多的記憶體空間。
    • 減少裝置功耗:記憶體耗用少了推理速度快了自然減少了裝置功耗;
  • 加快推理速度,通路一次

    32

    位浮點型可以通路四次

    int8

    整型,整型運算比浮點型運算更快;

    CPU

    int8

    計算的速度更快
  • 某些硬體加速器如 DSP/NPU 隻支援 int8。比如有些微處理器屬于

    8

    位的,低功耗運作浮點運算速度慢,需要進行

    8bit

    量化。

總結:模型量化主要意義就是加快模型端側的推理速度,并降低裝置功耗和減少存儲空間,

工業界一般隻使用

INT8

量化模型,如

NCNN

TNN

等移動端模型推理架構都支援模型的

INT8

量化和量化模型的推理功能。

通常,可以根據

FP32

INT8

的轉換機制對量化模型推理方案進行分類。一些架構簡單地引入了

Quantize

Dequantize

層,當從卷積或全連結層送入或取出時,它将

FP32

轉換為

INT8

或相反。在這種情況下,如下圖的上半部分所示,模型本身和輸入/輸出采用

FP32

格式。深度學習推理架構加載模型時,重寫網絡以插入

Quantize

Dequantize

層,并将權重轉換為

INT8

格式。

注意,之是以要插入反量化層(

Dequantize

),是因為量化技術的早期,隻有卷積算子支援量化,但實際網絡中還包含其他算子,而其他算子又隻支援

FP32

計算,是以需要把 INT8 轉換成 FP32。但随着技術的疊代,後期估計會逐漸改善乃至消除

Dequantize

操作,達成全網絡的量化運作,而不是部分算子量化運作。
一文搞懂模型量化算法
圖四:混合 FP32/INT8 和純 INT8 推理。紅色為 FP32,綠色為 INT8 或量化。

其他一些架構将網絡整體轉換為

INT8

格式,是以在推理期間沒有格式轉換,如上圖的下半部分。該方法要求算子(

Operator

)都支援量化,因為運算符之間的資料流是

INT8

。對于尚未支援的那些,它可能會回落到

Quantize/Dequantize

方案。

1.2,模型量化的方案

在實踐中将浮點模型轉為量化模型的方法有以下三種方法:

  1. data free

    :不使用校準集,傳統的方法直接将浮點參數轉化成量化數,使用上非常簡單,但是一般會帶來很大的精度損失,但是高通最新的論文

    DFQ

    不使用校準集也得到了很高的精度。
  2. calibration

    :基于校準集方案,通過輸入少量真實資料進行統計分析。很多晶片廠商都提供這樣的功能,如

    tensorRT

    、高通、海思、地平線、寒武紀
  3. finetune

    :基于訓練

    finetune

    的方案,将量化誤差在訓練時仿真模組化,調整權重使其更适合量化。好處是能帶來更大的精度提升,缺點是要修改模型訓練代碼,開發周期較長。

TensorFlow

架構按照量化階段的不同,其模型量化功能分為以下兩種:

  • Post-training quantization

    PTQ

    (訓練後量化、離線量化);
  • Quantization-aware training

    QAT

    (訓練時量化,僞量化,線上量化)。

1.2.1,PTQ 了解

PTQ

Post Training Quantization

是訓練後量化,也叫做離線量化,根據量化零點 x z e r o _ p o i n t x_{zero\_point} xzero_point​ 是否為

,訓練後量化分為對稱量化和非對稱量化;根據資料通道順序

NHWC

(TensorFlow) 這一次元區分,訓練後量化又分為逐層量化和逐通道量化。目前

nvidia

TensorRT

架構中使用了逐層量化的方法,每一層采用同一個門檻值來進行量化。逐通道量化就是對每一層每個通道都有各自的門檻值,對精度可以有一個很好的提升。

1.3,量化的分類

目前已知的加快推理速度機率較大的量化方法主要有:

  1. 二值化,其可以用簡單的位運算來同時計算大量的數。對比從 nvdia gpu 到 x86 平台,1bit 計算分别有 5 到128倍的理論性能提升。且其隻會引入一個額外的量化操作,該操作可以享受到 SIMD(單指令多資料流)的加速收益。
  2. 線性量化(最常見),又可細分為非對稱,對稱和

    ristretto

    幾種。在

    nvdia gpu

    x86

    arm

    和 部分

    AI

    晶片平台上,均支援

    8bit

    的計算,效率提升從

    1

    倍到

    16

    倍不等,其中

    tensor core

    甚至支援

    4bit

    計算,這也是非常有潛力的方向。線性量化引入的額外量化/反量化計算都是标準的向量操作,是以也可以使用

    SIMD

    進行加速,帶來的額外計算耗時不大。
  3. 對數量化,一種比較特殊的量化方法。兩個同底的幂指數進行相乘,那麼等價于其指數相加,降低了計算強度。同時加法也被轉變為索引計算。目前

    nvdia gpu

    x86

    arm

    三大平台上沒有實作對數量化的加速庫,但是目前已知海思

    351X

    系列晶片上使用了對數量化。

1.3.1,線性量化概述

與非線性量化不同,線性量化采用均勻分布的聚類中心,原始浮點資料和量化後的定點資料存在一個簡單的線性變換關系,因為卷積、全連接配接等網絡層本身隻是簡單的線性計算,是以線性量化中可以直接用量化後的資料進行直接計算。

2,量化算術

模型量化過程可以分為兩部分:将模型從 FP32 轉換為 INT8,以及使用 INT8 進行推理。本節說明這兩部分背後的算術原理。如果不了解基礎算術原理,在考慮量化細節時通常會感到困惑。

2.1,定點和浮點

定點和浮點都是數值的表示(representation),它們差別在于,将整數(integer)部分和小數(fractional)部分分開的點,點在哪裡。定點保留特定位數整數和小數,而浮點保留特定位數的有效數字(significand)和指數(exponent)。

絕大多數現代的計算機系統采納了浮點數表示方式,這種表達方式利用科學計數法來表達實數。即用一個尾數(Mantissa,尾數有時也稱為有效數字,它實際上是有效數字的非正式說法),一個基數(Base),一個指數(Exponent)以及一個表示正負的符号來表達實數。具體組成如下:

  • 第一部分為

    sign

    符号位 s s s,占 1 bit,用來表示正負号;
  • 第二部分為

    exponent

    指數偏移值 k k k,占 8 bits,用來表示其是 2 的多少次幂;
  • 第三部分是

    fraction

    分數值(有效數字) M M M,占 23 bits,用來表示該浮點數的數值大小。

基于上述表示,浮點數的值可以用以下公式計算:

( − 1 ) s × M × 2 k (-1)^s \times M \times 2^k (−1)s×M×2k

值得注意是,上述公式隐藏了一些細節,如指數偏移值 k k k 使用的時候需要加上一個固定的偏移值。

比如

123.45

用十進制科學計數法可以表示為 1.2345 × 1 0 2 1.2345\times 10^2 1.2345×102,其中

1.2345

為尾數,

10

為基數,

2

為指數。

單精度浮點類型

float

占用

32bit

,是以也稱作

FP32

;雙精度浮點類型

double

占用

64bit

一文搞懂模型量化算法
圖五:定點和浮點的格式和示例。

2.2,量化浮點

32-bit

浮點數和

8-bit

定點數的表示範圍如下表所示:

資料類型 最小值 最大值

FP32

-3.4e38 3.4e38

int8

-128 128

uint8

255

神經網絡的推理由浮點運算構成。

FP32

INT8

的值域是 [ ( 2 − 2 23 ) × 2 127 , ( 2 23 − 2 ) × 2 127 ] [(2−2^{23})×2^{127},(2^{23}−2)\times 2^{127}] [(2−223)×2127,(223−2)×2127] 和 [ − 128 , 127 ] [−128,127] [−128,127],而取值數量大約分别為 2 32 2^{32} 232 和 2 8 2^8 28 。

FP32

取值範圍非常廣,是以,将網絡從

FP32

轉換為

INT8

并不像資料類型轉換截斷那樣簡單。但是,一般神經網絡權重的值分布範圍很窄,非常接近零。圖八給出了

MobileNetV1

中十層(擁有最多值的層)的權重分布。

一文搞懂模型量化算法
圖八:十層 MobileNetV1 的權重分布。

根據偏移量 Z Z Z 是否為 0,可以将浮點數的線性量化分為兩類-對稱量化和非對稱量化。

當浮點值域落在 ( − 1 , 1 ) (-1,1) (−1,1) 之間,權重浮點資料的量化運算可使用下式的方法将 FP32 映射到 INT8,這是對稱量化。其中 x f l o a t x_{float} xfloat​ 表示 FP32 權重, x q u a n t i z e d x_{quantized} xquantized​ 表示量化的 INT8 權重, x s c a l e x_{scale} xscale​ 是縮放因子(映射因子、量化尺度(範圍)/

float32

的縮放因子)。

x f l o a t = x s c a l e × x q u a n t i z e d x_{float} = x_{scale} \times x_{quantized} xfloat​=xscale​×xquantized​

對稱量化的浮點值和

8

位定點值的映射關系如下圖,從圖中可以看出,對稱量化就是将一個

tensor

中的 [ − m a x ( ∣ x ∣ ) , m a x ( ∣ x ∣ ) ] [-max(|\mathrm{x}|),max(|\mathrm{x}|)] [−max(∣x∣),max(∣x∣)] 内的

FP32

值分别映射到

8 bit

資料的

[-128, 127]

的範圍内,中間值按照線性關系進行映射,稱這種映射關系是對稱量化。可以看出,對稱量化的浮點值和量化值範圍都是相對于零對稱的。

一文搞懂模型量化算法

因為對稱量化的縮放方法可能會将 FP32 零映射到 INT8 零,但我們不希望這種情況出現,于是出現了數字信号進行中的均一量化,即非對稱量化。數學表達式如下所示,其中 x z e r o _ p o i n t x_{zero\_point} xzero_point​ 表示量化零點(量化偏移)。

x f l o a t = x s c a l e × ( x q u a n t i z e d − x z e r o _ p o i n t ) x_{float} = x_{scale} \times (x_{quantized} - x_{zero\_point}) xfloat​=xscale​×(xquantized​−xzero_point​)

大多數情況下量化是選用無符号整數,即

INT8

的值域就為 [ 0 , 255 ] [0,255] [0,255] ,這種情況,顯然要用非對稱量化。非對稱量化的浮點值和

8

位定點值的映射關系如下圖:

一文搞懂模型量化算法

總的來說,權重量化浮點值可以分為兩個步驟:

  1. 通過在權重張量(Tensor)中找到 m i n min min 和 m a x max max 值進而确定 x s c a l e x_{scale} xscale​ 和 x z e r o _ p o i n t x_{zero\_point} xzero_point​。
  2. 将權重張量的每個值從 FP32 轉換為 INT8 。

    x f l o a t ∈ [ x f l o a t m i n , x f l o a t m a x ] x s c a l e = x f l o a t m a x − x f l o a t m i n x q u a n t i z e d m a x − x q u a n t i z e d m i n x z e r o _ p o i n t = x q u a n t i z e d m a x − x f l o a t m a x ÷ x s c a l e x q u a n t i z e d = x f l o a t ÷ x s c a l e + x z e r o _ p o i n t \begin{align} x_{float} &\in [x_{float}^{min}, x_{float}^{max}] \\ x_{scale} &= \frac{x_{float}^{max} - x_{float}^{min}}{x_{quantized}^{max} - x_{quantized}^{min}} \\ x_{zero\_point} &= x_{quantized}^{max} - x_{float}^{max} \div x_{scale} \\ x_{quantized} &= x_{float} \div x_{scale} + x_{zero\_point} \end{align} xfloat​xscale​xzero_point​xquantized​​∈[xfloatmin​,xfloatmax​]=xquantizedmax​−xquantizedmin​xfloatmax​−xfloatmin​​=xquantizedmax​−xfloatmax​÷xscale​=xfloat​÷xscale​+xzero_point​​​

注意,當浮點運算結果不等于整數時,需要額外的舍入步驟。例如将 FP32 值域 [−1,1] 映射到 INT8 值域 [0,255],有 x s c a l e = 2 255 x_{scale}=\frac{2}{255} xscale​=2552​,而 x z e r o _ p o i n t = 255 − 255 2 ≈ 127 x_{zero\_point}= 255−\frac{255}{2}≈127 xzero_point​=255−2255​≈127。

注意,量化過程中存在誤差是不可避免的,就像數字信号進行中量化一樣。非對稱算法一般能夠較好地處理資料分布不均勻的情況。

2.2,量化算術

量化的一個重要議題是用量化算術表示非量化算術,即量化神經網絡中的

INT8

計算是描述正常神經網絡的

FP32

計算,對應的就是反量化過程,也就是如何将

INT8

的定點資料反量化成

FP32

的浮點資料。

下面的等式 5-10 是反量化乘法 x f l o a t ⋅ y f l o a t x_{float} \cdot y_{float} xfloat​⋅yfloat​ 的過程。對于給定神經網絡,輸入 x x x、權重 y y y 和輸出 z z z 的縮放因子肯定是已知的,是以等式 14 的 M u l t i p l i e r x , y , z = x s c a l e y s c a l e z s c a l e Multiplier_{x,y,z} = \frac{x_{scale}y_{scale}}{z_{scale}} Multiplierx,y,z​=zscale​xscale​yscale​​ 也是已知的,在反量化過程之前可預先計算。是以,除了 M u l t i p l i e r x , y , z Multiplier_{x,y,z} Multiplierx,y,z​ 和 ( x q u a n t i z e d − x z e r o _ p o i n t ) ⋅ ( y q u a n t i z e d − y z e r o _ p o i n t ) (x_{quantized} - x_{zero\_point})\cdot (y_{quantized} - y_{zero\_point}) (xquantized​−xzero_point​)⋅(yquantized​−yzero_point​) 之間的乘法外,等式 16 中的運算都是整數運算。

z f l o a t = x f l o a t ⋅ y f l o a t z s c a l e ⋅ ( z q u a n t i z e d − z z e r o _ p o i n t ) = ( x s c a l e ⋅ ( x q u a n t i z e d − x z e r o _ p o i n t ) ) ⋅ ( y s c a l e ⋅ ( y q u a n t i z e d − y z e r o _ p o i n t ) ) z q u a n t i z e d − z z e r o _ p o i n t = x s c a l e ⋅ y s c a l e z s c a l e ⋅ ( x q u a n t i z e d − x z e r o _ p o i n t ) ⋅ ( y q u a n t i z e d − y z e r o _ p o i n t ) z q u a n t i z e d = x s c a l e ⋅ y s c a l e z s c a l e ⋅ ( x q u a n t i z e d − x z e r o _ p o i n t ) ⋅ ( y q u a n t i z e d − y z e r o _ p o i n t ) + z z e r o _ p o i n t M u l t i p l i e r x , y , z = x s c a l e ⋅ y s c a l e z s c a l e z q u a n t i z e d = M u l t i p l i e r x , y , z ⋅ ( x q u a n t i z e d − x z e r o _ p o i n t ) ⋅ ( y q u a n t i z e d − y z e r o _ p o i n t ) + z z e r o _ p o i n t \begin{align} z_{float} & = x_{float} \cdot y_{float} \\ z_{scale} \cdot (z_{quantized} - z_{zero\_point}) & = (x_{scale} \cdot (x_{quantized} - x_{zero\_point})) \cdot (y_{scale} \cdot (y_{quantized} - y_{zero\_point})) \\ z_{quantized} - z_{zero\_point} &= \frac{x_{scale} \cdot y_{scale}}{z_{scale}} \cdot (x_{quantized} - x_{zero\_point}) \cdot (y_{quantized} - y_{zero\_point}) \\ z_{quantized} &= \frac{x_{scale} \cdot y_{scale}}{z_{scale}} \cdot (x_{quantized} - x_{zero\_point}) \cdot (y_{quantized} - y_{zero\_point}) + z_{zero\_point} \\ Multiplier_{x,y,z} &= \frac{x_{scale} \cdot y_{scale}}{z_{scale}} \\ z_{quantized} &= Multiplier_{x,y,z} \cdot (x_{quantized} - x_{zero\_point}) \cdot (y_{quantized} - y_{zero\_point}) + z_{zero\_point} \\ \end{align} zfloat​zscale​⋅(zquantized​−zzero_point​)zquantized​−zzero_point​zquantized​Multiplierx,y,z​zquantized​​=xfloat​⋅yfloat​=(xscale​⋅(xquantized​−xzero_point​))⋅(yscale​⋅(yquantized​−yzero_point​))=zscale​xscale​⋅yscale​​⋅(xquantized​−xzero_point​)⋅(yquantized​−yzero_point​)=zscale​xscale​⋅yscale​​⋅(xquantized​−xzero_point​)⋅(yquantized​−yzero_point​)+zzero_point​=zscale​xscale​⋅yscale​​=Multiplierx,y,z​⋅(xquantized​−xzero_point​)⋅(yquantized​−yzero_point​)+zzero_point​​​

等式:反量化算術過程。

對于等式

10

可以應用的大多數情況, q u a n t i z e d quantized quantized 和 z e r o _ p o i n t zero\_point zero_point 變量 (x,y) 都是

INT8

類型, s c a l e scale scale 是

FP32

。實際上兩個

INT8

之間的算術運算會累加到

INT16

INT32

,這時

INT8

的值域可能無法儲存運算結果。例如,對于 x q u a n t i z e d = 20 x_{quantized}=20 xquantized​=20、 x z e r o _ p o i n t = 50 x_{zero\_point} = 50 xzero_point​=50 的情況,有 ( x q u a n t i z e d − x z e r o p o i n t ) = − 30 (x_{quantized} − x_{zero_point}) = −30 (xquantized​−xzerop​oint​)=−30 超出

INT8

值範圍 [ 0 , 255 ] [0,255] [0,255]。

資料類型轉換可能将 M u l t i p l i e r x , y , z ⋅ ( x q u a n t i z e d − x z e r o _ p o i n t ) ⋅ ( y q u a n t i z e d − y z e r o _ p o i n t ) Multiplier_{x,y,z} \cdot (x_{quantized} - x_{zero\_point}) \cdot (y_{quantized} - y_{zero\_point}) Multiplierx,y,z​⋅(xquantized​−xzero_point​)⋅(yquantized​−yzero_point​) 轉換為 INT32 或 INT16,和 z z e r o _ p o i n t z_{zero\_point} zzero_point​ 一起確定計算結果幾乎全部落入 INT8 值域 [0,255] 中。

對于以上情況,在工程中,比如對于卷積算子的計算,

sum(x*y)

的結果需要用 INT32 儲存,同時,

b

值一般也是

INT32

格式的,之後再

requantize

(重新量化)成

INT8

3,量化方法的改進

量化浮點部分中描述權重浮點量化方法是非常簡單的。在深度學習架構的早期開發中,這種簡單的方法能快速跑通

INT8

推理功能,然而采用這種方法的網絡的預測準确度通常會出現明顯的下降。

雖然 FP32 權重的值域很窄,在這值域中數值點數量卻很大。以上文的縮放為例, [ − 1 , 1 ] [−1,1] [−1,1] 值域中 2 31 2^{31} 231(是的,基本上是總得可表示數值的一半)個 FP32 值被映射到 256 256 256 個 INT8 值。

  • 量化類型:(

    SYMMETRIC

    ) 對稱量化和 (

    NON-SYMMETRIC

    ) 非對稱量化;
  • 量化算法:

    MINMAX

    KL

    散度、

    ADMM

  • 權重量化類型:

    per-channel

    per-layer

采用普通量化方法時,靠近零的浮點值在量化時沒有精确地用定點值表示。是以,與原始網絡相比,量化網絡一般會有明顯的精度損失。對于線性(均勻)量化,這個問題是不可避免的。

同時值映射的精度是受由 x f l o a t m i n x_{float}^{min} xfloatmin​ 和 x f l o a t m a x x_{float}^{max} xfloatmax​ 得到的 x s c a l e x_{scale} xscale​ 顯著影響的。并且,如圖十所示,權重中鄰近 x f l o a t m i n x_{float}^{min} xfloatmin​ 和 x f l o a t m a x x_{float}^{max} xfloatmax​ 附近的值通常是可忽略的,其實就等同于映射關系中浮點值的

min

max

值是可以通過算法選擇的。

一文搞懂模型量化算法
圖十将浮點量化為定點時調整最小值-最大值。

上圖展示了可以調整

min/max

來選擇一個值域,使得值域的值更準确地量化,而範圍外的值則直接映射到定點的 min/max。例如,當從原始值範圍 [ − 1 , 1 ] [−1,1] [−1,1] 中標明 x m i n f l o a t = − 0.9 x_{min}^{float} = −0.9 xminfloat​=−0.9 和 x m a x f l o a t = 0.8 x_{max}^{float} = 0.8 xmaxfloat​=0.8 , [ − 0.9 , 0.8 ] [−0.9,0.8] [−0.9,0.8] 中的值将能更準确地映射到 [ 0 , 255 ] [0,255] [0,255] 中,而 [ − 1 , − 0.9 ] [−1,−0.9] [−1,−0.9] 和 [ 0.8 , 1 ] [0.8,1] [0.8,1] 中的值分别映射為 0 0 0 和 255 255 255。

3.1,浮點數動态範圍選擇

參考幹貨:深度學習模型量化(低精度推理)大總結。

通過前文對量化算數的了解和上面兩種量化算法的介紹我們不難發現,為了計算

scale

zero_point

,我們需要知道

FP32 weight/activation

的實際動态範圍。對于推理過程來說,

weight

是一個常量張量,動态範圍是固定的,

activation

的動态範圍是變化的,它的實際動态範圍必須經過采樣擷取(一般把這個過程稱為資料校準(

calibration

))。

将浮點量化轉為定點時調整最小值/最大值(值域調整),也就是浮點數動态範圍的選擇,動态範圍的選取直接決定了量化資料的分布情況,處于動态範圍之外的資料将被映射成量化資料的邊界點,即值域的選擇直接決定了量化的誤差。

目前各大深度學習架構和三大平台的推理架構使用最多的有最大最小值(

MinMax

)、滑動平均最大最小值(

MovingAverageMinMax

)和

KL

距離(Kullback-Leibler divergence)三種方法,去确定浮點數的動态範圍。如果量化過程中的每一個

FP32

數值都在這個實際動态範圍内,我們一般稱這種為不飽和狀态;反之如果出現某些

FP32

數值不在這個實際動态範圍之内我們稱之為飽和狀态。

3.2,最大最小值(MinMax)

MinMax

是使用最簡單也是較為常用的一種采樣方法。基本思想是直接從

FP32

張量中選取最大值和最小值來确定實際的動态範圍,如下公式所示。

x m i n = { m i n ( X ) i f   x m i n = N o n e m i n ( x m i n , m i n ( X ) ) o t h e r w i s e x_{min} = \left\{\begin{matrix}min(X) & if\ x_{min} = None \\ min(x_{min}, min(X)) & otherwise\end{matrix}\right. xmin​={min(X)min(xmin​,min(X))​if xmin​=Noneotherwise​

x m a x = { m a x ( X ) i f   x m a x = N o n e m a x ( x m a x , m a x ( X ) ) o t h e r w i s e x_{max} = \left\{\begin{matrix}max(X) & if\ x_{max} = None \\ max(x_{max}, max(X)) & otherwise\end{matrix}\right. xmax​={max(X)max(xmax​,max(X))​if xmax​=Noneotherwise​

weights

而言,這種采樣方法是不飽和的,但是對于

activation

而言,如果采樣資料中出現離群點,則可能明顯擴大實際的動态範圍,比如實際計算時

99%

的資料都均勻分布在

[-100, 100]

之間,但是在采樣時有一個離群點的數值為

10000

,這時候采樣獲得的動态範圍就變成

[-100, 10000]

3.3,滑動平均最大最小值(MovingAverageMinMax)

MinMax

算法直接替換不同,MovingAverageMinMax 會采用一個超參數

c

(Pytorch 預設值為0.01)逐漸更新動态範圍。

x m i n = { m i n ( X ) i f x m i n = N o n e ( 1 − c ) x m i n + c    m i n ( X ) o t h e r w i s e x_{min} = \left\{\begin{matrix}min(X) & if x_{min} = None \\ (1-c)x_{min}+c \; min(X) & otherwise\end{matrix}\right. xmin​={min(X)(1−c)xmin​+cmin(X)​ifxmin​=Noneotherwise​

x m a x = { m a x ( X ) i f x m a x = N o n e ( 1 − c ) x m a x + c    m a x ( X ) o t h e r w i s e x_{max} = \left\{\begin{matrix}max(X) & if x_{max} = None \\ (1-c)x_{max}+c \; max(X) & otherwise\end{matrix}\right. xmax​={max(X)(1−c)xmax​+cmax(X)​ifxmax​=Noneotherwise​

這種方法獲得的動态範圍一般要小于實際的動态範圍。對于 weights 而言,由于不存在采樣的疊代,是以 MovingAverageMinMax 與 MinMax 的效果是一樣的。

3.4,KL 距離采樣方法(Kullback–Leibler divergence)

了解 KL 散度方法之前,我們先看下

TensorRT

關于值域範圍門檻值選擇的一張圖:

一文搞懂模型量化算法

這張圖展示的是不同網絡結構的不同

layer

的激活值分布統計圖,橫坐标是激活值,縱坐标是統計數量的歸一化表示,而不是絕對數值統計;圖中有卷積層和池化層,它們之間分布很不相同,是以合理的量化方法應該是适用于不同的激活值分布,并且減小資訊損失,因為從

FP32

INT8

其實也是一種資訊再編碼的過程。

簡單的将一個 tensor 中的 -|max| 和 |max| FP32 value 映射為 -127 和 127 ,中間值按照線性關系進行映射,這種映射關系為不飽和的(No saturation),即對稱的。對于這種簡單的量化浮點方法,試驗結果顯示會導緻比較大的精度損失。

通過上圖可以分析出,線性量化中使用簡單的量化浮點方法導緻精度損失較大的原因是:

  • 上圖的激活值統計針對的是一批圖檔,不同圖檔輸出的激活值不完全相同,是以圖中是多條曲線而不是一條曲線,曲線中前面一部分資料重合在一起了(紅色虛線),說明不同圖檔生成的大部分激活值其分布是相似的;但是在曲線的右邊,激活值比較大時(紅色實作圈起來的部分),曲線不重複了,一個激活值會對應多個不同的統計量,這時激活值分布是比較亂的。
  • 曲線後面激活值分布比較亂的部分在整個網絡層占是占少數的(比如 1 0 − 9 10^-9 10−9, 1 0 − 7 10^-7 10−7, 1 0 − 3 10^-3 10−3),是以曲線後面的激活值分布部分可以不考慮到映射關系中,隻保留激活值分布的主方向。

一般認為量化之後的資料分布與量化前的資料分布越相似,量化對原始資料資訊的損失也就越小,即量化算法精度越高。

KL

距離(也叫

KL

散度)一般被用來度量兩個分布之間的相似性。這裡的資料分布都是離散形式的,其離散資料的 KL 散度公式如下:

D K L ( P ∥ Q ) = ∑ i P ( i ) l o g a P ( i ) Q ( i ) = ∑ i P ( i ) [ l o g P ( x ) − l o g Q ( x ) ] D_{KL}(P \| Q) = \sum_i P(i)log_{a} \frac{P(i)}{Q(i)} = \sum_i P(i)[logP(x) - log Q(x)] DKL​(P∥Q)=i∑​P(i)loga​Q(i)P(i)​=i∑​P(i)[logP(x)−logQ(x)]

式中 P 和 Q 分布表示量化前 FP32 的資料分布和量化後的 INT8 資料分布。注意公式要求 P、Q 兩個統計直方圖長度一樣(也就是 bins 的數量一樣)。

TensorRT 使用 KL 散度算法進行量化校準的過程:首先在校準集上運作 FP32 推理,然後對于網絡每一層執行以下步驟:

  1. 收集激活輸出的直方圖。
  2. 生成許多具有不同飽和度門檻值的量化分布。
  3. 選擇最小化 KL_divergence(ref_distr, quant_distr) 的門檻值

    T

    ,并确定

    Scale

以上使用校準集的模型量化過程通常隻需幾分鐘時間。

3.5,總結

  • 對稱的,不飽和的線性量化,會導緻精度損失較大;
  • 通過最小化

    KL

    散度來選擇 飽和量化中的 門檻值

    |T|

    ;

4,量化實戰經驗

參考【商湯泰坦公開課】模型量化了解一下?

1,量化是一種已經獲得了工業界認可和使用的方法,在訓練 (Training) 中使用

FP32

精度,在推理 (Inference) 期間使用

INT8

精度的這套量化體系已經被包括

TensorFlow

TensorRT

PyTorch

MxNet

等衆多深度學習架構和啟用,地平線機器人、海思、安霸等衆多

AI

晶片廠商也在深度學習工具鍊中提供了各自版本的模型量化功能。

2,量化是一個大部分硬體平台都會支援的,是以比較常用;知識蒸餾有利于獲得小模型,還可以進一步提升量化模型的精度,是以這個技巧也會使用,尤其是在有已經訓好比較強的大模型的基礎上會非常有用。剪枝用的會相對較少,因為可以被網絡結構搜尋覆寫。

參考資料

  • NCNN Conv量化詳解(一)
  • 卷積神經網絡優化算法
  • 神經網絡量化簡介
  • QNNPACK 實作揭秘
  • 《8-bit Inference with TensorRT》

繼續閱讀