【昇腾CANN训练营第二期】【应用营】高玩赛作业:使用MindStudio完成YoLoV5和ResNet50的推理开发

网友投稿 617 2022-05-29

CANN训练营第二期  应用营 高玩赛作业链接:

https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=143438&extra=page=1

实操作业为:

学习路径: 1、视频课程:MindX应用使能组件介绍 https://www.hiascend.com/zh/activities/cloud2021/live/8120 2、实验课程:使用MindX SDK开发智能质检应用 https://lab.huaweicloud.com/testdetail_531 3、实验课程:MindX SDK + Pytorch yolov5 应用案例详解 https://bbs.huaweicloud.com/forum/thread-118598-1-1.html 课程作业: 在MindStudio中创建MindX SDK模板工程,并完成检测(yolov5)+分类(resnet50,从生昇腾社区ModelZoo获取,TensorFlow和Pytorch的均可)。 MindX SDK模板工程可以放到gitee上,参考附件。 评分规则: 在MindStudio中创建MindX SDK模板工程:10分 并完成检测:30分 分类:15分 推理应用开发:15分

解题思路分析:

作业中“学习路径”中的第二个链接的实验,张小白以前就做过了:

https://bbs.huaweicloud.com/forum/thread-137435-1-1.html

第一个链接的直播,好像讲的也是 MindX,并且也含了第二个链接的实验:

https://www.hiascend.com/zh/activities/cloud2021/live/8120

第三个链接,好像就可以指导作业了:

https://bbs.huaweicloud.com/forum/thread-118598-1-1.html

所以打开第三个链接,咱们就开始做作业吧!

听这次的 高玩赛 老师  @Fate丶SSS 的介绍,高玩赛的镜像跟 新手营的镜像一样,都是image-for-MindX。那么简单了,只需要将 新手营没有删除的 AI1S服务器开机,就可以开始做作业了。

如果你不小心删了,也不要紧请移驾 https://bbs.huaweicloud.com/blogs/285668 完成服务器购买等操作:

并根据 https://bbs.huaweicloud.com/blogs/285675 步骤,完成ResNet50网络的离线模型生成:

下面的操作是基于上述步骤执行完毕的情况下进行。

MindStudio的启动、创建工程和MindStudio配置:

开机-》启动 MindStudio

New Project

Next,选择  选择Sample(detection and classfication)(下图中的箭头请忽略,以文字为准)

点击Finish:

当点击工程中pipeline目录下的Sample.pipeline时,系统会提示,“There is no activated MindX SDK”,因此要配置下MindX SDK的位置:

在MindStudio菜单栏依次点击"Ascend"->"MindX SDK Manager"

在弹出的窗口点击 Install SDK

选择 SDK的路径:

选择online试试:(这是一个坑。。。)

它居然在装aarch64的版本,估计是对自己是X86的身份存在怀疑:

点击Finish

明显X86的SDK是不能用的。

还是通过local模式装SDK吧:

检查mindxsdk安装盘的位置:/home/HwHiAiUser/MindX

选择该目录下的run文件:

Next:

Next:

耐心等待安装完毕,点击Finish:

点击OK,这回pipeline的图形化界面终于出现了:

仔细查看pipleline的图形,以及对应的源码(Text):

这个sample。前面是YoLoV3,后面是 ResNet50.

而我们的高玩题目呢?要求前面是YoLoV5,后面是 ResNet50。

所以解题思路很简单:

1.要么一个一个做,比如先只做YoLoV5, 再开个MindX SDK项目只做ResNet50

2.或者把现在的pipeline改一下,前面改为YoLoV5。后面应该不用改了。

跑通YoLoV3+ResNet50:

先把现在的代码编译一下:

菜单栏点击”Build“->"Edit Build Configuration..."

点击build,会生成out目录下的main可执行代码:

运行下试试:选择local Run,按以下内容填写:

点击Run:会告诉你om模型不存在:

