最近打算寫乙個關於神經網路量化的入門教程,包括網路量化的基本原理、離線量化、量化訓練,以及全量化模型的推理過程,最後我會用 pytorch 從零構建乙個量化模型,幫助讀者形成更深刻的理解。
之所以要寫這系列教程,主要是想幫助初次接觸量化的同學快速入門。筆者在剛開始接觸模型量化時走了很多彎路,並且發現網上的資料和**對初學者來說太不友好。目前學術界的量化方法都過於花俏,能落地的極少,工業界廣泛使用的還是 google tflite 那一套量化方法,而 tflite 對應的大部分資料都只告訴你如何使用,能講清楚原理的也非常少。這系列教程不會涉及學術上那些花俏的量化方法,主要是想介紹工業界用得最多的量化方案 (即 tflite 的量化原理,對應 google 的** quantization and training of neural networks for efficient integer-arithmetic-only inference )
話不多說,我們開始。這一章中,主要介紹網路量化的基本原理,以及推理的時候如何跑量化模型。
量化並不是什麼新知識,我們在對影象做預處理時就用到了量化。回想一下,我們通常會將一張 uint8 型別、數值範圍在 0~255 的歸一成 float32 型別、數值範圍在 0.0~1.0 的張量,這個過程就是反量化。類似地,我們經常將網路輸出的範圍在 0.0~1.0 之間的張量調整成數值為 0~255、uint8 型別的資料,這個過程就是量化。所以量化本質上只是對數值範圍的重新調整,可以「粗略」理解為是一種線性對映。(之所以加「粗略」二字,是因為有些**會用非線性量化,但目前在工業界落地的還都是線性量化,所以本文只討論線性量化的方案)。
不過,可以明顯看出,反量化一般沒有資訊損失,而量化一般都會有精度損失。這也非常好理解,float32 能儲存的數值範圍本身就比 uint8 多,因此必定有大量數值無法用 uint8 表示,只能四捨五入成 uint8 型的數值。量化模型和全精度模型的誤差也來自四捨五入的 clip 操作。
這篇文章中會用到一些公式,這裡我們用 \(r\) 表示浮點實數,\(q\) 表示量化後的定點整數。浮點和整型之間的換算公式為:
\[r = s(q-z) \tag
\]\[q = round(\frac+z) \tag
\]其中,\(s\) 是 scale,表示實數和整數之間的比例關係,\(z\) 是 zero point,表示實數中的 0 經過量化後對應的整數,它們的計算方法為:
\[s = \frac-r_}-q_} \tag
\]\[z = round(q_ - \frac}) \tag
\]\(r_\)、\(r_\)分別是 \(r\) 的最大值和最小值,\(q_\)、\(q_\)同理。這個公式的推導比較簡單,很多資料也有詳細的介紹,這裡不過多介紹。需要強調的一點是,定點整數的 zero point 就代表浮點實數的 0,二者之間的換算不存在精度損失,這一點可以從公式 (2) 中看出來,把 \(r=0\) 代入後就可以得到 \(q=z\)。這麼做的目的是為了在 padding 時保證浮點數值的 0 和定點整數的 zero point 完全等價,保證定點和浮點之間的表徵能夠一致。
由於卷積網路中的卷積層和全連線層本質上都是一堆矩陣乘法,因此我們先看如何將浮點運算上的矩陣轉換為定點運算。
假設 \(r_1\)、\(r_2\) 是浮點實數上的兩個 \(n \times n\) 的矩陣,\(r_3\) 是 \(r_1\)、\(r_2\) 相乘後的矩陣:
\[r_3^=\sum_^n r_1^r_2^ \tag
\]假設 \(s_1\)、\(z_1\) 是 \(r_1\) 矩陣對應的 scale 和 zero point,\(s_2\)、\(z_2\)、\(s_3\)、\(z_3\)同理,那麼由 (5) 式可以推出:
\[s_3(q_3^-z_3)=\sum_^s_1(q_^-z_1)s_2(q_2^-z_2) \tag
\]\[q_3^=\frac\sum_^n(q_1^-z_1)(q_2^-z_2)+z_3 \tag
\]仔細觀察 (7) 式可以發現,除了\(\frac\),其他都是定點整數運算。那如何把 \(\frac\) 也變成定點運算呢?這裡要用到乙個 trick。假設 \(m=\frac\),由於 \(m\) 通常都是 (0, 1) 之間的實數 (這是通過大量實驗統計出來的),因此可以表示成 \(m=2^m_0\),其中 \(m_0\) 是乙個定點實數。注意,定點數並不一定是整數,所謂定點,指的是小數點的位置是固定的,即小數字數是固定的。因此,如果存在 \(m=2^m_0\),那我們就可以通過\(m_0\)的 bit 位移操作實現 \(2^m_0\),這樣整個過程就都在定點上計算了。
很多剛接觸量化的同學對這一點比較疑惑,下面我就用乙個簡單的示例說明這一點。我們把 \(m=\frac\) 代入 (7) 式可以得到:
\[q_3^=m\sum_^n(q_1^-z_1)(q_2^-z_2)+z_3=mp+z_3 \tag
\]這裡面 \(p\) 是乙個在定點域上計算好的整數。
假設 \(p=7091\),\(m=0.0072474273418460\) (\(m\) 可以通過 \(s\) 事先計算得到),那下面我們就是要找到乙個 \(m_0\) 和 \(n\),使得 \(mp=2^m_0 p\) 成立。我們可以用一段**來找到這兩個數:
m = 0.0072474273418460
p = 7091
def multiply(n, m, p):
result = m * p
mo = int(round(2 ** n * m)) # 這裡不一定要四捨五入截斷,因為python定點數不好表示才這樣處理
for n in range(1, 16):
multiply(n, m, p)
輸出:
可以看到,在 n=11、\(m_0=15\) 的時候,誤差就已經在 1 以內了。因此,只要 \(m_0p\) 的數值範圍在 21(32-11) 個 bit 內,就可以通過對 \(m_0p\) 右移 \(n\) 個 bit 來近似 \(mp\) 了,而這個誤差本身在可以接受的範圍內。這樣一來,(8) 式就可以完全通過定點運算來計算,即我們實現了浮點矩陣乘法的量化。
有了上面矩陣乘法的量化,我們就可以進一步嘗試對卷積網路的量化。
假設乙個這樣的網路:
這個網路只有三個模組,現在需要把 conv、fc、relu 量化。
假設輸入為 \(x\),我們可以事先統計樣本的最大值和最小值,然後計算出 \(s_x\)(scale) 和 \(z_x\)(zero point)。
同樣地,假設 conv、fc 的引數為 \(w_1\)、\(w_2\),以及 scale 和 zero point 為 \(s_\)、\(z_\)、\(s_\)、\(z_\)。中間層的 feature map 為 \(a_1\),\(a_2\),並且事先統計出它們的 scale 和 zero point 為 \(s_\)、\(z_\)、\(s_\)、\(z_\)。
\[a_1^=\sum_^n x^w_1^ \tag
\]根據之前的轉換,我們可以得到:
\[q_^=m\sum_^n(q_x^-z_x)(q_^-z_)+z_ \tag
\]其中 \(m=\fracs_}}\)。
得到 conv 的輸出後,我們不用反量化回 \(a_1\),直接用 \(q_\) 繼續後面的計算即可。
對於量化的 relu 來說,計算公式不再是 \(q_=max(q_, 0)\),而是 \(q_=max(q_,z_)\),並且 \(s_=s_\),\(z_=z_\) (為什麼是這樣,這一點留作思考題)。另外,在實際部署的時候,relu 或者 bn 通常是會整合到 conv 中一起計算的,這一點在之後的文章再講解。
得到 \(q_\) 後,我們可以繼續用 (8) 式來計算 fc 層。假設網路輸出為 \(y\),對應的 scale 和 zero point 為 \(s_y\)、\(z_y\),則量化後的 fc 層可以用如下公式計算:
\[q_^=m\sum_^n(q_^-z_)(q_^-z_)+z_\tag
\]然後通過公式 \(y=s_y(q_y-z_y)\) 把結果反量化回去,就可以得到近似原來全精度模型的輸出了。
可以看到,上面整個流程都是用定點運算實現的。我們在得到全精度的模型後,可以事先統計出 weight 以及中間各個 feature map 的 min、max,並以此計算出 scale 和 zero point,然後把 weight 量化成 int8/int16 型的整數後,整個網路便完成了量化,然後就可以依據上面的流程做量化推理了。
這篇文章主要介紹了矩陣量化的原理,以及如何把矩陣量化運用到卷積網路中,實現全量化網路的計算。這中間忽略了很多細節,比如 relu 和 conv 的合併、啟用函式的量化、量化訓練的流程等。後面的文章會繼續補充一些細節,並通過從零搭建乙個 pytorch 的量化模型來幫助讀者更好地理解中間的過程。
作為曾經在 ai 路上苦苦掙扎的過來人,想幫助小白們更好地思考各種 ai 技術的來龍去脈。
BP神經網路基本原理
2.1 bp 神經網路基本原理 bp網路模型處理資訊的基本原理是 輸入訊號 xi通過中間節點 隱層點 作用於輸出節點,經過非線形變換,產生輸出訊號 yk,網路訓練的每個樣本包括輸入向量 x和期望輸出量 t,網路輸出值 y與期望輸出值 t之間的偏差,通過調整輸入節點與隱層節點的聯接強度取值 wij和隱...
BP神經網路基本原理
2.1 bp 神經網路基本原理 bp網路模型處理資訊的基本原理是 輸入訊號 xi通過中間節點 隱層點 作用於輸出節點,經過非線形變換,產生輸出訊號 yk,網路訓練的每乙個樣本包含輸入向量 x和期望輸出量 t,網路輸出值 y與期望輸出值 t之間的偏差,通過調整輸入節點與隱層節點的聯接強度取值 wij和...
BP神經網路基本原理
2.1 bp 神經網路基本原理 bp網路模型處理資訊的基本原理是 輸入訊號 xi通過中間節點 隱層點 作用於輸出節點,經過非線形變換,產生輸出訊號 yk,網路訓練的每乙個樣本包含輸入向量 x和期望輸出量 t,網路輸出值 y與期望輸出值 t之間的偏差,通過調整輸入節點與隱層節點的聯接強度取值 wij和...