背景:
深度学习训练的模型,很多项目需要移植到板子上应用,这里记录了移植华为海思的芯片Hi3516CV500上的流程。在这里默认板子已经预装好系统,服务器的系统为ubuntu16.04。
目的:本文主要针对刚接触板子算法移植的一个简单工作手册,按顺序操作,基本问题不大。
一.服务器环境搭建及工具链安装
1.安装himix200交叉编译器
(1)解压: tar –xzf arm-himix200-linux.tgz
(2)运行: chmod +x arm-himix200-linux.install
(3) 安装: sudo ./arm-himix200-linux.install
(4)环境变量生效:source /etc/profile
注意:记录下交叉编译的位置,比如我的安装位置:/opt/hisi-linux/x86-arm/arm-himix200-linux
2.安装nfs文件系统
在开发调试过程中,我们需要在linux服务器上安装nfs,以便开发代码可以mount到板子来运行。
(1)执行如下命令:
sudo apt-get install nfs-kernel-server //install sw
sudo apt-get install nfs-common //install sw
sudo /etc/init.d/service nfs-kernel-server restart // Start service
(2)使nfs目录生效
sudo mkdir xx/xx/hisi_nfs //创建一个目录,路径以及nfs目录名由自己指定,这个目录下的内容将来会被mount到板子上
sudo vi /etc/exports //hisi_nfs为自己创建的nfs目录名
添加如下内容:
/media/data1/hisi_nfs *(rw,sync,no_root_squash,no_subtree_check)
exportfs -rf //来使得上面nfs目录设置生效。
(3) 开启telnet服务
作用:网络连接正常后,启动单板 telnet 服务,能够直接登录到单板上。
sudo apt-get install openbsd-inetd
sudo apt-get install telnetd
sudo /etc/init.d/openbsd-inetd restart
# 查看 telnet服务是否开启
sudo netstat -a | grep telnet
从服务器用telnet登录板子:
#在服务器终端:telnet address(单板地址)
telnet 192.168.xx.xx
二. opencv的交叉编译和准备
(1) 使用cmake-gui 交叉编译
#在服务器终端执行
cmake-gui
(2)选择交叉编译平台:
(3)修改配置
CMAKE_INSTALL_PREFIX: /media/XX/opencv-3.4.1/cmakebuild/hisicv500install
CMAKE_EXE_LINKER_FLAGS: -lpthread -lrt -ldl
BUILD_opencv_world: 选择对号
配置完成后点击generate来生成可编译得opencv代码
(4)进入build 编译: make -j8
(5)可能遇到的问题:
解决方法:
在common.cc头文件加:#define HAVE_PTHREAD
(6) make install
在路径/media/XX/opencv-3.4.1/cmakebuild/hisicv500install下可找到编译的库文件libopencv_world.so,和头文件include
三. pytorch模型转onnx
1.安装onnx工具
pip install onnx
2.pytorch模型转onnx可能遇到的问题:
(1)onnx只能输出静态图,因此不支持if-else分支。一次只能走一个分支。如果代码中有if-else语句,需要改写;
(2) onnx不支持步长为2的切片。例如a[::2,::2];
(3) onnx不支持对切片对象赋值。例如a[0,:,:,:]=b, 可以用torch.cat改写;
(4) onnx里面的resize要求output shape必须为常量;
(5) 在torch.onnx.export(model, inputs, output_onnx)的输入参数model里,应该只包含网络结构,也就是说model里只含有nn.Conv2d, nn.MaxPool2d, nn.BatchNorm2d, F.relu等等的这些算子组件,而不应该含有后处理模块的。图像预处理和后处理模块需要自己使用C++或者Python编程实现。
3.onnx模型验证
pytorch模型转onnx后,可以用opencv的dnn模块读取.onnx文件做前向测试,验证结果。
4. 安装ONNX Simplifier模型简化
执行命令:
pip3 install -U pip && pip3 install onnx-simplifier ## install onnx-simplifier
python3 -m onnxsim input_onnx_model output_onnx_model ## onnx simplify
5.onnx模型可视化
对简化后的onnx模型文件使用工具Netron可视化,看起来视图更清爽,输入输出参数更明了。netron网页版
四.onnx转caffe模型
1.caffe编译
(1)检查下自己网络结构中是否有特殊层,如果caffe中不支持的层,需要自己编写或者查找借鉴下;
(2) 修改caffe中xx/caffe/src/caffe/proto文件,把特殊层加进去,同时把特殊层的头文件加入xx/caffe/include/caffe/layers,把.cpp、.cu文件加入xx/caffe/src/caffe/layers中;
(3)正常编译caffe;
2.onnx转caffe模型
(1)使用工具ONNXToCaffe
工具链接 ONNXToCaffe
(2)在使用过程中可能遇到的问题
在运行过程中.prototxt文件中部分参数可能存在转错的情况,需要自己根据onnx可视化参数来修改对应转错的参数。把修改正确的.prototxt文件传入compareOnnxAndCaffe(onnx_path,prototxt_path,caffemodel_path)中。转换结束后,输出的模型转换相似度接近1.0,即可完成。
(3)caffe模型验证
对转换后的caffe模型进行前向推理验证,检验结构是否正确。
五.caffe转wk
1.完成Ruyi Studio的安装
(1)HiSVP_PC_V1.2.1.0/tools/nnie/windows/RuyiStudio-2.0.31下直接运行RuyiStudio.exe;
(2)可以不用按HiSVP 开发指南.pdf中的仿真环境配置,但是调试只能在板子上了,为了简便操作我没有配置仿真环境。
2.准备图片
(1) 根据官方文档介绍,量化用的图片应选择典型场景图片,一般从网络模型的测试场景中选择20-50张作为参考图片进行量化;
(2) 选择的图片要尽量覆盖模型的各个场景。不要选择偏僻场景,过度曝光、纯黑、纯白的图片,选择识别率高,色彩均匀的典型场景图片。
(3) 把图片尺寸和caffe的prototxt文件输入尺寸对齐(t通过填充resize方式);
3.创建工程
(1)在windows环境下,直接运行RuyiStudio.exe;
(2)依次点击File->New->NNIE Project,设置项目名称,检查芯片选择为Hi3559CV500,Project type选择Empty Project,ToolChains选择MinGW GCC,点击Finish。
(3)配置cfg文件并生成wk
配置好cfg文件之后,点击make wk按钮,生成相应的wk文件。
其中需要注意的问题:
[1]参数设置说明:
marked_prototxt:自动生成,不要对其进行修改。
log_level:选择Function level打印出每一层的量化输出,方便定位精度问题。
batch_num:一般情况下填写 1。
image_type: 一般情况下选择 U8。
RGB_order: 模型推理时图片输入为RGB或者BGR,根据自己的模型训练时的输入进行选择。
image_list:可以通过选择create,选择好需要的图片之后RuyiStudio会自动生成 image_list.txt,不需要自己创建txt。
norm_type: 查看开发指南里的定义,根据实际图像预处理选择减均值与乘方差的操作。该模型每个通道对应一个均值,mean.txt 分别写三个通道的均值,注意按照 RGB_ORDER设定的通道数填写的对应通道的mean,模型转换时会将图像预处理的相关操作加在wk模型里,先减均值后乘以scale。
其他的参数参考开发指南填写,填写完成后进行保存。
[2]RGB_order与输入图像通道之间的关系
六.编译自己的工程在板子上运行
1.写好自己的工程demo,例如demo.cpp;
2.修改Makefile文件为Makefile.Shared,执行make -f Makefile.Shared,生成动态库libnnieface.so;
3.执行编译命令:
/opt/hisi-linux/x86-arm/arm-himix200-linux/bin/arm-himix200-linux-g++ -o nnie_face_demo demo.cpp -L. -lnnieface -lopencv_world -lpthread -ldl -I /xx/Hi3516CV500R001C02SPC010/01.software/board/Hi3516CV500_SDK_V2.0.1.0/smp/a7_linux/mpp/include
#nnie_face_demo: 表示生成的可执行文件的名字
#nnieface: 表示自己编译的工程的动态库名字
编译完成后会生成可执行文件nnie_face_demo 。
4.登录板子运行demo
(1) 准备demo需要的文件
先把3中编译的可执行文件nnie_face_demo、待加载的.wk模型文件、测试图片、第三方库文件(libopencv_world.so )等demo需要用到的文件,全部拷贝到服务器:/media/data1/hisi_nfs文件夹下;
(2)从服务器登录板子
#在服务器终端:telnet address(单板地址)
telnet 172.xx.xx.61
(3)挂载文件夹
mount -t nfs 172.xx.xx.61:/media/data1/hisi_nfs /nfsroot -o nolock
##172.xx.xx.61: 为单板地址
##/media/data1/hisi_nfs: 为服务器要挂载的文件夹的绝对路径
##/nfsroot: 为板子上的文件夹路径
(4)运行
cd /nfsroot ##进入文件夹
cp -rt /nfsroot *.so /app/lib ##拷贝所有动态库文件到默认系统目录下
./nnie_face_demo ##执行,得到结果
(5) 关于在板子上运行的问题:
[1] 如果nfsroot内的文件比较大,可以把nfsroot拷贝到/mnt/ram/下(cp -rf /nfsroot /mnt/ram/);
[2] 需要把.so动态库拷贝到/app/lib下,否则无法运行,找不到动态库;
[3] 每次登出后/mnt/ram/下拷贝的文件会丢失,但是/app/lib下的不会丢失;
[4]海思板子上nnie网络输出的数据一定要除以4096.f(这是个硬性要求,即使caffe版本的不存在除以4096.f,这个主要是海思板子的数据转换问题);
参考:
https://blog.csdn.net/Will_young111/article/details/106209882
http://www.ai111.vip/thread-1079-1-1.html
https://blog.csdn.net/nihate/article/details/112731327?spm=1001.2014.3001.5501
https://blog.csdn.net/avideointerfaces/article/details/88722157
https://blog.csdn.net/avideointerfaces/article/details/89477828
https://blog.csdn.net/zxc024000/article/details/81272714
https://bbs.huaweicloud.com/blogs/271151