需要把 第三周作业( https://bbs.huaweicloud.com/blogs/285675 )转换好的ResNet50的离线模型 resnet50_aipp_tf.om 拷贝过来:

找到本项目所在的目录:

cd ~/AscendProjects/Resnet50

cd models/resnet50

cp /home/HwHiAiUser/MindX/resnet50/model/resnet50_aipp_tf.om .

顺便也把第二周作业( https://bbs.huaweicloud.com/blogs/285668 )生成的YoLoV3离线模型也拷过来:

cd ../yolov3

cp /home/HwHiAiUser/MindX/yolov3/yolov3_tf_bs1_fp16.om .

再重新运行:

运行结果如下:

具体内容看不清,贴出来一下:

2021-07-31 18:40:38 - [INFO] Resnet50 start running... 2021-07-31 18:40:38 - [INFO] Execute command on local: export LD_LIBRARY_PATH=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/lib:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/lib/plugins:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/lib:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/lib64:/root/AscendProjects/Resnet50/lib:/root/AscendProjects/Resnet50/lib/plugins:${LD_LIBRARY_PATH} && export GST_PLUGIN_SCANNER=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/libexec/gstreamer-1.0/gst-plugin-scanner && export GST_PLUGIN_PATH=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/lib/gstreamer-1.0:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/lib/plugins:/root/AscendProjects/Resnet50/lib/plugins && export MX_SDK_HOME=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1 && cd /root/AscendProjects/Resnet50/out && ./main Begin to initialize Log. The output directory(./logs) of logs file exist. Save logs information to specified directory(./logs). W0731 18:40:40.195328 5423 main.cpp:130] Results:{"MxpiObject":[{"MxpiClass":[{"classId":163,"className":"beagle","confidence":0.87109375}],"classVec":[{"classId":16,"className":"dog","confidence":0.99641436299999997,"headerVec":[]}],"x0":125.63256800000001,"x1":918.29089399999998,"y0":116.434044,"y1":597.21276899999998}]} 2021-07-31 18:40:41 - [INFO] Run finished, exit status: 0

JSON格式化后的结果如下:

{ "MxpiObject": [{ "MxpiClass": [{ "classId": 163, "className": "beagle", "confidence": 0.87109375 }], "classVec": [{ "classId": 16, "className": "dog", "confidence": 0.99641436299999997, "headerVec": [] }], "x0": 125.63256800000001, "x1": 918.29089399999998, "y0": 116.434044, "y1": 597.21276899999998 }] }

结果分析:

先进行了 YoLoV3的检测(检测结果放入ClassVec和x0,y0、x1、y1的坐标),然后进行了ResNet50的分类(分类结果放入MxpiClass)。

检测结果是:

在 "x0":125.63256800000001,"x1":918.29089399999998,"y0":116.434044,"y1":597.21276899999998}

这个框内,YoLoV3认为它是dog,ResNet认为它属于beagle(猎兔犬)。

当然,Sample代码并没有画出结果。

所以增加以下代码,画个结果的框吧。

参考 https://bbs.huaweicloud.com/forum/thread-137435-1-1.html  的内容增加OpenCV2的代码。

CMakeLists.txt:

Header path include_directories( ${MX_SDK_HOME}/include/ ${MX_SDK_HOME}/opensource/include/ ${MX_SDK_HOME}/opensource/include/opencv4/ ) # add host lib path link_directories( ${MX_SDK_HOME}/lib/ ${MX_SDK_HOME}/opensource/lib/ ${MX_SDK_HOME}/opensource/lib64/ ${MX_SDK_HOME}/opensource/include/opencv4/ ) add_executable(main main.cpp) target_link_libraries(main glog mxbase streammanager cpprest mindxsdk_protobuf opencv_world)

main.cpp

#include "opencv4/opencv2/opencv.hpp"

还有:

web::json::value jsonText = web::json::value::parse(result); if (jsonText.is_object()) { web::json::object textObject = jsonText.as_object(); auto itInferObject = textObject.find("MxpiObject"); if (itInferObject == textObject.end() || (!itInferObject->second.is_array())) { return 0; } auto iter = itInferObject->second.as_array().begin(); cv::Mat src = cv::imread("../data/test.jpg"); for (; iter != itInferObject->second.as_array().end(); iter++) { if (iter->is_object()) { auto modelInferObject = iter->as_object(); float x0 = 0; float x1 = 0; float y0 = 0; float y1 = 0; auto it = modelInferObject.find("x0"); if (it != modelInferObject.end()) { x0 = float(it->second.as_double()); } it = modelInferObject.find("x1"); if (it != modelInferObject.end()) { x1 = float(it->second.as_double()); } it = modelInferObject.find("y0"); if (it != modelInferObject.end()) { y0 = float(it->second.as_double()); } it = modelInferObject.find("y1"); if (it != modelInferObject.end()) { y1 = float(it->second.as_double()); } cv::Rect rect(x0, y0, x1 - x0, y1 - y0); cv::rectangle(src, rect, cv::Scalar(0, 255, 0),5, cv::LINE_8,0); } } cv::imwrite("./result_test.jpg", src); std::cout << "result_test.jpg produced in the directory:/home/user/AscendProjects/MyApp/out." << std::endl; }

重新编译:

