總歸來說 Data-Free Quantization (DFQ) 的目的是讓 floating model 做 weights 各種調整, 使得不管是 weights or activations 都變得適合 per tensor 量化.這樣理想上就不需用到 per channel 量化, 因為 per channel 雖然效果很好, 但硬體比較不友善, 且花的運算量較高. 另外 DFQ 屬於 Post-Training Quantization (PTQ) 方法. PTQ 對佈署到 edge 端很方便, 但一般來說 PTQ 都不如 Quantization-Aware Training (QAT) 的效果好, 因此 DFQ 嘗試提升效果.
- Cross-Layer Equalization (CLE): 輸入 fused BN 後的 float model M1f, floating 操作對 weights 做調整使得更均衡方便 per tensor 量化, 為 step 3 的前置作業, 輸出仍為 float model M2f.
- Bias Absorption (BA): 輸入 CLE 後的 float model M2f, floating 操作對 activations 做調整使得更均衡方便 per tensor 量化, 為 step 3 的前置作業, 輸出仍為 float model M3f.
- PTQ 量化: 輸入 CLE+BA 後的 float model M3f, 此時不管 weights or activations 都適合做 per-tensor 量化了, 所以直接 PTQ 輸出 int model M1i.
- Bias Correction (BC): 輸入 float model M1f 和 step 3 的 M1i, 並且(option)給一些 unlabeled 的代表 data, BC 會對 M1i 的 bias 參數補償因為量化造成的數值 mean 偏移, 輸出為最終 fixed point model M2i.
Qualcomm AI Lab 的 tool AIMET 說 BC 這一步驟可以用 AdaRound (需要一小部分的 unlabelled training data) 取代
其實認真看完論文, 覺得限制有點多啊! 很多時候不能套 CLE, 有時 BA 也用不了. 把限制條列一下:
⚠️ CLE 限制:
1. Activation functions f(⋅) 需為 piece-wise linear (e.g. ReLU, ReLU6, LeakyReLU, …)
2. 如果有 BN (Batch normalization) layer, 先把它 fuse 到 Conv 裡面, 所以第3點的限制才可以忽略 BN layer.
3. 相鄰的 layers 只能很單純是 f(W(2)f(W(1)x+b(1))+b(2)), 所以如果有 residual add 或 concat 才給 W(2) 作用的話就不行.
⚠️ BA 限制:
1. activations 的每個維度是高斯分佈, 或能取得其分布, 例如透過 observer
; 但在 AIMET 工具是假設有 BN 所以是高斯分布, 否則不用套用 BA
2. Activation functions f(⋅) 需為 ReLU (or ReLU6), LeakyReLU 這種不行
⚠️ BC 限制:
Empirical BC 需要給 representative data (可以是 unlabeled). 如果 Analytical BC (data-free) 則需有 BN —> ReLU —> Conv/FC 這樣順序的假設才能補償因 quantize 後 Conv/FC 這層輸出的 mean 偏移
接著我們描述一下 CLE, BA 和 BC 的動機, 然後再詳細介紹論文提出的這三個方法
Motivation
CLE 動機
Convolution kernels 在不同 output channels 來看, weights 的分佈有些很大有些很小, 這使得用統一一個 quantization parameter set 會不好. 所以如果能事先讓 weights 在不同 channel 的數值分佈接近, 這樣就適合用 per tensor quantization 了. 為此作者提出 Cross-Layer Equalizaiton (CLE) 方法. 圖來源為 AIMET Post-Training Quantization Techniques
BA 動機
不過做了 CLE 有個 side-effect 就是讓 activations 有可能反而不同 channels 分佈變的更不同, 為此作者提出 Bias Absorption (BA) 方法使得 activations 同樣適合 per-tensor quant.
BC 動機
另一方面, 其實 weights or input activations 經過 quantization 後, output activations 理想上希望是 un-biased, 但實際上都會有 bias, 如下圖
E[˜yj−yj]≈1N∑n(˜Wxn)j−(Wxn)j
Data Free Quantization (DFQ) 詳細解釋
Cross-Layer Equalization (CLE), 幫助 weights per-tensor 量化
對任何 s>0, 且 f(⋅) 是 piece-wise linear activation function:
f(x)={a1x+b1if x≤c1a2x+b2if c1<x≤c2⋮anx+bnif cn−1<x
這麼做有什麼好處呢? 考慮以下的情形
給定兩個相鄰的 layers: h=f(W(1)x+b(1)) 和 y=f(W(2)h+b(2)), 其中 f 是 piece-wise linear activation function.
則我們有:
y=f(W(2)f(W(1)x+b(1))+b(2))=f(W(2)Sˆf(S−1W(1)x+S−1b(1))+b(2))=f(ˆW(2)f(ˆW(1)x+ˆb(1))+b(2))
所以我們重新縮放了 weights: ˆW(2)=W(2)S, ˆW(1)=S−1W(1) and ˆb(1)=S−1b(1).
那麼怎麼設定最佳的 S 呢? 理想上, 透過 S 我們希望將 ˆW(1),ˆW(2) 變成適合 per tensor quantization.
- 定義 r(1)i:=max(W(1)i,:), 即為 W(1) 的 ith row vector 取 max.
- 同理 ˆr(1)i:=max(ˆW(1)i,:)=r(1)i/si.
類似地我們定義
- r(2)j:=max(W(2):,j), 即為 W(2) 的 jth column vector 取 max.
- ˆr(2)j:=max(ˆW(2):,j)=sj⋅r(2)j.
注意到一個是 row vector 另一個是 column vector 這是因為 W(1) 的 row vector 對應的是 W(2) 的 column vector. 即第一層 layer 的 output channel 對應的是第二層 layer 的 input channel 的概念
然後再令整個 weight matrix 的最大值為: R(1):=maxi(r(1)i) 和 R(2):=maxj(r(2)j)
大概示意圖長這樣子 最後就可以定義每一個 channel (1~m) 對於整個 weight matrix 的占比:
p(1)i=r(1)i/R(1); ˆp(1)i=ˆr(1)i/ˆR(1); 同理 p(2)j,ˆp(2)j
到這裡不難理解, 只是很多 terms 要消化一下而已
p(1)i 表示 ith row vector 對整個 matrix W(1) 的佔比, 想像上如果每個 rows 的佔比都很大, 那就整體適合 per-tensor quantization.
可以想像, 若 ˆp(1)i 比 p(1)i 大表示 ith row vector 的佔比經過 si 的調整變大, 但由於 si 在 W(1) 用除的但在 W(2) 用乘的, 導致 ˆp(2)i 比 p(2)i 小了, 意思是 ith column vector 的佔比反而變小. 所以一邊變大了但反而使另一邊變小了, 這一定是個 trade-off.
所以我們希望兩邊都顧到 (ˆp(1)iˆp(2)i 一起考慮) , 作者就定義了這樣的目標函式:
maxS∑iˆp(1)iˆp(2)i
這個問題的最佳解在論文的 Appendix A 有證明, 我們先把解寫出來:
si=1r(2)i√r(1)ir(2)i
詳細證明記錄在最後的 Appendix (論文證明有些沒懂補充一下自己想法).
Bias Absorption (BA), 幫助 activation per-tensor 量化
再說之前, 先了解以下範例.
首先對於 ReLU r(⋅) 來說一定存在一個 non-negative vector c 使得 ∀x
r(Wx+b−c)=r(Wx+b)−c;∀x(⋆)
舉一個簡單範例, 考慮某一個 channel i, data Wxi 的機率分佈為直角三角形: 當 b=3 的情況時, 則選 c=0.5 滿足 (⋆) 條件, 見下圖:
這個情況會滿足所有 x, 但如果 Wx 的分布不像範例一定大於某一個值 (想像上面的直角三角形分布變成高斯分佈) 則我們只能選擇滿足大部份的值
如果是高斯分佈的話 (則 Batch norm 的 mean, std 就可拿來用), 論文選擇 3 個標準差所以保證 99.865% 滿足. 高斯分佈在 μ±3σ 內的機率約為 0.9973002 [ref], 但由於我們要找的 c 只會忽略 <μ−3σ 的情況所以是 1−(1−0.9973002)/2≈99.865, 之後會有圖示比較清楚
有了以上概念後, 回頭過來看看經過 CLE 後還會發生什麼現象, 其中 r(⋅) 是 ReLU.
(突然渲染不出數學式子…煩阿) ˆW(1) and ˆW(2) 已經被 CLE 調整一波後數值分佈變得很接近 (適合 per-tensor quantization 👏🏻)
但 ˆb(1)=S−1b(1), 當 si<1 的時候會讓 channel i 的 activation 放大導致 activations, ˆW(1)x+ˆb(1), 的各 channel 之間分佈位置會不同, 因此也會讓 activations 不好做 quantization!
利用上面說的概念我們這樣推導: 其中 b⋆(1)=ˆb(1)−c 和 b⋆(2)=ˆW(2)c+b(2).
💡 目的是把 ˆW(1)x+ˆb(1) 從不適合做 per-tensor quant 變成 ˆW(1)x+b⋆(1) 容易做 per-tensor quant.
則 c 可以選擇盡量滿足所有 ˆW(1)x+ˆb(1) 的值, 要這麼做最暴力的方式是餵所有 training data 去看資料分布, 選擇滿足大部分的情況, 例如滿足 99.99% 的數值.
另外如果我們知道 ˆW(1)x+ˆb(1) 會再經過 Batch normalization, i.e. BN(ˆW(1)x+ˆb(1)) 只是 BN 忽略不寫而已, 則令 c=max(0,β−3γ), 其中 β,γ 分別是 Batch normalization 的 shift and scale parameters, 這樣直接就滿足大於-3標準差的 99.865% 機率了.
開頭的 DFQ 流程圖有先做 BN folding, 所以此時的 ˜W(1) 已經是 folding 後的, 因此要事先把 β,γ 存起來才能在這步驟用
我們來思考為啥 activations 從 ˆW(1)x+ˆb(1) 變成 ˆW(1)x+b⋆(1) 後就會比較好做 per-tensor quantization, 這是因為我們選擇的這些 ci 會讓維度 i 的 activation 對齊到剛好有 99.865% 大於 0, 而每個維度都依這樣的標準 align 自然就容易對整個 activations 做 quantization 了 (不需要 per-channel quant 了)!
圖示一下上面的意思, 為了方便令 ˆk=ˆW(1)x+ˆb(1), 其中 ˆki 表示第 i 維, 同理 k⋆=ˆW(1)x+b⋆(1) 和 k⋆i: 注意到雖然 activations k⋆ 適合 per-tensor quant 了, 但我們只是把這困難 pass 到 b⋆(2), 為啥這麼說呢? 因為 b⋆(2) 需要多加一項 ˆW(2)c, 但我們並不做任何保證 ,因此 activations z (看式 (8))仍然有可能每個 channel 維度分佈位置也都不同, 所以實務上採取 layer 1 and 2 做完, 再做 layer 2 and 3, 依此列推下去.
Bias Correction (BC)
如同在 motivation 稍微提到的, 令 ϵ=˜W−W 是 quantization error, ˜W 是 quant 後的參數. 且令 y=Wx,˜y=˜Wx, 分別是 quant 前後的 output activations, 則我們有 ˜y=y+ϵx.
由於 quantization 後可能 activations 的分布 mean 值不會跟原來一樣, i.e. 可能會 E[ϵx]≠0, 但可以透過下式被矯正回來: E[y]=E[˜y]−ϵE[x]
所以只需要對 quant 完的 output 加上 −ϵE[x], 但實務上不會這麼做, 而是做在 bias parameter 裡 (bias 加上 −ϵE[x]).
不過我們怎麼會知道 input activation 的期望值, E[x]?
做完上述 CLE + bias absorption 並得到量化 model 後跟原本 float model 比較可以得到 ϵ, 如果有 representative data (可以是 unlabeled) 情況下, 則丟 data 去計算 E[x] 就可以了. 注意要按照 layer 做, 也就是做 lth layer 的 BC 項時, 假設 1,2,..,l−1 layer 的 BC 項都 apply 上去了. 這叫做 Empirical Bias Correction, 詳見論文 Appendix D. (圖來源為 AIMET Post-Training Quantization Techniques)
但論文標題是 “Data-free”, 怎麼辦呢? 此時論文要求要有這樣的 blocks 關聯: 已知目前要處理的 layer 是 ˜y=˜Wx. 論文假設此 layer 之前還有 BN and ReLU 兩個 blocks. 注意到需有這樣的關聯存在才可以.
而 E[x] 可以利用 BN 後 xpre 是 normal distribution 的特性來算. 注意到經過 ReLU 後的 x 變成 clipped normal distribution, 而其 mean 可以利用 BN 的 shift and scale parameters 寫出 closed form 解.
詳細直接參考論文, Appendix C 有推導. 這樣的做法稱 Analytical Bias Correction. (圖來源為 AIMET Post-Training Quantization Techniques)
Experiments
由於 CLE and BA 目的是讓後面的 quantization 比較適合 per-tensor, 所以要觀察以下兩點:
1. 用了 CLE and/or BA 後, 由於輸出還是 float model, 那跟用之前的 float model 有無 performance 影響?
2. 用了 CLE and/or BA 後, 再用了 per-tensor 量化後, 能否逼近原本 float model (沒用 CLE/BA) 的 per-channel 量化?
結果 Table 1 顯示以上兩點都沒問題. 再來如果加入 BC 則觀察能否補償因 quantization 造成的 mean 偏移損失? 其中可以看 quantization model 有無套用 CLE+BA.
結果如 Table 2: Original model 直接硬做 PTQ to INT8 是慘不忍睹的 random 行為, 但直接加上 BC 補償後竟然就回到 52.02%!
如果先用 CLE+BA 在量化到 INT8, performance 為 Table 1 的最佳 70.92%. 這種情況再加上 BC 還能提升一點點 (多少表示可能還是存在一點點的 mean 偏移)
Clip@15 這個方法是直接對 weights 砍到 [-15, 15] 區間, 跟 CLE 目的一樣只是直接粗暴, 當然 BC 就能發揮更好的作用 (2.55% —> 70.43%).
剩下的實驗就不細說.
AIMET Quantization Flow
以下為 AIMET AutoQuant 建議的量化流程, 總結得很不錯:
圖中的 CLE 我猜已經包含 BA 了, 然後可以看到沒有 BC, 因為被 AdaRound 取代掉
也注意到在給 CLE 之前要先做 BatchNorm folding (如同我們在講 CLE 的限制 2)
流程就是建議先對 floating model 插好 fake quant op 來模擬 target HW 的 operators 行為 (QuantScheme Selection 那步). 先看看效果如何, 如果 OK 那 PTQ/QAT 都不需要.
接著才確認 BN folding 是否能幫助提升效果? 不行的話套看看 PTQ 的 CLE (w/wo AdaRound). 再不行就要走 QAT 了.
到這終於紀錄完, 這篇初看感覺應該可以很快看完, 一讀才發現細節真的有夠多, 頗不容易. 也因為很認真細讀才發現其實有不少限制. 不過還是很有收穫拉~
總之恭喜讀者(自己?)有耐心看完(寫完). ~~ 撒花收工 ~~