-
一、MindStudio 环境搭建Mindstudio 官网链接:cid:link_2本次实验使用 MindStudio 开发工具,按照此教程配置环境,安装 MindStudio。MindStudio 是一套基于华为自研昇腾 AI 处理器开发的 AI 全栈开发工具平台,该 IDE 上功能很多,涵盖面广,可以进行包括网络模型训练、移植、应用开发、推理运行及自定义算子开发等多种任 务。MindStudio 除了具有工程管理、编译、调试、运行等功能外,还能进行性能分析,算子比对,可以有效提高工作人员的开发效率。除此之外,MindStudio 还具有远端环境,运行任务可在远端实现,对于近端的个人设备要求不高,用户交互体验很好,可以让我们随时随地 进行使用。如需在Linux 安装昇腾套件包ascend-cann-toolkit(以下简称 CANN),请在官网下载 CANN。官网链接:cid:link_4用户手册:(本例中使用的版本为 5.1.RC2) https://www.hiascend.com/document/detail/zh/canncommercial/51RC2/overview/index.html代码链接为:cid:link_3需将代码仓下载到本地。MindStudio 下载打开官网链接,在跳转的如图 1-1 中点击“立即下载”。在如图 1-2 的跳转页面中,选择配套的 MindStudio 版本,本例使用的 CANN 包版本为 5.1.RC2, 故下载 MindStudio_5.0.RC2_win.exe。点击“软件包下载”后,跳出软件下载须知,阅读 MindStudio 软件许可协议,同意则勾选, 然后点击“立即下载”。如图 1-3 所示。软件安装下载完成后,在弹出的安装界面中点击“Next”。如图 1-4 所示:在接下来的界面中配置安装路径,点击“Browse...”选择安装的目的路径。完成后点击“Next>”。如图 1-5 所示在 Create Desktop Shortcut 中勾选 MindStudio,以在桌面创建 MindStudio 快捷方式。在 Update Context Menu 中勾选 Add “Open Folder as Project”以方便创建工程。接下来点击“Next >”。如图 1-6 所示:接下来点击“install”,如图 1-7 所示:待进度条结束后,点击“Next >”。如图 1-8 所示:勾选 Run MindStudio 可以立即打开 MindStudio。点击“Finish”完成安装。如图 1-9 所示:打开工程安装完成后,第一次打开 MindStudio 会出现如图 1-10 所示界面:如图 1-11 所示的 Projects,用于工程打开、创建:如图 1-12 所示的 Customize 可以进行颜色主题,字体等选择:图 1-12 Customize 界面可以安装所需要的插件,如图 1-13 所示:点击界面中的 Help 可以跳转到 MindStudio 社区,如图 1-14 所示:::图 1-14 Learn MindStudio 界面点击 Projects 中的 Open,如图 1-15 所示:选择刚下载好的代码仓文件,如图 1-16 所示:选择箭头所指的“Trust”,如图 1-17 所示:打开后,如图 1-18 所示:选择“File”->“Settings”来配置 CANN 包,如图 1-19:依次如图所示进行选择,点击“Change CANN”按钮,如图 1-20 所示:点击 Remote Connection 后的“田”,如图 1-21 所示,跳转到图 1-22 所示配置 SSH 界面。如图 1-22 所示,点击“+”,增加 ssh 连接。如图 1-23 所示,填写远端服务器的用户名,端口,密码等信息,点击“Test Connection”测试连接是否成功。出现如图 1-24 所示“Successfully connected!”后表明连接成功,点击“OK”:注:成功连接的服务器会被保存,下文中会用到。在此处可继续添加 GPU 服务器的 SSH:上述步骤完成后,在 Remote CANN location 中选择远端服务器的 CANN 包,如图 1-25 所示:点击“Finish”,等待片刻后即可完成安装。随后点击菜单栏中“Ascend”->“Convert to Ascend project”。如图 1-27 所示,在下拉框中做出如下选择,点击“ok”。转换成功后,菜单栏变成如图 1-28 所示:二.训练配置打开命令行选择菜单栏中的“Tools”,选择“Start SSH session”。选择所需要的服务器,如图 2-2 所示:配置本地到远端服务器的映射选择菜单栏中的“Tools”,点击“Deployment”,点击“Configuration”,如图 2-3 所示点击“+”,新建“deployment”,命名为“gpu”,点击“Connection”,选择配置好的 gpu 服务器的 ssh。点击右侧中间的“Mappings”,在左侧“Local Path”中选择需要在远端服务器运行的本地项目,在右侧“Deployment Path”中,配置服务器中的路径。如图 2-5 所示:同理可配置 NPU(192.168.99.113)服务器的 Deployment。在菜单栏中选择“File”,点击“Project Structure”,如图 2-6 所示:打开的 Project Structure 界面如图 2-7 所示,在左侧选择 SDKs,点击箭头所指的“+”,选择 “Add Python SDK”。点击“SSH Interpreter”,在“Deploy”中选择前文配置好的 gpu 服务器,在“Interpreter”中选择远端服务器上的 python 文件夹,“Name”会自动获取。如图 2-8 所示:配置好后,点击“OK”出现 python SDK,配置成功。如图 2-9 所示:点击“Project”,选择刚配置好的远端 SDK。如图 2-10 所示。点击左侧“Modules”,在右侧选择“Dependencies”,在 Module SDK 下拉框中选择刚配置好的远端 SDK,点击“OK”,如图 2-11 所示:点击菜单栏中的“Tools”,选择“Deployment”,选择“Automatic Upload”,修改代码保存后可自动上传到远端服务器。如图 2-12 所示:三、相关介绍模型概况ALBERT 架构的主干和 BERT 类似,都使用了基于 GELU 的非线性激活函数的 Transformer。但是其分别在两个地方减少了参数量。以下图为例可以看到模型的参数主要集中在两块,一块是 Token embedding projection block, 另一块是 Attention feed-forward block,前者占有 20% 的参数量,后者占有 80% 的参数量。数据集SQuAD 是 Stanford Question Answering Dataset 的缩写。这是一个阅读理解数据集,由众包工作者在一组维基百科文章上提出的问题组成,其中每个问题的答案都是相应文章中的一 段文本,某些问题可能无法回答。SQuAD2.0 组合了 SQuAD1.1 中的 10 万个问题,并增加了超过 5 万个无法回答的问题, 这些问题由众包工作者以对抗(adversarially)的方式设计,看起来与可回答的问题相似。为了在 SQuAD2.0 数据集上表现出色。系统不仅必须在可能的情况下回答问题,还必须确定篇章数据何时不支持回答,并避免回答。EM(Exact Match ) 和 F1 值是用于 SQuAD 的主要指标。Exact Match 是一种常见的评价标准,它用来评价预测中匹配到正确答案(ground truth answers)的百分比。代码介绍模型代码路径:src/transformers/models/mbart/modeling_albart.py主要类与函数介绍:Albert 源码整体和 bert 代码差异很小,为了实现灵活的参数共享,作者提出了一个Group 的概念。 源码中将每一层都分到一个指定 Group 之中,一个 Group 包含了多个相邻的层,同一个 Group 里面的层是参数共享的,这个 group 个数由 num_hidden_groups 参数决定,默认为 1。即所有的层 share 同一个 Transformer 权重。如 num_hidden_groups 为 2,num_hidden_layers 为 12,那么层分为两组。1~6 层是第一组,7~12 是第二组。如 num_hidden_groups 为 3,num_hidden_layers 为 12 ,那么层分为三组。1~4 为第一组 , 5~8 为 第 二 组 , 9~12 为 第 三 组 , 以 此 类 推 ...层索引 layer_idx 和组索引 group_idx 由代码计算得出:对于 group 编号较低的组,学习低抽象的知识,group 编号较高的组,学习相对较高抽象的知识,这个是 make sense 的。通过设定 num_hidden_groups 和 num_hidden_layers 可以灵活设定模型深度和共享的程度。可见 group 在源码中是一个比较重要的类型,其由 AlbertGroup 类实现。AlbertTransformer 在初始化之时,预先实例化了 num_hidden_groups 个 AlbertGroup,这个AlbertGroup 代表新的一层参数,里面还有一些细节,后文会描述。当 AlbertTransformer 计算到某一层时,直接在 group 列表中找到对应的 AlbertGroup 去forward,因此在梯度 backward 的时候,梯度的变化也会传递到对应的 AlbertGroup,这样就实现了多级参数共享的参数更新。AlbertTransformer 完整代码:AlbertGroup 完整代码:由此可见,假设一个 block 的参数量为 m。则实际的 encoder 的参数量 K 为:AlbertGroup 内部的层级由 inner_group_num 参数确定,默认为 1。其内部处理的逻辑也很简单,即 forward 多层的 AlbertLayer,这个 AlbertLayer 就代表着一个 block。K = m * inner_group_num * num_hidden_groupsinner_group_num 和 num_hidden_groups 默认均为 1。大多数预训练模型是基于默认参数训练的,所以这两个参数一般也不会改动。除非需要尝试调整共享程度进行重新预训练。除了Group 分组共享外 albert 还可以调整 block 内部的共享方式分为三种all : ffn 和 attention 都共享ffn :ffn 共享attention: attention 共享对于不同的内部共享,在初始化 Module 时将不共享组件实例化 inner_group_num * num_hidden_groups 个 保存在 ModuleList 之中,在 forward 时,按照索引定位到指定组件即可。四、GPU 训练首先要在 GPU 环境中安装 transformer 库,如已经安装,需要先通过 pip uninstall transfomer 命令卸载原版本之后然后在 transformer 路径下使用命令 pip install –e ./ 进行安装,如未安装,直接使用 pip install –e ./ 命令即可,如图 4-1 所示。安装完成之后方可进行模型训练,进入到 transformer/examples/pytorch/question- answering 路径下后输入如下启动代码后即可开始训练。下面将启动代码的参数进行说明model_name_or_path加载的模型权重dataset_name使用的数据集名称do_train是否执行训练,默认为 truedo_eval是否执行评估,默认为 trueper_device_train_batch_size训练批次大小fp16是否使用混合精度,默认为 falselearning_rate初始学习率pad_to_max_length是否把所有的输入 pad 到最大长度num_train_epochs训练轮数doc_stride将一个长文档拆分为块时,块之间要步数loss_scale混合精度的 scalefp16_opt_level混合精度的模式local_rank指定多卡训练的 id,默认值为-1(单卡训练)dataloader_drop_last是否覆盖之前下载的数据集,默认为 Trueoptim优化器选择output_dir重保存路径训练完成后得到如下结果,如图 4-2 所示。五、NPU 训练根据前文介绍的服务器连接,建立与 NPU 服务器的连接。打开终端如图 5-1 所示,点击“Start SSH session...”:选择已经成功连接的 192.168.99.113 服务器:打开成功后,依赖的安装同第四章 GPU 部分内容。本章介绍 NPU 服务器需要额外做的操作,如环境变量的配置,torch1.8 版本的使用,运行脚本的更改等。配置环境变量激活 conda 后,在任意路径执行 source /usr/local/Ascend/ascend-toolkit/set_env.shtorch1.8 的使用在 run_qa.py 脚本中增加 torch_npu 的引入,如图 5-5 所示:运行脚本的更改在 NPU 中使用 run_qa.py 脚本默认是单卡运算,如需多卡,需使用 ddp 进行指定,如图 5-6所示:点击配置可视化运行设置“Edit Configurations...”,运行如图 5-7 所示:配置好图中所圈画出来的地方,点击“OK运行后结果可在 train_0.log 中查看:六、总结与分享本文介绍了 MindStudio 工具的下载安装,以及使用 MindStudio 工具完成与 GPU 服务器和 NPU 服务器的连接,并完成 albert 模型的训练。训练过程中遇到的问题及解决方案: Question1:Loss 震荡不收敛Answer:调小 learning-rateQuestion2:模型训练精度 NPU 单 P 达标,8P 不达标:Answer: 混合精度使用 O1,将 O2 注释.开发过程中遇到的问题可以在昇腾论坛发帖提问,也可以查看其他案例的分享以熟悉流 程。除了参考官方指导文档外,帮助更多的还是开发者社区,如下图所示,推荐大家多看些 经验分享,写的很详细也很有帮助。MindStudio 论坛:cid:link_1
-
使用MindStudio进行Pytorch离线推理全流程1 MindStudio环境搭建本次实验在MindStudio上进行,请先按照教程配置环境,安装MindStudio。MindStudio的是一套基于华为自研昇腾AI处理器开发的AI全栈开发工具平台,该IDE上功能很多,涵盖面广,可以进行包括网络模型训练、移植、应用开发、推理运行及自定义算子开发等多种任务。MindStudio除了具有工程管理、编译、调试、运行等一般普通功能外,还能进行性能分析,算子比对,可以有效提高工作人员的开发效率。除此之外,MindStudio具有远端环境,运行任务在远端实现,对于近端的个人设备的要求不高,用户交互体验很好,可以让我们随时随地进行使用。2 VPN安装和配置安装好MindStudio后,需要配置远程环境。请按照教程进行VPN客户端的安装与配置。安装好VPN后,可以先在终端用ssh指令测试连接。(这一步是验证网络连接是否可用,也可以跳过)3 创建推理工程打开MindStudio,点击New Project,进入新建工程界面。选择Ascend APP。填入项目名spnasnet_100。首次新建训练工程时,需要配置CANN的版本。点击Change。点击 + 配置远程连接,然后根据选项填入自己服务器的ip地址、端口号、用户名和密码等。配置Remote CANN location。该参数需要填入ascend-toolkit在服务器上的路径地址。在这里,我们toolkit的路径如下:/usr/local/Ascend/ascend-toolkit/5.1.RC1。点击finishing进行配置。初次配置时时间稍长,请耐心等待。点击Next,选择Pytorch Project。点击Finish,完成工程创建,进入工程主界面。4 配置SSH和Deployment在MindStudio的远程服务中,定义了SSH 配置和Deployment两个概念。前者SSH 配置类似MobaxTerm中的Session的概念,用户可以保存多个远程服务器的连接配置。后者Deployment管理远程开发时的本地文件与远程文件的同步。配置好Deployment后,我们就可以像使用本地python环境一样去使用远程的python环境了。点击File -> Settings -> Tools,即可看到两个设置的入口,下面分别介绍如何配置他们。4.1 配置SSH首先点击SSH Configurations,再点击 + 配置远程连接,然后根据选项填入自己服务器的ip地址、端口号、用户名和密码等。测试成功点击Apply即可保存配置,以后就可以一键连接啦!4.2 配置DeploymentDeployment配置能够更精准地连接远程服务,它需要选择一个SSH连接定位远程主机,然后设置本地与远程项目目录的对应关系。如下图所示创建一个新的Deployment。如图310是我创建的Deployment名字,首先选择连接哪一个SSH服务,然后测试连接是否可用。下一步,设置项目目录映射关系,点击Mappings,然后选择本地的项目目录和远程的项目目录(最好是提前创建好文件夹),接下来跑代码的时候MindStudio会保证这两个目录文件的同步。配置好Mappings后,建议配置Excluded Paths,因为MindStudio的默认同步行为会把Mappings对应目录的文件保持完全相同,这意味着只存在于远程的数据集文件夹会被删除(如果本地没有数据集)。在此我配置了几个需要排除的文件夹目录。5 配置远程python解释器现在,SSH和Deployment的映射关系已经配置好了,但是MindStudio还不知道python解释器的位置。因此,下面将介绍如何配置python解释器。点击File -> Project Structure->SDKs可以看到如图所示的界面。点击+号,可以新增python SDK和JDK。这里只演示Python的添加方法。点击Add Python SDK后,将弹出下图所示的界面,点击左侧的SSH Interpreter,如下图所示,首先选择使用哪一个Deployment,这是刚刚我们配置过的。然后选择python解释器的路径。图中的路径是MindStudio自动检测出来的,但一般需要自己找自己的Python环境安装目录。如果是conda环境,可以使用which python找到python的安装路径。然后点击Project,选择刚才添加到MindStudio中的python解释器,将其作为本项目使用的解释器。6 数据集准备6.1 数据预处理上传好数据集以后,执行 preprocess_spnasnet_100_pytorch.py脚本,生成数据集预处理后的bin文件。第一个参数为原始数据验证集(.jpeg)所在路径,第二个参数为输出的二进制文件(.bin)所在路径。每个图像对应生成一个二进制文件。MindStudio会首先上传本地文件到远程服务器,将本地的文件同步到远程这个过程可能很慢,同步完成后开始运行Python代码,MindStudio会实时地在控制台打印输出:6.2 生成数据集info文件执行get_info.py脚本,生成数据集信息文件。第一个参数为模型输入的类型,第二个参数为生成的bin文件路径,第三个为输出的info文件,第四、第五个为宽高信息。执行结果:7 模型转换本模型基于开源框架PyTorch训练的spnasnet_100进行模型转换。先使用PyTorch将模型权重文件.pth转换为.onnx文件,再使用ATC工具将.onnx文件转为离线推理模型文件.om文件。首先获取权重文件。单击Link在PyTorch开源框架获中取经过训练的spnasnet_100权重文件model_best.pth.tar,源码中已提供下载权重文件。7.1 导出onnx文件使用pthtar2onnx.py脚本将.pth文件转换为.onnx文件7.2 导出om文件从onnx转为om需要用atc工具,MindStudio提供了atc工具的窗口化应用,它会根据用户选择自动生成atc指令。Model Converter的入口如图所示:选择onnx模型路径,模型输出名称,目标设备,输入格式和batchsize等信息。MindStudio自动生成如下atc指令,用户可以在此做最后的校验,点击Finish即可开始进行模型转换。模型转换成功:8 模型推理使用benchmark工具进行推理。这个和前面的python脚本不同,它在MindStudio中属于ACL应用,可以如图所示创建应用:点击 + 号,再点击Ascend App:然后进行如下配置:参数详情请参见《CANN推理benchmark工具用户指南》。推理后的输出默认在当前目录result下。执行结果:运行出错:error while loading shared libraries: libascendcl.so: cannot open shared object file: No such file or directory.这个错误是因为没有配置好环境变量。因为我们在终端运行它时,一般要先执行一下:source /usr/local/Ascend/ascend-toolkit/set_env.sh,这一步操作在MindStudio中可以通过如图所示的方法配置环境变量解决:变量内容就是/usr/local/Ascend/ascend-toolkit/set_env.sh的内容,读者可以直接复制使用。LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/lib64:/usr/local/Ascend/ascend-toolkit/latest/lib64/plugin/opskernel:/usr/local/Ascend/ascend-toolkit/latest/lib64/plugin/nnengine:$LD_LIBRARY_PATH;PYTHONPATH=/usr/local/Ascend/ascend-toolkit/latest/python/site-packages:/usr/local/Ascend/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe:$PYTHONPATH;PATH=/usr/local/Ascend/ascend-toolkit/latest/bin:/usr/local/Ascend/ascend-toolkit/latest/compiler/ccec_compiler/bin:$PATH;ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest;ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp;TOOLCHAIN_HOME=/usr/local/Ascend/ascend-toolkit/latest/toolkit;ASCEND_HOME_PATH=/usr/local/Ascend/ascend-toolkit/latest设置变量后,再次启动运行,可以在控制台看到,在执行benchmark前,会首先export环境变量。修改后代码运行成功:可以获得batch16 310单卡吞吐率为1379.94×4 = 5519.76 fps9 精度验证调用vision_metric_ImageNet.py脚本与数据集标签val_label.txt比对,可以获得Accuracy Top5数据,结果保存在result.json中。第一个参数为生成推理结果所在路径,第二个参数为标签数据,第三个参数为生成结果文件路径,第四个参数为生成结果文件名称。获得精度数据如下:310 Top1 accuracy为74.2%,Top5 accuracy为91.94%。
-
Bilibili视频链接:https://www.bilibili.com/video/BV1zD4y187Pg/?vd_source=3c13d92bfc824135ee1784f59673e7d4一、 MindStudio 介绍与安装相关课程:昇腾全流程开发工具链(MindStudio)在线课程,提供了系统的、全面的MindStudio使用,可为初学者、一线工程师、经验丰富的开发者提供参考和帮助。本课程主要介绍MindStudio在昇腾AI开发中的使用,作为昇腾AI全栈中的全流程开发工具链,提供覆盖训练模型、推理应用和自定义算子开发三个场景下端到端工具,极大地提高开发效率。1、 MindStudio介绍MindStudio 提供您在AI开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。依靠模型可视化、算力测试、IDE本地仿真调试等功能,MindStudio能够帮助您在一个工具上就能高效便捷地完成AI应用开发。MindStudio采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能。1.功能介绍●针对安装与部署,MindStudio提供多种部署方式,支持多种主流操作系统,为开发者提供最大便利。 ●针对网络模型的开发,MindStudio支持TensorFlow、PyTorch、MindSpore框架的模型训练,支持多种主流框架的模型转换。集成了训练可视化、脚本转换、模型转换、精度比对等工具,提升了网络模型移植、分析和优化的效率。 ●针对算子开发,MindStudio提供包含UT测试、ST测试、TIK 算子调试等的全套算子开发流程。支持 TensorFlow、PyTorch、MindSpore 等多种主流框架的TBE和AICPU自定义算子开发。 ●针对应用开发,MindStudio 集成了Profiling性能调优、编译器、MindX SDK的应用开发、可视化pipeline业务流编排等工具,为开发者提供了图形化的集成开发环境,通过 MindStudio能够进行工程管理、编译、调试、性能分析等全流程开发,能够很大程度提高开发效率。2.功能框架MindStudio功能框架如图1所示,目前含有的工具链包括:模型转换工具、模型训练工具、自定义算子开发工具、应用开发工具、工程管理工具、编译工具、流程编排工具、精度比对工具、日志管理工具、性能分析工具、设备管理工具等多种工具。图1工具链功能架构3.工具功能MindStudio工具中的主要几个功能特性如下:工程管理:为开发人员提供创建工程、打开工程、关闭工程、删除工程、新增工程文件目录和属性设置等功能。SSH管理:为开发人员提供新增SSH连接、删除SSH连接、修改SSH连接、加密SSH密码和修改SSH密码保存方式等功能。应用开发:针对业务流程开发人员,MindStudio工具提供基于AscendCL(Ascend Computing Language)和集成 MindX SDK 的应用开发编程方式,编程后的编译、运行、结果显示等一站式服务让流程开发更加智能化,可以让开发者快速上手。 自定义算子开发:提供了基于TBE和AICPU的算子编程开发的集成开发环境,让不同平台下的算子移植更加便捷,适配昇腾AI处理器的速度更快。 离线模型转换:训练好的第三方网络模型可以直接通过离线模型工具导入并转换成离线模型,并可一键式自动生成模型接口,方便开发者基于模型接口进行编程,同时也提供了离线模型的可视化功能。 日志管理:MindStudio为昇腾AI处理器提供了覆盖全系统的日志收集与日志分析解决方案,提升运行时算法问题的定位效率。提供了统一形式的跨平台日志可视化分析能力及运行时诊断能力,提升日志分析系统的易用性。 性能分析:MindStudio以图形界面呈现方式,实现针对主机和设备上多节点、多模块异构体系的高效、易用、可灵活扩展的系统化性能分析,以及针对昇腾AI处理器的性能和功耗的同步分析,满足算法优化对系统性能分析的需求。 设备管理:MindStudio提供设备管理工具,实现对连接到主机上的设备的管理功能。 精度比对:可以用来比对自有模型算子的运算结果与Caffe、TensorFlow、ONNX标准算子的运 算结果,以便用来确认神经网络运算误差发生的原因。 开发工具包的安装与管理:为开发者提供基于昇腾 AI处理器的相关算法开发套件包 Ascend-canntoolkit,旨在帮助开发者进行快速、高效的人工智能算法开发。开发者可以将开发套件包安装到MindStudio上,使用MindStudio进行快速开发。Ascend-cann-toolkit包含了基于昇腾AI处理器开发依赖的头文件和库文件、编译工具链、调优工具等。2、 MindStudio安装MindStudio安装:安装指南-5.0.RC1-MindStudio,昇腾社区 (hiascend.com)提供MindStudio环境搭建指导视频全流程讲解、实操演示助您轻松完成环境搭建。1. 场景介绍●纯开发场景(分部署形态):在非昇腾AI设备上安装MindStudio和Ascend-cann-toolkit开发套件包。可作为开发环境仅能用于代码开发、编译等不依赖于昇腾设备的开发活动(例如ATC模型转换、算子和推理应用程序的纯代码开发)。如果想运行应用程序或进行模型训练等,需要通过MindStudio远程连接功能连接已部署好运行环境所需软件包的昇腾AI设备。 ●开发运行场景(共部署形态):在昇腾AI设备上安装MindStudio、Ascend-cann-toolkit 开发套件包、npu-firmware安装包、npu-driver安装包和AI框架(进行模型训练时需要安装)。作为开发环境,开发人员可以进行普通的工程管理、代码编写、编译、模型转换等功能。同时可以作为运行环境,运行应用程序或进行模型训练。2. 软件包介绍MindStudio:提供图形化开发界面,支持应用开发、调试和模型转换功能,同时还支持网络移植、优化和分析等功能。 Ascend-cann-toolkit:开发套件包。为开发者提供基于昇腾AI处理器的相关算法开发工具包,旨在帮助开发者进行快速、高效的模型、算子和应用的开发。开发套件包只能安装在Linux服务器上,开发者可以在安装开发套件包后,使用MindStudio开发工具进行快速开发。二、MindX SDK介绍与安装1、MindX SDK介绍MindX SDK提供昇腾AI处理器加速的各类AI软件开发套件(SDK),提供极简易用的 API,加速AI应用的开发。 应用开发旨在使用华为提供的SDK和应用案例快速开发并部署人工智能应用,是基于现有模型、使用pyACL提供的Python语言API库开发深度神经网络应用,用于实现目标识别、图像分类等功能。通过MindStudio实现SDK应用开发分为基础开发与深入开发,通常情况下用户关注基础开发即可,基础开发主要包含如何通过现有的插件构建业务流并实现业务数据对接,采用模块化的设计理念,将业务流程中的各个功能单元封装成独立的插件,通过插件的串接快速构建推理业务。mxManufacture & mxVision关键特性:●配置文件快速构建AI推理业务。 ●插件化开发模式,将整个推理流程“插件化”,每个插件提供一种功能,通过组装不同的插件,灵活适配推理业务流程。 ●提供丰富的插件库,用户可根据业务需求组合JPEG解码、抠图、缩放、模型推理、数据序列化等插件。 ●基于Ascend Computing Language(ACL),提供常用功能的高级API,如模型推理、解码、预处理等,简化Ascend芯片应用开发。 ●支持自定义插件开发,用户可快速地将自己的业务逻辑封装成插件,打造自己的应用插件。2、MindX SDK 安装步骤1 Windows场景下基于MindStudio的SDK应用开发,请先确保远端环境上 MindX SDK软件包已安装完成,安装方式参见MindX SDK 2.0.4 mxManufacture用户指南和MindX SDK 2.0.4 mxVision用户指南的“使用命令行方式开发”>“安装 MindX SDK 开发套件”章节。步骤2 在Windows本地进入工程创建页面,工具栏点击 File > Settings > Appearance & Behavior > System Settings > MindX SDK 进入MindX SDK管理界面。界面中MindX SDK Location为软件包的默认安装路径,默认安装路径为 “C:\Users\用户名\Ascend\mindx_sdk”。 单击 Install SDK 进入 Installation settings 界面,如图2。图2 Installation settings 界面如图3所示,为MindX SDK的安装界面,各参数选择如下:Remote Connection:远程连接的用户及IP。 Remote CANN location:远端环境上CANN开发套件包的路径,需配置到版本号一级。Remote SDK location:远端环境上SDK的路径,请配置到版本号一级。IDE将同步该层级下的include、opensource、python、samples文件夹到本地Windows环境,层级选择错误将导致安装失败。 Local SDK location:同步远端环境上SDK文件夹到本地的路径。默认安装路径为“C:\Users\用户名\Ascend\mindx_sdk”。图3 MindX SDK 的安装界面步骤3 单击OK结束,返回SDK管理界面,可查看安装后的SDK的信息,可单击OK结束安装流程。三、基于CTC算法的语音热词唤醒模型介绍随着嵌入式设备、移动设备的快速发展,部署在嵌入式、移动设备的程序越来越多。语音处理应用已在机器人、汽车电子、ATM机等嵌入式、移动设备得到广泛应用。程序、系统在移动设备上运行,必须具有较小的内存占用和较低的计算能力。关键字检测KWS( Keyword Spotting ) 使用深度神经网络DNN训练音频,基于训练的模型对关键字唤醒、推理。基于CTC算法的语音热词唤醒模型基于TensorFlow框架。KWS模型每25ms计算40维log-mel特征,帧移位为10ms。每一帧左重复23帧,向右重复8帧,并将其输入DNN。四、运行基于CTC算法的语音热词唤醒模型步骤1、打开基于CTC算法的语音热词唤醒模型●基于CTC算法的语音热词唤醒模型代码连接:cid:link_5 ●通过SecoClient连接VPN,以确保MindStudio能够连接远程服务器。●双击MindStudio点击右上角Open按钮,选择事先准备好的KWS模型,点击Ok即可进入工程。如图4所示。图4 导入KeywordCTC项目●进入工程后显示如图5界面图5 项目打开界面●单击菜单栏 Ascend > Convert To Ascend Project,如图6所示。图6 工程转换界面●弹出如图7窗口。图7 转换晟腾功能配置对窗口参数介绍如下,用户请根据实际场景选择。Project Type:可选择三种工程类型,分别为Ascend Operator、Ascend Training和Ascend App。确定了Project Type后,再选择项目类型对应的Framework,Framework可选择框架如表1所示。Project TypeFrameworkAscend OperatorMindSporePyTorchTensorFlowONNXAscend TrainingMindSporePyTorchTensorFlowAscend AppAscend ACL AppAscend Python ACL AppAscend MindX SDK App表1 FrameWork可选框架Project Desc:项目描述。单击OK,工程目录以树状呈现。此时成功创建带有.project文件的昇腾工程如图8,请以实际创建结果为准。图8 转换晟腾功能成功界面2、 基于CTC算法的语音热词唤醒模型训练●在项目Project区的KeywordCTC项目目录树找到kws_train_2.py文件,双击打开,如图9所示。kws_train_2.py文件是基于CTC算法的语音热词唤醒模型的训练文件。图9打开kws_train2.py界面●Kws_train2中主要代码介绍:图10 主要代码介绍1图11 主要代码介绍2●在工具栏选择Run>Edit Configurations...进入运行配置界面。配置Deployment,点击Run,将代码同步到远程服务器如图12。图12 Deployment配置●在工具栏选择Tools>Start SSH session…如图13。图13 选择Strat SHH session●选择终端连接的服务器图14 选择服务器连接●远程终端开启后,在MindStudio底部状态栏目的Remote Terminal图标由之前的灰色变为蓝色,并展示欢迎界面如图15。图15 连接成功界面●输入 cd MindStudio-WorkSpace/KeywordCTC进入同步到服务器的代码,输入ll命令展示内容如图16。图16 服务器上的代码目录展示●输入python kws_train_2.py 命令进行模型训练如图17、图18。图17 开始训练图18 训练过程●kws_train_2.py文件开启模型训练结束如图19。图19 训练结束●训练结束后在在result_CTC_2下生成model_weights.h5文件如图20。图20 生成model_weights.h53、 基于CTC算法的语音热词唤醒模型转换●通过pip install 命令安装onnx和tf2onnx如图21、图22。图21 安装onnx图22 安装tf2onnx●输入python keras2onnx.py命令将model_weights.h5模型转换成pb模型如图23。图23 keras2onnx.py开始执行●模型转换成功在tmp_model下可以看到saved_model.pb模型如图24。图24 pb模型生成成功●输入python -m tf2onnx.convert --saved-model tmp_model --output model1.onnx --opset 11命令将pb模型转换为onnx模型如图25、图26。图25 pb模型开始转onnx模型图26 pb模型转onnx模型过程●模型转换成功输入ll命令查看,可以看到model.onnx模型如图27。图27 生成model1.onnx输入命令:Exportinstall_path=/usr/local/Ascend/ascend toolkit/latestexportPATH=/usr/local/python3.7.5/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATHexportPYTHONPATH=${install_path}/atc/python/site-packages:$PYTHONPATHexportLD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATHexportASCEND_OPP_PATH=${install_path}/oppexportASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/设置模型转换环境。●借助ACT工具将onnx模型转换为om模型。atc --framework=5 --model=model1.onnx --output=modelctc1 --input_format=ND --input_shape="input:1,958,13" --log=debug --soc_version=Ascend310输入这行命令,模型转换如图28。图28 onnx模型开始转换om模型图29 om模型转换成功生成modelctc1.om文件4、基于CTC算法的语音热词唤醒模型评估模型训练完成后,运行性能评估文件评估模型性能,判断模型是否正常以及达到训练精度。kws_evaluate.py文件是基于CTC算法的语音热词唤醒模型的模型性能评估文件。●kws_evaluate.py主要代码介绍如下图30、图31。图30 kws_evaluate.py代码介绍1图31 kws_evaluate.py代码介绍2●输入python kws_evaluate.py命令进行模型性能评估如图32、图33。图32 kws_evaluate.py开始运行图33 kws_evaluate.py运行过程●运行结束后在result_CTC_2下面生成performance.txt文件,输入more performance.txt命令查看结果如图34。图34 performance.txt内容●performanc.txt文件里给出性能评价数据,包括keywords、TP、FN、FP 等其中TP,TN,FP,FN的理解定义为:第一个字母T/F代表预测的结果是否和实际情况相符,即如果真实情况为正样本(P),预测为正样本(P),则为T;如果真实情况为负样本(N),预测为负样本(N),则为T;如果真实情况为P,预测为N,则为F;如果真实情况为N预测为P,则为F。第二个字母P/N代表预测结果的正负:如果预测为正样本,则为P;如果预测为负样本,则为N。TP:true positive,被判定为正样本,事实上也是正样本;TN:true negative,被判定为负样本,事实上也是负样本;FP:false positive,被判定为正样本,但事实上是负样本;FN:false negative,被判定为负样本,但事实上是正样本;5、基于CTC算法的语音热词唤醒预测●kws_predict.py主要代码介绍如下图35。图35 kws_predict.py主要代码介绍●kws_predict.py运用训练模型对指定的音频文件进行预测。●输入python kws_predict.py命令运行kws_predict.py文件如图36、图37。图36 kws_predict.py文件开始运行图37 kws_predict.py文件运行过程●基于CTC算法的语音热词唤醒预测结果,如图38、图39所示。图38是从音频文件预测“北京”热词的结果;图39是从含噪音的音频文件预测“北京”热词的结果。图38 推理结果1图39 推理结果2五、推广MindStudio提供图形化开发界面,支持应用开发、调试和模型转换功能,同时还支持网络移植、优化和分析等功能,功能强大。文档以图文说明用MindStudio IDE分析基于CTC算法的语音热词唤醒的训练、精度评估、推理的过程。六、从昇腾社区获取更多帮助开发者在使用 MindStudio 或进行算子开发过程中遇到任何问题,都可以来昇腾社区获得更多的帮助。昇腾官网:昇腾社区-官网丨昇腾万里 让智能无所不及 (hiascend.com)昇腾社区:昇腾众智计划-昇腾社区 (hiascend.com)昇腾论坛:昇腾论坛 (hiascend.com)
-
扫码进下方任一微信群,并报名CANN训练营可参与抽奖参与开发板领取规则①参与抽奖者需进群并报名CANN训练营,仅参与未报名无效②中奖后请及时联系小助手,公布后10个工作日内未提供具体信息视为无效报名链接:cid:link_1 直播链接: https://2b87aad812c94b3392d218f35fa6ca3f.shixizhi.huawei.com/live/viewer.htm?actId=7da1rk37&liveId=1579653306145419265&tenant_id=1493401497873534978
-
MindStudio是一套基于华为昇腾AI处理器开发的AI全栈开发平台,包括基于芯片的算子开发、以及自定义算子开发,同时还包括网络层的网络移植、优化和分析,另外在业务引擎层提供了一套可视化的AI引擎拖拽式编程服务,极大的降低了AI引擎的开发门槛,全平台通过Web的方式向开发者提供以下4项服务功能。针对安装与部署,MindStudio提供多种部署方式,支持多种主流操作系统,为开发者提供最大便利。针对算子开发,MindStudio提供包含UT测试、ST测试、TIK算子调试等的全套算子开发流程。支持TensorFlow、PyTorch、MindSpore等多种主流框架的TBE和AI CPU自定义算子开发。针对网络模型的开发,MindStudio支持TensorFlow、Pytorch、MindSpore框架的模型训练,支持多种主流框架的模型转换。集成了训练可视化、脚本转换、模型转换、精度比对等工具,提升了网络模型移植、分析和优化的效率。针对应用开发,MindStudio集成了Profiling性能调优、编译器、MindX SDK的应用开发、可视化pipeline业务流编排等工具,为开发者提供了图形化的集成开发环境,通过MindStudio能够进行工程管理、编译、调试、性能分析等全流程开发,能够很大程度提高开发效率。详细入门教程可以登录后通过附件下载 ↓↓↓
-
我在用点云的onnx模型向om模型转换的时候,转换报错:Input shape digit should be -1 or greater than 0。我看文档说onnx模型转换shape是NCHW,而我的onnx模型是(15000,5),因为是点云模型,不需要NCHW,请问这种情况该怎么处理?
-
详细情况如下:1、在SD卡模式下,RGMII网络能正常访问。2、在SD卡模式下,短接uart1,RGMII网络不通3、把硬件从SD卡模式切换到EMMC模式,并短接uart1 RGMII网络还是不通4、模组已升级(指定版本):https://support.huawei.com/enterprise/zh/software/252823273-ESW2000337766https://support.huawei.com/enterprise/zh/software/251857128-ESW2000262521
-
使用官方教程中的脚本,尝试MindSpore上云时,报错如图:
-
MindX SDK——Overlap-CRNN重叠文本识别设计案例1 案例概述本开发样例使用CRNN完成重叠文本的识别任务,供用户参考。 本系统基于昇腾Ascend310卡。本仓库是重叠文本任务的下游任务,即在完成对重叠文本还原后针对mask识别出文本。1.1 支持的产品本系统采用Atlas300-3010作为实验验证的硬件平台,并支持Atlas200RC以及Atlas500的硬件平台.具体产品实物图和硬件参数请参见《Atlas 300 AI加速卡 用户指南(型号 3010)》。由于采用的硬件平台为含有Atlas 300的Atlas 800 AI服务器 (型号3010),而服务器一般需要通过网络访问,因此需要通过笔记本或PC等客户端访问服务器,而且展示界面一般在客户端。1.2 支持的版本版本号查询方法,在Ascend产品环境下,运行命令:npu-smi info1.3 软件方案介绍软件方案主要为还原文本的识别系统,子系统功能具体描述请参考 表1.1 系统方案各子系统功能描述。重叠文本识别子系统可以实现识别还原后图像的mask的输入,然后通过等比例放缩等操作最后对图像进行识别,本方案选择使用crnn作为重叠文本识别模型。系统方案中各模块功能如表1.2 所示。表1.1 系统方案各子系统功能描述:序号子系统功能描述1重叠文本识别子系统重叠文本识别子系统将上一个子系统得到的结果,进行等比例放缩操作,放缩的大小与模型的输入大小有关,之后将结果送入到文字识别模型进行文字识别,并将识别结果进行输出。表1.2 系统方案中各模块功能:序号子系统功能描述1输入图像将图像(JPG格式)通过pillow库读入。2输入字典将字典(txt格式)通过本地代码输入到pipeline中。3图像解码通过PILLOW第三方库对图像解码。4图像放缩文字识别模型的输入为固定维度,所以需要放射变换的结果进行等比例放缩。5文字识别在图像放缩后,将缓存区数据送入文字识别模型。本方案选用crnn进行文本识别6结果可视化通过pillow库可视化单张图像的识别。1.4 代码目录结构与说明eg:本sample工程名称为Overlap-CRNN,工程目录如下图所示:├── crnn_single_infer.py #单张图片推理 ├── crnn_infer.py #精度测试 ├── README.md ├── ch_sim_en_digit_symble.txt #字典 ├── models #不同类型的模型文件 │ ├── air_model │ │ ├── crnn.air │ └── ckpt_model │ │ ├── crnn.ckpt │ └── om_model │ │ ├── crnn.om ├── dataset #测试数据集 │ ├── img │ ├── map_record.json │ └── annotation.json1.5 技术实现流程图实现流程图如下图所示:1.6 特性及适用场景本案例中的 CRNN模型适用于英文的灰度图像的识别,并可以返回测试图像的word-based的精度值。本模型在以下几种情况去噪效果良好:图像中文字清晰可见、排版工整、字符大小适中等。在以下几种情况去噪效果不太好:图像中文字模糊、排版随意、字符较小等。1.7 代码地址本项目的代码地址为:cid:link_32 环境依赖请列出环境依赖软件和版本。推荐系统为ubuntu 18.04或centos 7.6,环境依赖软件和版本如下表:软件名称版本mindspore1.8.1MindX SDK3.0RC2Ascend-CANN-toolkit5.1.RC2ubuntu18.04.1 LTSpython3.9.2cv24.5.5.64numpy1.23.1pillow9.1.0在编译运行项目前,需要设置环境变量:环境变量介绍. ${sdk_path}/set_env.sh . ${ascend_toolkit_path}/set_env.sh3 模型训练模型均在GPU下训练得到,如果需要使用本仓库提供的模型进行推理或模型转换,请务必参照GPU所需的参数设置,然后将模型按照提供的文件夹目录放至即可。相关模型的下载链接如下:[下载链接]cid:link_1)步骤1 从昇腾社区的modelzoo中下载官方CRNN模型代码,并按安装官方文档中的步骤完成训练:下载链接CRNN_for_MindSpore_1.2_code/default_config.yamlmodel_version: "V2" # V2可以在GPU和Ascend上训练 label_dict: "PATH/TO/ch_sim_en_digit_symble.txt" # 使用自己的字典的路径 max_text_length: 12 image_width: 112 class_num: 6703 blank: 6702 train_dataset_path: "" # 训练数据集路径 train_eval_dataset: "synth" # 名称使用synth train_eval_dataset_path: "" # 测试数据路径CRNN_for_MindSpore_1.2_code/src/dataset.py将第41行的:letters = [letter for letter in config1.label_dict]修改为:letters = [] with open(config1.label_dict, 'r') as f: for line in f: letter = line.strip('\n') letters.append(letter) f.close()将CaptchaDataset函数更换为:class CaptchaDataset: """ create train or evaluation dataset for crnn Args: img_root_dir(str): root path of images max_text_length(int): max number of digits in images. device_target(str): platform of training, support Ascend and GPU. """ def __init__(self, img_root_dir, is_training=True, config=config1): if not os.path.exists(img_root_dir): raise RuntimeError( "the input image dir {} is invalid!".format(img_root_dir)) self.img_root_dir = img_root_dir if is_training: self.imgslist = os.path.join(self.img_root_dir, 'annotation_train.txt') else: self.imgslist = os.path.join(self.img_root_dir, 'annotation_test.txt') self.img_names = {} self.img_list = [] with open(self.imgslist, 'r') as f: for line in f: img_name, img_label = line.strip('\n').split('\t') self.img_list.append(img_name) self.img_names[img_name] = str(img_label) f.close() self.max_text_length = config.max_text_length self.blank = config.blank self.class_num = config.class_num self.sample_num = len(self.img_list) self.batch_size = config.batch_size print("There are totally {} samples".format(self.sample_num)) def __len__(self): return self.sample_num def __getitem__(self, item): img_name = self.img_list[item] try: im = Image.open(os.path.join(self.img_root_dir, img_name)) except IOError: print("%s is a corrupted image" % img_name) return self[item + 1] im = im.convert("RGB") r, g, b = im.split() im = Image.merge("RGB", (b, g, r)) image = np.array(im) if not check_image_is_valid(image): print("%s is a corrupted image" % img_name) return self[item + 1] text = self.img_names[img_name] label_unexpanded = text_to_labels(text) label = np.full(self.max_text_length, self.blank) if self.max_text_length < len(label_unexpanded): label_len = self.max_text_length else: label_len = len(label_unexpanded) for j in range(label_len): label[j] = label_unexpanded[j] return image, labelCRNN_for_MindSpore_1.2_code/src/metric.py将第18行的字典label_dict = "abcdefghijklmnopqrstuvwxyz0123456789"修改为( dict_path 为自行准备的字典 ch_sim_en_digit_symble.txt ,可在本仓库下找到):label_dict = [] with open("[dict_path]", 'r') as f: for line in f: letter = line.strip('\n') label_dict.append(letter) f.close()步骤2 训练得到ckpt模型文件后,进入CRNN_for_MindSpore_1.2_code文件夹下执行命令(修改ckpt_file和air_file_name参数为自己的路径):python export.py --ckpt_file [ckpt_file] --file_name [air_file_name] --file_format AIR4 模型推理步骤1 将生成的AIR模型转移到推理服务器,放至在Overlap-CRNN/models/air_model路径下。cd ./Overlap-CRNN mkdir models cd models mkdir air_model步骤2 进入推理服务器执行命令(修改air_model_path和output_model_path参数为自己的路径):atc --model=[air_model_path] --framework=1 --output=[output_model_path] --soc_version=Ascend310 --output_type=FP32 --op_select_implmode=high_precision --input_shape="input:1,3,32,112"模型转换工具(ATC)相关介绍如下:ATC介绍相关模型的下载链接如下:模型下载步骤3 执行该命令会在当前目录下生成项目需要的模型文件[output_model].om。执行后终端输出为:ATC start working now, please wait for a moment. ATC run success, welcome to the next use.表示命令执行成功。步骤4 将任意一张jpg格式的图片存到当前目录下(./Overlap-CRNN),命名为test.jpg。步骤5 按照模型转换获取om模型,放置在Overlap-CRNN/models/om_model/路径下。若未自行转换模型,使用的是仓库提供的模型,则无需修改相关文件,否则修改crnn_single_infer.py中相关配置,将MODEL_PATH对象的路径改成实际的om模型的路径;IMAGE_PATH对象的路径改成实际的测试图片的路径;SAVE_PATH对象设置成需要保存可视化图像的路径。相关参数在Overlap-CRNN/crnn_single_infer.py下:MODEL_PATH = "./models/om_model/crnn.om" IMAGE_PATH = "./test.jpg" SAVE_PATH = "./show.jpg"步骤6 在命令行输入 如下命令运行整个工程:python crnn_single_infer.py步骤7 运行结束输出show.jpg5 测试精度步骤1 在Overlap-CRNN/dataset/路径下准备相同格式的数据集(已提供测试用的数据集,按照文件目录放至即可:下载链接)步骤2 在命令行输入 如下命令运行整个工程:python crnn_infer.py模型在测试集上的精度达标,最终模型的的acc为89.17%,满足精度要求(acc≥80%)。
-
使用的是mindspore1.7版本源代码为
-
bilibili视频链接:使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用9、本地编写python文件1、main.pymain.py主要进行一些推理前的操作和调用infer.py进行推理,以及调用postprocess.py进行推理结果后处理。步骤一:导入相关包,并定义相关函数步骤二:编写各个函数parser_args函数用于读入执行改文件时所需的一些参数def parser_args(): parser = argparse.ArgumentParser(description="FasterRcnn inference") parser.add_argument("--img_path", type=str, required=False, default="../data/test/crop/", help="image directory.") parser.add_argument( "--pipeline_path", type=str, required=False, default="../pipeline/fasterrcnn_ms_dvpp.pipeline", help="image file path. The default is 'config/maskrcnn_ms.pipeline'. ") parser.add_argument( "--model_type", type=str, required=False, default="dvpp", help= "rgb: high-precision, dvpp: high performance. The default is 'dvpp'.") parser.add_argument( "--infer_mode", type=str, required=False, default="infer", help= "infer:only infer, eval: accuracy evaluation. The default is 'infer'.") parser.add_argument( "--infer_result_dir", type=str, required=False, default="../data/test/infer_result", help= "cache dir of inference result. The default is '../data/test/infer_result'.") parser.add_argument("--ann_file", type=str, required=False, help="eval ann_file.") arg = parser.parse_args() return argget_img_metas函数用于记录图像缩放比例def get_img_metas(file_name): img = Image.open(file_name) img_size = img.size org_width, org_height = img_size resize_ratio = cfg.MODEL_WIDTH / org_width if resize_ratio > cfg.MODEL_HEIGHT / org_height: resize_ratio = cfg.MODEL_HEIGHT / org_height img_metas = np.array([img_size[1], img_size[0]] + [resize_ratio, resize_ratio]) return img_metasprocess_img函数用于对图像进行预处理def process_img(img_file): img = cv2.imread(img_file) model_img = mmcv.imrescale(img, (cfg.MODEL_WIDTH, cfg.MODEL_HEIGHT)) if model_img.shape[0] > cfg.MODEL_HEIGHT: model_img = mmcv.imrescale(model_img, (cfg.MODEL_HEIGHT, cfg.MODEL_HEIGHT)) pad_img = np.zeros( (cfg.MODEL_HEIGHT, cfg.MODEL_WIDTH, 3)).astype(model_img.dtype) pad_img[0:model_img.shape[0], 0:model_img.shape[1], :] = model_img pad_img.astype(np.float16) return pad_imgcrop_on_slide函数用于对图片进行滑窗裁剪,因为输入的图片尺寸大多都为4000*1000左右,不利于缺陷的识别和推理,对其进行滑窗裁剪后,得到的多张小图片更利于缺陷识别和推理def crop_on_slide(cut_path, crop_path, stride): if not os.path.exists(crop_path): os.mkdir(crop_path) else: remove_list = os.listdir(crop_path) for filename in remove_list: os.remove(os.path.join(crop_path, filename)) output_shape = 600 imgs = os.listdir(cut_path) for img in imgs: if img.split('.')[1] != "jpg" and img.split('.')[1] != "JPG": raise ValueError("The file {} is not jpg or JPG image!".format(img)) origin_image = cv2.imread(os.path.join(cut_path, img)) height = origin_image.shape[0] width = origin_image.shape[1] x = 0 newheight = output_shape newwidth = output_shape while x < width: y = 0 if x + newwidth <= width: while y < height: if y + newheight <= height: hmin = y hmax = y + newheight wmin = x wmax = x + newwidth else: hmin = height - newheight hmax = height wmin = x wmax = x + newwidth y = height # test crop_img = os.path.join(crop_path, ( img.split('.')[0] + '_' + str(wmax) + '_' + str(hmax) + '_' + str(output_shape) + '.jpg')) cv2.imwrite(crop_img, origin_image[hmin: hmax, wmin: wmax]) y = y + stride if y + output_shape == height: y = height else: while y < height: if y + newheight <= height: hmin = y hmax = y + newheight wmin = width - newwidth wmax = width else: hmin = height - newheight hmax = height wmin = width - newwidth wmax = width y = height # test crop_img = os.path.join(crop_path, ( img.split('.')[0] + '_' + str(wmax) + '_' + str(hmax) + '_' + str( output_shape) + '.jpg')) cv2.imwrite(crop_img, origin_image[hmin: hmax, wmin: wmax]) y = y + stride x = width x = x + stride if x + output_shape == width: x = widthimage_inference函数用于流的初始化,推理所需文件夹的创建、图片预处理、推理时间记录、推理后处理、推理结果可视化def image_inference(pipeline_path, s_name, img_dir, result_dir, rp_last, model_type): sdk_api = SdkApi(pipeline_path) if not sdk_api.init(): exit(-1) if not os.path.exists(result_dir): os.makedirs(result_dir) img_data_plugin_id = 0 img_metas_plugin_id = 1 logging.info("\nBegin to inference for {}.\n\n".format(img_dir)) file_list = os.listdir(img_dir) total_len = len(file_list) if total_len == 0: logging.info("ERROR\nThe input directory is EMPTY!\nPlease place the picture in '../data/test/cut'!") for img_id, file_name in enumerate(file_list): if not file_name.lower().endswith((".jpg", "jpeg")): continue file_path = os.path.join(img_dir, file_name) save_path = os.path.join(result_dir, f"{os.path.splitext(file_name)[0]}.json") if not rp_last and os.path.exists(save_path): logging.info("The infer result json({}) has existed, will be skip.".format(save_path)) continue try: if model_type == 'dvpp': with open(file_path, "rb") as fp: data = fp.read() sdk_api.send_data_input(s_name, img_data_plugin_id, data) else: img_np = process_img(file_path) sdk_api.send_img_input(s_name, img_data_plugin_id, "appsrc0", img_np.tobytes(), img_np.shape) # set image data img_metas = get_img_metas(file_path).astype(np.float32) sdk_api.send_tensor_input(s_name, img_metas_plugin_id, "appsrc1", img_metas.tobytes(), [1, 4], cfg.TENSOR_DTYPE_FLOAT32) start_time = time.time() result = sdk_api.get_result(s_name) end_time = time.time() - start_time if os.path.exists(save_path): os.remove(save_path) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR with os.fdopen(os.open((save_path), flags, modes), 'w') as fp: fp.write(json.dumps(result)) logging.info( "End-2end inference, file_name: {}, {}/{}, elapsed_time: {}.\n".format(file_path, img_id + 1, total_len, end_time)) draw_label(save_path, file_path, result_dir) except Exception as ex: logging.exception("Unknown error, msg:{}.".format(ex)) post_process()步骤三:main方法编写if __name__ == "__main__": args = parser_args() REPLACE_LAST = True STREAM_NAME = cfg.STREAM_NAME.encode("utf-8") CUT_PATH = "../data/test/cut/" CROP_IMG_PATH = "../data/test/crop/" STRIDE = 450 crop_on_slide(CUT_PATH, CROP_IMG_PATH, STRIDE) image_inference(args.pipeline_path, STREAM_NAME, args.img_path, args.infer_result_dir, REPLACE_LAST, args.model_type) if args.infer_mode == "eval": logging.info("Infer end.\nBegin to eval...") get_eval_result(args.ann_file, args.infer_result_dir)2、infer.pyinfer.py中是主要的sdk推理步骤,包括流的初始化到流的销毁,编写完成后在main.py中调用。步骤一:导入相关包,并定义相关类和函数步骤二:编写各个函数init魔法属性用来构造sdk实例化对象def __init__(self, pipeline_cfg): self.pipeline_cfg = pipeline_cfg self._stream_api = None self._data_input = None self._device_id = Nonedel魔法属性用来销毁实例化对象def __del__(self): if not self._stream_api: return self._stream_api.DestroyAllStreams()_convert_infer_result函数用来将推理结果输出def _convert_infer_result(infer_result): data = infer_result.get('MxpiObject') if not data: logging.info("The result data is empty.") return infer_result for bbox in data: if 'imageMask' not in bbox: continue mask_info = json_format.ParseDict(bbox["imageMask"], MxpiDataType.MxpiImageMask()) mask_data = np.frombuffer(mask_info.dataStr, dtype=np.uint8) bbox['imageMask']['data'] = "".join([str(i) for i in mask_data]) bbox['imageMask'].pop("dataStr") return infer_resultinit函数用来stream manager的初始化def init(self): try: with open(self.pipeline_cfg, 'r') as fp: self._device_id = int( json.loads(fp.read())[self.STREAM_NAME]["stream_config"] ["deviceId"]) logging.info("The device id: {}.".format(self._device_id)) # create api self._stream_api = StreamManagerApi() # init stream mgr ret = self._stream_api.InitManager() if ret != 0: logging.info("Failed to init stream manager, ret={}.".format(ret)) return False # create streams with open(self.pipeline_cfg, 'rb') as fp: pipe_line = fp.read() ret = self._stream_api.CreateMultipleStreams(pipe_line) if ret != 0: logging.info("Failed to create stream, ret={}.".format(ret)) return False self._data_input = MxDataInput() except Exception as exe: logging.exception("Unknown error, msg:{}".format(exe)) return False return Truesend_data_input函数用来传输推理数据def send_data_input(self, stream_name, plugin_id, input_data): data_input = MxDataInput() data_input.data = input_data unique_id = self._stream_api.SendData(stream_name, plugin_id, data_input) if unique_id < 0: logging.error("Fail to send data to stream.") return False return Truesend_img_input函数用来传入图片def send_img_input(self, stream_name, plugin_id, element_name, input_data, img_size): vision_list = MxpiDataType.MxpiVisionList() vision_vec = vision_list.visionVec.add() vision_vec.visionInfo.format = 1 vision_vec.visionInfo.width = img_size[1] vision_vec.visionInfo.height = img_size[0] vision_vec.visionInfo.widthAligned = img_size[1] vision_vec.visionInfo.heightAligned = img_size[0] vision_vec.visionData.memType = 0 vision_vec.visionData.dataStr = input_data vision_vec.visionData.dataSize = len(input_data) buf_type = b"MxTools.MxpiVisionList" return self._send_protobuf(stream_name, plugin_id, element_name, buf_type, vision_list)send_tensor_input函数用来传入张量数据def send_tensor_input(self, stream_name, plugin_id, element_name, input_data, input_shape, data_type): tensor_list = MxpiDataType.MxpiTensorPackageList() tensor_pkg = tensor_list.tensorPackageVec.add() # init tensor vector tensor_vec = tensor_pkg.tensorVec.add() tensor_vec.deviceId = self._device_id tensor_vec.memType = 0 tensor_vec.tensorShape.extend(input_shape) tensor_vec.tensorDataType = data_type tensor_vec.dataStr = input_data tensor_vec.tensorDataSize = len(input_data) buf_type = b"MxTools.MxpiTensorPackageList" return self._send_protobuf(stream_name, plugin_id, element_name, buf_type, tensor_list)get_result函数用来获得推理结果def get_result(self, stream_name, out_plugin_id=0): infer_res = self._stream_api.GetResult(stream_name, out_plugin_id, self.INFER_TIMEOUT) if infer_res.errorCode != 0: logging.info("GetResultWithUniqueId error, errorCode={}, errMsg={}".format(infer_res.errorCode, infer_res.data.decode())) return None res_dict = json.loads(infer_res.data.decode()) return self._convert_infer_result(res_dict)_send_protobuf函数用来对目标检测结果进行序列化def _send_protobuf(self, stream_name, plugin_id, element_name, buf_type, pkg_list): protobuf = MxProtobufIn() protobuf.key = element_name.encode("utf-8") protobuf.type = buf_type protobuf.protobuf = pkg_list.SerializeToString() protobuf_vec = InProtobufVector() protobuf_vec.push_back(protobuf) err_code = self._stream_api.SendProtobuf(stream_name, plugin_id, protobuf_vec) if err_code != 0: logging.error( "Failed to send data to stream, stream_name:{}, plugin_id:{}, " "element_name:{}, buf_type:{}, err_code:{}.".format( stream_name, plugin_id, element_name, buf_type, err_code)) return False return True3、postprocess.py对经过滑窗裁剪后的小图片进行推理,最后得到的推理结果也是在小图片上,因此需要对推理结果进行后处理,将小图片上的推理结果还原到未经过滑窗裁剪的图片上。步骤一:导入相关包,并定义相关函数步骤二:编写各个函数json_to_txt函数用来将得到的json格式推理结果转为txt格式def json_to_txt(infer_result_path, savetxt_path): if os.path.exists(savetxt_path): shutil.rmtree(savetxt_path) os.mkdir(savetxt_path) files = os.listdir(infer_result_path) for file in files: if file.endswith(".json"): json_path = os.path.join(infer_result_path, file) with open(json_path, 'r') as fp: result = json.loads(fp.read()) if result: data = result.get("MxpiObject") txt_file = file.split(".")[0] + ".txt" flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR with os.fdopen(os.open(os.path.join(savetxt_path, txt_file), flags, modes), 'w') as f: if file.split('_')[0] == "W0003": temp = int(file.split("_")[2]) - 600 else: temp = int(file.split("_")[1]) - 600 for bbox in data: class_vec = bbox.get("classVec")[0] class_id = int(class_vec["classId"]) confidence = class_vec.get("confidence") xmin = bbox["x0"] ymin = bbox["y0"] xmax = bbox["x1"] ymax = bbox["y1"] if xmax - xmin >= 5 and ymax - ymin >= 5: f.write( str(xmin + temp) + ',' + str(ymin) + ',' + str(xmax + temp) + ',' + str( ymax) + ',' + str( round(confidence, 2)) + ',' + str(class_id) + '\n')hebing_txt函数用来将滑窗裁剪后的小图片推理结果还原到原始图片上def hebing_txt(txt_path, save_txt_path, remove_txt_path, cut_path): if not os.path.exists(save_txt_path): os.makedirs(save_txt_path) if not os.path.exists(remove_txt_path): os.makedirs(remove_txt_path) fileroot = os.listdir(save_txt_path) remove_list = os.listdir(remove_txt_path) for filename in remove_list: os.remove(os.path.join(remove_txt_path, filename)) for filename in fileroot: os.remove(os.path.join(save_txt_path, filename)) data = [] for file in os.listdir(cut_path): data.append(file.split(".")[0]) txt_list = os.listdir(txt_path) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR for image in data: fw = os.fdopen(os.open(os.path.join(save_txt_path, image + '.txt'), flags, modes), 'w') for txtfile in txt_list: if image.split('_')[0] == "W0003": if image.split('_')[1] == txtfile.split('_')[1]: for line in open(os.path.join(txt_path, txtfile), "r"): fw.write(line) else: if image.split('_')[0] == txtfile.split('_')[0]: for line in open(os.path.join(txt_path, txtfile), "r"): fw.write(line) fw.close() fileroot = os.listdir(save_txt_path) for file in fileroot: oldname = os.path.join(save_txt_path, file) newname = os.path.join(remove_txt_path, file) shutil.copyfile(oldname, newname)py_cpu_nms、plot_bbox、nms_box函数用来对还原后的推理结果进行nms去重处理,在进行滑窗裁剪时,为了不在裁剪时将缺陷切断从而保留所有缺陷,所以设置的滑窗步长小于小图片尺寸,因此得到的推理结果会有重复,需进行nms去重处理def py_cpu_nms(dets, thresh): x1 = dets[:, 0] y1 = dets[:, 1] x2 = dets[:, 2] y2 = dets[:, 3] areas = (y2 - y1 + 1) * (x2 - x1 + 1) scores = dets[:, 4] keep = [] index = scores.argsort()[::-1] while index.size > 0: i = index[0] # every time the first is the biggst, and add it directly keep.append(i) x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap y11 = np.maximum(y1[i], y1[index[1:]]) x22 = np.minimum(x2[i], x2[index[1:]]) y22 = np.minimum(y2[i], y2[index[1:]]) w = np.maximum(0, x22 - x11 + 1) # the weights of overlap h = np.maximum(0, y22 - y11 + 1) # the height of overlap overlaps = w * h ious = overlaps / (areas[i] + areas[index[1:]] - overlaps) idx = np.where(ious <= thresh)[0] index = index[idx + 1] # because index start from 1 return keep def plot_bbox(dets, c='k'): x1 = dets[:, 0] y1 = dets[:, 1] x2 = dets[:, 2] y2 = dets[:, 3] plt.plot([x1, x2], [y1, y1], c) plt.plot([x1, x1], [y1, y2], c) plt.plot([x1, x2], [y2, y2], c) plt.plot([x2, x2], [y1, y2], c) plt.title(" nms") def nms_box(image_path, image_save_path, txt_path, thresh, obj_list): if not os.path.exists(image_save_path): os.makedirs(image_save_path) remove_list = os.listdir(image_save_path) for filename in remove_list: os.remove(os.path.join(image_save_path, filename)) txt_list = os.listdir(txt_path) for txtfile in tqdm.tqdm(txt_list): boxes = np.loadtxt(os.path.join(txt_path, txtfile), dtype=np.float32, delimiter=',') if boxes.size > 5: if os.path.exists(os.path.join(txt_path, txtfile)): os.remove(os.path.join(txt_path, txtfile)) flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL modes = stat.S_IWUSR | stat.S_IRUSR fw = os.fdopen(os.open(os.path.join(txt_path, txtfile), flags, modes), 'w') keep = py_cpu_nms(boxes, thresh=thresh) img = cv.imread(os.path.join(image_path, txtfile[:-3] + 'jpg'), 0) for label in boxes[keep]: fw.write(str(int(label[0])) + ',' + str(int(label[1])) + ',' + str(int(label[2])) + ',' + str( int(label[3])) + ',' + str(round((label[4]), 2)) + ',' + str(int(label[5])) + '\n') x_min = int(label[0]) y_min = int(label[1]) x_max = int(label[2]) y_max = int(label[3]) color = (0, 0, 255) if x_max - x_min >= 5 and y_max - y_min >= 5: cv.rectangle(img, (x_min, y_min), (x_max, y_max), color, 1) font = cv.FONT_HERSHEY_SIMPLEX cv.putText(img, (obj_list[int(label[5])] + str(round((label[4]), 2))), (x_min, y_min - 7), font, 0.4, (6, 230, 230), 1) cv.imwrite(os.path.join(image_save_path, txtfile[:-3] + 'jpg'), img) fw.close()post_process函数用来调用以上编写的函数,最后在main.py中被调用def post_process(): infer_result_path = "../data/test/infer_result" txt_save_path = "../data/test/img_txt" json_to_txt(infer_result_path, txt_save_path) txt_path = "../data/test/img_txt" all_txt_path = "../data/test/img_huizong_txt" nms_txt_path = "../data/test/img_huizong_txt_nms" cut_path = "../data/test/cut" hebing_txt(txt_path, all_txt_path, nms_txt_path, cut_path) cut_path = "../data/test/cut" image_save_path = "../data/test/draw_result" nms_txt_path = "../data/test/img_huizong_txt_nms" obj_lists = ['qikong', 'liewen'] nms_box(cut_path, image_save_path, nms_txt_path, thresh=0.1, obj_list=obj_lists)10、代码运行前面的步骤完成之后,我们就可以进行代码的运行了,本项目中,图片的输入输出位置都是用的相对路径,因此不需要修改路径参数,按以下步骤进行模型推理:步骤一:放置待检测图片本项目中,将图片放置在./python/data/test/cut目录下,例如我放的图片:步骤二:在main.py中设置好初始图片所在位置和结果图片保存位置。步骤三:设置运行脚本运行应用点击下图箭头所指,设置自己的运行脚本点击绿色箭头,开始运行运行成功,查看推理结果五、常见问题在使用 MindStudio 时,遇到问题,可以登陆华为云论坛云计算论坛开发者论坛技术论坛-华为云 (huaweicloud.com)进行互动,提出问题,会有专家老师为你解答。1、CANN 连接错误连接服务器 SSH 成功,但是连接 CANN 失败:点击OK,点击Show Error Details,查看报错信息:问题:权限不够,无法连接。解决方案:在远程环境自己的工作目录下重新下载CANN后,再连接CANN即可。2、后处理插件权限问题如图,运行时显示权限不够:两种解决方案:方案一:在远程终端中找到后处理插件所在位置,修改其权限为640,如图:修改完成后,需将改文件设置为不同步,如图:方案二:在远程终端环境中找到后处理插件所在位置,将其复制到MindX SDK自带的后处理插件库文件夹下,并修改其权限为640,然后修改pipeline文件中后处理插件所在位置。注:MindX SDK自带的后处理插件库文件夹一般为${MX_SDK_HOME}/lib/modelpostprocessors/
-
bilibili视频链接:使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用一、MindStudio1、MindStudio介绍MindStudio简介:MindStudio 提供您在 AI 开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。依靠模型可视化、算力测试、IDE 本地仿真调试等功能,MindStudio 能够帮助您在一个工具上就能高效便捷地完 成 AI 应用开发。MindStudio 采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能。功能简介针对安装与部署,MindStudio 提供多种部署方式,支持多种主流操作系统, 为开发者提供最大便利。针对网络模型的开发,MindStudio 支持 TensorFlow、PyTorch、MindSpore 框 架的模型训练,支持多种主流框架的模型转换。集成了训练可视化、脚本转换、模型转换、精度比对等工具,提升了网络模型移植、分析和优化的效率。针对算子开发,MindStudio 提供包含 UT 测试、ST 测试、TIK 算子调试等的全套算子开发流程。支持 TensorFlow、PyTorch、MindSpore 等多种主流框架 的 TBE 和 AI CPU 自定义算子开发。针对应用开发,MindStudio 集成了 Profiling 性能调优、编译器、MindX SDK 的应用开发、可视化 pipeline 业务流编排等工具,为开发者提供了图形化 的集成开发环境,通过 MindStudio 能够进行工程管理、编译、调试、性能分析等全流程开发,能够很大程度提高开发效率。功能框架MindStudio功能框架如下图所示,目前含有的工具链包括:模型转换工具、模型训练工具、自定义算子开发工具、应用开发工具、工程管理工具、编译工具、流程编排工具、精度比对工具、日志管理工具、性能分析工具、设备管理工具等多种工具。场景介绍开发场景:在非昇腾AI设备(如windosw平台)上安装MindStudio和Ascend-cann-toolkit开发套件包。在该开发场景下,我们仅用于代码开发、编译等不依赖昇腾设备的活动,如果要运行应用程序或者模型训练等,需要通过MindStudio远程连接(SSH)已经部署好运行环境所需要软件包(CANN、MindX SDK等)的昇腾AI设备。开发运行场景:在昇腾AI设备(昇腾AI服务器)上安装MindStudio、Ascend-cann-toolkit开发套件包等安装包和AI框架(进行模型训练时需要安装)。在该开发环境下,开发人员可以进行代码编写、编译、程序运行、模型训练等操作。软件包介绍MindStudio:提供图形化开发界面,支持应用开发、调试和模型转换功能, 同时还支持网络移植、优化和分析等功能,可以安装在linux、windows平台。Ascend-cann-toolkit:开发套件包。为开发者提供基于昇腾 AI 处理器的相关算法开发工具包,旨在帮助开发者进行快速、高效的模型、算子和应用的开发。开发套件包只能安装在 Linux 服务器上,开发者可以在安装开发套件包后,使用 MindStudio 开发工具进行快速开发。注:由于Ascend-cann-toolkit只能安装在linux服务器上,所以在Windows场景下代码开发时,需先安装MindStudio软件,再远程连接同步Linux服务器的CANN和MindX SDK到本地。二、MindX SDK1、MindX SDK介绍MindX SDK 提供昇腾 AI 处理器加速的各类 AI 软件开发套件(SDK),提供极简易用的 API,加速 AI 应用的开发。应用开发旨在使用华为提供的 SDK 和应用案例快速开发并部署人工智能应用,是基于现有模型、使用pyACL 提供的 Python 语言 API 库开发深度神经网络 应用,用于实现目标识别、图像分类等功能。mxManufacture & mxVision 关键特性:配置文件快速构建 AI 推理业务。插件化开发模式,将整个推理流程“插件化”,每个插件提供一种功能,通过组装不同的插件,灵活适配推理业务流程。提供丰富的插件库,用户可根据业务需求组合 Jpeg 解码、抠图、缩放、模型推理、数据序列化等插件。基于 Ascend Computing Language(ACL),提供常用功能的高级 API,如模型推理、解码、预处理等,简化 Ascend 芯片应用开发。支持自定义插件开发,用户可快速地将自己的业务逻辑封装成插件,打造自己的应用插件。三、可视化流程编排介绍1、SDK基础概念通过 stream(业务流)配置文件,Stream manager(业务流管理模块)可识别需要构建的 element(功能元件)以及 element 之间的连接关系,并启动业务流程。Stream manager 对外提供接口,用于向 stream 发送数据和获取结果,帮助用户实现业务对接。Plugin(功能插件)表示业务流程中的基础模块,通过 element 的串接构建成一个 stream。Buffer(插件缓存)用于内部挂载解码前后的视频、图像数据, 是 element 之间传递的数据结构,同时也允许用户挂载 Metadata(插件元数据), 用于存放结构化数据(如目标检测结果)或过程数据(如缩放后的图像)2、可视化流程编排MindX SDK 实现功能的最小粒度是插件,每一个插件实现特定的功能,如图片解码、图片缩放等。流程编排是将这些插件按照合理的顺序编排,实现负责的功能。可视化流程编排是以可视化的方式,开发数据流图,生成 pipeline 文件供应用框架使用。下图为推理业务流 Stream 配置文件 pipeline 样例。配置文件以 json 格式编写,用户必须指定业务流名称、元件名称和插件名称,并根据需要,补充元件属性和下游元件名称信息。四、项目开发(Python)本项目主要介绍在Windows场景下使用MindStudio软件,连接远程服务器配置的MindX SDK、CANN环境,采用Faster R-CNN模型对GDxray焊接缺陷数据集进行焊接缺陷检测的应用开发。项目参考模型地址:Faster R-CNN项目代码地址:contrib/Faster_R-CNN · Ascend/mindxsdk-referenceappsGDXray是一个公开X射线数据集,其中包括一个关于X射线焊接图像(Welds)的数据,该数据由德国柏林的BAM联邦材料研究和测试研究所收集。Welds集中W0003 包括了68张焊接公司的X射线图像。本项目基于W0003数据集并在焊接专家的帮助下将焊缝和其内部缺陷标注。数据集下载地址:cid:link_61、MindStudio安装点击超链接下载MindStudio安装包MindStudio安装包下载点击超链接,进入MindStudio用户手册,在安装指南下安装操作中可以看见MindStudio具体的安装操作。MindStudio用户手册2、新建一个项目点击Ascend App,新建一个项目,在D:\Codes\python\Ascend\MyApp位置下创建自己的项目。点击 Change 安装CANN,进入 Remote CANN Setting 界面,如下图所示,远程连接需要配置SSH连接,点击**"+"**,进入SSH连接界面。参数解释Remote Connection远程服务器 IPRemote CANN location远程服务器中 CANN 路径下图为SSH连接界面中,ssh远程连接需配置远程终端账号,点击**"+"**后,进入SSH连接配置界面。下图为SSH配置界面,配置好后点击Test Connection,出现 ”Sucessfully connected!“即配置成功。返回到 Remote CANN Setting 界面,输入远程CANN路径完成 CANN 安装,点击 OK。接着,选择MindX SDK Project(Python),如下图所示,被圈出来的4个项目,上面两个是空模板,在这里面创建我们自己的工程项目,因为我们要创建Python版的应用,所以被单独框出来的这个;下面两个是官方给出的样例项目,如果对目录结构和应该写哪些代码不太熟悉的话,也可以创建一个样例项目先学习一下。选择完成后,点击Finish完成项目的创建进入项目,项目创建完成后,可根据自己需要新建文件、文件夹。3、MindX SDK安装步骤1、 Windows 场景下基于 MindStuido 的 SDK 应用开发(本地远程连接服务器端MindX SDK),请先确保远端环境上 MindX SDK 软件包已安装完成。(远程安装MindX SDK开发套件)步骤2、在 Windows 本地进入工程创建页面,工具栏点击 File > Settings > Appearance & Behavior> System Settings > MindX SDK 进入 MindX SDK 管理界面(只有安装CANN后才会出现MindX SDK按钮)。界面中 MindX SDK Location 为软件包的默认安装路径,默认安装路径为 “C:\Users\用户\Ascend\mindx_sdk”。单击 Install SDK 进入Installation settings 界面。如图所示,为 MindX SDK 的安装界面,各参数选择如下:Remote Connection:远程连接的用户及 IP。Remote CANN location:远端环境上 CANN 开发套件包的路径,请配置到版 本号一级。Remote SDK location:远端环境上 SDK 的路径,请配置到版本号一级。IDE 将同步该层级下的include、opensource、python、samples 文件夹到本地 Windows 环境,层级选择错误将导致安装失败。Local SDK location:同步远端环境上 SDK 文件夹到本地的路径。默认安装路径为“C:\Users\用户名\Ascend\mindx_sdk”。步骤 3 :单击 OK 结束,返回 SDK 管理界面如下图,可查看安装后的 SDK 的信息,可单击 OK结束安装流程。4、工程目录结构介绍在实际开发中,需要在./postprocess下编写后处理插件,在./python/Main下编写需要运行的python文件,在./python/models下放置模型相关配置文件,在./python/pipeline下编写工作流文件,本项目工程开发结束后的目录如下图所示。5、文件同步(可选)本地文件与远程文件同步一般自行决定是否需要该功能,若不进行文件同步,在后续编译文件或者运行应用时,MindStudio也会自行将项目文件同步到远端用户目录下MindStudio-WorkSpace文件夹中。在顶部菜单栏中选择 Tools > Deployment > Configuration ,如图:点击已连接的远程环境后,点击Mappings可添加需要同步的文件夹,点击Excluded Paths可添加同步的文件下不需要同步的文件。6、Faster R-CNN模型转换用户使用 Caffe/TensorFlow 等框架训练好的第三方模型,可通过 ATC 工具将其转换为昇腾 AI 处理器支持的离线模型(*.om 文件),模型转换过程中可以实现算子调度的优化、权重数据重排、内存使用优化等,可以脱离设备完成模型的预处理,详细架构如下图。在本项目中,要将 mindspore 框架下训练好的模型(.air 文件),转换为昇腾 AI 处理器支持的离线模型(.om 文件),具体步骤如下:步骤 1: 点击 Ascend > Model Converter,进入模型转换界面,参数配置如图所示,若没有CANN Machine,请参见第四章第二节 CANN 安装。各参数解释如下表所示:参数解释CANN MachineCANN 的远程服务器Model File*.air 文件的路径(可以在本地,也可以在服务器上)Target SoC Version模型转换时指定芯片型号Model Name生成的 om 模型名字Output Path生成的 om 模型保存在本地的路径Input Format输入数据格式Input Nodes模型输入节点信息步骤 2: 配置完成后,点击Next,进行数据预处理设置,配置完成后点击Next,如图:步骤 3: 进行模型转换命令及环境变量设置,该项目配置示例如图:各参数解释如下表所示:参数解释Additional Arguments执行命令时需要添加的其他参数配置Environment Variables环境变量设置Command Preview查看经过前面一系列配置后最终的命名形式步骤 4: 配置完成后,点击Finish进行模型转换。步骤 5:等待出现如下图所示的提示,模型转换成功。步骤 6:双击转换成功的 om 模型文件,可以查看网络结构。如下图所示。7、编写后处理插件并编译以下需要编写的文件均在./postprocess/目录下1、头文件FasterRcnnMindsporePost.hFasterRcnnMindsporePost.h头文件包含了类的声明(包括类里面的成员和方法的声明)、函数原型、#define 常数等。其中,#include 类及#define 常数如代码所示;定义的初始化参数结构体如代码所示;类里面的成员和方法的声明如代码所示。/* * Copyright (c) 2022. Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef FASTERRCNN_MINSPORE_PORT_H #define FASTERRCNN_MINSPORE_PORT_H #include <algorithm> #include <vector> #include <map> #include <opencv4/opencv2/opencv.hpp> #include "MxBase/ErrorCode/ErrorCode.h" #include "MxBase/CV/Core/DataType.h" #include "MxBase/PostProcessBases/ObjectPostProcessBase.h" namespace MxBase { class FasterRcnnMindsporePost : public ObjectPostProcessBase { public: FasterRcnnMindsporePost() = default; ~FasterRcnnMindsporePost() = default; FasterRcnnMindsporePost(const FasterRcnnMindsporePost &other); FasterRcnnMindsporePost &operator=(const FasterRcnnMindsporePost &other); APP_ERROR Init(const std::map<std::string, std::shared_ptr<void>> &postConfig) override; APP_ERROR DeInit() override; APP_ERROR Process(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos = {}, const std::map<std::string, std::shared_ptr<void>> &configParamMap = {}) override; bool IsValidTensors(const std::vector<TensorBase> &tensors) const; private: void ObjectDetectionOutput(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos); void GetValidDetBoxes(const std::vector<TensorBase> &tensors, std::vector<DetectBox> &detBoxes, uint32_t batchNum); void ConvertObjInfoFromDetectBox(std::vector<DetectBox> &detBoxes, std::vector<ObjectInfo> &objectInfos, const ResizedImageInfo &resizedImageInfos); APP_ERROR ReadConfigParams(); private: const uint32_t DEFAULT_CLASS_NUM_MS = 8; const float DEFAULT_SCORE_THRESH_MS = 0.7; const float DEFAULT_IOU_THRESH_MS = 0.5; const uint32_t DEFAULT_RPN_MAX_NUM_MS = 1000; const uint32_t DEFAULT_MAX_PER_IMG_MS = 128; uint32_t classNum_ = DEFAULT_CLASS_NUM_MS; float scoreThresh_ = DEFAULT_SCORE_THRESH_MS; float iouThresh_ = DEFAULT_IOU_THRESH_MS; uint32_t rpnMaxNum_ = DEFAULT_RPN_MAX_NUM_MS; uint32_t maxPerImg_ = DEFAULT_MAX_PER_IMG_MS; }; extern "C" { std::shared_ptr<MxBase::FasterRcnnMindsporePost> GetObjectInstance(); } } // namespace MxBase #endif // FASTERRCNN_MINSPORE_PORT_H2、源文件FasterRcnnMindsporePost.cpp这里我们主要是实现在头文件中定义的函数,接下来做一个简要的概括ReadConfigParams函数用来读取目标检测类别信息、以及一些超参数如scoreThresh、iouThreshInit函数用来进行目标检测后处理中常用的初始化IsValidTensors函数用来判断输出结果是否有效GetValidDetBoxes函数用来获取有效的推理信息ConvertObjInfoFromDetectBox函数用来将推理信息转为标注框信息ObjectDetectionOutput函数用来输出得到的推理结果Process函数用来做预处理/* * Copyright (c) 2022. Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <boost/property_tree/json_parser.hpp> #include <opencv4/opencv2/core.hpp> #include <opencv4/opencv2/opencv.hpp> #include "acl/acl.h" #include "FasterRcnnMindsporePost.h" #include "MxBase/CV/ObjectDetection/Nms/Nms.h" namespace { // Output Tensor const int OUTPUT_TENSOR_SIZE = 3; const int OUTPUT_BBOX_SIZE = 3; const int OUTPUT_BBOX_TWO_INDEX_SHAPE = 5; const int OUTPUT_BBOX_INDEX = 0; const int OUTPUT_CLASS_INDEX = 1; const int OUTPUT_MASK_INDEX = 2; const int BBOX_INDEX_LX = 0; const int BBOX_INDEX_LY = 1; const int BBOX_INDEX_RX = 2; const int BBOX_INDEX_RY = 3; const int BBOX_INDEX_PROB = 4; const int BBOX_INDEX_SCALE_NUM = 5; } // namespace namespace MxBase { FasterRcnnMindsporePost &FasterRcnnMindsporePost::operator=(const FasterRcnnMindsporePost &other) { if (this == &other) { return *this; } ObjectPostProcessBase::operator=(other); return *this; } APP_ERROR FasterRcnnMindsporePost::ReadConfigParams() { APP_ERROR ret = configData_.GetFileValue<uint32_t>("CLASS_NUM", classNum_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No CLASS_NUM in config file, default value(" << classNum_ << ")."; } ret = configData_.GetFileValue<float>("SCORE_THRESH", scoreThresh_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No SCORE_THRESH in config file, default value(" << scoreThresh_ << ")."; } ret = configData_.GetFileValue<float>("IOU_THRESH", iouThresh_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No IOU_THRESH in config file, default value(" << iouThresh_ << ")."; } ret = configData_.GetFileValue<uint32_t>("RPN_MAX_NUM", rpnMaxNum_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No RPN_MAX_NUM in config file, default value(" << rpnMaxNum_ << ")."; } ret = configData_.GetFileValue<uint32_t>("MAX_PER_IMG", maxPerImg_); if (ret != APP_ERR_OK) { LogWarn << GetError(ret) << "No MAX_PER_IMG in config file, default value(" << maxPerImg_ << ")."; } LogInfo << "The config parameters of post process are as follows: \n" << " CLASS_NUM: " << classNum_ << " \n" << " SCORE_THRESH: " << scoreThresh_ << " \n" << " IOU_THRESH: " << iouThresh_ << " \n" << " RPN_MAX_NUM: " << rpnMaxNum_ << " \n" << " MAX_PER_IMG: " << maxPerImg_ << " \n"; } APP_ERROR FasterRcnnMindsporePost::Init(const std::map<std::string, std::shared_ptr<void>> &postConfig) { LogInfo << "Begin to initialize FasterRcnnMindsporePost."; APP_ERROR ret = ObjectPostProcessBase::Init(postConfig); if (ret != APP_ERR_OK) { LogError << GetError(ret) << "Fail to superinit in ObjectPostProcessBase."; return ret; } ReadConfigParams(); LogInfo << "End to initialize FasterRcnnMindsporePost."; return APP_ERR_OK; } APP_ERROR FasterRcnnMindsporePost::DeInit() { LogInfo << "Begin to deinitialize FasterRcnnMindsporePost."; LogInfo << "End to deinitialize FasterRcnnMindsporePost."; return APP_ERR_OK; } bool FasterRcnnMindsporePost::IsValidTensors(const std::vector<TensorBase> &tensors) const { if (tensors.size() < OUTPUT_TENSOR_SIZE) { LogError << "The number of tensor (" << tensors.size() << ") is less than required (" << OUTPUT_TENSOR_SIZE << ")"; return false; } auto bboxShape = tensors[OUTPUT_BBOX_INDEX].GetShape(); if (bboxShape.size() != OUTPUT_BBOX_SIZE) { LogError << "The number of tensor[" << OUTPUT_BBOX_INDEX << "] dimensions (" << bboxShape.size() << ") is not equal to (" << OUTPUT_BBOX_SIZE << ")"; return false; } uint32_t total_num = classNum_ * rpnMaxNum_; if (bboxShape[VECTOR_SECOND_INDEX] != total_num) { LogError << "The output tensor is mismatched: " << total_num << "/" << bboxShape[VECTOR_SECOND_INDEX] << ")."; return false; } if (bboxShape[VECTOR_THIRD_INDEX] != OUTPUT_BBOX_TWO_INDEX_SHAPE) { LogError << "The number of bbox[" << VECTOR_THIRD_INDEX << "] dimensions (" << bboxShape[VECTOR_THIRD_INDEX] << ") is not equal to (" << OUTPUT_BBOX_TWO_INDEX_SHAPE << ")"; return false; } auto classShape = tensors[OUTPUT_CLASS_INDEX].GetShape(); if (classShape[VECTOR_SECOND_INDEX] != total_num) { LogError << "The output tensor is mismatched: (" << total_num << "/" << classShape[VECTOR_SECOND_INDEX] << "). "; return false; } auto maskShape = tensors[OUTPUT_MASK_INDEX].GetShape(); if (maskShape[VECTOR_SECOND_INDEX] != total_num) { LogError << "The output tensor is mismatched: (" << total_num << "/" << maskShape[VECTOR_SECOND_INDEX] << ")."; return false; } return true; } static bool CompareDetectBoxes(const MxBase::DetectBox &box1, const MxBase::DetectBox &box2) { return box1.prob > box2.prob; } static void GetDetectBoxesTopK(std::vector<MxBase::DetectBox> &detBoxes, size_t kVal) { std::sort(detBoxes.begin(), detBoxes.end(), CompareDetectBoxes); if (detBoxes.size() <= kVal) { return; } LogDebug << "Total detect boxes: " << detBoxes.size() << ", kVal: " << kVal; detBoxes.erase(detBoxes.begin() + kVal, detBoxes.end()); } void FasterRcnnMindsporePost::GetValidDetBoxes(const std::vector<TensorBase> &tensors, std::vector<DetectBox> &detBoxes, uint32_t batchNum) { LogInfo << "Begin to GetValidDetBoxes."; auto *bboxPtr = (aclFloat16 *)GetBuffer(tensors[OUTPUT_BBOX_INDEX], batchNum); // 1 * 80000 * 5 auto *labelPtr = (int32_t *)GetBuffer(tensors[OUTPUT_CLASS_INDEX], batchNum); // 1 * 80000 * 1 auto *maskPtr = (bool *)GetBuffer(tensors[OUTPUT_MASK_INDEX], batchNum); // 1 * 80000 * 1 // mask filter float prob = 0; size_t total = rpnMaxNum_ * classNum_; for (size_t index = 0; index < total; ++index) { if (!maskPtr[index]) { continue; } size_t startIndex = index * BBOX_INDEX_SCALE_NUM; prob = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_PROB]); if (prob <= scoreThresh_) { continue; } MxBase::DetectBox detBox; float x1 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_LX]); float y1 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_LY]); float x2 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_RX]); float y2 = aclFloat16ToFloat(bboxPtr[startIndex + BBOX_INDEX_RY]); detBox.x = (x1 + x2) / COORDINATE_PARAM; detBox.y = (y1 + y2) / COORDINATE_PARAM; detBox.width = x2 - x1; detBox.height = y2 - y1; detBox.prob = prob; detBox.classID = labelPtr[index]; detBoxes.push_back(detBox); } GetDetectBoxesTopK(detBoxes, maxPerImg_); } void FasterRcnnMindsporePost::ConvertObjInfoFromDetectBox(std::vector<DetectBox> &detBoxes, std::vector<ObjectInfo> &objectInfos, const ResizedImageInfo &resizedImageInfo) { for (auto &detBoxe : detBoxes) { if (detBoxe.classID < 0) { continue; } ObjectInfo objInfo = {}; objInfo.classId = (float)detBoxe.classID; objInfo.className = configData_.GetClassName(detBoxe.classID); objInfo.confidence = detBoxe.prob; objInfo.x0 = std::max<float>(detBoxe.x - detBoxe.width / COORDINATE_PARAM, 0); objInfo.y0 = std::max<float>(detBoxe.y - detBoxe.height / COORDINATE_PARAM, 0); objInfo.x1 = std::max<float>(detBoxe.x + detBoxe.width / COORDINATE_PARAM, 0); objInfo.y1 = std::max<float>(detBoxe.y + detBoxe.height / COORDINATE_PARAM, 0); objInfo.x0 = std::min<float>(objInfo.x0, resizedImageInfo.widthOriginal - 1); objInfo.y0 = std::min<float>(objInfo.y0, resizedImageInfo.heightOriginal - 1); objInfo.x1 = std::min<float>(objInfo.x1, resizedImageInfo.widthOriginal - 1); objInfo.y1 = std::min<float>(objInfo.y1, resizedImageInfo.heightOriginal - 1); LogDebug << "Find object: " << "classId(" << objInfo.classId << "), confidence(" << objInfo.confidence << "), Coordinates(" << objInfo.x0 << ", " << objInfo.y0 << "; " << objInfo.x1 << ", " << objInfo.y1 << ")."; objectInfos.push_back(objInfo); } } void FasterRcnnMindsporePost::ObjectDetectionOutput(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos) { LogDebug << "FasterRcnnMindsporePost start to write results."; auto shape = tensors[OUTPUT_BBOX_INDEX].GetShape(); uint32_t batchSize = shape[0]; for (uint32_t i = 0; i < batchSize; ++i) { std::vector<MxBase::DetectBox> detBoxes; std::vector<ObjectInfo> objectInfo; GetValidDetBoxes(tensors, detBoxes, i); LogInfo << "DetBoxes size: " << detBoxes.size() << " iouThresh_: " << iouThresh_; NmsSort(detBoxes, iouThresh_, MxBase::MAX); ConvertObjInfoFromDetectBox(detBoxes, objectInfo, resizedImageInfos[i]); objectInfos.push_back(objectInfo); } LogDebug << "FasterRcnnMindsporePost write results successed."; } APP_ERROR FasterRcnnMindsporePost::Process(const std::vector<TensorBase> &tensors, std::vector<std::vector<ObjectInfo>> &objectInfos, const std::vector<ResizedImageInfo> &resizedImageInfos, const std::map<std::string, std::shared_ptr<void>> &configParamMap) { LogDebug << "Begin to process FasterRcnnMindsporePost."; auto inputs = tensors; APP_ERROR ret = CheckAndMoveTensors(inputs); if (ret != APP_ERR_OK) { LogError << "CheckAndMoveTensors failed, ret=" << ret; return ret; } ObjectDetectionOutput(inputs, objectInfos, resizedImageInfos); LogInfo << "End to process FasterRcnnMindsporePost."; return APP_ERR_OK; } extern "C" { std::shared_ptr<MxBase::FasterRcnnMindsporePost> GetObjectInstance() { LogInfo << "Begin to get FasterRcnnMindsporePost instance."; auto instance = std::make_shared<FasterRcnnMindsporePost>(); LogInfo << "End to get FasterRcnnMindsporePost Instance"; return instance; } } } // namespace MxBase3、CMakeLists.txt编译脚本在编译脚本中,需要指定 CMake最低版本要求、项目信息、编译选项等参数,并且需要指定特定头文件和特定库文件的搜索路径。除此之外,要说明根据FasterRcnnMindsporePost.cpp源文件生成libfasterrcnn_mindspore_post.so可执行文件,同时需要指定可执行文件的安装位置,通常为{MX_SDK_HOME}/lib/modelpostprocessors/cmake_minimum_required(VERSION 3.5.2) project(fasterrcnnpost) add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) set(PLUGIN_NAME "fasterrcnn_mindspore_post") set(TARGET_LIBRARY ${PLUGIN_NAME}) set(ACL_LIB_PATH $ENV{ASCEND_HOME}/ascend-toolkit/latest/acllib) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories($ENV{MX_SDK_HOME}/include) include_directories($ENV{MX_SDK_HOME}/opensource/include) include_directories($ENV{MX_SDK_HOME}/opensource/include/opencv4) include_directories($ENV{MX_SDK_HOME}/opensource/include/gstreamer-1.0) include_directories($ENV{MX_SDK_HOME}/opensource/include/glib-2.0) include_directories($ENV{MX_SDK_HOME}/opensource/lib/glib-2.0/include) link_directories($ENV{MX_SDK_HOME}/lib) link_directories($ENV{MX_SDK_HOME}/opensource/lib/) add_compile_options(-std=c++11 -fPIC -fstack-protector-all -pie -Wno-deprecated-declarations) add_compile_options("-DPLUGIN_NAME=${PLUGIN_NAME}") add_compile_options("-Dgoogle=mindxsdk_private") add_definitions(-DENABLE_DVPP_INTERFACE) message("ACL_LIB_PATH:${ACL_LIB_PATH}.") include_directories(${ACL_LIB_PATH}/include) add_library(${TARGET_LIBRARY} SHARED ./FasterRcnnMindsporePost.cpp ./FasterRcnnMindsporePost.h) target_link_libraries(${TARGET_LIBRARY} glib-2.0 gstreamer-1.0 gobject-2.0 gstbase-1.0 gmodule-2.0) target_link_libraries(${TARGET_LIBRARY} plugintoolkit mxpidatatype mxbase) target_link_libraries(${TARGET_LIBRARY} -Wl,-z,relro,-z,now,-z,noexecstack -s) install(TARGETS ${TARGET_LIBRARY} LIBRARY DESTINATION $ENV{MX_SDK_HOME}/lib/modelpostprocessors/)4、配置编译环境步骤一:指定“CMakeLists.txt”编译配置文件在工程界面左侧目录找到“CMakeLists.txt”文件,右键弹出并单击如所示“Load CMake Project”,即可指定此配置文件进行工程编译。注:本项目编译文件CMakeLists.txt在目录./postprocess/下,上图仅作为功能展示步骤二:编译配置在MindStudio工程界面,依次选择“Build > Edit Build Configuration...”,进入编译配置页面,如图,配置完成后单击“OK”保存编译配置。5、执行编译单击“Build”编译工程。如果在编译过程中无错误提示,且编译进度到“100%”,则表示编译成功,如图。编译成功后,会在项目目录下生成build文件夹,里面有我们需要的可执行文件如图,也可在CMakeLists.txt中最后一行指定可执行文件安装的位置。8、pipeline文件编排pipeline文件编排是python版SDK最主要的推理开发步骤,作为一个目标检测任务,主要包括以下几个步骤: 图片获取 → 图片解码 → 图像缩放 → 目标检测 → 序列化 → 结果发送,以下介绍pipeline文件流程编排步骤:步骤一:在顶部菜单栏中选择“Ascend>MindX SDK Pipeline”,打开空白的pipeline绘制界面,如图:步骤二:从左方插件库中拖动所需插件,放入编辑区,如图:以下介绍本项目中,各个插件的功能:插件名称插件功能appsrc0第一个输入张量,包含了图像数据appsrc1第二个输入张量,包含了图像元数据,主要是图像原始尺寸和图像缩放比mxpi_imagedecoder0用于图像解码,当前只支持JPG/JPEG/BMP格式mxpi_imageresize0对解码后的YUV格式的图像进行指定宽高的缩放,暂时只支持YUV格式的图像mxpi_tensorinfer0对输入的两个张量进行推理mxpi_objectpostprocessor0继承图像后处理基类,用于对目标检测模型推理的输出张量进行后处理mxpi_dataserialize0将stream结果组装成json字符串输出appsink0从stream中获取数据步骤三:单击选中编辑区内的插件,在插件属性展示区自定义配置(如插件属性中的路径参数),如图:步骤四:单击编辑区空白区域,插件两端出现接口,按照一定顺序用鼠标连接以上插件,然后点击编辑区下方Format进行格式化,最后点击编辑区下方Save保存pipeline文件,编写好的pipeline文件可视化结果如下图所示:接下来展示文本代码:{ "im_fasterrcnn": { "stream_config": { "deviceId": "0" }, "appsrc0": { "props": { "blocksize": "409600" }, "factory": "appsrc", "next": "mxpi_imagedecoder0" }, "mxpi_imagedecoder0": { "factory": "mxpi_imagedecoder", "next": "mxpi_imageresize0" }, "mxpi_imageresize0": { "props": { "parentName": "mxpi_imagedecoder0", "resizeHeight": "768", "resizeWidth": "1280", "resizeType": "Resizer_KeepAspectRatio_Fit" }, "factory": "mxpi_imageresize", "next": "mxpi_tensorinfer0:0" }, "appsrc1": { "props": { "blocksize": "409600" }, "factory": "appsrc", "next": "mxpi_tensorinfer0:1" }, "mxpi_tensorinfer0": { "props": { "dataSource": "mxpi_imageresize0,appsrc1", "modelPath": "../models/conversion-scripts/fasterrcnn_mindspore.om" }, "factory": "mxpi_tensorinfer", "next": "mxpi_objectpostprocessor0" }, "mxpi_objectpostprocessor0": { "props": { "dataSource": "mxpi_tensorinfer0", "postProcessConfigPath": "../models/fasterrcnn_coco2017.cfg", "labelPath": "../models/coco2017.names", "postProcessLibPath": "../../postprocess/build/libfasterrcnn_mindspore_post.so" }, "factory": "mxpi_objectpostprocessor", "next": "mxpi_dataserialize0" }, "mxpi_dataserialize0": { "props": { "outputDataKeys": "mxpi_objectpostprocessor0" }, "factory": "mxpi_dataserialize", "next": "appsink0" }, "appsink0": { "factory": "appsink" } } }
-
我用pytorch1.4.0在gpu服务器上训练了一个图像分割模型,然后想在atlas200dk上部署我的模型,想问一下如何把pytorch的pth文件或者onnx文件,直接在atlas200dk上进行模型转化变成om模型?然后在python环境下推理?有没有相关的资料或者代码可以参考
-
【Atlas200产品】【Atlas200原理图功能】 原理图,申请帮忙审核,谢谢邮件已发送,请帮忙审核,谢谢3.8v电压可以测到,但是系统没有启动。
-
大版本号是5.1.rc2取用的openEuler版本是:openEuler-22.03-LTS-aarch64-dvd.iso用sd_maker制卡,查看log是解压iso后找不到文件。make_os_sd.sh处理iso时,并没有initrd.img.gz这个文件。是否还要其它的镜像文件?谢谢。
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签