重新执行:

上图绿色的就是YoLoV3标记出来的框。

PipeLine:YoLoV3替换为YoLoV5:

既然 YoLoV3和ResNet50都跑通了。那么把 YoLoV5替换掉 YoLoV3就可以。

参考 https://bbs.huaweicloud.com/forum/thread-118598-1-1.html

类似 YoLoV3 的编排,对比链接中 YoLoV5的pipeline。我们做个修改:

可以先把  YoLoV3 的pipeline备份下

检视一下,

YoLoV3有aippconfig、coco.names、yolov3_tf_bs1_fp16.cfg还有一个om,另外还有一个libMpYOLOv3PostProcessor.so

看看对应的yolov5是否齐全:

aipp_yolov5.cfg

那就先生成YoLoV5的离线模型。

YoLoV5的离线模型的生成:

mkdir /root/yolov5s_convert

cd /root/yolov5s_convert

wget https://github.com/ultralytics/yolov5/archive/v2.0.tar.gz --no-check-certificate

tar -xzf v2.0.tar.gz

vi yolov5-2.0/models/export.py

修改第48行opset_version为11

下载权重文件 yolov5s.pt

cd yolov5-2.0

wget https://github.com/ultralytics/yolov5/releases/download/v2.0/yolov5s.pt --no-check-certificate

python models/export.py --weights ./yolov5s.pt --img 640 --batch 1

好像还得装个pytorch。

去PyPorch官网下载 Pytorch 1.8.1:

pip3 install torch==1.8.1+cpu torchvision==0.9.1+cpu torchaudio==0.8.1 -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html

重新执行:

python models/export.py --weights ./yolov5s.pt --img 640 --batch 1

报缺_lzma模块:

查资料找解决方案:https://blog.csdn.net/moxiao1995071310/article/details/97399809/

照此办理:

apt-get install libbz2-dev

apt-get install lzma

apt-get install liblzma-dev

重新编译python3.7.5:

cd /root/Python-3.7.5

./configure --prefix=/usr/local/python3.7.5 --enable-optimizations --enable-shared

...

make

...

需要耐心等待416个test走完。。这是一个漫长的过程:

make install

...

验证下:

下面反复执行:

python models/export.py --weights ./yolov5s.pt --img 640 --batch 1

系统会报缺什么模块,然后我们就按照要求装什么模块:

pip install pyyaml

pip install tqdm

pip install onnx

pip install coremltools -i https://pypi.tuna.tsinghua.edu.cn/simple/

这次再执行:

python models/export.py --weights ./yolov5s.pt --img 640 --batch 1

这到底是成功了还是失败了?

检查了一下,并没有生成onnx文件。应该还是有问题的:

度娘搜索:'google.protobuf.descriptor' has no attribute '_internal_create_key'

https://blog.csdn.net/lemon4869/article/details/107299879

照此办理:

pip install --upgrade protobuf -i https://pypi.tuna.tsinghua.edu.cn/simple/

再来:

python models/export.py --weights ./yolov5s.pt --img 640 --batch 1

。。。

。。。

这回好像真的生成了onnx文件。

这个onnx文件终于生成了。先撒个小花。。。。

然后继续:

python3.7 -m onnxsim --skip-optimization yolov5s.onnx yolov5s_sim.onnx

pip install --upgrade pip

pip install onnx-simplifier

对onnx图使用onnx-simplifer进行简化:

python3.7 -m onnxsim --skip-optimization yolov5s.onnx yolov5s_sim.onnx

下载 https://bbs.huaweicloud.com/forum/thread-118598-1-1.html

帖子的mxManufacture_yolov5_example.zip 附件,解压,

上传slicy脚本:modify_yolov5s_slice.py

修改模型Slice算子

python3.7 modify_yolov5s_slice.py yolov5s_sim.onnx

生成 yolov5s_sim_t.onnx

在当前目录下编辑2个文件:

编辑 aipp_yolov5.cfg

编辑trans_onnx2om.sh

听 @Fate丶SSS 老师说, 目前的image-for-mindx镜像已经不需要升级 tranpose_d.patch补丁了。

下面开始做ATC模型转换:

bash trans_onnx2om.sh

转换成功,OM离线模型文件已成功生成。

将与yolov5s_sim_t.om相适应的配置文件yolov5.cfg和标签文件coco.names上传到同一目录:

下面正式把sample.pipelin的YoLoV3的目标检测部分修改为YoLoV5的目标检测部分了!

打开MindStudio,在Models目录下创建一个yolov5的目录,再到终端将前面准备好的文件都复制到这个目录下:

