保姆级教程 - atlas500部署yolov3-tiny检测实时视频流 [2] - yolov3-tiny模型转换到om
【摘要】 保姆级教程 - atlas500部署yolov3-tiny检测实时视频流 [2] - yolov3-tiny模型转换到om 保姆级教程 - atlas500部署yolov3-tiny检测实时视频流 [2] - yolov3-tiny模型转换到om 2、yolov3-tiny转换到om模型 (1)weight -> ckpt (2)模型固化ckpt -> pb - 确定yolov3和yolo...
保姆级教程 - atlas500部署yolov3-tiny检测实时视频流 [2] - yolov3-tiny模型转换到om
接上文 ->
[内网环境下docker部署atlas500 开发环境 [踩坑记录]]:
https://bbs.huaweicloud.com/forumreview/thread-186744-1-1.html
后续开发需要很多华为atlas官方的知识,版本迭代较快,我们应该以官方文档为主:https://support.huaweicloud.com/adevg-atlas500app/atlas500development_01_0001.html
还有对应cann版本的推理、训练文档:昇腾CANN社区版(5.0.4.alpha002)(训练)、昇腾CANN社区版(5.0.4.alpha002)(推理)
2、yolov3-tiny转换到om模型
本文采用darknet原生的yolov3-tiny进行训练:https://pjreddie.com/darknet/ ,训练过程在此不再介绍
由于训练出的模型是weights,而atlas CANN目前对tensorflow、yolov3支持最好。(yolov5目前暂不建议使用?但有很多大佬应用了) 详看模型支持列表:https://support.huaweicloud.com/ug-mfac-mindxsdk201/atlasmx_02_0129.html
而CANN的atc模型转换,也主要支持tf和caffe。本文采用weight -> ckpt ->pb -> atc转换为om模型的方案
(1)weight -> ckpt
从weight模型提取出ckpt权重。
借助项目: https://github.com/mystic123/tensorflow-yolo-v3
通过convert_weights.py提取ckpt权重,其中可指定yolov3 或 yolov3-tiny:
其中,本文使用tf1.15,通过浏览一些样例发现tf1.15应该是目前支持最好的
# -*- coding: utf-8 -*-
import tensorflow as tf
import yolo_v3
import yolo_v3_tiny
from utils import load_coco_names, load_weights
FLAGS = tf.app.flags.FLAGS
tf.app.flags.DEFINE_string(
'class_names', './model/voc.names', 'File with class names')
tf.app.flags.DEFINE_string(
'weights_file', './model/yolov3-tiny.weights', 'Binary file with detector weights')
tf.app.flags.DEFINE_string(
'data_format', 'NHWC', 'Data format: NCHW (gpu only) / NHWC')
tf.app.flags.DEFINE_bool(
'tiny', True, 'Use tiny version of YOLOv3')
tf.app.flags.DEFINE_bool(
'spp', False, 'Use SPP version of YOLOv3')
tf.app.flags.DEFINE_string(
'ckpt_file', './saved_model/yolov3-tiny.ckpt', 'Chceckpoint file')
def main(argv=None):
if FLAGS.tiny:
model = yolo_v3_tiny.yolo_v3_tiny
elif FLAGS.spp:
model = yolo_v3.yolo_v3_spp
else:
model = yolo_v3.yolo_v3
classes = load_coco_names(FLAGS.class_names)
# placeholder for detector inputs
# any size > 320 will work here
inputs = tf.placeholder(tf.float32, [1, 416, 416, 3])
with tf.variable_scope('detector'):
detections = model(inputs, len(classes),
data_format=FLAGS.data_format)
load_ops = load_weights(tf.global_variables(
scope='detector'), FLAGS.weights_file)
saver = tf.train.Saver(tf.global_variables(scope='detector'))
with tf.Session() as sess:
sess.run(load_ops)
save_path = saver.save(sess, save_path=FLAGS.ckpt_file)
print('Model saved in path: {}'.format(save_path))
if __name__ == '__main__':
tf.app.run()
提取出的ckpt文件如下:
checkpoint # 文本文件,记录了保存的最新的checkpoint文件以及其它checkpoint文件列表
yolov3-tiny.ckpt.data-00000-of-00001 # 保存当前参数值
yolov3-tiny.ckpt.index # 保存当前参数名
yolov3-tiny.ckpt.meta # 保存当前图结构
(2)模型固化ckpt -> pb
模型固化和om模型转换最重要的是,确定模型的输入输出节点
模型固化流程可以参考对应版本的cann训练文档进行实现:https://support.huaweicloud.com/tfmigr-cann504alpha2training/atlasmprtg_13_9023.html
本文在仓库https://github.com/wizyoung/YOLOv3_TensorFlow的基础上,进行模型固化,代码参考如下:
import tensorflow as tf
from tensorflow.python.framework import graph_util
from tensorflow.python.platform import gfile
"""
将ckpt权重解释:
checkpoint:文本文件,记录了保存的最新的checkpoint文件以及其它checkpoint文件列表。
model.ckpt.data-00000-of-00001:保存当前参数值
model.ckpt.index:保存当前参数名
model.ckpt.meta:保存当前图结构
"""
def freeze_graph(input_path, output_path):
# 指定输出节点名称
# output_node_names = "yolov3/yolov3_head/feature_map_1,yolov3/yolov3_head/feature_map_2,yolov3/yolov3_head/feature_map_3"
output_node_names = 'yolov3-tiny/convolutional10/BiasAdd,yolov3-tiny/convolutional13/BiasAdd'
saver = tf.train.import_meta_graph(input_path+".meta", clear_devices=True) # 保存tf模型的计算图结构
graph = tf.get_default_graph()
input_graph_def = graph.as_graph_def()
with tf.Session() as sess:
saver.restore(sess, input_path)
output_graph_def = graph_util.convert_variables_to_constants(
sess=sess,
input_graph_def=input_graph_def, # = sess.graph_def,
output_node_names=output_node_names.split(","))
with tf.gfile.GFile(output_path, 'wb') as fgraph:
fgraph.write(output_graph_def.SerializeToString())
if __name__=="__main__":
input_path = "./ckpt_convert_pro/yolov3-tiny.ckpt"
output_path = "./pb_model/yolov3-tiny.pb"
freeze_graph(input_path, output_path)
其中,重要的是指定ckpt权重的输出节点名称。可以通过tensorboard可视化ckpt权重,找到没有继续输出节点的终结点。
-
tensorboard可视化ckpt权重
import tensorflow as tf from tensorflow.summary import FileWriter sess = tf.Session() ckpt_path= "./ckpt_convert_pro/yolov3-voc_50000.ckpt.meta" tf.train.import_meta_graph(ckpt_path) FileWriter("__tb_yolov3", sess.graph)
终端执行#
tensorboard --logdir=./ --host=127.0.0.15
显示,
TensorBoard 1.15.0 at http://127.0.0.15:6006/ (Press CTRL+C to quit
就可以在http://127.0.0.15:6006/地址中可视化网络结构了。
- 确定yolov3和yolov3-tiny的输出节点
其中,yolov3的三个输出节点:yolov3/yolov3_head/feature_map_1,yolov3/yolov3_head/feature_map_2,yolov3/yolov3_head/feature_map_3
yolov3-tiny的两个输出节点:
yolov3-tiny/convolutional10/BiasAdd,yolov3-tiny/convolutional13/BiasAdd
- 确定yolov3和yolov3-tiny的输入节点
- 转换后的pb模型可以用Netron查看网络结构,确定pb模型的输入节点。
例如本文yolov3的输入节点是:Placeholder:1,416,416,3
NHWC输入格式
确定模型的输入输出节点后,可以进行ATC模型转换。
(3)ATC 模型转换
昇腾张量编译器(Ascend Tensor Compiler,简称ATC)是昇腾CANN架构体系下的模型转换工具, 它可以将开源框架的网络模型或Ascend IR定义的单算子描述文件(json格式)转换为昇腾AI处理器支持的.om格式离线模型。
本文提供简单的模型转换流程,转换后的模型是否能正确推理,还要结合正确的前处理、后处理操作。
ATC模型转换可参考对应CANN版本的官方文档:https://support.huaweicloud.com/atctool-cann504alpha2infer/atlasatc_16_0001.html
由于atlas500只提供应用推理,上文提供的dockerfile文件中,并没有安装CANN-toolkit。本文是在atlas200DK,安装CANN-toolkit。首先输入atc命令,看环境是否安装:
(关于cann-toolkit环境搭建:https://support.huaweicloud.com/atctool-cann504alpha2infer/atlasatc_16_0004.html)
HwHiAiUser@davinci-mini:~$ atc
ATC start working now, please wait for a moment.
ATC run failed, Please check the detail log, Try 'atc --help' for more information
E10004: Value for [--model] is empty.
[--framework] is required. Must be [0(Caffe) or 1(MindSpore) or 3(TensorFlow) or 5(Onnx)].
ATC模型转换命令:以yolov3为例,tiny模型相同:
atc --model="./yolov3_416_tf1.15.pb" --framework=3 --input_shape="Placeholder:1,416,416,3" --out_nodes="yolov3/yolov3_head/feature_map_1:0;yolov3/yolov3_head/feature_map_2:0;yolov3/yolov3_head/feature_map_3:0" --insert_op_conf=./yolov3_personcar_416_RGB888_U2BGR_0112.cfg --input_format=NHWC --output="./yolov3_416_tf1.15" --soc_version=Ascend310
–model:输入pb模型路径
–framework:原始框架类型
- 0:Caffe
- 1:MindSpore
- 3:TensorFlow
- 5:ONNX
–input_shape:指定输入节点的shape
–out_nodes: 指定输出节点
–insert_op_conf:插入算子的配置文件路径与文件名,例如aipp预处理算子。
–input_format:输入数据格式。
-
Caffe默认为NCHW;
-
TensorFlow默认为NHWC
–output:如果是开源框架的网络模型,存放转换后的离线模型的路径以及文件名(不带后缀)
–soc_version:模型转换时指定芯片版本。
(4)AIPP、DVPP预处理算子介绍
由于本文业务需求,需要达到视频流的实时目标检测。对整个前处理、芯片推理、后处理的流程速度要求很高,而atlas500主要作为AI推理端,host侧(Hi3559A cpu芯片)计算能力相对较弱。我们希望大部分前后处理操作都放到硬件端device侧运行,也就是借助acend310。所以我们需要了解Acend提供的硬件端的AIPP和DVPP操作:
- 官方介绍
AIPP(Artificial Intelligence Pre-Processing)AI预处理,是昇腾AI处理器提供的硬件图像预处理模块。
DVPP (数字视觉预处理模块) 作为昇腾AI软件栈中的编解码和图像转换模块,当来自系统内存和网络的视频或图像数据进入昇腾AI处理器的计算资源中运算之前,由于Davinci架构对输入数据有固定的格式要求,如果数据未满足架构规定的输入格式、分辨率等要求,就需要调用DVPP进行格式的转换,才可以进行后续的神经网络计算步骤。
按照我们理解,AIPP是作为预处理模块,对图像前处理的补充。而DVPP可以对视频进行硬件编解码、对图像进行格式转换。
- 主要功能
AIPP:色域转换、图像归一化、抠图、减均值/乘系数等功能
DVPP:视频解码(VDEC)模块、视频编码(VENC)模块、JPEG解码(JPEGD)模块、JPEG编码(JPEGE)模块、PNG解码(PNGD)模块和视觉预处理(VPC)模块。
- 调用方式
AIPP需要在模型转换时,加载相应参数,AIPP的预处理操作在AI Core上,在模型推理阶段完成(真正输入模型进行推理之前)。
DVPP可以在应用开发的前处理阶段时,通过ACL架构提供的API接口开发。
因此,我们可以回顾yolov3模型部署的前后处理阶段,图像前处理,需要对不同输入尺度的图像resize以符合模型输入尺度。为了检测精度,多数采用等比例缩放 -> padding -> 归一化的操作。其中,等比例缩放、padding可以通过DVPP的VPC接口进行实现。归一化操作可以通过AIPP的减均值/乘系数实现。
同时,由于DVPP视频解码模块的输出为对齐后的YUV420SP类型,但正常我们的模型输入都是RGB,需要我们借助AIPP对输入图像进行色域转换,即,输入YUV420SP 2 RGB。
色域转换参考文档:https://support.huaweicloud.com/atctool-cann504alpha2infer/atlasatc_16_0023.html#section4。
需要理解,AIPP作为模型推理前的操作,文档中YVU420SP_U8转RGB,指的是AIPP算子需要输入 YVU420SP_U8的图像,即,前处理的输出、模型推理阶段的输入应该是YVU420SP_U8。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)