tensorflow之模型压缩
tensorflow的模型在移动端运行时往往需要进行模型压缩。这主要有于两方面的原因:
- 模型过大不易加载和下载,运行时内存占用率太高。
- 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’
上述转换操作的各个意思为:
-
remove_node : 该参数表示删除节点,后面的参数表示删除的节点类型,注意该操作有可能删除一些必须节点
-
fold_constans: 查找模型中始终为常量的表达式,并用常量替换他们。
-
fold_batch_norms: 训练过程中使用批量标准化时可以优化在Conv2D或者MatMul之后引入的Mul。需要在fold_cnstans之后使用。(fold_old_batch_norms和他的功能一样,主要是为了兼容老版本)
-
quantize_weights:将float型数据改为8位计算方式(默认对小于1024的张量不会使用),该方法是压缩模型的主要手段。
-
strip_unused_nodes:除去输入和输出之间不使用的节点,对于解决移动端内核溢出存在很大的作用。
-
merge_duplicate_nodes: 合并一些重复的节点
-
sort_by_execution_order: 对节点进行排序,保证给定点的节点输入始终在该节点之前。
具体的其他操作还可以参见:
更多案例请关注“思享会Club”公众号或者关注思享会博客:http://gkhelp.cn/