/root/AscendProjects/Resnet50/models/yolov5

cp /root/yolov5s_convert/yolov5-2.0/aipp_yolov5.cfg .

cp /root/yolov5s_convert/yolov5-2.0/coco.names .

cp /root/yolov5s_convert/yolov5-2.0/yolov5s_sim_t.om .

cp /root/yolov5s_convert/yolov5-2.0/yolov5.cfg .

修改 resize部分,改为640X640且等比缩放

"mxpi_imageresize0": { "props": { "parentName": "mxpi_imagedecoder0", "resizeHeight": "640", "resizeWidth": "640", "resizeType": "Resizer_KeepAspectRatio_Fit" }, "factory": "mxpi_imageresize", "next": "mxpi_modelinfer0" },

修改infer推理部分,将YoLoV3改为YoLoV5:

"mxpi_modelinfer0": { "props": { "modelPath": "../models/yolov5/yolov5s_sim_t.om", "postProcessConfigPath": "../models/yolov5/yolov5.cfg", "labelPath": "../models/yolov5/coco.names", "postProcessLibPath": "libMpYOLOv5PostProcessor.so" }, "factory": "mxpi_modelinfer", "next": "mxpi_imagecrop0" },

为了表示这次处理的是yolov5的结果,我们将main.cpp输出的代码做个修改:

并删除out下的jpg文件:

重新编译:

重新运行:

可以看出,result_test-yolov5文件已生成。

输出结果如下:

2021-08-01 00:45:11 - [INFO] Resnet50 start running... 2021-08-01 00:45:11 - [INFO] Execute command on local: export LD_LIBRARY_PATH=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/lib:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/lib/plugins:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/lib:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/lib64:/root/AscendProjects/Resnet50/lib:/root/AscendProjects/Resnet50/lib/plugins:${LD_LIBRARY_PATH} && export GST_PLUGIN_SCANNER=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/libexec/gstreamer-1.0/gst-plugin-scanner && export GST_PLUGIN_PATH=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/opensource/lib/gstreamer-1.0:/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1/lib/plugins:/root/AscendProjects/Resnet50/lib/plugins && export MX_SDK_HOME=/usr/local/Ascend/mindx_sdk/mxVision_2.0.1/linux-x86_64/mxVision-2.0.1 && cd /root/AscendProjects/Resnet50/out && ./main Begin to initialize Log. The output directory(./logs) of logs file exist. Save logs information to specified directory(./logs). W0801 00:45:12.691449 21204 main.cpp:131] Results:{"MxpiObject":[{"MxpiClass":[{"classId":163,"className":"beagle","confidence":0.837890625}],"classVec":[{"classId":16,"className":"dog","confidence":0.672381699,"headerVec":[]}],"x0":73.496948200000006,"x1":939.73120100000006,"y0":132.934708,"y1":603.36547900000005}]} result_test-yolov5.jpg produced in the directory:/root/AscendProjects/Resnet50/out. 2021-08-01 00:45:13 - [INFO] Run finished, exit status: 0

格式化结果:

{ "MxpiObject": [{ "MxpiClass": [{ "classId": 163, "className": "beagle", "confidence": 0.837890625 }], "classVec": [{ "classId": 16, "className": "dog", "confidence": 0.672381699, "headerVec": [] }], "x0": 73.496948200000006, "x1": 939.73120100000006, "y0": 132.934708, "y1": 603.36547900000005 }] }

貌似 confidence要比前面YoLoV3的低一点。

前面YoLoV3+ResNet50的结果如下:(前面贴过了,再重贴一遍,便于比较)

