十歲的小男孩
本文為終端移植的一個小章節。
目錄
背景
理論
實踐
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/