1. 程式人生 > >tensorflow之模型壓縮

tensorflow之模型壓縮

tensorflow的模型在移動端執行時往往需要進行模型壓縮。這主要有於兩方面的原因:1.模型過大不易載入和下載,執行時記憶體佔用率太高。2. tensorflow的模型在訓練的過程中可能為了訓練會新增一些操作和節點,而tensorflow的移動端只專注於推理,這樣在執行時就會產生一些核心不存在的錯誤。所以此時需要通過壓縮來減少一些和輸入及輸出不相關的節點。下面介紹一下模型壓縮的方式。

一、環境需求

為了能夠使用graph_transform進行模型的轉化,首先需要安裝bazel,通過 bazel build tensorflow / tools / graph_transforms:transform_graph編譯產生transform_graph。具體的bazel安裝方式可以參考:

https://blog.csdn.net/hh_2018/article/details/81003375  。

二、確定輸入節點和輸出節點

該步尤為重要,應為在使用transform_graph方法進行模型轉化時,往往會根據輸入節點和輸出節點的方式確定哪些節點或者哪些操作會被省略,所以一定要確定模型的輸入和輸出。

如果不知道模型的輸入和輸出可以使用summarize_graph的方式對圖進行分析。具體使用方式如下:首先通過 bazel build tensorflow / tools / graph_transforms:summarize_graph產生summarize_graph,然後再通過bazel-bin來執行。具體例子如下:

bazel-bin/tensorflow/tools/graph_transforms/summarize_graph --in_graph=../model/mtcnn_frozen_model.pb

得到的結果為

Found 3 possible inputs: (name=pnet/input, type=float(1), shape=[?,?,?,3]) (name=rnet/input, type=float(1), shape=[?,24,24,3]) (name=onet/input, type=float(1), shape=[?,48,48,3]) 
No variables spotted.
Found 7 possible outputs: (name=pnet/prob1, op=RealDiv) (name=pnet/conv4-2/BiasAdd, op=BiasAdd) (name=rnet/prob1, op=RealDiv) (name=rnet/conv5-2/conv5-2, op=BiasAdd) (name=onet/prob1, op=RealDiv) (name=onet/conv6-2/conv6-2, op=BiasAdd) (name=onet/conv6-3/conv6-3, op=BiasAdd) 
Found 495860 (495.86k) const parameters, 0 (0) variable parameters, and 0 control_edges
Op types used: 58 Const, 50 Identity, 24 Relu, 24 Neg, 19 BiasAdd, 12 Conv2D, 12 Add, 12 Mul, 7 MatMul, 6 MaxPool, 3 Max, 3 Placeholder, 3 RealDiv, 3 Exp, 3 Sub, 3 Sum, 2 Reshape
To use with tensorflow/tools/benchmark:benchmark_model try these arguments:
bazel run tensorflow/tools/benchmark:benchmark_model -- --graph=../model/mtcnn_frozen_model.pb --show_flops --input_layer=pnet/input,rnet/input,onet/input --input_layer_type=float,float,float --input_layer_shape=-1,-1,-1,3:-1,24,24,3:-1,48,48,3 --output_layer=pnet/prob1,pnet/conv4-2/BiasAdd,rnet/prob1,rnet/conv5-2/conv5-2,onet/prob1,onet/conv6-2/conv6-2,onet/conv6-3/conv6-3
 

通過分析上述結果我們可以發現模型的輸入和輸出(該方法主要是針對已經存在的模型,使用者並不知道拿的模型是什麼樣子的,也就無法知道模型的輸入和輸出)

三、模型轉變。

知道模型的輸入和輸出之後可以根據自己的想法進行模型的轉變,具體如下:

 bazel-bin/tensorflow/tools/graph_transforms/transform_graph --in_graph=../model/mtcnn_frozen_model.pb  --inputs='pnet/input,rnet/input,onet/input'   --outputs='pnet/prob1,pnet/conv4-2/BiasAdd,rnet/prob1,rnet/conv5-2/conv5-2,onet/prob1,onet/conv6-2/conv6-2,onet/conv6-3/conv6-3'   --out_graph=../model/quantized_mtcnn_frozen_model.pb   --transforms='remove_nodes(op=Identity, op=CheckNumerics)
  fold_constants(ignore_errors=true)
  fold_batch_norms
  fold_old_batch_norms
  quantize_weights
  strip_unused_nodes
  merge_duplicate_nodes
  sort_by_execution_order'

上述轉換操作的各個意思為:

1. remove_node : 該引數表示刪除節點,後面的引數表示刪除的節點型別,注意該操作有可能刪除一些必須節點

2. fold_constans: 查詢模型中始終為常量的表示式,並用常量替換他們。

3.fold_batch_norms: 訓練過程中使用批量標準化時可以優化在Conv2D或者MatMul之後引入的Mul。需要在fold_cnstans之後使用。(fold_old_batch_norms和他的功能一樣,主要是為了相容老版本)

4. quantize_weights:將float型資料改為8位計算方式(預設對小於1024的張量不會使用),該方法是壓縮模型的主要手段。

5. strip_unused_nodes:除去輸入和輸出之間不使用的節點,對於解決移動端核心溢位存在很大的作用。

6. merge_duplicate_nodes: 合併一些重複的節點

7: sort_by_execution_order: 對節點進行排序,保證給定點的節點輸入始終在該節點之前。

 

具體的其他操作還可以參見:

https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/graph_transforms/#quantize_weights