1,概述
模型量化屬於模型壓縮的范疇,模型壓縮的目的旨在降低模型的內存大小,加速模型的推斷速度(除了壓縮之外,一些模型推斷框架也可以通過內存,io,計算等優化來加速推斷)。
常見的模型壓縮算法有:量化,剪枝,蒸餾,低秩近似以及緊湊模型設計(如mobileNet)等操作。但在這里有些方法只能起到縮減模型大小,而起不到加速的作用,如稀疏化剪枝。而在現代的硬件設備上,其實更關注的是模型推斷速度。今天我們就講一種既能壓縮模型大小,又能加速模型推斷速度:量化。
量化一般可以分為兩種模式:訓練后的量化(post training quantizated)和訓練中引入量化(quantization aware training)。
訓練后的量化理解起來比較簡單,將訓練后的模型中的權重由float32量化到int8,並以int8的形式保存,但是在實際推斷時,還需要反量化為float類型進行計算。這種量化的方法在大模型上表現比較好,因為大模型的抗噪能力很強,但是在小模型上效果就很差。
訓練中引入量化是指在訓練的過程中引入偽量化操作,即在前向傳播時,采用量化后的權重和激活,但是在反向傳播時仍是對float類型的權重做梯度更新;在預測時將全部采用int8的方式進行計算。
注:模型除了可以量化到int8之外,還可以量化到float16,int4等,只是在作者看來量化到int8之后,能保證壓縮效果和准確率損失最優。
2,quantization aware training
論文:Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference
quantization aware training技術來源於上面這篇論文,現在在tensorflow和pytorch中都提供了相應的接口。
作者在本文中提供了一種將float32量化到int8的策略,並給出了一個推斷框架和訓練框架,推斷框架讓模型可以有效的整數運算硬件上運行,訓練框架和推斷框架相輔相成,可以降低精度的損失。我們先來看看推斷框架:
Quantizated Inference
1, Quantization scheme
首先定義q為量化值,r為真實浮點值。本文拋棄了之前采用查找表的方式將浮點值映射到整數值,而是引入了一個映射關系來表示,公式如下:
上面式子中S為縮放稀疏,Z為"Zero-Point",其實Z就是真實浮點值0映射到整數時對應的值,這個值的存在是有一定意義的,因為無論是在圖像中還是NLP中都會有用0做padding值來補全的,映射到整數后,也應該有這樣一個值的存在,這個值就是Z。在這里S和Z可以稱為量化參數,對於每個權重矩陣和每個激活數組都有一對這樣的值。
用C++中的結構體來表示這個數據結構的話,如下:
在這里QType既可以是int8,也可以是float16,int4等。
2,Integer-arithmetic-only matrix multiplication
對於兩個浮點數矩陣之間的運算,可以全部轉換成整數運算,公式如下:
在上面的式子中只有M是一個浮點數,所以這里會有一個浮點運算,作者在這里好像為了避開浮點運算,做了下面一個操作,但沒怎么看懂,有興趣的可以自己。
3,Efficient handling of zero-points
個人理解在上面的式子4中因為兩個矩陣都需要減去相應的Z值,減法運算之后得到的值有可能會突破int8的范圍,到時候就需要int16來存儲,但整個運算為了控制在int8的類型下計算,作者做了下面的變換。至於作者提到的2N^3的計算復雜度,即使轉換完之后還是存在的,這個復雜度就是兩個矩陣的計算復雜度。
4,Implementation of a typical fused layer
上面的描述了權重的矩陣運算,但除此之外在一個神經網絡中還含有bias和激活函數的映射,因為int8類型的矩陣運算完之后的值應該是在int32之內的,所以bias選擇int32的類型,這樣的選擇一是因為bias在整個神經網絡中只占據極少的一部分,此外bias的作用其實非常重要,高精度的bias可以降低模型的偏差。因此加上bias之后就變成了int32,我們需要再次轉換成int8類型,之后再進入到激活中。具體如下圖所示:
Training with simulated quantization
為什么要采用這種量化策略,前面也說了對於大模型采用post training quantizated的方法是可以的,但是小模型容易導致精度損失較大。具體的量化策略如下:
1,weights再輸入進行卷積之前就開始量化,如果有bn層,將bn層融入到weights中。
2,激活在激活函數執行完之后再量化。
具體的如下如所示:
具體的量化公式如下:
也是min-max的方式,上面式子中(a, b)是針對浮點數的量化范圍,n可以理解為對於int8,$n = 2^8$。上面的⌊·⌉ 其實是一個將浮點數轉為最近且小於它的整數的符號,該符號內部就是量化函數。
1,Learning quantization ranges
對於上面的量化范圍(a, b),weight和activation是不一樣的,對於weight來說很簡單,就是該權重中最大最小值,但是對於activation是不太一樣的, 對於activation采用了EMA(滑動平均)來對輸入中的最大最小值計算得到的,但是在訓練初期,因為輸入的值變化較大,會影響到滑動平均的值,因此在初期不對activation做量化,而是在網絡穩定之后再引入。具體量化算法如下:
2,Batch normalization folding
對於bn層,在訓練時是一個單獨的層存在,但是在推斷時為了提升效率是融合到卷積或全連接層的權重和偏置中的,如下圖:
為了模擬推斷,訓練時需要將bn層考慮進權重,然后再做量化。具體公式如下:
參考文獻:
Quantizing deep convolutional networks for efficient inference: A whitepaper
Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference