模型量化


十歲的小男孩

  本文為終端移植的一個小章節。

目錄

    背景

    理論

    實踐

Quantize

背景

  Neural Network模型一般都會占用很大的磁盤空間,比如AlexNet的模型文件就超過了200 MB.模型包含了數百萬的參數,絕大部分的空間都用來存儲這些模型的參數了。這些參數是浮點數類型的,普通的壓縮算法很難壓縮它們的空間。

  一般模型的內部的計算都采用了浮點數計算,浮點數的計算會消耗比較大的計算資源(空間和cpu/gpu時間),如果在不影響模型准確率的情況下,模型內部可以采用其他簡單數值類型進行計算的話,計算速度會提高很多,消耗的計算資源會大大減小,尤其是對於移動設備來說,這點尤其重要。由此引入量化技術。

  量化即通過減少表示每個權重所需的比特數來壓縮原始網絡。

理論

  對量化的實現是通過把常見操作轉換為等價的八位版本達到的。涉及的操作包括卷積,矩陣乘法,激活函數,池化操作,以及拼接。對模型可以壓縮到1/4。

我們發現模型屬於同一層的參數值會分布在一個較小的區間內,比如-10, 30之間,我們可以記下這個最小值和最大值,在采用8位數量化(可以有其他選擇)的情況下,可以把同一層的所有參數都線性映射(也可以采用非線性映射進一步壓縮空間)到區間[-10, 30]之間的255個8位整數中的最接近的一個數,例如如下映射:

Quantized | Float
--------- | -----
0         | -10.0
255       | 30.0
128       | 10.0

這樣模型文件的大小就基本壓縮到了原來的25%,而且在加載的時候可以恢復到原來的數值,當然恢復的數值跟壓縮之前會有差異,但事實證明,模型對這種壓縮造成的噪音表現的很健壯。

滿足第一個需求就這么簡單,模型不需要改變,需要改變的是模型的存儲和加載部分;但是要解決第二個問題就不這么簡單了,事實證明,模型內部的計算如果都采用8位整形數來計算的話,模型的表現會相差很大,原因是模型的訓練過程中,需要計算梯度,然后運用一定的學習算法,不斷的更新參數,每次的更新量可能是很小的。所以模型的訓練過程需要高精度的浮點型數值的。那么模型的預測過程是否可以使用整形數值代替呢?事實證明是可行的。

TensorFlow中模型的量化過程是這樣實現的:

將模型中實現了對應的量化操作的操作符替換成量化操作符,經過轉換后,輸入輸出依舊是float,將input從浮點數轉換成8 bit,只不過中間的計算是用過8 bit來計算的。

這里寫圖片描述

圖1 原始的計算圖

這里寫圖片描述

圖2 量化后的計算圖

這里寫圖片描述

圖3 優化量化處理后的計算圖,去掉冗余操作

Quantize:

  quantize取input中的min和max,分別對應被量化的input中的最小值(0)和最大值(255),把[min, max]這個區間均勻分成255個小區間,把input中的值對應到對應的區間中。

Dequantize:

  反量化操作則是把上述操作反向執行。

之所以這么做,tensorflow的論述是:

  1. 權重、活化張量的數值通常分布在一個相對較小的范圍中(weight:-15 ~ 15,activatios:-500 ~ 1000);

  2. 神經網絡對噪音的適應性強,將數量化到一個更小的數集中並不會對整體的結果帶來很大的影響;
  3. 通過量化操作,可以有效提高點乘的計算效率。

實踐

  使用TensorFlow工具進行量化壓縮

  在使用tensorflow這個功能時候需要先下載tensorflow的源代碼:

git clone https://github.com/tensorflow/tensorflow.git

進入tensorflow根目錄,這里使用tools文件下的兩個工具進行量化壓縮:graph_transforms、quantization。
安裝bazel進行tensorflow工具包的編譯。
這里需要注意的是,bazel最好使用最新的,這樣編譯tensorflow就不會報接口未部署的一些錯誤。
Linux安裝bazel:
https://github.com/bazelbuild/bazel/release
找到bazel-x.x.x-installer-linux-x86_64.sh下載到本地並安裝。可以按照git的安裝方法進行安裝。
安裝完畢后開始進行編譯tensorflow:

bazel build tensorflow/tools/graph_transforms:transform_graph
bazel build tensorflow/tools/quantization:quantize_graph

編譯需要占據很多內存以及cpu資源,建議在性能好點的機器上編譯。 
編譯完成后使用:

pb_in=$pb_path
pb_out=$pb_path_out
graph_trans=tensorflow/bazel-bin/tensorflow/tools/graph_transforms/transform_graph
$graph_trans --in_graph=$pb_in --out_graph=$pb_in --inputs='input_data' --outputs='softmax' --transforms='
  add_default_attributes
  fold_constants(ignore_errors=true)
  fold_batch_norms
  fold_old_batch_norms
  quantize_weights
  quantize_nodes
  strip_unused_nodes
  sort_by_execution_order'

對於第二個工具quantize_graph。

bazel-bin/tensorflow/tools/quantization/quantize_graph \  
--input=input.pb  
--output_node_names="softmax2"   
--print_nodes  
--output=out.pb \  
--mode=eightbit  
--logtostderr 

參考文獻:

https://blog.csdn.net/xygl2009/article/details/80596392?utm_source=blogxgwz1

https://blog.csdn.net/andeyeluguo/article/details/80898142?utm_source=blogxgwz0

https://blog.csdn.net/shuzfan/article/details/51678499?utm_source=blogxgwz1

https://petewarden.com/2016/05/03/how-to-quantize-neural-networks-with-tensorflow/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM