python3.7.5安装(装在usr/local 以后复制到home目录)
检查系统是否安装python依赖以及gcc等软件。
分别使用如下命令检查是否安装gcc,make以及python依赖软件等。
gcc --version
make --version
cmake --version
g++ --version
dpkg -l zlib1g| grep zlib1g| grep ii
dpkg -l zlib1g-dev| grep zlib1g-dev| grep ii
dpkg -l libsqlite3-dev| grep libsqlite3-dev| grep ii
dpkg -l openssl| grep openssl| grep ii
dpkg -l libssl-dev| grep libssl-dev| grep ii
dpkg -l libffi-dev| grep libffi-dev| grep ii
dpkg -l unzip| grep unzip| grep ii
dpkg -l pciutils| grep pciutils| grep ii
dpkg -l net-tools| grep net-tools| grep ii
若分别返回如下信息则说明已经安装,进入下一步。
gcc (Ubuntu 7.3.0-3ubuntu1~18.04) 7.3.0
g++ (Ubuntu 7.3.0-3ubuntu1~18.04) 7.3.0
GNU Make 4.1
cmake version 3.10.2
zlib1g:amd64 1:1.2.11.dfsg-0ubuntu2 amd64 compression library - runtime
zlib1g-dev:amd64 1:1.2.11.dfsg-0ubuntu2 amd64 compression library - development
libsqlite3-dev:amd64 3.22.0-1ubuntu0.3 amd64 SQLite 3 development files
openssl 1.1.1-1ubuntu2.1~18.04.5 amd64 Secure Sockets Layer toolkit - cryptographic utility
libssl-dev:amd64 1.1.1-1ubuntu2.1~18.04.5 amd64 Secure Sockets Layer toolkit - development files
libffi-dev:amd64 3.2.1-8 amd64 Foreign Function Interface library (development files)
unzip 6.0-21ubuntu1 amd64 De-archiver for .zip files
pciutils 1:3.5.2-1ubuntu1.1 amd64 Linux PCI Utilities
net-tools 1.60+git20161116.90da8a0-1ubuntu1 amd64 NET-3 networking toolkit
否则请执行如下安装命令
sudo apt-get install -y gcc g++ make cmake zlib1g zlib1g-dev libsqlite3-dev openssl libssl-dev libffi-dev unzip pciutils net-tools
一、ATC模型转换
1 yolov5
(1)pt文件转换为onnx文件
下载ultralytics-5.0(软件包名为yolov5-5.0.tar.gz)。
wget https://github.com/ultralytics/yolov5/archive/v5.0.tar.gz
tar -xzf yolov5-5.0.tar.gz
vi yolov5-5.0/models/export.py
:set number
i
# 修改第77行opset_version为11
:wq!
在yolov5-5.0目录运行如下命令:
python models/export.py --weights ./yolov5s.pt --img 640 --batch 1
运行结果:生成yolov5s.onnx文件。
(2)onnx文件简化及算子处理
首先对导出的onnx图使用onnx-simplifer工具进行简化。在yolov5-5.0目录运行如下命令:
python -m onnxsim --skip-optimization yolov5s.onnx yolov5s_sim.onnx
运行结果:生成yolov5s_sim.onnx文件。
(3)然后利用附件脚本yolov5_demo/models/yolov5/modify_yolov5s_slice.py修改模型Slice算子。将附件脚本上传yolov5-5.0目录,运行如下命令:(查看netron视图编号是否一致,不一致需要改算子编号)
import sys
import onnx
INT_MAX = sys.maxsize
model_path = sys.argv[1]
model = onnx.load(model_path)
def get_node_by_name(nodes, name: str):
for n in nodes:
if n.name == name:
return n
return -1
"""
before:
input
/ \
slice4 slice14 slice24 slice34
| | | |
slice9 slice19 slice29 slice39
\ \ / /
concat
after:
input
/ \
slice4 slice24
| |
t t
/ \ / \
slice9 slice19 slice29 slice39
| | | |
t t t t
\ \ / /
concat
"""
model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_24"))
model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_34"))
prob_info1 = onnx.helper.make_tensor_value_info('to_slice9', onnx.TensorProto.FLOAT, [1, 3, 640, 320])
prob_info3 = onnx.helper.make_tensor_value_info('to_slice19', onnx.TensorProto.FLOAT, [1, 3, 640, 320])
prob_info5 = onnx.helper.make_tensor_value_info('from_slice9', onnx.TensorProto.FLOAT, [1, 3, 320, 320])
prob_info6 = onnx.helper.make_tensor_value_info('from_slice19', onnx.TensorProto.FLOAT, [1, 3, 320, 320])
prob_info7 = onnx.helper.make_tensor_value_info('from_slice29', onnx.TensorProto.FLOAT, [1, 3, 320, 320])
prob_info8 = onnx.helper.make_tensor_value_info('from_slice39', onnx.TensorProto.FLOAT, [1, 3, 320, 320])
# slice4 slice24后的Transpose
node1 = onnx.helper.make_node(
'Transpose',
inputs=['131'],
outputs=['to_slice9'],
perm=[0, 1, 3, 2]
)
node3 = onnx.helper.make_node(
'Transpose',
inputs=['141'],
outputs=['to_slice19'],
perm=[0, 1, 3, 2]
)
# slice9 slice19 slice29 slice39后的Transpose
node5 = onnx.helper.make_node(
'Transpose',
inputs=['from_slice9'],
outputs=['136'],
perm=[0, 1, 3, 2]
)
node6 = onnx.helper.make_node(
'Transpose',
inputs=['from_slice19'],
outputs=['146'],
perm=[0, 1, 3, 2]
)
node7 = onnx.helper.make_node(
'Transpose',
inputs=['from_slice29'],
outputs=['156'],
perm=[0, 1, 3, 2]
)
node8 = onnx.helper.make_node(
'Transpose',
inputs=['from_slice39'],
outputs=['166'],
perm=[0, 1, 3, 2]
)
model.graph.node.append(node1)
model.graph.node.append(node3)
model.graph.node.append(node5)
model.graph.node.append(node6)
model.graph.node.append(node7)
model.graph.node.append(node8)
# slice9 slice19 换轴
model.graph.initializer.append(onnx.helper.make_tensor('starts_9', onnx.TensorProto.INT64, [1], [0]))
model.graph.initializer.append(onnx.helper.make_tensor('ends_9', onnx.TensorProto.INT64, [1], [INT_MAX]))
model.graph.initializer.append(onnx.helper.make_tensor('axes_9', onnx.TensorProto.INT64, [1], [2]))
model.graph.initializer.append(onnx.helper.make_tensor('steps_9', onnx.TensorProto.INT64, [1], [2]))
newnode1 = onnx.helper.make_node(
'Slice',
name='Slice_9',
inputs=['to_slice9', 'starts_9', 'ends_9', 'axes_9', 'steps_9'],
outputs=['from_slice9'],
)
model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_9"))
model.graph.node.insert(9, newnode1)
newnode2 = onnx.helper.make_node(
'Slice',
name='Slice_19',
inputs=['to_slice19', 'starts_9', 'ends_9', 'axes_9', 'steps_9'],
outputs=['from_slice19'],
)
model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_19"))
model.graph.node.insert(19, newnode2)
# slice29 slice39 换轴
model.graph.initializer.append(onnx.helper.make_tensor('starts_29', onnx.TensorProto.INT64, [1], [1]))
model.graph.initializer.append(onnx.helper.make_tensor('ends_29', onnx.TensorProto.INT64, [1], [INT_MAX]))
model.graph.initializer.append(onnx.helper.make_tensor('axes_29', onnx.TensorProto.INT64, [1], [2]))
model.graph.initializer.append(onnx.helper.make_tensor('steps_29', onnx.TensorProto.INT64, [1], [2]))
newnode3 = onnx.helper.make_node(
'Slice',
name='Slice_29',
inputs=['to_slice9', 'starts_29', 'ends_29', 'axes_29', 'steps_29'],
outputs=['from_slice29'],
)
model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_29"))
model.graph.node.insert(29, newnode3)
newnode4 = onnx.helper.make_node(
'Slice',
name='Slice_39',
inputs=['to_slice19', 'starts_29', 'ends_29', 'axes_29', 'steps_29'],
outputs=['from_slice39'],
)
model.graph.node.remove(get_node_by_name(model.graph.node, "Slice_39"))
model.graph.node.insert(39, newnode4)
# onnx.checker.check_model(model)
onnx.save(model, sys.argv[1].split('.')[0] + "_t.onnx")
python modify_yolov5s_slice.py yolov5s_sim.onnx
运行结果:生成yolov5s_sim_t.onnx文件。
注意:5.0的modify_yolov5s_slice.py和2.0 3.0的都不一样
2 Unet
把训练好的模型转onnx。# Copyright 2021 Huawei Technologies Co., Ltd
import torch
import torch.onnx
import sys
sys.path.append(r"./pytorch-ssd")
from modeling.unet import *
def pth2onx(model_path, out_path):
model = Unet(n_channels=3, n_classes=6)
#参考代码改
print("begin to load model")
ckpt = torch.load(model_path, map_location='cpu')
model.load_state_dict(ckpt['state_dict'])
#model = model.cuda()
input_names = ["image"]
dummy_input = torch.randn(1, 3, 256, 256)
print("begin to export")
torch.onnx.export(model, dummy_input, out_path, input_names=input_names,
opset_version=11, verbose=True)
print("end export")
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: python SSD_MobileNet_pth2onnx.py
sys.exit(0)
model_path = sys.argv[1]
out_path = sys.argv[2]
pth2onx(model_path, out_path)
对导出的onnx图使用onnx-simplifer工具进行简化。
python -m onnxsim unet .onnx unet_sim.onnx
公司的unet模型没有多余的padding算子,不需要特殊操作。
如果使用官网的模型,需要处理掉多余的padding算子,用netron查看对应的算子编号逐个修改。否则转om会算子报错padv3不支持。
import onnx
def GetNodeIndex(graph, node_name):
index = 0
for i in range(len(graph.node)):
if graph.node[i].name == node_name:
index = i
break
return index
model = onnx.load("unet_sat_sim.onnx")
model.graph.node[GetNodeIndex(model.graph,'Concat_107')].input[1] = '275'
node_list = ["Pad_106"]
max_idx = len(model.graph.node)
rm_cnt = 0
for i in range(len(model.graph.node)):
if i < max_idx:
n = model.graph.node[i - rm_cnt]
if n.name in node_list:
print("remove {} total {}".format(n.name, len(model.graph.node)))
model.graph.node.remove(n)
max_idx -= 1
rm_cnt += 1
model.graph.node[GetNodeIndex(model.graph,'Concat_85')].input[1] = '239'
node_list = ["Pad_84"]
max_idx = len(model.graph.node)
rm_cnt = 0
for i in range(len(model.graph.node)):
if i < max_idx:
n = model.graph.node[i - rm_cnt]
if n.name in node_list:
print("remove {} total {}".format(n.name, len(model.graph.node)))
model.graph.node.remove(n)
max_idx -= 1
rm_cnt += 1
model.graph.node[GetNodeIndex(model.graph,'Concat_63')].input[1] = '203'
node_list = ["Pad_62"]
max_idx = len(model.graph.node)
rm_cnt = 0
for i in range(len(model.graph.node)):
if i < max_idx:
n = model.graph.node[i - rm_cnt]
if n.name in node_list:
print("remove {} total {}".format(n.name, len(model.graph.node)))
model.graph.node.remove(n)
max_idx -= 1
rm_cnt += 1
model.graph.node[GetNodeIndex(model.graph,'Concat_41')].input[1] = '167'
node_list = ["Pad_40"]
max_idx = len(model.graph.node)
rm_cnt = 0
for i in range(len(model.graph.node)):
if i < max_idx:
n = model.graph.node[i - rm_cnt]
if n.name in node_list:
print("remove {} total {}".format(n.name, len(model.graph.node)))
model.graph.node.remove(n)
max_idx -= 1
rm_cnt += 1
onnx.checker.check_model(model)
onnx.save(model, "unet_sat_sim_final.onnx")
二、下载ATC工具。
1 安装 Python3开发环境
安装前请先使用pip3.7.5 list命令检查是否安装相关依赖,若已经安装,则请跳过该步骤;若未安装,则安装命令如下(如果只有部分软件未安装,则如下命令修改为只安装还未安装的软件即可)。其中:toolkit包中算子比对工具依赖:protobuf、scipy;profiling工具依赖:protobuf、grpcio、grpcio-tools、requests。
如果使用非root用户安装Python及其依赖,用户需要在本步骤中的每句命令结尾加上--user,保证安装的正常进行。命令示例为:pip3.7.5 install attrs --user
pip3.7.5 install attrs psutil decorator numpy protobuf==3.11.3 scipy sympy cffi grpcio grpcio-tools requests --user -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3.7.5 install attrs
pip3.7.5 install psutil
pip3.7.5 install decorator
pip3.7.5 install numpy
pip3.7.5 install protobuf==3.11.3
pip3.7.5 install scipy
pip3.7.5 install sympy
pip3.7.5 install cffi
pip3.7.5 install grpcio
pip3.7.5 install grpcio-tools
pip3.7.5 install requests
2 安装环境依赖
我们是在普通用户下安装的,首先确保当前环境中有一个普通用户和一个root用户,如果是新建的虚拟机需要先给root用户配置密码后才可以正常登录root用户(sudo passwd root)。以下安装普通用户以ascend举例。
用户权限配置。
普通用户安装开发套件,需要有sudo权限,所以首先需要给普通用户配置权限。
切换为root用户。
su root
给sudoer文件配置写权限,并打开该文件。
chmod u+w /etc/sudoers
vi /etc/sudoers
在该文件“ # User privilege specification”下面增加如下内容:
其中,ascend为开发环境种普通用户用户名,需要根据自己的环境修改。
配置源
源配置。
由于安装过程中涉及很多apt依赖和pip依赖的安装,所以配置一个国内源是一个加快进度的好办法。
配置ubuntu18.04-x86的apt清华源。
root用户下打开apt源文件。
vi /etc/apt/sources.list
将源文件内容替换为以下ubuntu18.04-x86的apt清华源。
root@ubuntu:/home/ascend# cat /etc/apt/sources.list
# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
root@ubuntu:/home/ascend#
安装相关apt依赖。
普通用户下安装,这些是开发环境中套件包所依赖的一些apt软件,都需要成功安装。
sudo apt-get install -y gcc make cmake unzip zlib1g zlib1g-dev libsqlite3-dev openssl libssl-dev libffi-dev pciutils net-tools
3 安装python环境(装在主目录)
执行以下命令,进入普通用户家目录。
cd $HOME
下载python3.7.5源码包并解压。
wget https://www.python.org/ftp/python/3.7.5/Python-3.7.5.tgz
tar -zxvf Python-3.7.5.tgz
进入解压后的文件夹,执行配置、编译和安装命令。
cd Python-3.7.5
./configure --prefix=/usr/local/python3.7.5 --enable-shared
make
sudo make install
执行以下命令将so拷贝到lib中,并设置软链接。
sudo cp /usr/local/python3.7.5/lib/libpython3.7m.so.1.0 /usr/lib
sudo ln -s /usr/local/python3.7.5/bin/python3 /usr/bin/python3.7
sudo ln -s /usr/local/python3.7.5/bin/pip3 /usr/bin/pip3.7
sudo ln -s /usr/local/python3.7.5/bin/python3 /usr/bin/python3.7.5
sudo ln -s /usr/local/python3.7.5/bin/pip3 /usr/bin/pip3.7.5
执行以下命令,安装环境所需的相关pip依赖。
pip3.7.5 install attrs psutil decorator numpy protobuf==3.11.3 scipy sympy cffi grpcio grpcio-tools requests --user
4 安装toolkit开发工具包 华为官网下载
https://support.huawei.com/enterprise/zh/ascend-computing/cann-pid-251168373/software
将包放置到开发环境普通用户的$HOME目录下。
并执行以下命令,切换到普通用户的$HOME目录下。
cd $HOME
ascend
执行以下命令,给run包增加可执行权限。
chmod 755 *.run
执行以下命令,安装toolkit包。
./Ascend-Toolkit-20.0.0.RC1-x86_64-linux_gcc7.3.0.run –install
三、使用ATC工具把onnx转化成om文件(避免版本问题,使用华为主机ATC,无需配置环境变量)
1 配置环境变量
export PATH=/usr/local/python3.7.5/bin:/home/wyc/Ascend/ascend-toolkit/latest/atc/ccec_compiler/bin:/home/wyc/Ascend/ascend-toolkit/latest/atc/bin:$PATH
export PYTHONPATH=/home/wyc/Ascend/ascend-toolkit/latest/atc/python/site-packages:/home/wyc/Ascend/ascend-toolkit/latest/atc/python/site-packages/auto_tune.egg/auto_tune:$/home/wyc/Ascend/ascend-toolkit/latest/atc/python/site-packages/schedule_search.egg
export export LD_LIBRARY_PATH=/home/wyc/Ascend/ascend-toolkit/latest/lib64:/home/wyc/Ascend/ascend-toolkit/latest/compiler/lib64/plugin/opskernel:/home/wyc/Ascend/ascend-toolkit/latest/compiler/lib64/plugin/nnengine:$LD_LIBRARY_PATH:${HOME}/Ascend/ascend-toolkit/latest/atc/lib64/stub
export SLOG_PRINT_TO_STDOUT=1
export ASCEND_AICPU_PATH=/home/wyc/Ascend/ascend-toolkit/latest
export ASCEND_OPP_PATH=/home/wyc/Ascend/ascend-toolkit/latest/opp
export TOOLCHAIN_HOME=/home/wyc/Ascend/ascend-toolkit/latest/toolkit
export ASCEND_AUTOML_PATH=/home/wyc/Ascend/ascend-toolkit/latest/tools
2 运行atc指令(如果以root身份运行,也要安装相关依赖)
atc --model=yolov5s_sim_t.onnx --framework=5 --output=yolov5s --input_format=NCHW --input_shape="images:1,3,640,640" --enable_small_channel=1 --insert_op_conf=aipp_yolov5.cfg --soc_version=Ascend310 –log=info
\atc --model=unet_sim_t.onnx --framework=5 –output=unet --input_format=NCHW --input_shape="images:1,3,480,480" --enable_small_channel=1 --soc_version=Ascend310 –log=info
参数说明:
--model:待转换的ONNX模型。
--framework:5代表ONNX模型。
--output:输出的om模型。
--input_format:输入数据的格式。
--input_shape:输入数据的shape。
--insert_op_conf=./aipp_yolov5.cfg:AIPP插入节点,通过config文件配置算子信息,功能包括图片色域转换、裁剪、归一化,主要用于处理原图输入数据,常与DVPP配合使用,详见下文数据预处理。
详细ATC命令转换学习请参考:
https://support.huaweicloud.com/atctool-cann502alpha5infer/atlasatc_16_0001.html
PS:unet 模型的预处理要和python 端的一致(归一化用aipp做)
示例 yolov5
aipp_op {
aipp_mode : static
related_input_rank : 0
input_format : YUV420SP_U8 //输入格式,经过dvpp解码是yuv格式,这里转rgb
src_image_size_w : 640
src_image_size_h : 640 //尺寸一样
crop : false
csc_switch : true
rbuv_swap_switch : false// 这里可以控制输出rgb或者bgr,官网手册有各种转化模板
matrix_r0c0 : 256
matrix_r0c1 : 0
matrix_r0c2 : 359//旋转矩阵
matrix_r1c0 : 256
matrix_r1c1 : -88
matrix_r1c2 : -183
matrix_r2c0 : 256
matrix_r2c1 : 454
matrix_r2c2 : 0
input_bias_0 : 0
input_bias_1 : 128
input_bias_2 : 128
var_reci_chn_0 : 0.0039216
var_reci_chn_1 : 0.0039216
var_reci_chn_2 : 0.0039216 //归一化的方差倒数,这里只做了归一化没有做标准化,unet都要作
}
unet示例
aipp_op {
aipp_mode : static
related_input_rank : 0
input_format : YUV420SP_U8
src_image_size_w : 512
src_image_size_h : 512
crop : false
csc_switch : true
rbuv_swap_switch : false
matrix_r0c0 : 256
matrix_r0c1 : 0
matrix_r0c2 : 359
matrix_r1c0 : 256
matrix_r1c1 : -88
matrix_r1c2 : -183
matrix_r2c0 : 256
matrix_r2c1 : 454
matrix_r2c2 : 0
input_bias_0 : 0
input_bias_1 : 128
input_bias_2 : 128
mean_chn_0: 0
mean_chn_1: 0
mean_chn_2: 0
mean_chn_3: 0//每个通道的均值
min_chn_0: 0.0
min_chn_1: 0.0
min_chn_2: 0.0
min_chn_3: 0.0//每个通道减去的数值
var_reci_chn_0 : 0.0039216
var_reci_chn_1 : 0.0039216
var_reci_chn_2 : 0.0039216
}
四、模型推理
1 修改
run.sh中MX_SDK_HOME为MindX SDK安装目录
export MX_SDK_HOME=/root/MindX_SDK/mxVision
2、执行run.sh
bash run.sh
五、YoLoV5 demo详解
1 技术流程图
视频解码:调用DVPP解码能力,转换为 YUV 格式图像数据。
图像缩放:调用DVPP,将图像缩放到一定尺寸大小。
目标检测:YoLoV5模型针对图像进行目标检测。
模型后处理:针对推理结果进行后处理文字转换。
数据序列化:将stream结果组装成json字符串输出。
2 pipeline详解
参数说明:
modelPath:模型路径,请根据模型实际路径修改。
postProcessConfigPath:模型配置文件路径,请根据模型配置文件的实际路径修改。
labelPath:标签文件路径,请根据标签文件的实际路径修改。
3 源码详解
main.cpp