模型量化原理及tflite示例

模型量化

什麼是量化

模型的weights數據通常是float32的,量化即將他們轉換爲int8的。固然其實量化有不少種,主流是int8/fp16量化,其餘的還有好比git

  • 二進制神經網絡:在運行時具備二進制權重和激活的神經網絡,以及在訓練時計算參數的梯度。
  • 三元權重網絡:權重約束爲+1,0和-1的神經網絡
  • XNOR網絡:過濾器和卷積層的輸入是二進制的。 XNOR 網絡主要使用二進制運算來近似卷積。
    如今不少框架或者工具好比nvidia的TensorRT,xilinx的DNNDK,TensorFlow,PyTorch,MxNet 等等都有量化的功能.

量化的優缺點

量化的優勢很明顯了,int8佔用內存更少,運算更快,量化後的模型能夠更好地跑在低功耗嵌入式設備上。以應用到手機端,自動駕駛等等。
缺點天然也很明顯,量化後的模型損失了精度。形成模型準確率降低.github

量化的原理

先來看一下計算機如何存儲浮點數與定點數:


其中負指數決定了浮點數所能表達的絕對值最小的非零數;而正指數決定了浮點數所能表達的絕對值最大的數,也即決定了浮點數的取值範圍。
float的範圍爲-2^128 ~ +2^128. 能夠看到float的值域分佈是極其廣的。api

說回量化的本質是:找到一個映射關係,使得float32與int8可以一一對應. 。那問題來了,float32可以表達值域是很是廣的,而int8只能表達[0,255].
怎麼可以用255個數表明無限多(其實也不是無限多,不少,可是也仍是有限個)的浮點數?網絡

幸運地是,實踐證實,神經網絡的weights每每是集中在一個很是狹窄的範圍,以下:

因此這個問題解決了,即咱們並不須要對值域-2^128 ~ +2^128的全部值都作映射。但即使是一個很小的範圍,好比[-1,1]可以表達的浮點數也是很是多的,因此勢必
會有多個浮點數被映射成同一個int8整數.從而形成精度的丟失.框架

這時候,第二個問題來了,爲何量化是有效的,爲何weights變爲int8後,並不會讓模型的精度降低太多?
在搜索了大量的資料之後,我發現目前並無一個很嚴謹的理論解釋這個事情.工具

您可能會問爲何量化是有效的(具備足夠好的預測準確度),尤爲是將 FP32 轉換爲 INT8 時已經丟失了信息?嚴格來講,目前還沒有出現相關的嚴謹的理論。一個直覺解釋是,神經網絡被過分參數化,進而包含足夠的冗餘信息,裁剪這些冗餘信息不會致使明顯的準確度降低。相關證據是,對於給定的量化方法,FP32 網絡和 INT8 網絡之間的準確度差距對於大型網絡來講較小,由於大型網絡過分參數化的程度更高學習

和深度學習模型同樣,不少時候,咱們沒法解釋爲何有的參數就是能work,量化也是同樣,實踐證實,量化損失的精度不會太多,do not know why it works,it just works.spa

如何作量化

由如下公式完成float和int8之間的相互映射.
\(x_{float} = x_{scale} \times (x_{quantized} - x_{zero\_point})\)
其中參數由如下公式肯定:

舉個例子,假設原始fp32模型的weights分佈在[-1.0,1.0],要映射到[0,255],則\(x_{scale}=2/255\),\(x_{zero\_point}=255-1/(2/255)=127\)code

量化後的乘法和加法:
依舊以上述例子爲例:
咱們能夠獲得0.0:127,1.0:255的映射關係.
那麼原先的0.0 X 1.0 = 0.0 注意:並不是用127x255再用公式轉回爲float,這樣算獲得的float=(2/255)x(127x255-127)=253


咱們假設全部layer的數據分佈都是一致的.則根據上述公式可得\(z_{quantized}=127\),再將其轉換回float32,即0.0.blog

同理加法:


tflite_convert

平常吐槽:tensorflow sucks. tensorflow要不是大公司開發的,絕對不可能這麼流行. 文檔混亂,又多又雜,api難理解難使用.

tensorflow中使用tflite_convert作模型量化.用法:

tflite_convert \
  --output_file=/tmp/foo.cc \
  --graph_def_file=/tmp/mobilenet_v1_0.50_128/frozen_graph.pb \
  --inference_type=QUANTIZED_UINT8 \
  --input_arrays=input \
  --output_arrays=MobilenetV1/Predictions/Reshape_1 \
  --default_ranges_min=0 \
  --default_ranges_max=6 \
  --mean_values=128 \
  --std_dev_values=127

官方指導:https://www.tensorflow.org/lite/convert/cmdline_examples
關於各參數的說明參見:
https://www.tensorflow.org/lite/convert/cmdline_reference

關於參數mean_values,std_dev_values比較讓人困惑.tf的文檔裏,對這個參數的描述有3種形式.

  • (mean, std_dev)
  • (zero_point, scale)
  • (min,max)
    轉換關係以下:
std_dev = 1.0 / scale
mean = zero_point

mean = 255.0*min / (min - max)
std_dev = 255.0 / (max - min)

結論:
訓練時模型的輸入tensor的值在不一樣範圍時,對應的mean_values,std_dev_values分別以下:

  • range (0,255) then mean = 0, std_dev = 1
  • range (-1,1) then mean = 127.5, std_dev = 127.5
  • range (0,1) then mean = 0, std_dev = 255

參考:
https://heartbeat.fritz.ai/8-bit-quantization-and-tensorflow-lite-speeding-up-mobile-inference-with-low-precision-a882dfcafbbd
https://stackoverflow.com/questions/54830869/understanding-tf-contrib-lite-tfliteconverter-quantization-parameters/58096430#58096430
https://arleyzhang.github.io/articles/923e2c40/
https://zhuanlan.zhihu.com/p/79744430
https://zhuanlan.zhihu.com/p/58182172

相關文章
相關標籤/搜索