{ "MxpiObject": [{ "MxpiClass": [{ "classId": 163, "className": "beagle", "confidence": 0.87109375 }], "classVec": [{ "classId": 16, "className": "dog", "confidence": 0.99641436299999997, "headerVec": [] }], "x0": 125.63256800000001, "x1": 918.29089399999998, "y0": 116.434044, "y1": 597.21276899999998 }

下面考虑在图片中叠加 YoLoV5检测和ResNet50分类的className结果:

需要解析出

MxpiObject/MxpiClass/className

MxpiObject/classVec/className

RapidJSON的安装与使用

由于代码中的json神操作张小白不是很明白,所以自行下载了RapidJSON:http://rapidjson.org/zh-cn/index.html

RapidJSON 是只有头文件的 C++ 库。

github比较慢,换成在 gitee上的镜像

切换到 项目的目录,将include目录复制到项目下:

将 取json报文的和图片叠加文字部分加上去:

#include "rapidjson/document.h" #include "rapidjson/prettywriter.h" #include "rapidjson/stringbuffer.h" #include using namespace rapidjson; using namespace cv;

在取到result之后,保存YoLoV5的className和ResNet50的className:

std::string myClassName1 , myClassName2; rapidjson::Document dom; unsigned int i,j; if(!dom.Parse(result.c_str()).HasParseError()) { if(dom.HasMember("MxpiObject") && dom["MxpiObject"].IsArray()){ const rapidjson::Value& arr= dom["MxpiObject"]; for (i = 0; i < arr.Size(); ++i) { const rapidjson::Value& obj = arr; if(obj.HasMember("MxpiClass") && obj["MxpiClass"].IsArray()){ const rapidjson::Value& arr2= obj["MxpiClass"]; for (j = 0; j < arr2.Size(); ++j) { const rapidjson::Value& obj2 = arr2[j]; if(obj2.HasMember("className") && obj2["className"].IsString()){ myClassName1 = obj2["className"].GetString(); std::cout << "className:" << myClassName1 << std::endl; } else{ } }//end of for j } if(obj.HasMember("classVec") && obj["classVec"].IsArray()){ const rapidjson::Value& arr2= obj["classVec"]; for (j = 0; j < arr2.Size(); ++j) { const rapidjson::Value& obj2 = arr2[j]; if(obj2.HasMember("className") && obj2["className"].IsString()){ myClassName2 = obj2["className"].GetString(); std::cout << "className:" << myClassName2 << std::endl; } else{ } }//end of for j } } //end of for i } else{ } } else{ std::cout << "Parse Result Json string error" << std::endl; }

并在最后 画框的时候加上 文字部分:

cv::Rect rect(x0, y0, x1 - x0, y1 - y0); cv::rectangle(src, rect, cv::Scalar(0, 255, 0),5, cv::LINE_8,0); cv::putText(src,myClassName1,cv::Point(x0+50,y0+50),FONT_HERSHEY_SIMPLEX,1,cv::Scalar(255,255,0)); cv::putText(src,myClassName2,cv::Point(x0+50,y0+100),FONT_HERSHEY_SIMPLEX,1,cv::Scalar(255,255,0));

为了可以灵活地切换图片,我们将输入的图片和输出的图片都设置个变量

// read image file and build stream input // std::string picFileName = "../data/test.jpg"; // std::string picFileName_result = "../out/test_result.jpg"; std::string picFileName = "../data/test_tiger.jpg"; std::string picFileName_result = "../out/test_tiger_result.jpg"; // std::string picFileName = "../data/test_rabbit2.jpg"; // std::string picFileName_result = "../out/test_rabbit2_result.jpg";

为了可以切换pipeline,我们将pipeline文件也随时做调整

// std::string pipelineConfigPath = "../pipeline/Sample.pipeline"; // std::string pipelineConfigPath = "../pipeline/YoloV5.pipeline"; // std::string pipelineConfigPath = "../pipeline/yoloV3.pipeline"; std::string pipelineConfigPath = "../pipeline/yoloV3-resnet50.pipeline";

重新编译,运行:

YoloV3+ResNet50认为它是 dog和 beagle(猎兔犬)

从上图可见,类别也在图片中叠加上去了!!

张小白另找了老虎的照片做了如下的试验:

编译:

运行:

YoLoV3认为它是个斑马:zebra

而YoLoV5认为它啥也不是:

而YoLoV3+ResNet50就这样认为:

ResNet50分类倒是对的。确实是老虎。

Fate老师解释说,本来YoLoV3和YoLoV5里面就没有老虎这个选项,所以看不出来反而是对的。如果将其看成是斑马,那反而说明YoloV5比YoloV3的精度要高。。。

额,,,不知道童鞋们Get到没有。。

其实这样高玩赛的作业应该算是做完了吧。

希望同学们能够通过这次CANN训练营应用营的深度学习训练,能够成功使用MindX SDK和MindStudio进行高阶推理。(掌握技能很重要的,也许有个母老虎还需要你去目标检测和分类一下呢。。。)

【昇腾CANN训练营第二期】【应用营】高玩赛作业:使用MindStudio完成YoLoV5和ResNet50的推理开发

(全文完,谢谢阅读)

CANN训练营第二期 高玩赛已经开启,请点击:https://bbs.huaweicloud.com/forum/thread-129524-1-1.html

添加下方工作人员微信,添加备注:CANN训练营~ 邀请进群~

C++ pytorch 昇腾 深度学习 神经网络

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【技术教程]】【微码开发】微码开发入门 - 基础模板开发
下一篇:Java NIO:浅析I/O模型
相关文章