前言
本文主要梳理了整体移植过程,分成以下几个流程:
1、模型从ckpt转换成pb
2、CPU推理用于验证
3、模型量化
4、MLU在线推理
5、MLU离线推理
实验环境:sdk1.6.1+python3.5+tensorflow
代码参考链接:https://github.com/CambriconECO/TensorFlow_Resnet50_Inference
一、模型从ckpt转换成pb
MLU在线推理时使用的是量化后的pb,但Tensorflow官网中提供的原始模型大部分都是checkpoint的形式,所以先要将ckpt格式的模型转换为pb格式。如果已经有pb模型可以直接跳到第2步开始。
下载ckpt文件:http://download.tensorflow.org/models/resnet_v1_50_2016_08_28.tar.gz
进入到Cambrcion TensorFlow源码目录中:
① 生成没有权值的pb
在tensorflow_models/research/slim目录下执行:
python export_inference_graph.py \
|
②与下载好的ckpt结合生成带权值的pb文件
在tensorflow目录下执行:
bazel-bin /tensorflow/python/tools/freeze_graph \ --input_graph= /path/to/resnet50_v1 .pb \ 第①步生成的pb路径 --input_checkpoint= /path/to/resnet_v1_50 .ckpt \ 下载好的ckpt路径 --input_binary= true \ --output_graph= /path/to/frozen_resnet50_v1 .pb \ 待生成的有权重的pb路径 --output_node_names=resnet_v1_50 /predictions/Reshape_1 pb的最后节点信息 |
上述步骤执行完则可以生成待量化的有权重pb文件。
注意:以下CPU推理、模型量化、MLU在线推理使用同一套代码执行,只要选择不同的选项即可
Cambricon TensorFlow对底层进行了修改,用户只要对自己原有的demo和代码做简单的修改,设置相应的环境变量就能够完成CPU推理、模型量化和在线推理。
二、CPU推理
①如何运行
在tf_resnet50_v1目录下执行:
# 对一张图片进行推理,输出top5类别及概率,概率从小到大输出 python tf_forward.py --input_pb resnet50_v1.pb --mode cpu |
运行结果:
---------------------TOP_5------------------------------------------- [ 273 , 270 , 279 , 271 , 281 ] [ 0.025609186 , 0.07962891 , 0.121683314 , 0.29227442 , 0.39985612 ] [ '273:coyote, prairie wolf, brush wolf, Canis latrans' , '270:timber wolf, grey wolf, gray wolf, Canis lupus' , '279:kit fox, Vulpes macrotis' , '271:white wolf, Arctic wolf, Canis lupus tundrarum' , '281:grey fox, gray fox, Urocyon cinereoargenteus' ] |
②关键代码
# 设置对应环境变量 if FLAGS.mode = = 'cpu' : os.environ[ 'MLU_VISIBLE_DEVICES' ] = '' #表示使用CPU进行推理 # 前处理 if FLAGS.mode = = 'cpu' : image = image - mean # 推理 image = image[np.newaxis, :] images = np.repeat(image, FLAGS.batch_size, axis = 0 ) out = session.run(output, feed_dict = { input [ 0 ]:images}) |
三、模型量化
在MLU在线推理时,需要使用到量化的pb模型。所以在推理前,需要进行量化操作。
①如何运行
在tf_resnet50_v1目录下执行:
cp resnet50_v1_quant_param.txt_param resnet50_v1_quant_param.txt # 设置量化配置初始文件 python tf_forward.py --input_pb resnet50_v1.pb --mode quant # 量化 |
执行完成后,会将量化参数写入resnet50_v1_quant_param.txt文件,保存了对应层的量化参数,在后续的在线推理中会设置环境变量引用到该文件。
②量化初始配置文件内容
bit_width: 8 # 量化位宽, 8 或者 16 quant_mode:naive # 量化模式,目前只支持naive模式 # 这个表示开启convfirst convfirst_param: { node_name: resnet_v1_50/conv1/Conv2D # 网络中第一个conv节点的名称 mean: 124 , 116 , 127 # 对应通道均值 std: 1 , 1 , 1 # 方差 color_mode: rgb } |
注意:
若⼀个⽹络要使⽤ convfirst,要满⾜以下⼏个条件:
- ⽹络的前处理不能包含在 graph 中
- ⽹络的前处理必须是以下形式或者可以转换为以下形式:input = ( input – mean ) / std
- ⽹络的第⼀层必须是 Conv2D,输⼊图⽚必须是 3 通道
③量化关键代码
# 设置环境变量 if FLAGS.mode = = 'quant' : os.environ[ 'MLU_VISIBLE_DEVICES' ] = '' # 量化仍使用CPU推理 os.environ[ 'MLU_QUANT_PARAM' ] = 'resnet50_v1_quant_param.txt' # 设置量化参数环境变量 os.environ[ 'MLU_RUNNING_MODE' ] = '0' # 0表示量化,1表示在线推理 # 前处理同CPU,后续的在线推理无须在CPU上做减均值除方差的前处理,因为已经挪到第一层conv2d上 if FLAGS.mode = = 'quant' : image = image - mean # 推理 image = image[np.newaxis, :] images = np.repeat(image, FLAGS.batch_size, axis = 0 ) out = session.run(output, feed_dict = { input [ 0 ]:images}) |
四、MLU在线推理
①如何运行
在tf_resnet50_v1目录下执行:
在线逐层推理:
python tf_forward.py --input_pb resnet50_v1.pb --mode online_layer |
运行结果:
---------------------TOP_5------------------------------------------- [ 270 , 281 , 279 , 278 , 271 ] [ 0.066077225 , 0.090369955 , 0.13002093 , 0.15906543 , 0.4323373 ] [ '270:timber wolf, grey wolf, gray wolf, Canis lupus' , '281:grey fox, gray fox, Urocyon cinereoargenteus' , '279:kit fox, Vulpes macrotis' , '278:red fox, Vulpes vulpes' , '271:white wolf, Arctic wolf, Canis lupus tundrarum' ] |
在线融合推理:
python tf_forward.py --input_pb resnet50_v1.pb --mode online_fusion |
运行结果:
---------------------TOP_5------------------------------------------- [ 273 , 270 , 279 , 271 , 281 ] [ 0.025817871 , 0.08343506 , 0.086120605 , 0.26635742 , 0.46118164 ] [ '273:coyote, prairie wolf, brush wolf, Canis latrans' , '270:timber wolf, grey wolf, gray wolf, Canis lupus' , '279:kit fox, Vulpes macrotis' , '271:white wolf, Arctic wolf, Canis lupus tundrarum' , '281:grey fox, gray fox, Urocyon cinereoargenteus' ] |
②关键代码
# 设置环境变量 if FLAGS.mode = = 'online_layer' : os.environ[ 'MLU_VISIBLE_DEVICES' ] = '0' # 0表示使用MLU推理 os.environ[ 'MLU_QUANT_PARAM' ] = 'resnet50_v1_quant_param.txt' # 使用量化参数文件 os.environ[ 'MLU_RUNNING_MODE' ] = '1' # 1表示运行推理 os.environ[ 'MLU_STATIC_NODE_FUSION' ] = 'false' # 逐层模式设置为false if FLAGS.mode = = 'online_fusion' : os.environ[ 'MLU_VISIBLE_DEVICES' ] = '0' os.environ[ 'MLU_QUANT_PARAM' ] = 'resnet50_v1_quant_param.txt' os.environ[ 'MLU_RUNNING_MODE' ] = '1' os.environ[ 'MLU_STATIC_NODE_FUSION' ] = 'true' # 融合模式设置为true # 推理,无须在cpu上做减均值除方差的前处理 image = image[np.newaxis, :] images = np.repeat(image, FLAGS.batch_size, axis = 0 ) out = session.run(output, feed_dict = { input [ 0 ]:images}) |
五、MLU离线推理
①生成离线模型,和上述推理使用同一套代码
在tf_resnet50_v1目录下执行:
python tf_forward.py --input_pb resnet50_v1.pb --mode offline |
运行后即可在当前目录生成.cambricon和.cambricon_twins文件。.cambricon为生成的离线模型,.cambricon_twins存储了离线模型相关信息,可以打开进行查看离线模型融合情况。
关键代码
if FLAGS.mode = = 'offline' : os.environ[ 'MLU_VISIBLE_DEVICES' ] = '0' os.environ[ 'MLU_QUANT_PARAM' ] = 'resnet50_v1_quant_param.txt' os.environ[ 'MLU_RUNNING_MODE' ] = '1' os.environ[ 'MLU_STATIC_NODE_FUSION' ] = 'true' if FLAGS.mode = = 'offline' : config.mlu_options.save_offline_model = True # 保存离线模型 config.mlu_options.offline_model_name = "resnet50_v1.cambricon" # 离线模型名 |
② 离线推理
使用CNRT接口调用生成的离线模型.cambricon完成推理
在cnrt_resnet50_demo目录下执行:
# 编译 make # 运行 . /cnrt_resnet50_demo .. /tf_resnet50_v1/resnet50_v1 .cambricon subnet0 0 0 .. /tf_resnet50_v1/fox .jpg 1 |
运行结果:
---------------------------TOP_5----------------------------- 275 272 281 279 278 0.00621033 0.02034 0.0823364 0.131348 0.756836 275 :dhole, Cuon alpinus 272 :red wolf, maned wolf, Canis rufus, Canis niger 281 :grey fox, gray fox, Urocyon cinereoargenteus 279 :kit fox, Vulpes macrotis 278 :red fox, Vulpes vulpes ------------------------------------------------------------- |
关键代码解析: