• [经验分享] 用MindStudio完成基于CTC算法的语音热词唤醒
    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)
  • [经验分享] 行李箱安检边缘套件开发经验分享
    bilibili视频链接:【行李箱安检识别】 https://www.bilibili.com/video/BV12A41197HJ/?share_source=copy_web&vd_source=c70245f8912fa536541e7d4ea81c352f1.MindStudio介绍MindStudio是一套基于华为自研昇腾AI处理器开发的AI全栈开发工具平台,该IDE上功能很多,涵盖面广,可以进行包括网络模型训练、移植、应用开发、推理运行及自定义算子开发等多种任务。MindStudio除了具有工程管理、编译、调试、运行等一般功能外,还能进行性能分析,算子比对,可以有效提高工作人员的开发效率。除此之外,MindStudio具有远端环境,运行任务在远端实现,对于近端的个人设备的要求不高,用户交互体验很好,可以让我们随时随地进行使用。2.案例模型本项目目的是利用MindStudio开发基于Pytorch的训练模型和基于MindX SDK的推理项目。项目对x光安检图象进行推理,利用目标检测框架,对警棍、老虎钳、榔头、充电宝、剪刀、扳手、枪支、子弹、喷罐、手铐、小刀、打火机以上目标进行检测,将检测得到的不同类的目标用不同颜色的矩形框标记。支持硬件平台:本项目以昇腾Atlas310卡、Atlas 200DK为主要的硬件推理平台。3.环境搭建3.1远端环境搭建在服务器Linux端(aarch64架构):1)下载好 MindX SDK mxvision 2.0.4 下载参考链接。在远端任意用户文件夹下,将Ascend-mindxsdk-mxvision_2.0.4_linux-aarch64.run文件上传chmod +x Ascend-mindxsdk-mxvision_2.0.4_linux-aarch64.run ./Ascend-mindxsdk-mxvision_3.0.RC2_linux-x86_64.run --install安装完成后,使环境变量生效:export DDK_PATH=$HOME/Ascend/ascend-toolkit/latestexport NPU_HOST_LIB=$DDK_PATH/acllib/lib64/stubsource ~/Ascend/ascend-toolkit/set_env.shcd ~/software/mxVision/./set_env.sh下载好CANN 5.0.4,下载参考链接。同样在任意用户文件夹下,上传Ascend-cann-toolkit_5.1.RC2.2_linux-aarch64.runchmod +x Ascend-cann-toolkit_5.1.RC2.2_linux-aarch64.run./Ascend-cann-toolkit_5.1.RC2.2_linux-aarch64.run --install显示如下则CANN 5.0.4安装完成。安装完成后,可以创建一个env.txt 文件将文档中红框路径保存以下。3.2 本地(windows端)环境搭建1)windows版本MindStudio。按照官方步骤进安装,同时安装相应依赖。2)安装任意版本的Anoconda。3)按照官方教程进行vpn连接。进入众智实验室容器IP。4)同步CANN。打开MindStudio,在File中选择File > Settings > Appearance & Behavior > System Settings > CANN点击change CANN进入下图界面,选择远端CANN安装的位置配置好后返回上一界面显示如图。5)在File > Settings > Appearance & Behavior > System Settings > MindX SDK,进入MindX SDK管理页面,点击Install进入远程配置界面。在Remote Connection一栏点击加号,配置远程连接,输入申请的账号密码等相关信息。在Remote CANN Location 一栏选择远端安装CANN Toolkits的路径,具体到版本,这里选择的是5.0.4版本。在Remote SDK Location 一栏选择远端安装MindX SDK的路径,这里选择的是Mxvision 2.0.4 版本。Local SDK location为本地默认的SDK安装位置,会将远端的SDK同步过来。点击ok后开始同步。配置完成后,界面如下图所示。4.Pytorch yolox模型训练流程点击File >New >Project 创建一个空训练工程。选择Pytorch项目。创建好工程后将YOLOX训练代码git 到本地。git clone cid:link_5注:由于网络问题,github上的代码经常可能克隆失败,可以直接去原网页下载好代码解压到目录中。下载好的文件目录如图所示。接下来在终端使用conda命令为此工程配置一个虚拟环境。需要的版本python=3.9conda create -n YOLOX_pt python=3.9执行后命令行如图:按y生成环境。之后安装工程所要求的包。pip install -r requirements.txt显示安装成功,这里如果显示安装onnx失败,将requirements中的onnx版本删除,再次运行安装命令即可。此处onnx版本不影响训练。我们还需要安装gpu版本的pytorch才能进行训练,执行下面命令conda install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch安装完毕后conda list #查看当前已安装包将数据集下载后解压到本地。开始配置exp文件。使用yolox-m模型标准进行训练。在项目的exps> default中找到yolox-m默认配置文件,对文件中路径、参数进行修改。 配置好之后将tools > train.py文件拷贝到文件根目录下,运行python train.py -f ./exps/default/yolox_m.py -d 0 -b 2 --fp16 -o其中标蓝为你的exp文件位置如下界面表示开始训练。最终训练文件会保存在YOLOX_outputs >yolo-m中Train_log会记录训练时的全部信息。我们可以得到best_cpkt.pth权重文件。再将pth文件转换成为onnx权重文件,便于后续离线模型转换。python export_onnx.py --output-name yoloxray1.onnx -n yolox-m -c D:/project/YOLOX2/YOLOX_outputs/yolox_m/best_ckpt.pth5.模型推理App开发流程1)创建工程接下来进行app边缘开发任务,需先创建一个推理工程,点击File >New >Project,选择Ascend APP工程之后建立一个MindX SDK for Python空工程。2)选择编译器点击File >Project structure为项目配置远端python编译器。在SDK一栏点击下拉菜单,点击Add Python SDK进入选择编译器页面,选择SSH,在Interpreter一栏选择一个远端python路径。选择好后分别点击左边Project、Modules、SDKs,可以看到刚才添加的编译器。点击Apply应用配置。环境配置完成,接下来就可以在本地进行开发工作了。3)创建项目目录本次工程目录结构如下图所示在python目录下Main目录放置程序的主要函数test目录,放置测试数据相关内容(测试数据的名称label文件)test_img目录,放置测试图片pipeline目录,放置pipeline文件在config目录下放置各种参数设置文件,包括流的推理日志参数文件sdk.conf、logging.conf。在postprocess目录下放置现成的yolox后处理插件的代码接下来将目录先上传到远端。进入Files >settings界面,选择左方的tools下的Deployment界面在Mappings下选择项目的远端同步路径在Excluded Paths下,点击左下角加号减号,还可以删改不进行同步的文件,我们可以排除掉模型文件等较大文件,这样可以加快流程开发速度。我们排除掉除了项目中Python/Main路径下的主函数文件外,其余所有的文件路径,可以减少文件上传和下载的时间。之后右键文件根目录,点击Deployment >Upload to将项目整体同步一次到远端。4)onnx 模型转换成 om离线模型1. 预处理参数设置利用官方提供的aipp转换方式对模型转换参数进行设置。这里介绍一下aipp预处理方法,AIPP(Artificial Intelligence Pre-Processing)人工智能预处理,用于在AI Core上完成图像预处理,包括改变图像尺寸、色域转换(转换图像格式)、减均值/乘系数(改变图像像素),数据处理之后再进行真正的模型推理。该模块功能与DVPP相似,都是用于图像数据预处理,但与DVPP相比,由于DVPP各组件基于处理速度和处理占有量的考虑,对输入、输出有特殊的限制,如对输出图片的宽高有对齐要求,且其输出格式通常为YUV420SP等格式。这样的设定虽在视频分析的场景下有非常广阔的输入,但深度学习模型的输入通常为RGB或BGR,且输入图片尺寸各异,因此ATC工具流程中提供了AIPP功能模块。创建一个空cfg文件。根据官方的文档说明设置参数。原模型图片格式为YUV420SP_U8,转换成BGR格式模型,详细参数需按照以下设置。选择静态aipp。所有参数如图编写成的yolox_bgr.cfg,放于根目录的config文件夹下。可视化模型转换将第四节训练好的onnx模型上传到远端服务器上,点击Ascend >Model convert进入模型转换界面,选择服务器上的onnx模型。Output Path选择本地任意位置。Type为UINT8。之后点击next附:点击模型右边的眼睛按钮还可以可视化的查看模型选择aipp参数文件选择图片格式为BGR之后点击next。环境变量在之前已经设置好了,所以这里不配置也可以转换成功。点击finish,等待模型开始转换,最终结果如下,表示模型转换成功。如果转换失败,则需要手动添加以下环境变量 insall_path=/usr/local/Ascend/ascend-toolkit/latestLD_LIBRARY_PATH=${install_path}/atc/lib64:${install_path}/acllib/lib64:$LD_LIBRARY_PATHASCEND_OPP_PATH=${install_path}/oppASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest/然后再次进行转换最后,将生成好的om模型文件上传到远端Python/models路径下。5)后处理的标签文件、后处理插件配置。标签文件coco.names 生成创建一个coco.names文件,将标签内容填入保存。放在Python/models路径下,上传至远端。配置后处理参数文件yolox_eval.cfg。以下为各参数介绍,可以根据模型需要来选择。CLASS_NUM类别数量。80OBJECTNESS_THRESH是否为目标的阈值,大于阈值即认为是目标。0.3IOU_THRESH两个框的IOU阈值,超过阈值即认为同一个框。0.45以yolox_eval.cfg保存,放在configs路径下,上传至远端。3.后处理插件(.so文件)生成点击Tools >Start SSH,进入远端的终端cd 到postprocess目录下,执行bash build.sh会在远端当前路径下,生成yolox后处理插件。注:在这里注意如果编译失败,需要在终端通过export重新配置编译环境,包括MindX SDK路径和CANN路径。6)pipeline编排此次插件处理流程如下点击Ascend > MindX SDK pipeline进入可视化设计界面。根据流程编排插件在左边search界面搜索需要的插件拖动插件名称到右方,生成一个插件。按照此方法依次将需要的插件拖动至右方。点击每个插件右边的小点,将插件顺次连接。如果觉得排列不整齐,可以点击Format按钮让他们变整齐>> 最终所有插件依次连接效果如下。点击每个插件,可以在右方设置好每个插件的的参数。具体每个插件的功能和参数说明在官方文档中。decoder的参数。resizer的参数。在tensorinfer中选择刚才转换好的推理模型路径。在postprocessor插件中配置好远端cfg、names、so文件路径参数点击save之后会生成一个new.pipeline文件,我们将文件放于Python/pipeline中。将pipeline文件命名为pre_post.pipeline,上传至远端。7)main函数编写首先创建流:若创建失败则退出。运用StreamManagerApi 读取pipeline。载入图片,进行推理,获得带有框的图片输出。获得框向量和物体名称以及置信度,进行画框,并将结果写入test_img文件,保存名称为pre_post_bgr.jpg最后不要忘了销毁流至此主函数编写完毕,命名为pre_post.py,放到python/Main目录下。6.编译执行在主界面点击图示Edit configurations配置运行参数。Executable :选择需要执行的Main函数文件Command Arguments:如果在运行时有arg参数可以进行配置,本项目主函数中参数已经设置好了所以不用配置。Environment variables:一栏配置远端的环境变量,请确保配置好以下路径:SDK-path: mxVision SDK 安装路径ascend-toolkit-path: CANN 安装路径点击apply然后关闭界面。配置好后点击旁边的三角键,我们的主函数就可以传输到远端进行编译了。编译成功,等待远端output文件夹传输至本地后,在目录下查看结果。7.性能验证1.下载验证数据集将数据集上传到远端,进行性能验证。小提示:建议将工程文件的数据集和模型文件之类大型文件都排除在同步列表之外。2.运行路径``python/test``下的文件 parse_coco.py 参数:--json_file=data/annotations/instances_test2017.json--img_path=data/test2017注:这里路径最好换成你上传的数据集所在的绝对路径 若运行成功,会在该目录下生成文件夹ground_truth,其中包含每张图像上提取的目标框真实位置与类别的txt文件。3.接下来将每张图的预测结果转为txt文件,并保存在同一文件夹下,其步骤如下:打开MindX SDK安装路径下的日志配置文件vim ${MX_SDK_HOME}/config/sdk.conf之后修改参数 enable_ps=true,开启日志记录,之后pipeline运行时会在指定文件夹生成运行日志。修改完毕后,运行该路径下文件python/Main/python3 eval_nopre_post.py 若运行成功,会在``python/test`` 路径下生成 test_nopre_post 文件夹,该目录下包含有每张图像上的检测结果的 txt 文件。同时会得到fps为32 > 20,满足性能要求运行命令: python/test/python3 map_calculate.py 参数:--npu_txt_path="./test_nopre_post" 得到以上结果,使用MindX SDK环境推理精度为47.43%,与原模型精度一致。8.FAQ1)ModuleNotFoundError:No module named XXX大多是因为在运行程序前未配置好路径,请检查CANNToolKits和MindX SDK路径配置问题。配置远端CANNToolsKits包时提示permission denied建议非root权限用户选择非usr/local路径下的CannTooKits包进行配置,否则会出现权限不够的问题。模型转换时无法使用前处理问题按照提示,模型的输入必须满足type为utf8的格式,之后才可以进行模型转换。详情可以参照官方模型参数说明。色域转换配置说明 - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)9.从昇腾论坛获得更多支持如上述步骤中在在实践中仍然遇到其他问题,包括om模型参数设置问题,调用streamMannagerApi时的问题,都可以在论坛中提出自己的问题或者查找相关问题,我的很多问题都是在这里解决的。也非常推荐大家一期建设这个论坛。昇腾社区-官网丨昇腾万里 让智能无所不及 (hiascend.com)
  • [经验分享] Yolact边缘套件开发经验分享
    bilibili视频链接:【YOLACT边缘套件开发经验分享】 https://www.bilibili.com/video/BV18R4y1k7kY/?share_source=copy_web&vd_source=c70245f8912fa536541e7d4ea81c352f1.MindStudio介绍MindStudio是一套基于华为自研昇腾AI处理器开发的AI全栈开发工具平台,该IDE上功能很多,涵盖面广,可以进行包括网络模型训练、移植、应用开发、推理运行及自定义算子开发等多种任务。MindStudio除了具有工程管理、编译、调试、运行等一般普通功能外,还能进行性能分析,算子比对,可以有效提高工作人员的开发效率。除此之外,MindStudio具有远端环境,运行任务在远端实现,对于近端的个人设备的要求不高,用户交互体验很好,可以让我们随时随地进行使用。2.模型介绍YOLACT是2019年发表在ICCV上面的一个实时实例分割的模型,它主要是通过两个并行的子网络来实现实例分割的。(1)Prediction Head分支生成各个anchor的类别置信度、位置回归参数以及mask的掩码系数;(2)Protonet分支生成一组原型mask。然后将原型mask和mask的掩码系数相乘,从而得到图片中每一个目标物体的mask。论文中还提出了一个新的NMS算法叫Fast-NMS,和传统的NMS算法相比只有轻微的精度损失,但是却大大提升了分割的速度。3.环境搭建3.1开发环境安装 Windows版本MindStudio。按照官方安装步骤进行Windows平台MindStudio环境配置。[参考链接](cid:link_4)在下载界面中选择软件包下载,根据系统和习惯选择相应包进行下载。如果下载的.exe文件,下载后进行安装。3.2远端环境配置3.2.1 安装CANNCANN(Compute Architecture for Neural Networks)是华为公司针对AI场景推出的异构计算架构,通过提供多层次的编程接口,支持用户快速构建基于昇腾平台的AI应用和业务。首先下载CANN安装包,选择并下载平台开发套件软件包。[参考链接](cid:link_6)下载完成后按照如下步骤进行安装,详细说明参考昇腾社区。[参考链接](cid:link_2)以软件包的安装用户登录安装环境。若安装依赖中安装依赖的用户为root用户,则软件包的安装用户可自行指定;若安装依赖中安装依赖的用户为非root用户,请确保软件包的安装用户与该用户保持一致。将获取到的开发套件包上传到安装环境任意路径(如“/home/package”)。进入软件包所在路径。增加对软件包的可执行权限。chmod +x 软件包名.run软件包名.run表示开发套件包Ascend-cann-toolkit_{version}_linux-{arch}.run,请根据实际包名进行替换。执行如下命令校验软件包安装文件的一致性和完整性。./软件包名.run --check执行以下命令安装软件(以下命令支持--install-path=等参数,具体参数说明请参见参数说明)。./软件包名.run –installCANN软件提供进程级环境变量设置脚本,供用户在进程中引用,以自动完成环境变量设置。用户进程结束后自动失效。示例如下(以root用户默认安装路径为例):. /usr/local/Ascend/ascend-toolkit/set_env.sh 用户也可以通过修改~/.bashrc文件方式设置永久环境变量,操作如下:以运行用户在任意目录下执行vi ~/.bashrc命令,打开.bashrc文件,在文件最后一行后面添加上述内容。执行:wq!命令保存文件并退出。执行source ~/.bashrc命令使其立即生效。3.3创建项目3.3.1新建项目点击New Project。选择Ascend App,配置好项目名称,如果没有同步CANN,请点击Change按钮。第一次使用需要配置远端服务器,点击+号进行配置。输入远程服务器信息,测试连接成功后点击OK。回到Remote CANN Setting界面,在Remote CANN location行右边选择CANN位置。选择CANN所在位置选择后点击finish等待同步文件同步完成后点击Next,继续创建工程选择MindX SDK project(Python),然后点击finish。3.3.2配置Deployment点击Tools->Deployment,选择Configuration。可以在Deployment中点击+号,输入名字添加。然后再Connection中点击SSH configuration右边的…,添加服务器。完成后可以在Connection中看到已经成功添加服务器,并可以通过Test Connection测试连接是否成功。点击Mappings,在Deployment Path下方的路径选择,选择远程代码路径。右侧Excluded Path可以选择不拉取的文件,比如不需要把数据集拉取到本地,就选择Mappings路径中的无需拉取的文件。右击Project,选择Deployment,选择Download from,选择刚才所设置的源,等待代码拉取。3.3.3配置远端解释器点击File->Project Structrue ->SDK 配置python SDK。点击加号添加Python SDK。选择SSH Interpreter,选择deployment,Interpreter和Name会自动填充,如果需要自定远端Python版本,则点击Interpreter后面的按钮(如下图所示),打开远端目录,选择需要的Python点击Project,如图所示,选择刚刚配置好的远端SDK,点击OK使配置生效。3.3.4配置MindX SDK打开MindStudio,在File中选择File > Settings > Appearance & Behavior > System Settings > MindX SDK,进入MindX SDK管理页面,点击Install进入远程配置界面。在配置前,请确保远端环境已经配置好MindX SDK和CANN Toolkits。在Remote Connection一栏配置远程连接,输入申请的账号密码等相关信息。在Remote CANN Location 一栏选择远端安装CANN Toolkits的路径,具体到版本,这里选择的是5.0.4版本。在Remote SDK Location 一栏选择远端安装MindSDK的路径,这里选择的时Mxvision 2.0.4 版本。Local SDK location为本地默认的xSDK安装位置,会将远端的SDK同步过来。点击ok后开始同步,配置完成后,如果界面如下图所示,则表示成功。4. 本地Git clone代码点击最下方的Terminal,打开本地终端。可以看到左下角已经打开本地终端。复制Github代码链接:cid:link_5, 在本地终端输入git clone cid:link_5并运行。5. 项目开发5.1onnx转om离线模型转换我使用的是Pytorch模型,他的权重是一个pth文件,而Mind SDK里面支持的是om模型,所以我们需要进行一个转换。首先我们要把我们的pth文件转换成onnx文件,然后再转换成om模型。5.2.1 pth转换成onnxpth转换成onnx模型首先就是要加载权重,然后用权重来初始化自己的模型,随后调用torch自带的转onnx函数就可以完成模型的转换。代码仓库链接如下:cid:link_5pth模型我们直接下载,链接如下:cid:link_3在om转onnx时,需要将predict.py中21行代码改为mode = "export_onnx",然后运行python3 predict.py就可以得到onnx模型。5.2.2 onnx转om模型选择Ascend->Model Converter在Model File中选择需要转换的onnx模型路径,选择后会自动分析模型,分析后得到如下。这里软件自动解析模型,将模型的输入形状填写到了Shape下,在Type下也自动填写了精度类型。具体ACT模型转换时所有可以用到的参数,可以在此链接中详细查询https://www.hiascend.com/document/detail/zh/mindstudio/50RC3/msug/msug_000394.html。点击Select选择输出结点。找到模型的所有输出节点,右击后选择select选择所有输出结点后点击OK,返回界面后点击Next由于本模型中未使用AIPP,继续点击Next。这一步无需修改,点击Finish。可以看到ATC工具开始运行转换模型。模型转换成功后得到如下输出5.2pipeline编写 绘制整个流程的流程图,画出流程图如下。图像读取步骤中我选择使用cv2完成。据流程图编写完整的pipeline,创建yolact.pipline文件,打开后进行插件编排。首先选择输入插件,我选择使用appsrc插件,将其拖出来。之后使用推理插件mxpi_tensorinfer0,两者之间拖动连线连接起来。点击mxpi_tensorinfer0插件,在modelPath中选择推理使用的om模型路径,如何转换得到om模型会在下文讲到。以此类推,完成所有插件编排后结果如下。点击Text,可以看到想要插件流程的代码。5.3main函数编写创建流:若创建失败则退出。运用StreamManagerApi 读取pipeline。载入图片,进行推理。对推理结果进行后处理。推理结果保存并计算精度至此主函数编写完毕,命名为main.py,放到主目录下。 6. 运行推理放入一张生活场景的图片,点击Run下的Edit ConfigurationDeployment选择我们所在服务器,Executable选择执行文件,即main.py,Command Arguments中可以输入我们想要输入的参数。比如我们在执行图像可视化时,就输入—image=”street.jpg”。点击OK完成设置,然后点击工具类的三角形图标,开始运行。可以看到文件夹中已经生成了img.jpg输出结果。可视化结果图像如下。7. 精度测评基于coco数据集进行精度测评,coco数据集放置目录结构如下。├── data│ ├── coco_test│ │ ├── annotations │ │ ├── images ├── convert│ └── -----├── model_data │ └── -----├── utils │ └── -----├── images │ └── -----├── main.py ├── README.md 执行精度评估,同理在Run下的Edit Configuration中配置运行设置。配置如下,设置main.py为执行文件,不需要添加任何参数。点击OK完成配置并点击运行。运行精度结果如下得到精度结果如下:精度指标精度bbox mAP 0.5:0.9530.4%bbox mAP 0.552.0%segm mAP 0.5:0.9527.3%segm mAP 0.547.7%对比原代码仓库的精度如下:可见精度结果对比完全一致。
  • [MindX SDK] 波比跳运动小程序
    波比跳运动小程序1 介绍波比跳运动小程序基于 MindX SDK 开发,在 Ascend 310 芯片上进行目标检测,将检测结果保存成视频。项目主要流程:1)视频流程:通过 live555 服务器进行拉流输入视频,然后进行视频解码将 H.264 格式的视频解码为图片,图片缩放后经过模型推理进行波比跳检测,识别结果经过后处理后利用 cv 可视化识别框,以视频的形式输出,同时生成文本文件记录视频中完成的波比跳个数。2)小程序流程:通过微信小程序开发者将摄像头截取的图片数据上传至腾讯云桶中,然后后端将桶中数据下载至本地并将数据输入至流水线内,接着进行图片解码和缩放,最后经过模型推理进行波比跳检测,识别结果经过后处理后上传至腾讯云桶中,为前端小程序使用。1.1 支持的产品昇腾 310(推理)1.2 支持的版本本样例配套的 CANN 版本为 5.1.RC1,MindX SDK 版本为 3.0.RC3。MindX SDK 安装前准备可参考《用户指南》,安装教程1.3 软件方案介绍基于 MindX SDK 的波比跳运动小程序业务流程为:通过微信小程序开发者将摄像头截取的图片数据上传至腾讯云桶中,然后后端将桶中数据下载至本地并经mxpi_appsrc拉流插件输入,然后使用图片解码插件mxpi_imagedecoder将图片解码,再通过图像缩放插件mxpi_imageresize将图像缩放至满足检测模型要求的输入图像大小要求,缩放后的图像输入模型推理插件mxpi_modelinfer得到检测结果,根据检测结果改变波比跳识别的状态机状态,并更新波比跳识别个数,最后上传记录波比跳识别个数的txt文件到腾讯云桶中,以供小程序使用。1.4 代码目录结构与说明本 Sample 工程名称为 Burpee_Detection,工程目录如下图所示:├── envs │   └── env.sh     //基础环境变量与atc转换需要的环境变量 ├── readme_img         //ReadMe图片资源 │   ├── app_1.jpg   │   ├── app_2.jpg   │   ├── app_3.jpg   │   ├── app_4.jpg   │   ├── app_5.jpg   │   ├── dataset.jpg   │   ├── video.jpg   │   ├── app_flow.jpg   │   ├── video_flow.jpg │   ├── dark.jpg ├── model │   ├── atc.sh                   //atc运行脚本 ├── pipeline │   ├── burpee_detection_p.pipeline//图片识别使用的pipeline文件 │   └── burpee_detection_v.pipeline//视频识别使用的pipeline文件 ├── App_burpee_detection │   ├── app_main.py           //识别,保存结果,并进行性能测试 │   └── run.sh                 //运行脚本 ├── Pic_burpee_detection │   ├── map_calculate.py     //mAP计算(精度计算) │   ├── pic_main.py           //识别,保存结果,并进行性能测试 │   └── run.sh                 //运行脚本 ├── Video_burpee_detection │   ├── video_main.py         //识别,保存结果,并进行性能测试 │   └── run.sh                 //运行脚本 └── README.md本项目的代码地址为:cid:link_61.5 技术实现流程图视频流程:小程序应用后端流程:1.6 特性及使用场景举例该应用特色在于mindsdk与小程序的结合,其并不局限于波比跳的计数,该应用模式仍适用于其他实时图像识别类小程序功能的开发。 对于画面内单人,且光线正常的情况下小程序都能正常且精准的计数。在精度和性能上,该应用实现流程都超过了要求水平,但仍有一些场景,情况不适用:· 光线极暗的情况下,由于前端获取的数据的清晰度较低且mindsdk中图片解码插件只适用jpg,精度会大幅下降 · mindsdk只存在rtsp拉流的插件,如若推流以视频形式在小程序与后端之间传输,需自行编写新的推流插件 · 当画面人物为正对摄像头做波比跳时,会出现检测不到动作的情况,用户应侧对摄像头。正对很难判断动作是否标准。2 环境依赖软件名称版本说明获取方式MindX SDK3.0.RC3mxVision软件包链接ubuntu18.04.1 LTS操作系统Ubuntu官网获取Ascend-CANN-toolkit5.1.RC1Ascend-cann-toolkit开发套件包链接live5551.09实现视频转 rtsp 进行推流链接ffmpeg2021-10-14实现 mp4 格式视频转为 H.264 格式视频链接微信开发者工具1.06.2207210实现小程序的使用链接小程序导入代码-微信小程序代码链接腾讯桶内文件夹格式-压缩包解压后文件夹内文件形式即为桶内文件形式链接对象储存 python sdk-小程序相关python sdk快速入门链接模型文件-pt 模型文件,onnx 模型文件,om 模型文件,names文件,模型配置文件链接在运行项目需要的环境变量如下,运行前不需要特别设置,环境依赖已经写入脚本中,脚本在Burpee_Detection/envs目录下:export MX_SDK_path=""# mxVision 安装路径 export Ascend_toolkit_path=""#CANN 安装路径 ​ # MindXSDK 环境变量: . /${MX_SDK_path}/set_env.sh ​ # CANN 环境变量: . /${Ascend_toolkit_path}/set_env.sh注:其中${MX_SDK_path}替换为用户的SDK安装路径;Ascend_toolkit_path替换为ascend-toolkit开发套件包所在路径。3 模型转换以及依赖安装本项目使用的模型是波比跳识别的模型。模型文件可以直接下载。(下载链接在第二小节)3.1 模型转换使用模型转换工具 ATC 将 onnx 模型转换为 om 模型,模型转换工具相关介绍参考链接:CANN 社区版 。步骤如下:步骤1 下载onnx模型,请移动至Burpee_Detection/model目录下;若下载om模型文件,请跳过模型转换步骤。(下载链接在第二小节)步骤2 将best.onnx文件移动至Burpee_Detection/model目录下,然后运行model目录下的atc.shbash /model/atc.sh执行该命令后会在当前文件夹下生成项目需要的模型文件ATC start working now, please wait for a moment. ATC run success, welcome to the next use.表示命令执行成功。3.2 准备按照第3小节软件依赖安装 live555 和 ffmpeg,按照 Live555离线视频转RTSP说明文档将 mp4 视频转换为 H.264 格式。并将生成的 H.264 格式的视频上传到live/mediaServer目录下,然后修改pipeline目录下的burpee_detection_v.pipeline文件中mxpi_rtspsrc0的内容。"mxpi_rtspsrc0":{ "props": { "rtspUrl":"rtsp://xxx.xxx.xxx.xxx:xxxx/xxx.264",  // 修改为自己所使用的的服务器和文件名 },    "factory": "mxpi_rtspsrc", "next": "mxpi_videodecoder0" }4 运行与测试4.1 运行4.1.1 视频步骤1 按照第 2 小节 环境依赖 中的步骤设置环境变量。步骤2 按照第 3 小节 模型转换 中的步骤获得 om 模型文件,放置在 Burpee_Detection/models 目录下。步骤3 修改burpee_detection_v.pipeline中mxpi_modelinfer0中postProcessLibPath的值${MX_SDK_path}为 MindX SDK 的安装路径步骤4 按照 3 小节 准备 中的步骤创建rtsp流以实现本地视频的rtsp拉流操作。步骤5 运行。在 Burpee_Detection/Video_burpee_detection 目录下执行命令:bash run.sh运行可视化结果会以video_result.mp4视频形式保存在Burpee_Detection/Video_burpee_detection目录下 波比跳识别个数会以result.txt文件形式保存在Burpee_Detection/Video_burpee_detection目录下4.1.2 小程序步骤1 按照第 4 小节 视频 中的步骤1到步骤3搭建小程序后端环境。步骤2 运行。在 Burpee_Detection/App_burpee_detection 目录下执行命令:bash run.sh步骤3 创建obs桶内文件夹和文件,如下所示├── input   //存放小程序获取数据 ├── result //存放后端处理的数据输出结果 ├── state   //用于判断小程序状态(前端改写,后端查看) ├── state.txt //前端放入state文件夹的文件 ├── result.txt//存放后端处理的计数值步骤4 下载微信开发者工具并登录,在微信公众平台注册小程序并获取AppID步骤5 点击导入,选择小程序代码文件夹并打开(代码可下载,下载链接在第二小节),点击编译模式选中pages目录下的子目录bind并选择bind,点击详情-本地设置,选中不效验合法域名后(可在小程序公众平台开发管理-开发设置中,配置合法域名),点击真机调试,然后用手机扫描二维码步骤6 进入微信小程序页面,点击开始计数,小程序将摄像头以40ms(fps=25)的速率拍摄照片,并上传至腾讯云桶内,后台接收图片并处理步骤7 人物在摄像头前进行波比跳,后台实时更新波比跳个数并将结果发送至桶内,小程序端以0.1s的速率刷新页面展示的个数步骤8 点击结束,小程序停止发送图像并清理上传至桶内的图片释放内存,后端等待小程序下次开始计数4.2 性能与精度测试步骤1 准备测试数据集(数据集内应有数据以及对应的标签,格式为yolo),并将data文件夹放在Burpee_Detection目录下步骤2 打开Burpee_Detection/Pic_burpee_detection目录下pic_burpee_detection.py文件,将变量 INPUT_PATH ,OUTPUT_PATH ,OUTPUT_PIC_PATH分别初始化为 ["../data/images/test/"],[".././Pic_burpee_detection/result_test/"],[".././Pic_burpee_detection/result_test_pic/"]步骤3 在Burpee_Detection/Pic_burpee_detection目录下运行run.sh脚本,对data/images/test目录下的图片进行识别并输出结果bash run.sh运行脚本后会生成经过 SDK 后的推理结果结果保留在result_test目录下以.txt格式保存。 结果可视化效果保留在result_test_pic目录下以.jpg格式保存运行结果中会有Spend time:是识别所有图片所用的时间,fps:计算得到的帧数Image count:237 Spend time:5.785876989364624 fps:40.961811050536376步骤4 在Burpee_Detection/Pic_burpee_detection目录下运行map_calculate.py脚本,计算精度。python3.9.2 map_calculate.py测试结果98.67% = crouch AP 84.93% = jump AP 94.91% = support AP m_ap = 92.83%4.3 特殊情况测试数据为光线较暗时(无光源的情况下)图片测试结果:No objects detected!!!当测试无目标时会有对应报错
  • [经验分享] 使用MindStudio的HPO界面工具进行调优
    一、MindStudio介绍1.1基本介绍MindStudio为用户提供在AI开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。通过依靠模型可视化、算力测试、IDE本地仿真调试等功能,MindStudio能够帮助用户在一个工具上就能高效便捷地完成AI应用开发。另一方面,MindStudio采用插件化扩展机制,以支持开发者通过开发插件来扩展已有功能。在本案例中所使用的MindStudio版本为5.0.RC1,具体安装流程可参考MindStudio安装教程(https://www.hiascend.com/document/detail/zh/mindstudio/50RC3/instg/instg_000002.html)。具体的,MindStudio的功能包括:针对安装与部署,MindStudio提供多种部署方式,支持多种主流操作系统,为开发者提供最大便利。针对网络模型的开发,MindStudio支持TensorFlow、Pytorch、MindSpore框架的模型训练,支持多种主流框架的模型转换。集成了训练可视化、脚本转换、模型转换、精度比对等工具,提升了网络模型移植、分析和优化的效率。针对算子开发,MindStudio提供包含UT测试、ST测试、TIK算子调试等的全套算子开发流程。支持TensorFlow、PyTorch、MindSpore等多种主流框架的TBE和AI CPU自定义算子开发。针对应用开发,MindStudio集成了Profiling性能调优、编译器、MindX SDK的应用开发、可视化pipeline业务流编排等工具,为开发者提供了图形化的集成开发环境,通过MindStudio可以进行工程管理、编译、调试、性能分析等全流程开发,可以很大程度提高开发效率。MindStudio功能框架如图1所示,目前含有的工具链包括:模型转换工具、模型训练工具、自定义算子开发工具、应用开发工具、工程管理工具、编译工具、流程编排工具、精度比对工具、日志管理工具、性能分析工具、设备管理工具等多种工具。图11.2 MindStudio工具中的主要功能特性:工程管理:为开发人员提供创建工程、打开工程、关闭工程、删除工程、新增工程文件目录和属性设置等功能。SSH管理:为开发人员提供新增SSH连接、删除SSH连接、修改SSH连接、加密SSH密码和修改SSH密码保存方式等功能。应用开发:针对业务流程开发人员,MindStudio工具提供基于AscendCL(Ascend Computing Language)和集成MindX SDK的应用开发编程方式,编程后的编译、运行、结果显示等一站式服务让流程开发更加智能化,可以让开发者快速上手。自定义算子开发:提供了基于TBE和AI CPU的算子编程开发的集成开发环境,让不同平台下的算子移植更加便捷,适配昇腾AI处理器的速度更快。离线模型转换:训练好的第三方网络模型可以直接通过离线模型工具导入并转换成离线模型,并可一键式自动生成模型接口,方便开发者基于模型接口进行编程,同时也提供了离线模型的可视化功能。日志管理:MindStudio为昇腾AI处理器提供了覆盖全系统的日志收集与日志分析解决方案,提升运行时算法问题的定位效率。提供了统一形式的跨平台日志可视化分析能力及运行时诊断能力,提升日志分析系统的易用性。性能分析:MindStudio以图形界面呈现方式,实现针对主机和设备上多节点、多模块异构体系的高效、易用、可灵活扩展的系统化性能分析,以及针对昇腾AI处理器的性能和功耗的同步分析,满足算法优化对系统性能分析的需求。设备管理:MindStudio提供设备管理工具,实现对连接到主机上的设备的管理功能。精度比对:可以用来比对自有模型算子的运算结果与Caffe、TensorFlow、ONNX标准算子的运算结果,以便用来确认神经网络运算误差发生的原因。开发工具包的安装与管理:为开发者提供基于昇腾AI处理器的相关算法开发套件包Ascend-cann-toolkit,旨在帮助开发者进行快速、高效的人工智能算法开发。开发者可以将开发套件包安装到MindStudio上,使用MindStudio进行快速开发。Ascend-cann-toolkit包含了基于昇腾AI处理器开发依赖的头文件和库文件、编译工具链、调优工具等。1.3.安装指南:使用MindStudio前,首先应确定其使用场景,包括纯开发场景和开发运行场景两种:纯开发场景(分部署形态):在非昇腾AI设备上安装MindStudio和Ascend-cann-toolkit开发套件包。可作为开发环境仅能用于代码开发、编译等不依赖于昇腾设备的开发活动(例如ATC模型转换、算子和推理应用程序的纯代码开发)。如果想运行应用程序或进行模型训练等,需要通过MindStudio远程连接功能连接已部署好运行环境所需软件包的昇腾AI设备。开发运行场景(共部署形态):在昇腾AI设备上安装MindStudio、Ascend-cann-toolkit开发套件包、npu-firmware安装包、npu-driver安装包和AI框架(进行模型训练时需要安装)。作为开发环境,开发人员可以进行普通的工程管理、代码编写、编译、模型转换等功能。同时可作为运行环境,运行应用程序或进行模型训练。其中,不管哪种场景,都需要安装MindStudio、Ascend-cann-toolkit开发套件包:MindStudio:提供图形化开发界面,支持应用开发、调试和模型转换功能,同时还支持网络移植、优化和分析等功能。Ascend-cann-toolkit:开发套件包。为开发者提供基于昇腾AI处理器的相关算法开发工具包,旨在帮助开发者进行快速、高效的模型、算子和应用的开发。开发套件包只能安装在Linux服务器上,开发者可以在安装开发套件包后,使用MindStudio开发工具进行快速开发部署。1.4安装方案:1.4.1安装方案——LinuxMindStudio和Ascend-cann-toolkit可以使用Linux服务器上原生桌面自带的终端gnome-terminal进行安装,也可以在Windows服务器上通过SSH登录到Linux服务器进行安装。因为MindStudio是一款GUI程序,所以在Windows服务器上通过SSH登录到Linux服务器进行安装时,需要使用集成了X server的SSH终端(比如MobaXterm,该工具版本需要为v20.2及以上)。纯开发场景(分部署形态):该场景下纯开发环境需要安装MindStudio和Ascend-cann-toolkit,如图2所示。昇腾AI设备上运行环境的安装操作请参见《CANN 软件安装指南》。图2开发运行场景(共部署形态):该场景下需要安装如图3所示软件包,其中驱动、固件、Ascend-cann-toolkit和AI框架包的安装操作请参见《CANN 软件安装指南》。图31.4.2安装方案——WindowsMindStudio可以单独安装在Windows上。在安装MindStudio前需要在Linux服务器上安装部署好Ascend-cann-toolkit开发套件包,之后在Windows上安装MindStudio,安装完成后通过配置远程连接的方式建立MindStudio所在的Windows服务器与Ascend-cann-toolkit开发套件包所在的Linux服务器的连接,实现全流程开发功能。纯开发场景(分部署形态):该场景下在Windows服务器上安装MindStudio,昇腾AI设备上的驱动、固件、Ascend-cann-toolkit和AI框架包的安装操作请参见《CANN 软件安装指南》。图4开发运行场景(共部署形态):该场景下在Windows服务器上安装MindStudio,在纯开发环境需要安装Ascend-cann-toolkit,两者建立连接后,形成了集成MindStudio的纯开发环境。昇腾AI设备上运行环境的安装部署操作请参见《CANN 软件安装指南》,此场景运行环境多为端侧、边侧设备如Atlas 500 智能小站和Atlas 200 DK 开发者套件等。图5Windows工控机场景:该场景下在Windows服务器上安装MindStudio、驱动、固件和Windows版nnrt,其中驱动、固件和Windows版nnrt需要参见《CANN Windows版用户指南》进行安装。纯开发环境需要安装Ascend-cann-toolkit,与MindStudio连接后基于两者开发的应用程序可在Windows服务器上运行。图61.5.安装流程:1.5.1安装流程——Linux图7 Linux环境下,MindStudio安装流程如图7所示。环境要求:MindStudio安装的环境要求如表1,可对照着判断是否满足条件。表1 MindStudio环境要求类别限制要求说明硬件内存:最小4GB,推荐8GB磁盘空间:最小6GB若Linux宿主机内存为4G,在MindStudio中进行模型转换时,建议Model文件大小不超过350M,如果超过此规格,操作系统可能会因为超过安全内存阈值而工作不稳定。若Linux宿主机配置升级,比如8G内存,则相应支持的操作对象规格按比例提升。例如,内存由4G升级到8G,则Model文件建议大小不超过700M。系统语言en_US.UTF-8当前仅支持系统语言为英文。请以任意用户使用locale命令在任意路径下查询编码格式,若系统返回“LANG=en_US.UTF-8”,则表示正确;否则,请以root用户使用“vim /etc/default/locale”命令修改“LANG=en_US.UTF-8”,重启(使用reboot命令)使之生效。系统要求操作系统可以通过ssh登录,同时打开ssh的X11Forwarding功能glibc版本应大于或等于2.27ssh服务的开启和X11Forwarding的配置请参见启动MindStudio时无法显示图形化界面。对于Docker环境,启动容器时需要映射ssh端口,如docker run -p {宿主机端口}:{容器内ssh端口} ...若系统glibc版本小于2.27,请参见启动MindStudio时报glibc版本太低问题处理。已验证支持的操作系统Ubuntu 18.04-x86_64Ubuntu 18.04-aarch64Ubuntu 20.04-x86_64Ubuntu 20.04-aarch64EulerOS 2.8-aarch64EulerOS 2.9-aarch64EulerOS 2.9-x86_64EulerOS 2.10-aarch64EulerOS 2.10-x86_64OpenEuler 20.03-x86_64OpenEuler 20.03-aarch64OpenEuler 22.03 LTS-x86_64OpenEuler 22.03 LTS-aarch64CentOS 7.6/8.2-x86_64CentOS 7.6/8.2-aarch64银河麒麟OS V10 SP1-aarch64中标麒麟OS 7.6-aarch64-准备软件包:软件安装前,请参考表2获取所需软件包和对应的数字签名文件。其中在软件数字签名验证方面,为了防止软件包在传递过程或存储期间被恶意篡改,下载软件包时需下载对应的数字签名文件用于完整性验证。在软件包下载之后,可以参考《OpenPGP签名验证指南》,对从网站下载的软件包进行PGP数字签名校验。如果校验失败,则不要直接使用该软件包,应先联系华为技术支持工程师解决。使用软件包安装/升级之前,也需要按上述过程先验证软件包的数字签名,确保软件包未被篡改过。表2 软件包软件包说明MindStudio_{version}_linux.tar.gzMindStudio软件包,含有GUI的集成开发环境。MindStudio安装包解压后包含以下文件:bin:MindStudio的执行目录及依赖的二进制文件build.txt:安装包构建信息classpath.txt:MindStudio运行时ClassPath加载顺序文件icons.db:MindStudio运行时SVG图标预编译数据库缓存文件Install-Linux-tar.txt:MindStudio安装说明jbr:64位系统的依赖库以及文件lib:Java依赖库license:所用的第三方依赖的许可证LICENSE.txt:Apache Licence说明文档NOTICE.txt:注意事项plugins:MindStudio所用到的基本插件及Java库product-info.json:MindStudio版本号以及执行文档路径redist:Java辅助注解tools:工具库Ascend-cann-toolkit_{version}_linux-{arch}.runAscend-cann-toolkit开发套件包,包含开发辅助工具和相关开发接口的开发套件包。如果环境上已安装Ascend-cann-toolkit开发套件包,则无需再次获取。准备安装用户:如果已安装Ascend-cann-toolkit开发套件包,请使用Ascend-cann-toolkit开发套件包的安装用户安装MindStudio。如果未安装Ascend-cann-toolkit开发套件包(可参考《CANN 软件安装指南》的“安装开发环境”章节),请执行如下操作:创建安装用户可使用root或非root用户进行安装。若使用root用户安装,可直接开始安装依赖。若使用已存在的非root用户安装,须保证该用户对$HOME目录具有读写以及可执行权限。若使用新的非root用户安装,则需要先创建该用户,请参见如下方法创建(请以root用户执行以下命令)。创建用户组和安装用户并设置该用户的$HOME目录。其中usergroup为用户组,username为用户名。groupadd usergroup    useradd -g usergroup -d /home/username -m username -s /bin/bash以HwHiAiUser组为例,可执行如下命令创建软件包安装用户并加入到HwHiAiUser组中。groupadd HwHiAiUseruseradd -g HwHiAiUser -d /home/username -m username -s /bin/bash执行以下命令设置非root用户密码。passwd username安装依赖:安装MindStudio和Ascend-cann-toolkit开发套件包前需要安装相关依赖。具体的依赖列表可参考官方文档。安装MindStudio:在完成了软件包至安装依赖,以及Ascend-cann-toolkit开发套件包的安装后,可以进行MindStudio的安装,其具体的安装步骤如下:使用MindStudio的安装用户上传软件包至待安装环境。解压MindStudio软件包:使用MindStudio的安装用户在软件包所在路径执行如下命令,解压MindStudio_{version}_linux.tar.gz软件包,tar -zxvf MindStudio_{version}_linux.tar.gz,解压后包的内容以及说明请参见表3。表3 参数说明参数说明Projects页签(工程管理)New Project创建新工程,创建后工程保存在“$HOME/AscendProjects”目录。Open打开已有工程。System Profiler进入System Profiling界面。Get from Version Control…用版本控制工具下载代码仓并打开。Customize页签(定制化个性设置)Color theme设置颜色主题。Accessibility设置辅助功能,包括设置IDE字体大小和针对红绿色视觉缺陷调整颜色。Keymap设置键盘映射,MindStudio会根据您的环境自动建议预定义的键盘映射,请确保它与您正在使用的操作系统匹配,或者手动选择与您习惯使用的另一个IDE或编辑器中的快捷方式匹配的操作系统。Import Settings…从自定义配置目录导入MindStudio个性化设置。All Settings…进入设置界面。Plugins页签(插件管理)Marketplace插件市场,可搜索并下载需要的插件。Installed查看已安装的插件。Learn MindStudio页签(MindStudio实用帮助)使用MindStudio的安装用户进入软件包解压后的MindStudio/bin目录并启动MindStudio。进入导入设置界面,如图8所示界面。图8如果没有报错信息且能正常进入欢迎界面,则表示MindStudio安装成功。图91.5.2安装流程——Windows将MindStudio安装在Windows服务器上时,Windows服务器为本地环境,Linux服务器为远端环境。MindStudio安装流程如图10所示。图10环境要求:本地环境要求:Windows 10 x86_64操作系统本地安装依赖:Python(版本要求:3.7~3.9),MinGW,Cmake,ACLlib(可选,Windows工控机场景开发Windows应用)配置远端环境:共部署形态远端昇腾AI设备:可参考《CANN 软件安装指南》部署好昇腾AI设备。分部署形态远端纯开发环境:可根据远端Linux服务器的具体系统版本,参见准备安装用户、安装依赖和配置编译环境章节配置MindStudio使用环境。请参考《CANN 软件安装指南》安装Ascend-cann-toolkit开发套件包。准备软件包:软件安装前,请参考表4获取所需软件包和对应的数字签名文件。表4 软件包软件包说明MindStudio_{version}_win.zipMindStudio免安装压缩包,含有GUI的集成开发环境。MindStudio_{version}_win.exeMindStudio安装包,含有GUI的集成开发环境。安装依赖:根据官方流程安装Python依赖,安装MinGW依赖,安装ACLlib包,安装Cmake。安装MindStudio:在完成上述步骤,即可进行MindStudio的安装。双击MindStudio_{version}_win.exe安装包,开始安装MindStudio。进入MindStudio Setup界面,单击“Next”,如图11所示。图11选择MindStudio的安装路径后,单击“Next”,如图12所示。图12用户根据需要勾选安装选项后,单击“Next”,如图13所示。图13选择或创建MindStudio安装路径下的启动菜单文件夹,单击“Install”,如图14所示。图14开始安装MindStudio,完成后单击“Next”,如图15所示。图15完成MindStudio安装配置,单击“Finish”,如图16所示。图16进入MindStudio安装目录的bin文件夹,双击MindStudio应用程序启动MindStudio,导入设置界面,如图17所示界面。图17如果没有报错信息且能正常进入欢迎界面,则表示MindStudio安装成功,如图18所示。图18二、超参数优化基本介绍在机器学习、深度学习中,有两类参数,一类需要从数据中学习和估计得到,称为模型参数(Parameter);另一类需要人为设定,称为超参数(Hyperparameter),例如学习率、正则化系数等。超参数优化,是指用自动化的算法来优化超参数,从而提升模型的精度、性能等指标。使用HPO能力,可以快速高效地在超参数空间中测试选择最佳的超参数组合,节省大量人力和时间。当前MindStudio提供的HPO能力支持Random、ASHA、BOHB、BOSS、PBT等HPO算法,适用于常见的深度神经网络的超参数优化,包括单目标优化和随机帕累托的多目标超参选择。三、超参数优化前期准备工作AutoML(Auto Machine Learning)包括模型自动生成和调优和训练工程超参数自动调优。昇腾模型开发用户可以通过模型自动性能调优功能找到性能更好的模型。AI初学者可以通过AutoML工具结合数据集,自动生成满足需求的模型,对训练超参进行自动调优。训练工程超参数优化(Hyperparameter Optimization,简称HPO),支持在昇腾910 AI处理器上训练,覆盖MindSpore,PyTorch,TensorFlow框架,用自动化的算法来优化超参数,从而提升模型的精度、性能等指标。模型自动生成和调优以昇腾910 AI处理器的搜索训练,昇腾310 AI处理器和昇腾310P AI处理器的推理验证为前提,覆盖MindSpore,PyTorch框架,面向分类、检测分割场景实现模型自动生成和调优。这个场景主要功能是基于数据集自动生成模型和基于预训练模型进行微调后自动生成模型。业务流程如图19所示:图 193.1环境准备使用AutoML工具前,可参考《CANN 软件安装指南》手册完成环境搭建,其他环境要求请参见训练服务器和推理服务器。使用非root用户运行任务时,需要以root用户将运行用户加入驱动运行用户组(例如:HwHiAiUser)中,保证普通用户对run包的lib库有读权限。集群配置中的训练和推理服务器需安装Vega,训练服务器安装noah_vega,推理服务器安装evaluate_service,具体可参考Vega官网自行安装。noah_vega提供安全通信特性,相关配置请参照安全配置说明,用户在AutoML安装完成后需要参照该说明正确配置vega之后才能以通信安全的方式运行训练任务。如果使用1.8.0及以上版本的安全特性noah_vega包,启动任务时需要在命令末端增加“-s”参数。用户根据需要自行安装以下AI框架包:MindSpore:请参考MindSpore官网安装MindSpore框架。PyTorch:请参考《CANN软件安装指南》的“安装PyTorch”章节编译安装PyTorch1.5.0框架。安装Torchvision依赖,可参考以下方法进行安装:在x86_64架构下安装Torchvision包:       pip3 install --user torchvision==0.6.0在aarch64架构下先从azureology/torchvision下载源码,执行以下命令安装0.6.0版本的Torchvision包:       python setup.py install若Pytorch下需要统计模型的参数量信息,则需要安装依赖thop:       pip3 install --user thopTensorFlow:参考《CANN 软件安装指南》安装tfplugin框架插件包和TensorFlow。请注意CANN版本与MindSpore、PyTorch和TensorFlow的版本配套关系。3.1.1训练服务器所有训练服务器的Python版本需要保持一致。已安装sshd。在各个训练服务器上的~/.bashrc文件中配置如下环境变量:source $HOME/Ascend/ascend-toolkit/set_env.sh   #请根据实际情况替换CANN软件包安装路径source {$HOME/Ascend/tfplugin/set_env.sh       #安装tfplugin时需要配置,请根据实际情况替换CANN软件包安装路径#以下为单卡训练时的配置,请根据实际环境和需求配置export DEVICE_ID=0  #单卡训练使用的device_id#以下6项为多卡训练时的配置,请根据实际环境和需求改动export RANK_ID=0   #指定调用卡的逻辑IDexport RANK_SIZE=8    #指定调用卡的数量export RANK_TABLE_FILE=多卡环境组网信息json文件所在路径  #从多卡环境组网信息json文件中选择要使用的device_idexport NPU_VISIBLE_DEVICES=0,1,2,3,4,5,6,7   #执行多卡任务时需要使用的device_idexport DEVICE_ID=0    #执行多卡训练任务时单卡阶段指定使用的device_idexport TF_CPP_MIN_LOG_LEVEL=3  #该项可控制TF框架本身日志级别的打印,0-DEBUG,1-INFO,2-WARNING,3-ERROR​​说明如果训练服务器中没有多卡环境组网信息json文件,请参见配置分布式环境变量在训练服务器上生成多卡环境组网信息json文件。当运行任务的用户为普通用户时,需要保证普通用户对该文件有可读权限。3.1.2推理服务器在推理服务器上的~/.bashrc文件中配置如下环境变量:​​source $HOME/Ascend/ascend-toolkit/set_env.sh   #请根据实际情况替换CANN软件包安装路径export install_path=$HOME/Ascend/ascend-toolkit/latest    #请根据实际情况替换CANN软件包安装路径export DDK_PATH=${install_path}  #评估服务编译时使用export NPU_HOST_LIB=${install_path}/{arch-os}/devlib   #评估服务编译时使用参见Link配置推理工具,并启动推理服务。说明推理工具中,-t参数为指定推理服务器的芯片型号,默认值Ascend310。若不使用该参数,默认在昇腾310 AI处理器上启动推理服务,参数取值如下。昇腾310 AI处理器参数值:Ascend310(默认)昇腾310P AI处理器参数值:Ascend310P*,例如Ascend310P1其中,*根据芯片性能提升等级、芯片核数使用等级等因素会有不同的取值。请参考《ToolBox用户指南》的“Ascend-DMI工具使用>设备实时状态查询”章节查询芯片详细信息。3.1.3 Vega的安全配置要求:Python3.9及以上dask和distributed版本为2022.2.0Vega的安全配置,包括如下步骤:安装OpenSSL首先要安装OpenSSL 1.1.1,从源码编译安装,或者直接安装编译后的发行包。然后安装OpenSSL的python接口,如下:pip3 install --user pyOpenSSL==19.0.0生成CA根证书执行如下命令生成CA证书:openssl genrsa -out ca.key 409openssl req -new -x509 -key ca.key -out ca.crt -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>"注意:以上<country>、<province>、<city>、<organization>、<group>、<cn>根据实际情况填写,去掉符号<>,本文后面的配置也是同样的。并且CA的配置需要和其他的不同。RSA密钥长度建议在3072位及以上,如本例中使用4096长度。缺省证书有效期为30天,可使用-days参数调整有效期,如-days 365,设置有效期为365天。生成评估服务用的证书评估服务支持加密证书和普通证书:若使用加密证书,需要安装华为公司的KMC安全组件,参考生成加密证书章节若使用普通证书,参考生成普通证书章节生成加密证书执行以下命令,获得证书配置文件:查询openssl配置文件所在的路径:openssl version -d在输出信息中,找到类似于OPENSSLDIR: "/etc/pki/tls",其中"/etc/pki/tls"即为配置文件所在目录。拷贝配置文件到当前目录:cp /etc/pki/tls/openssl.cnf .在配置文件中openssl.cnf中,增加如下配置项:req_extensions = v3_req # The extensions to add to a certificate request执行如下脚本,生成评估服务器所使用的证书的加密私钥,执行该命令时,会提示输入加密密码,密码的强度要求如下:密码长度大于等于8位必须包含至少1位大写字母必须包含至少1位小写字母必须包含至少1位数字必须包含至少1位特殊字符openssl genrsa -aes-256-ofb -out server.key 4096然后再执行如下命令,生成证书,并删除临时文件:openssl req -new -key server.key -out server.csr -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>" -config ./openssl.cnf -extensions v3_reqopenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -extfile ./openssl.cnf -extensions v3_reqrm server.csr执行如下脚本生成评估服务客户端所使用的证书的加密私钥,执行该命令时,会提示输入加密密码,密码的强度要求如服务器端私钥,且和服务器端私钥密码不同,请记录好该密码,后继还需使用:openssl genrsa -aes-256-ofb -out client.key 4096然后再执行如下命令,生成证书,并删除临时文件:openssl req -new -key client.key -out client.csr -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>" -config ./openssl.cnf -extensions v3_reqopenssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -extfile ./openssl.cnf -extensions v3_reqrm client.csr生成普通证书执行如下脚本,生成评估服务器端和客户端使用的证书的私钥和证书:openssl genrsa -out server.key 4096openssl req -new -key server.key -out server.csr -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>" -config ./openssl.cnf -extensions v3_reqopenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -extfile ./openssl.cnf -extensions v3_reqrm server.csropenssl genrsa -out client.key 4096openssl req -new -key client.key -out client.csr -extensions v3_ca  -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>" -config ./openssl.cnf -extensions v3_reqopenssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -extfile ./openssl.cnf -extensions v3_reqrm client.csr生成Dask用的证书执行如下脚本,生成Dask服务器端和客户端使用的证书的私钥和证书:openssl genrsa -out server_dask.key 4096openssl req -new -key server_dask.key -out server_dask.csr -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>" -config ./openssl.cnf -extensions v3_reqopenssl x509 -req -in server_dask.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server_dask.crt -extfile ./openssl.cnf -extensions v3_reqrm server_dask.csropenssl genrsa -out client_dask.key 4096openssl req -new -key client_dask.key -out client_dask.csr -subj "/C=<country>/ST=<province>/L=<city>/O=<organization>/OU=<group>/CN=<cn>" -config ./openssl.cnf -extensions v3_reqopenssl x509 -req -in client_dask.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client_dask.crt -extfile ./openssl.cnf -extensions v3_reqrm client_dask.csr删除CA私钥:rm ca.key加密私钥口令若加密服务器使用加密证书,则需要执行本章节余下步骤,若使用普通证书,则跳过该章节。加密生成评估服务的服务器端和客户端的私钥口令,需要安装华为公司KMC安全组件,并将该安全组件动态链接库所在的目录添加到LD_LIBRARY_PATH中。export LD_LIBRARY_PATH=<Directory where the KMC dynamic link library is located>:$LD_LIBRARY_PATH接下来安装Vega,使用Vega的密码加密工具调用KMC安全组件对密码加密。 在执行如下命令时,请输入在生成私钥时输入的口令,该命令会生成加密后的口令,请注意保存,在配置文件中会使用到这两个加密后的口令:vega-encrypt_key --cert=server.crt --key=server.key --key_component_1=ksmaster_server.dat --key_component_2=ksstandby_server.datvega-encrypt_key --cert=client.crt --key=client.key --key_component_1=ksmaster_client.dat --key_component_2=ksstandby_client.dat配置安全相关的配置文件请在当前用户的主目录下创建.vega目录,并将如上生成的秘钥、证书、加密材料等,拷贝到该目录下,并改变权限:mkdir ~/.vegamv * ~/.vega/chmod 600 ~/.vega/*说明如上的秘钥、证书、加密材料也可以放到其他目录位置,注意访问权限要设置为600,并在后继的配置文件中同步修改该文件的位置,需要使用绝对路径。在训练集群上,需要保留ca.crt、client.key、client.crt、ksmaster_client.dat、ksstandby_client.dat、server_dask.key、server_dask.crt、client_dask.key、client_dask.crt,并删除其他文件。评估服务上,需要保留ca.crt、server.key、server.crt、ksmaster_server.dat、ksstandby_server.dat,并删除其他文件。以下为默认配置的加密套件:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES128-GCM-SHA256:DHE-DSS-AES256-GCM-SHA384:DHE-RSA-AES128-CCM:DHE-RSA-AES256-CCM如需缩小范围,可在client.ini与vega.ini中加入配置:ciphers=ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES256-CCM在~/.vega目录下创建server.ini和client.ini。在训练集群中,需要配置~/.vega/server.ini和~/.vega/client.ini:server.ini:[security]  # 以下文件路径需要修改为绝对路径    ca_cert=<~/.vega/ca.crt>    server_cert_dask=<~/.vega/server_dask.crt>    server_secret_key_dask=<~/.vega/server_dask.key>    client_cert_dask=<~/.vega/client_dask.crt>    client_secret_key_dask=<~/.vega/client_dask.key>client.ini:[security]  # 以下文件路径需要修改为绝对路径    ca_cert=<~/.vega/ca.crt>    client_cert=<~/.vega/client.crt>    client_secret_key=<~/.vega/client.key>    encrypted_password=<加密后的client端的口令>  # 如果使用普通证书, 此项配置为空    key_component_1=<~/.vega/ksmaster_client.dat>  # 如果使用普通证书, 此项配置为空    key_component_2=<~/.vega/ksstandby_client.dat>  # 如果使用普通证书, 此项配置为空在评估服务器上,需要配置~/.vega/vega.ini:[security]  # 以下文件路径需要修改为绝对路径    ca_cert=<~/.vega/ca.crt>    server_cert=<~/.vega/server.crt>    server_secret_key=<~/.vega/server.key>    encrypted_password=<加密后的server端的口令>  # 如果使用普通证书, 此项配置为空    key_component_1=<~/.vega/ksmaster_server.dat>  # 如果使用普通证书, 此项配置为空    key_component_2=<~/.vega/ksstandby_server.dat>  # 如果使用普通证书, 此项配置为空配置评估服务守护服务使用systemctl管理评估服务器进程,当进程出现异常时自动重启,保证评估服务器连续性。首先创建一个启动评估服务的脚本run_evaluate_service.sh,内容如下,注意替换<ip>、<path>为真实IP和目录:vega-evaluate_service-service -i <ip> -w <path>然后再创建一个守护服务的文件evaluate-service.service,脚本内容如下,注意替换为真实的脚本位置:[Unit]    Description=Vega Evaluate Service Daemon[Service]    Type=forking    ExecStart=/<your_run_script_path>/run.sh    Restart=always    RestartSec=60[Install]    WantedBy=multi-user.target然后将evaluate-service.service拷贝到目录/usr/lib/systemd/system中,并启动该服务:sudo cp evaluate-service.service /usr/lib/systemd/system/sudo systemctl daemon-reloadsudo systemctl start evaluate-service配置HCCL白名单请参考Ascend提供的配置指导。注意事项模型风险对于AI框架来说,模型就是程序,模型可能会读写文件、发送网络数据。例如Tensorflow提供了本地操作API tf.read_file, tf.write_file,返回值是一个operation,可以被Tensorflow直接执行。 因此对于未知来源的模型,请谨慎使用,使用前应该排查该模型是否存在恶意操作,消除安全隐患。运行脚本风险Vega提供的script_runner功能可以调用外部脚本进行超参优化,请确认脚本来源,确保不存在恶意操作,谨慎运行未知来源脚本。KMC组件不支持多个用户同时使用若使用KMC组件对私钥密码加密,需要注意KMC组件不支持不同的用户同时使用KMC组件。若需要切换用户,需要在root用户下,使用如下命令查询当前信号量:ipcs然后删除查询到的当前所有的信号量:ipcrm -S '<信号量>'删除开源软件中不适用的私钥文件Vega安装时,会自动安装Vega所依赖的开源软件,请参考列表。部分开源软件的安装包中可能会带有测试用的私钥文件,Vega不会使用这些私钥文件,删除这些私钥文件不会影响Vega的正常运行。可执行如下命令所有的私钥文件:find ~/.local/ -name *.pem在以上命令列出的所有文件中,找到Vega所依赖的开源软件的私钥文件。一般私钥文件的名称中会带有单词key,打开这些文件,可以看到以-----BEGIN PRIVATE KEY-----开头,以-----END PRIVATE KEY-----结尾,这些文件都可以删除。Horovod和TensorFlow在安全模式下,Vega不支持Horovod数据并行,也不支持TensorFlow框架,Vega在运行前检查若是Horovod数据并行程序,或者TensorFlow框架,会自动退出。限定Distributed仅使用tls1.3协议进行通信若需要限定开源软件Distributed的组件间的通信仅使用tls1.3协议,需要配置~/.config/dask/distributed.yamldistributed.yaml:distributed: comm: tls: min-version: 1.3请参考Dask的配置指导。3.2集群管理创建新集群在菜单栏选择“Ascend > AutoML > Cluster Manager”。进入“Cluster Manager”界面。单击“+New Cluster”。进入“Add Cluster”界面,如图20所示。界面参数说明如表5所示。单击“OK”,完成新集群创建。图 20表5参数说明Cluster Name集群名称,在所有集群里具有唯一性。只支持英文字母、数字或者下划线,以英文字母开头,且长度不超过32个字符。例如:Cluster_01。Evaluation Service评估服务,通过下拉框选择已通过SSH配置好的远端环境。Evaluation Service Port评估服务器端口,仅支持输入1~65535之间的数字,默认值为8888。Training Service训练服务器,通过下拉框选择已通过SSH配置好的远端训练环境。Primary训练服务集群主节点,通过下拉框选择已通过SSH配置好的远端训练环境。Add添加训练服务。单击选择此项后,“Secondary”、“Data Sharing Service”和“NFS Server Path”参数才会在界面体现。Secondary训练服务集群从节点,通过下拉框选择已通过SSH配置好的远端训练环境。单击删除按钮可以删除从节点。Data Sharing Service数据共享服务器,通过下拉框选择已通过SSH配置好的远端环境。NFS Server PathNFS服务器路径。例如:/home/test/nfs_cache。Workspace所有训练服务器的工作路径。例如:/home/test/nfs_folder。删除集群在菜单栏选择“Ascend > AutoML > Cluster Manager”。进入“Cluster Manager”界面。单击需要删除的集群后方的,如图21所示。图 21四、模型开发使用HPO界面工具调优流程4.1 前提条件已安装1.1.3版本的pandas依赖包,执行以下命令以安装:pip install pandas==1.1.3 --user4.2 修改模型训练脚本修改用户模型训练脚本,添加dump_objective函数,并在此脚本中调用此函数,保存待优化指标。代码段截图如图22所示。图22用户可参考{CANN包安装路径}/ascend-toolkit/latest/tools/ascend_automl/algorithms /script_hpo/hpo_ui_sample.py进行操作,此样例使用以下语句保存平均耗时和精度指标。如图23所示。图23其中dump_objective函数的入参objective_key要与步骤4.3中General Config页签中填写的Objectives优化目标一致,objective_value为用户脚本中优化目标值。HPO功能在用户指定的搜索空间内,进行超参数采样,并对每一组超参数调起一个用户模型的训练任务。通过以上修改,用户脚本可在模型训练任务完成后,将超参数对应的精度、性能等信息传递给HPO主进程,以便后续选出最优超参。4.3 配置General Config在菜单栏选择“Ascend > AutoML > HPO”,进入General Config页签,如图24所示。详细参数说明如表5所示。图24表 5 参数说明参数说明Compute Nodes Cluster计算集群选择。Parallel Search多卡或者单卡配置按钮,按钮开状态为多卡,关闭为单卡。Total Epochs搜索epoch配额。在HPO过程中,每个训练任务会消耗一定数量的epochs,所有训练任务的epoch总和小于此Total Epochs项。用户可参考Total Epochs*time_per_epoch / num_of_device来估算时间。Task Work Path当前运行用户目录下的工作路径,HPO过程的输出路径。需用户选定或者输入存在且有读权限路径,且文件路径中不包含非法字符。Search Alogorithom Type搜索算法,目前仅支持AshaHpo算法。Objectives优化目标,单击右侧“+”图标可添加需要优化的目标。在文本框中输入优化目标,例如平均精度、训练迭代耗时等。Max:表示期望优化目标最大化。Min:表示期望优化目标最小化。单击右侧删除图标可以删除对应的优化目标参数项。4.4 配置Train Config单击“Next”,进入Train Config页签,如图25所示。详细参数说明如表6所示。图25表 6 参数说明参数说明Train Script4.2中的用户的模型训练脚本,需为存在的可读Python脚本,不包含非法字符。在HPO调优过程中会调用该脚本。Env Variables环境变量。单击右侧按钮添加环境变量。当General Config页签开启Parallel Search参数时,需配置以下环境变量:NPU_VISIBLE_DEVICES:可用的device。RANK_SIZE:device列表长度。RANK_TABLE_FILE:组网信息文件(若在环境准备已配置该环境变量,则不用在此处进行配置)。用户需要先配置组网信息文件,具体可参考cid:link_4。BATCH_TASK_INDEX:任务编号,一般配置为0。当General Config页签关闭Parallel Search参数时,需配置DEVICE_ID实现在指定卡上运行。Search Space搜索空间,单击右侧的“+”按钮可以添加以下搜索内容。Key:搜索关键字,需要优化的用户脚本输入参数名,这里需要优化的是“lr”和“momentum”参数,因此填“--lr”和“--momentum”,必填项。Type:搜索类型。支持CATEGORY、BOOL、INT、INT_EXP、FLOAT、FLOAT_EXP,必填项。Range:当前Key的搜索范围。需手动输入,内容用英文逗号分隔,必填项。单击删除图标可以删除对应的搜索空间。说明:搜索类型可选以下六种:CATEGORY 分组类型,用户在Range中给出可选的取值,可以为任意的数据类型,如:[18, 34, 50, 101],[0.3, 0.7, 0.9],['Adam', 'SGD'],[[1, 0, 1],[0, 0, 1]]。BOOL 布尔类型,对应Range取值为[True, False]。INT 整数类型,对应Range设置最小值和最大值,均匀采样,如:[10, 100]。INT_EXP 整数类型,对应Range设置最小值和最大值,指数采样,如:[1, 100000]。FLOAT 浮点数类型,对应Range设置最小值和最大值,均匀采样,如:[0.1, 0.9]。FLOAT_EXP 浮点数类型,对应Range设置最小值和最大值,指数采样,如:[0.1, 100000.0]。Other Options其他参数项,单击右侧的“+”按钮可以添加不需要优化的参数。Key:不需要优化的用户脚本入参名,可选项。示例中不需要优化的有“--weight_decay”参数,因此填入“--weight_decay”Value:用户指定的入参值,选填项。单击删除图标可以删除对应的其他参数项。Epoch Name在HPO的不同阶段,对网络训练不同的epoch,这一epoch值由HPO进程给出,不需用户指定。因此,用户需将脚本入参中,代表epoch的参数名称,填入此栏,以便HPO过程中将HPO算法给出的epoch值传入用户脚本。例如:4.2中示例,此项应填“--epochs ”说明:如果待优化的训练脚本不能传入epoch参数,需要用户将训练脚本修改为能传入epoch参数的形式。Device Name在HPO过程中,启动多个训练任务,使用不同的超参数进行网络训练。不同的训练任务使用不同的AI芯片,AI芯片ID由HPO进程给出,不需用户指定。因此,用户需将脚本入参中,代表AI芯片ID的参数名称,填入此栏,以便HPO过程中将这一参数自动传入用户脚本。例如:1中示例,此项应填“--device”说明:如果待优化的训练脚本不能传入该device参数,需要用户将训练脚本修改为能传入device参数的形式。传入的device值的格式为“npu:x”,其中x可能为0,1,2,3,4,5,6,7。4.5 预览配置结果单击“Next”,进入Preview页签,如图26、27所示。图26图27基于前面的两个配置界面,可以生成配置文件config.yml,接口文件train.py,启动文件run.sh,并发送到远端服务器,调起HPO任务。此页面提供命令行命令的预览。单击“Finish”之后运行HPO任务。如图28、29、30所示说明可使用vega-process查询正在运行的任务,使用vega-kill -p PID或vega-kill -t task_id结束正在运行的vega任务。图28图29图304.6 过程和结果获取任务开始后,HPO窗口关闭,Output窗口中将提示可到远端查看HPO任务运行过程和结果,如图31~35所示。图31图32图33图34图35在Output窗口所示路径下会生成tasks文件夹,tasks文件夹下有名为{task_id}的文件夹,此文件下有文件夹logs、output和workers。├── tasks│   ├── {task_id}│   │   ├──logs│   │   │   ├──hpo_worker_{worker_id}。log // 第worker_id个worker上进行hpo的日志文件│   │   │   ├──pipeline.log                // 整个hpo任务日志文件│   │   ├──output│   │   │   ├──config.yml                       // 配置文件│   │   │   ├──report.json                      // hpo任务的报告文件│   │   │   ├──hpo│   │   │   │   ├──hps_{worker_id}.json           //搜索出的最佳超参值│   │   │   │   ├──performance_{worker_id}.json   //搜索出的最佳优化指标值│   │   │   │   ├──output.csv                     //优化指标值汇总文件│   │   ├──workers│   │   │   ├──hpo│   │   │   │   ├──{worker_id}│   │   │   │   │   ├──hps_{worker_id}.json           //超参值│   │   │   │   │   ├──performance_{worker_id}.json   //优化目标值五、经验总结利用HPO界面调优会在所指定的路径下生成相应的执行文件,直接在后台执行run.sh文件会报错。图36解决办法:可更改生成的config.yml文件中的task_id为非纯数字的名称,然后利用vega config.yml -d NPU命令在后台执行HPO调优。图37六、关于MindStudio更多的内容如果需要了解关于MindStudio更多的信息,请查阅昇腾社区中MindStudio的[用户手册](https://www.hiascend.com/document/detail/zh/mindstudio/50RC3/progressiveknowledge/index.html),里面模型训练、脚本转换、模型开发、算子开发、精度对比、AI Core Error分析工具、AutoML工具(Beta)、Benchmark工具、专家系统工具等各种使用安装操作的详细介绍。如果在使用MindStudio过程中遇到任何问题,也可以在昇腾社区中的[昇腾论坛](https://www.huaweicloud.com)进行提问,会有华为内部技术人员对其进行解答,如下图。图38
  • [MindX SDK] Overlap-CRNN重叠文本识别设计案例
    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%)。
  • [经验分享] 使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用(下)
    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/
  • [经验分享] 使用MindStudio开发基于MindX SDK的X射线图像缺陷检测应用(上)
    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" } } }
  • [技术干货] Fast-SCNN(语义分割/Pytorch)
    语义分割,也称为全像素语义分割(full-pixel semantic segmentation),是一种典型的计算机视觉问题,其中图像中的每个像素根据其所属的感兴趣对象被分配类别ID。 早期的计算机视觉问题只发现边缘(线条和曲线)或渐变等元素,但它们从未完全按照人类感知的方式提供像素级别的图像理解。语义分割将属于同一目标的图像部分聚集在一起来解决这个问题,从而扩展了其应用领域。Fast-SCNN是一个实时的语义分割模型。其基于现有的two-branch方法(BiSeNet),引入了一个learning to downsample模块,在cityscapes上得到68.0%的miou本案例是Fast-SCNN论文复现的体验案例,模型基于Fast-SCNN: Fast Semantic Segmentation Network中提出的模型结构实现,会载入预训练模型,训练数据集为Cityscape.具体算法介绍:cid:link_0注意事项:本案例使用框架**:** PyTorch1.4.0运行代码方法**:** 点击本页面顶部菜单栏的三角形运行按钮或按Ctrl+Enter键 运行每个方块中的代码JupyterLab的详细用法**:** 请参考《ModelAtrs JupyterLab使用指导》碰到问题的解决办法**:** 请参考《ModelAtrs JupyterLab常见问题解决办法》1.数据和代码下载运行下面代码,进行数据和代码的下载和解压缩本案例使用Cityscape子集,数据位于fast-scnn/datasets中import os# 数据代码下载!wget https://obs-aigallery-zc.obs.cn-north-4.myhuaweicloud.com/algorithm/fast-scnn.zip# 解压缩os.system('unzip fast-scnn.zip -d ./')--2021-06-16 15:28:21-- https://obs-aigallery-zc.obs.cn-north-4.myhuaweicloud.com/algorithm/fast-scnn.zipResolving proxy-notebook.modelarts.com (proxy-notebook.modelarts.com)... 192.168.6.62Connecting to proxy-notebook.modelarts.com (proxy-notebook.modelarts.com)|192.168.6.62|:8083... connected.Proxy request sent, awaiting response... 200 OKLength: 2215542147 (2.1G) [application/zip]Saving to: ‘fast-scnn.zip’fast-scnn.zip 100%[===================>] 2.06G 356MB/s in 6.2s 2021-06-16 15:28:27 (343 MB/s) - ‘fast-scnn.zip’ saved [2215542147/2215542147]02.模型训练2.1依赖库安装及加载import timeimport copyimport datetimeimport sysimport osos.system('pip install thop')os.system('pip install tabulate')os.system('pip install -U PyYAML')root_path = './fast-scnn/'os.chdir(root_path)import loggingimport torchimport torch.nn as nnimport torch.utils.data as dataimport torch.nn.functional as Ffrom torchvision import transformsfrom tools.train import *from segmentron.data.dataloader import get_segmentation_datasetfrom segmentron.models.model_zoo import get_segmentation_modelfrom segmentron.solver.loss import get_segmentation_lossfrom segmentron.solver.optimizer import get_optimizerfrom segmentron.solver.lr_scheduler import get_schedulerfrom segmentron.utils.distributed import *from segmentron.utils.score import SegmentationMetricfrom segmentron.utils.filesystem import save_checkpointfrom segmentron.utils.options import parse_argsfrom segmentron.utils.default_setup import default_setupfrom segmentron.utils.visualize import show_flops_paramsfrom segmentron.utils.visualize import get_color_palletefrom segmentron.config import cfgimport argparseimport matplotlib.pyplot as pltfrom PIL import Image/home/ma-user/anaconda3/envs/Pytorch-1.4.0/lib/python3.6/site-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.26.3) or chardet (3.0.4) doesn't match a supported version! RequestsDependencyWarning)INFO:root:Using MoXing-v2.0.0.rc0-19e4d3abINFO:root:Using OBS-Python-SDK-3.20.9.12.2训练参数设置详细参数设置可以查看 fast-scnn/configs/cityscapes_fast_scnn.yaml 和 fast-scnn/segmentron/config/settings.pyparser = argparse.ArgumentParser(description='Run')parser.add_argument('--num_nodes', type=int, default=1)parser.add_argument('--cuda_visiable', type=str, default='0')parser.add_argument('--config_file', default='./configs/cityscapes_fast_scnn.yaml', help='config file path')parser.add_argument('--training_dataset', default='/home/ma-user/work/fast-scnn/datasets/', help='Training dataset directory')# cuda settingparser.add_argument('--no-cuda', action='store_true', default=False, help='disables CUDA training')parser.add_argument('--local_rank', type=int, default=0)# pre trainedparser.add_argument('--resume', type=str, default='./pre-trained_weights/best_model.pth', help='put the path to resuming file if needed')parser.add_argument('--log-iter', type=int, default=10, help='print log every log-iter') # for evaluationparser.add_argument('--val-epoch', type=int, default=1, help='run validation every val-epoch')parser.add_argument('--skip-val', action='store_true', default=False, help='skip validation during training') args, unknown = parser.parse_known_args()# get configcfg.update_from_file(args.config_file)cfg.PHASE = 'train'cfg.ROOT_PATH = root_pathcfg.check_and_freeze()# setup python train environment, logger, seed..default_setup(args)2.3开始训练trainer = Trainer(args)trainer.train()3.模型测试3.1设置测试图像路径可以上传你想要测试的图像,并修改路径args.input_img = './tools/test.png'3.2加载模型¶# image transformtransform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(cfg.DATASET.MEAN, cfg.DATASET.STD),])model = get_segmentation_model().to(args.device)model.eval()print('模型加载成功')INFO:root:load pretrained model from ./trained_model/model/best_model.pthINFO:root:Shape unmatched weights: []INFO:root:模型加载成功3.3开始测试if os.path.isdir(args.input_img): img_paths = [os.path.join(args.input_img, x) for x in os.listdir(args.input_img)]else: img_paths = [args.input_img]for img_path in img_paths: image = Image.open(img_path).convert('RGB') images = transform(image).unsqueeze(0).to(args.device) with torch.no_grad(): output = model(images) pred = torch.argmax(output[0], 1).squeeze(0).cpu().data.numpy() mask = get_color_pallete(pred).convert('RGB') plt.figure(figsize=(20,20)) # 显示缩放比例 plt.subplot(1,2,1) plt.imshow(image) plt.subplot(1,2,2) plt.imshow(mask) plt.show()
  • [技术干货] Transformer-机器翻译
    Transformer机器翻译,是指使用计算机将一种自然语言转换为另一种自然语言的过程。这里,自然语言是指日常使用的人类语言(如中文、英语),区别于人工为特定目的创造的语言(如计算机编程语言)。 机器翻译是自然语言处理(NLP)的一个研究分支,是人工智能的终极目标之一,具有重要的科学研究价值。 2017年,谷歌在论文《Attention Is All You Need》中提出了Transformer模型。这种基于自注意力机制的模型能够很好地解决序列模型的问题,比如机器翻译。Transformer应用在机器翻译任务中,不仅提高了翻译的效果,由于其高度并行化的设计,还大幅提高了训练的效率。本案例是《Attention Is All You Need》论文复现的体验案例,数据集为WMT2014 英语-德语数据集 具体算法介绍:cid:link_0注意事项:1.本案例使用框架:PyTorch1.4.02.本案例使用硬件:GPU: 1*NVIDIA-V100NV32(32GB) | CPU: 8 核 64GB3.运行代码方法: 点击本页面顶部菜单栏的三角形运行按钮或按Ctrl+Enter键 运行每个方块中的代码4.JupyterLab的详细用法: 请参考《ModelAtrs JupyterLab使用指导》5.碰到问题的解决办法**:** 请参考《ModelAtrs JupyterLab常见问题解决办法》1.下载代码和数据import moxing as mox mox.file.copy_parallel('obs://obs-aigallery-zc/algorithm/Transformer_translate','./Transformer_translate')INFO:root:Using MoXing-v1.17.3-43fbf97f INFO:root:Using OBS-Python-SDK-3.20.72.模型训练2.1依赖库的加载与安装# -*- coding: utf-8 -*- from __future__ import print_function import os root_path = './Transformer_translate' os.chdir(root_path) os.system('pip install --upgrade numpy') os.system('pip install --ignore-installed PyYAML==5.4.1') os.system('pip install fairseq') os.system('pip install sacremoses') os.system('pip install nltk') os.system('pip install subword-nmt') os.system('pip install tqdm')02.2参数设置import tqdm import argparse parser = argparse.ArgumentParser(description='Training') parser.add_argument('--resume_net', default='no', type=str, help='resume net for retraining') parser.add_argument('--training_dataset', default='./data/data-bin', help='Training dataset directory') parser.add_argument('--save_folder', default='./outputs', help='Location to save checkpoint models') parser.add_argument('--max_tokens', default=4096, type=int) parser.add_argument('--optimizer', default='adam', type=str) parser.add_argument('--weight_decay', default=0.0, type=float) parser.add_argument('--lr', default=0.0007, type=float) parser.add_argument('--clip_norm', default=0, type=float) parser.add_argument('--load_weights', type=str, default='./model/model.pth', metavar='PATH') parser.add_argument('--eval', default='False', type=str, choices=['True', 'False']) parser.add_argument('--restore', default='True', type=str, choices=['True', 'False']) # For evaluation parser.add_argument('--eval_result_path', default='./outputs/eval') args, unknown = parser.parse_known_args() import shutil def get_files_tree(src="src_path"): req_files = [] for r, d, files in os.walk(src): for file in files: src_file = os.path.join(r, file) src_file = src_file.replace('\\', '/') if src_file.endswith('.db'): continue req_files.append(src_file) return req_files def copy_tree_force(src_path="",dest_path=""): """ make sure that all the paths has correct slash characters. """ for cf in get_files_tree(src=src_path): df= cf.replace(src_path, dest_path) if not os.path.exists(os.path.dirname(df)): os.makedirs(os.path.dirname(df)) shutil.copy2(cf, df) train_input_dir = args.training_dataset if not os.path.exists(train_input_dir): os.makedirs(train_input_dir) else: print(train_input_dir, 'already exists') if not os.path.exists(args.eval_result_path): os.makedirs(args.eval_result_path) model_path=args.load_weights # Train command=''' CUDA_VISIBLE_DEVICES=0 fairseq-train '''+ train_input_dir +''' \ --restore-file '''+ model_path +''' \ --save-dir '''+ args.save_folder +''' \ --optimizer '''+ args.optimizer +''' \ --adam-betas '(0.9, 0.98)' \ --clip-norm '''+ str(args.clip_norm) +''' \ --lr-scheduler inverse_sqrt \ --warmup-init-lr 1e-07 \ --warmup-updates 4000 \ --lr '''+ str(args.lr) +''' \ --min-lr 1e-09 \ --criterion label_smoothed_cross_entropy \ --label-smoothing 0.1 \ --weight-decay '''+ str(args.weight_decay) +''' \ --max-tokens '''+ str(args.max_tokens) +''' \ --save-interval-updates 50 \ --max-update 50 \ --keep-interval-updates 20 \ --decoder-attention-heads 16 \ --decoder-embed-dim 1024 \ --decoder-ffn-embed-dim 4096 \ --decoder-layerdrop 0 \ --decoder-layers 6 \ --decoder-output-dim 1024 \ --encoder-attention-heads 16 \ --encoder-embed-dim 1024 \ --encoder-ffn-embed-dim 4096 \ --encoder-layerdrop 0 \ --encoder-layers 6 \ --source-lang en \ --share-decoder-input-output-embed \ --target-lang de \ --optimizer adam \ --optimizer-overrides {} \ --reset-optimizer \ --save-interval 0 \ --keep-last-epochs 1 \ --max-epoch 31 \ --max-source-positions 1024 \ --max-target-positions 1024 \ --max-tokens 3584 \ --min-loss-scale 0.0001 \ --min-lr 1e-09 \ --stop-time-hours 0.1 \ --arch transformer_wmt_en_de '''./data/data-bin already exists2.3开始训练print(command) ret = os.system(command) copy_tree_force('./model', args.save_folder) print('training end')CUDA_VISIBLE_DEVICES=0 fairseq-train ./data/data-bin --restore-file ./model/model.pth --save-dir ./outputs --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-07 --warmup-updates 4000 --lr 0.0007 --min-lr 1e-09 --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --weight-decay 0.0 --max-tokens 4096 --save-interval-updates 50 --max-update 50 --keep-interval-updates 20 --decoder-attention-heads 16 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-layerdrop 0 --decoder-layers 6 --decoder-output-dim 1024 --encoder-attention-heads 16 --encoder-embed-dim 1024 --encoder-ffn-embed-dim 4096 --encoder-layerdrop 0 --encoder-layers 6 --source-lang en --share-decoder-input-output-embed --target-lang de --optimizer adam --optimizer-overrides {} --reset-optimizer --save-interval 0 --keep-last-epochs 1 --max-epoch 31 --max-source-positions 1024 --max-target-positions 1024 --max-tokens 3584 --min-loss-scale 0.0001 --min-lr 1e-09 --stop-time-hours 0.1 --arch transformer_wmt_en_de 0 [] training end3.模型测试# -*- coding: utf-8 -*- from tqdm import tqdm from fairseq.models.transformer import TransformerModel from nltk.translate.bleu_score import sentence_bleu import os import torch import numpy as np from PIL import Image from io import BytesIO from collections import OrderedDict import torch.backends.cudnn as cudnn cudnn.benchmark = True class ModelClass(): def __init__(self, model_path): self.model_path = model_path # 本行代码必须保留,且无需修改 self.device = torch.device("cpu") print(self.model_path) path=os.getcwd() self.model= TransformerModel.from_pretrained( model_name_or_path= './', checkpoint_file='outputs/model.pth', data_name_or_path='outputs/newstest2014', bpe='subword_nmt', bpe_codes='outputs/bpecodes' ) self.model.eval() self.model = self.model.to(self.device) print('load model success') def translate(self, data): pre_text = self.model.translate(data) return pre_text 需要翻译的自然语言需要是英语,输出为德语,可自行修改成想要翻译的话text_input = "I am lucky." Translator = ModelClass('./outputs/model.pth') result = Translator.translate(text_input) print(result)INFO:fairseq.file_utils:loading archive file ./ INFO:fairseq.file_utils:loading archive file outputs/newstest2014 ./outputs/model.pth INFO:fairseq.tasks.translation:[en] dictionary: 32768 types INFO:fairseq.tasks.translation:[de] dictionary: 32768 types INFO:fairseq.models.fairseq_model:Namespace(activation_dropout=0.0, activation_fn='relu', adam_betas='(0.9, 0.98)', adam_eps=1e-08, adaptive_input=False, adaptive_softmax_cutoff=None, adaptive_softmax_dropout=0, arch='transformer_wmt_en_de_big', attention_dropout=0.1, batch_size=None, bpe='subword_nmt', bpe_codes='outputs/bpecodes', bpe_separator='@@', clip_norm=0.0, criterion='label_smoothed_cross_entropy', cross_self_attention=False, data='outputs/newstest2014', decoder_attention_heads=16, decoder_embed_dim=1024, decoder_embed_path=None, decoder_ffn_embed_dim=4096, decoder_input_dim=1024, decoder_layerdrop=0, decoder_layers=6, decoder_layers_to_keep=None, decoder_learned_pos=False, decoder_normalize_before=False, decoder_output_dim=1024, device_id=0, distributed_backend='nccl', distributed_init_method='tcp://learnfair0487:59946', distributed_port=59946, distributed_rank=0, distributed_world_size=128, dropout=0.3, encoder_attention_heads=16, encoder_embed_dim=1024, encoder_embed_path=None, encoder_ffn_embed_dim=4096, encoder_layerdrop=0, encoder_layers=6, encoder_layers_to_keep=None, encoder_learned_pos=False, encoder_normalize_before=False, eval_bleu_detok='space', eval_bleu_remove_bpe=None, eval_tokenized_bleu=False, fp16=True, ignore_prefix_size=0, label_smoothing=0.1, layernorm_embedding=False, left_pad_source=True, left_pad_target=False, log_format='json', log_interval=10, lr=[0.001], lr_scheduler='inverse_sqrt', lr_shrink=0.1, max_epoch=0, max_sentences=None, max_sentences_valid=None, max_source_positions=1024, max_target_positions=1024, max_tokens=3584, max_update=300000, min_lr=1e-09, momentum=0.99, no_cross_attention=False, no_epoch_checkpoints=False, no_progress_bar=False, no_save=False, no_scale_embedding=False, no_token_positional_embeddings=False, num_batch_buckets=0, optimizer='adam', quant_noise_pq=0, quant_noise_pq_block_size=8, quant_noise_scalar=0, relu_dropout=0.0, restore_file='checkpoint_last.pt', sample_without_replacement=256000, save_dir='/checkpoint02/myleott/2018-05-18/paracrawl_en_de.fp16.maxupd300000.upsamplewmt31.samp_wo_repl256000.transformer_wmt_en_de_big.shareemb.adam.beta0.9,0.98.initlr1e-07.warmup4000.lr0.001.clip0.0.drop0.3.wd0.0.ls0.1.maxtok3584.seed2.ngpu128', save_interval=1, secondary_train_data='/private/home/myleott/data/paracrawl/en-de/paracrawl-release1.en-de.no_url.shuf_uniq_norm.scored.filtered.preprocessed', seed=2, sentence_avg=False, share_all_embeddings=True, share_decoder_input_output_embed=True, skip_invalid_size_inputs_valid_test=False, source_lang='en', target_lang='de', task='translation', tie_adaptive_weights=False, train_subset='train', truncate_source=False, update_freq=[1.0], upsample_primary=31, use_old_adam=False, valid_subset='valid', validate_interval=1, warmup_init_lr=1e-07, warmup_updates=4000, weight_decay=0.0) load model success Ich bin Glück .
  • [技术干货] DynamicRCNN(目标检测/PyTorch)
    计算机视觉领域最基本的三个任务是:分类、目标定位、目标检测。分类的目标是要识别出给出一张图像是什么类别标签(在训练集中的所有类别标签中,给出的这张图属于那类标签的可能性最大);定位的目标不仅要识别出来是什么物体(类标签),还要给出物体的位置,位置一般用bounding box(边框)标记;目标检测是多个物体的定位,即要在一张图中定位出多个目标物体,目标检测任务包含分类和目标定位。DynamicRCNN是一种two-stage的目标检测算法。本案例是DynamicRCNN论文复现的体验案例,模型基于Dynamic R-CNN: Towards High Quality Object Detection via Dynamic Training中提出的模型结构实现,会载入预训练模型,训练数据集为COCO.具体算法介绍:cid:link_0注意事项:本案例使用框架**:** PyTorch1.0.0本案例使用硬件**:** GPU运行代码方法**:** 点击本页面顶部菜单栏的三角形运行按钮或按Ctrl+Enter键 运行每个方块中的代码JupyterLab的详细用法**:** 请参考《ModelAtrs JupyterLab使用指导》碰到问题的解决办法**:** 请参考《ModelAtrs JupyterLab常见问题解决办法》1.数据和代码下载运行下面代码,进行数据和代码的下载和解压本案例使用coco数据,共80个类别。import moxing as moximport osmox.file.copy_parallel('s3://obs-aigallery-zc/algorithm/DynamicRCNN-last','./DynamicRCNN-last')2.模型训练2.1依赖库安装及加载import osos.system('pip install pycocotools')root_path = './DynamicRCNN-last/'os.chdir(root_path)from PIL import Image, ImageDrawfrom tqdm import tqdmfrom io import BytesIOfrom collections import OrderedDictimport torch.backends.cudnn as cudnnfrom torch.utils.data import DataLoader, Datasetimport torchvision.transforms as transformsimport matplotlib.pyplot as pltimport sysimport argparseimport cv2import numpy as npimport torchfrom realTrain import trainfrom config import config as cfgfrom network import Networkfrom dynamic_rcnn.engine.checkpoint import DetectronCheckpointerfrom dynamic_rcnn.engine.comm import synchronize, get_rank, get_world_size,all_gather, is_main_processfrom dynamic_rcnn.utils.logger import setup_loggerfrom dynamic_rcnn.utils.pyt_utils import mkdir, draw_boxfrom dynamic_rcnn.datasets.structures.image_list import to_image_listcudnn.benchmark = True2.2训练参数设置详细的参数可以看DynamicRCNN-last/config.pyparser = argparse.ArgumentParser( description="PyTorch Object Detection Training")parser.add_argument("--local_rank", type=int, default=0)parser.add_argument("--training_iter", type=int, default=100)parser.add_argument("--num_gpus", type=int, default=1)parser.add_argument("--eval",type=str,default='False')parser.add_argument("--load_weight",type=str, default='std')parser.add_argument("--check_period",type=int,default=5000)## add or alter by BLBparser.add_argument('--training_dataset', default='./coco_data', help='Training dataset directory') parser.add_argument('--save_folder', default='./model', help='Location to save checkpoint models')parser.add_argument('--data_url', default='./coco_data', type=str, help='the training and validation data path')args, unknown = parser.parse_known_args()2.3开始训练train(args)world size: 12021-05-24 16:42:46,091 train INFO: Using 1 GPUsINFO:train:Using 1 GPUs2021-05-24 16:42:46,094 train INFO: Namespace(check_period=5000, data_url='./coco_data', distributed=False, eval='False', load_weight='std', local_rank=0, num_gpus=1, save_folder='./model', training_dataset='./coco_data', training_iter=100)INFO:train:Namespace(check_period=5000, data_url='./coco_data', distributed=False, eval='False', load_weight='std', local_rank=0, num_gpus=1, save_folder='./model', training_dataset='./coco_data', training_iter=100)2021-05-24 16:42:54,256 train INFO: Loading checkpoint from /home/ma-user/work/DynamicRCNN-last/trained_model/model/iteration_270000_mAP_49.2.pthINFO:train:Loading checkpoint from /home/ma-user/work/DynamicRCNN-last/trained_model/model/iteration_270000_mAP_49.2.pth2021-05-24 16:42:57,417 train INFO: 加载了本地预训练好的,达到论文精度的best_model.pth进行迁移训练INFO:train:加载了本地预训练好的,达到论文精度的best_model.pth进行迁移训练loading annotations into memory...Done (t=0.91s)creating index...index created!{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 13: 12, 14: 13, 15: 14, 16: 15, 17: 16, 18: 17, 19: 18, 20: 19, 21: 20, 22: 21, 23: 22, 24: 23, 25: 24, 27: 25, 28: 26, 31: 27, 32: 28, 33: 29, 34: 30, 35: 31, 36: 32, 37: 33, 38: 34, 39: 35, 40: 36, 41: 37, 42: 38, 43: 39, 44: 40, 46: 41, 47: 42, 48: 43, 49: 44, 50: 45, 51: 46, 52: 47, 53: 48, 54: 49, 55: 50, 56: 51, 57: 52, 58: 53, 59: 54, 60: 55, 61: 56, 62: 57, 63: 58, 64: 59, 65: 60, 67: 61, 70: 62, 72: 63, 73: 64, 74: 65, 75: 66, 76: 67, 77: 68, 78: 69, 79: 70, 80: 71, 81: 72, 82: 73, 84: 74, 85: 75, 86: 76, 87: 77, 88: 78, 89: 79, 90: 80}2021-05-24 16:42:58,405 train INFO: Start trainingINFO:train:Start training2021-05-24 16:42:58,406 train INFO: max_iter:100INFO:train:max_iter:1002021-05-24 16:44:35,066 train INFO: eta: 0:06:26 iter: 20 loss: 1.1161 (1.1389) rpn_cls_loss: 0.0197 (0.0700) rpn_bbox_loss: 0.0415 (0.0787) rcnn_cls_loss: 0.6070 (0.6549) rcnn_bbox_loss: 0.3246 (0.3352) time: 5.6187 (4.8328) data: 0.0111 (0.0345) lr: 0.000200 max mem: 22685INFO:train:eta: 0:06:26 iter: 20 loss: 1.1161 (1.1389) rpn_cls_loss: 0.0197 (0.0700) rpn_bbox_loss: 0.0415 (0.0787) rcnn_cls_loss: 0.6070 (0.6549) rcnn_bbox_loss: 0.3246 (0.3352) time: 5.6187 (4.8328) data: 0.0111 (0.0345) lr: 0.000200 max mem: 226852021-05-24 16:45:19,010 train INFO: eta: 0:03:30 iter: 40 loss: 0.9624 (1.0859) rpn_cls_loss: 0.0257 (0.0521) rpn_bbox_loss: 0.0129 (0.0623) rcnn_cls_loss: 0.5040 (0.6171) rcnn_bbox_loss: 0.3610 (0.3545) time: 0.6644 (3.5150) data: 0.0101 (0.0231) lr: 0.000200 max mem: 22685INFO:train:eta: 0:03:30 iter: 40 loss: 0.9624 (1.0859) rpn_cls_loss: 0.0257 (0.0521) rpn_bbox_loss: 0.0129 (0.0623) rcnn_cls_loss: 0.5040 (0.6171) rcnn_bbox_loss: 0.3610 (0.3545) time: 0.6644 (3.5150) data: 0.0101 (0.0231) lr: 0.000200 max mem: 226852021-05-24 16:46:25,833 train INFO: eta: 0:02:18 iter: 60 loss: 0.9568 (1.0441) rpn_cls_loss: 0.0139 (0.0471) rpn_bbox_loss: 0.0165 (0.0556) rcnn_cls_loss: 0.4574 (0.5867) rcnn_bbox_loss: 0.3618 (0.3547) time: 0.6814 (3.4571) data: 0.0088 (0.0191) lr: 0.000200 max mem: 22685INFO:train:eta: 0:02:18 iter: 60 loss: 0.9568 (1.0441) rpn_cls_loss: 0.0139 (0.0471) rpn_bbox_loss: 0.0165 (0.0556) rcnn_cls_loss: 0.4574 (0.5867) rcnn_bbox_loss: 0.3618 (0.3547) time: 0.6814 (3.4571) data: 0.0088 (0.0191) lr: 0.000200 max mem: 226852021-05-24 16:47:02,932 train INFO: eta: 0:01:01 iter: 80 loss: 0.9744 (1.0196) rpn_cls_loss: 0.0375 (0.0494) rpn_bbox_loss: 0.0299 (0.0577) rcnn_cls_loss: 0.4399 (0.5507) rcnn_bbox_loss: 0.3812 (0.3619) time: 0.6615 (3.0565) data: 0.0109 (0.0174) lr: 0.000200 max mem: 22986INFO:train:eta: 0:01:01 iter: 80 loss: 0.9744 (1.0196) rpn_cls_loss: 0.0375 (0.0494) rpn_bbox_loss: 0.0299 (0.0577) rcnn_cls_loss: 0.4399 (0.5507) rcnn_bbox_loss: 0.3812 (0.3619) time: 0.6615 (3.0565) data: 0.0109 (0.0174) lr: 0.000200 max mem: 229862021-05-24 16:47:28,373 train INFO: eta: 0:00:00 iter: 100 loss: 0.9252 (1.0421) rpn_cls_loss: 0.0358 (0.0691) rpn_bbox_loss: 0.0289 (0.0606) rcnn_cls_loss: 0.4498 (0.5464) rcnn_bbox_loss: 0.3488 (0.3661) time: 0.6337 (2.6996) data: 0.0111 (0.0164) lr: 0.000200 max mem: 22986INFO:train:eta: 0:00:00 iter: 100 loss: 0.9252 (1.0421) rpn_cls_loss: 0.0358 (0.0691) rpn_bbox_loss: 0.0289 (0.0606) rcnn_cls_loss: 0.4498 (0.5464) rcnn_bbox_loss: 0.3488 (0.3661) time: 0.6337 (2.6996) data: 0.0111 (0.0164) lr: 0.000200 max mem: 229862021-05-24 16:47:28,378 train INFO: Saving checkpoint to ./model/checkpoints/model_0000100.pthINFO:train:Saving checkpoint to ./model/checkpoints/model_0000100.pth2021-05-24 16:47:29,013 train INFO: Saving checkpoint to ./model/checkpoints/final_model.pthINFO:train:Saving checkpoint to ./model/checkpoints/final_model.pth2021-05-24 16:47:31,185 train INFO: Total training time: 0:04:32.776027 (2.7278 s / it)INFO:train:Total training time: 0:04:32.776027 (2.7278 s / it)3.模型测试3.1预测类别这80类就是COCO数据集中包括的类别id2name={1: 'person', 2: 'bicycle',3: 'car',4: 'motorcycle',5: 'airplane',6: 'bus',7: 'train',8: 'truck',9: 'boat',10: 'traffic light',11: 'fire hydrant',12: 'stop sign',13: 'parking meter',14: 'bench', 15: 'bird',16: 'cat',17: 'dog',18: 'horse',19: 'sheep',20: 'cow',21: 'elephant',22: 'bear',23: 'zebra',24: 'giraffe',25: 'backpack',26: 'umbrella',27: 'handbag',28: 'tie',29: 'suitcase',30: 'frisbee', 31: 'skis',32: 'snowboard',33: 'sports ball',34: 'kite',35: 'baseball bat',36: 'baseball glove',37: 'skateboard',38: 'surfboard',39: 'tennis racket',40: 'bottle',41: 'wine glass',42: 'cup',43: 'fork',44: 'knife', 45: 'spoon',46: 'bowl',47: 'banana',48: 'apple',49: 'sandwich',50: 'orange',51: 'broccoli',52: 'carrot',53: 'hot dog',54: 'pizza',55: 'donut',56: 'cake',57: 'chair',58: 'couch',59: 'potted plant', 60: 'bed',61: 'dining table',62: 'toilet',63: 'tv',64: 'laptop',65: 'mouse',66: 'remote',67: 'keyboard',68: 'cell phone',69: 'microwave',70: 'oven',71: 'toaster',72: 'sink',73: 'refrigerator',74: 'book', 75: 'clock',76: 'vase',77: 'scissors',78: 'teddy bear',79: 'hair drier',80: 'toothbrush'}3.3展示预测结果¶if __name__ == '__main__': img_path = 'test.jpg' # 你可以选择你想测试的图片,并修改路径 model_path='./trained_model/model/iteration_270000_mAP_49.2.pth' img = predict(img_path,model_path) plt.figure(figsize=(10,10)) #设置窗口大小 plt.imshow(img) plt.show()2021-05-24 17:03:46,379 test.inference INFO: Loading checkpoint from ./trained_model/model/iteration_270000_mAP_49.2.pth2021-05-24 17:03:46,379 test.inference INFO: Loading checkpoint from ./trained_model/model/iteration_270000_mAP_49.2.pth
  • [技术干货] Stable Diffusion文字生成图像
    视频操作观看链接:cid:link_3点击Run in ModelArts,将会进入到ModelArts CodeLab中,这时需要你登录华为云账号,如果没有账号,则需要注册一个,且要进行实名认证,参考 cid:link_0 即可完成账号注册和实名认证。 登录之后,等待片刻,即可进入到CodeLab的运行环境Stable Diffusion文字生成图像 🎨Stable Diffusion 是由 CompVis、Stability AI 和 LAION 共同开发的一个文本转图像模型,它通过 LAION-5B 子集大量的 512x512 图文模型进行训练,我们只要简单的输入一段文本,Stable Diffusion 就可以迅速将其转换为图像,同样我们也可以置入图片或视频,配合文本对其进行处理。接下来 我们会展示如何将 Stable Diffusion 与 🤗 Hugging Face 🧨 Diffusers 的库一起使用。让我们一起动手试验一下吧Stable Diffusion Pipeline使用方法本案例可以使用GPU,也可以使用CPU来运行,GPU生成单张图片约20秒,CPU需6分钟您可以使用如下命令来查询当前机器的GPU是否可用,如果运行结果是一个表格,则表示GPU可用。!nvidia-smiTue Nov 22 16:03:56 2022 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 440.33.01 Driver Version: 440.33.01 CUDA Version: 10.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 Tesla P100-PCIE... On | 00000000:00:0D.0 Off | 0 | | N/A 34C P0 26W / 250W | 0MiB / 16280MiB | 0% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | No running processes found | +-----------------------------------------------------------------------------+步骤一:安装需要的运行环境耗时约1-2分钟!pip install --upgrade pip !pip install torch==1.12.1 torchvision==0.13.1 torchaudio==0.12.1 !pip install diffusers==0.2.4 !pip install transformers==4.21.1 scipy==1.7.3 ftfy==6.1.1 !pip install "ipywidgets>=7,<8"步骤二:下载AI模型预训练权重文件,加载模型用户可访问Hugging Face Hub获取token,进行下载,下载时间约6分钟左右。本案例已将其模型转存至华为云OBS中,运行如下代码,下载权重即可。下载耗时约30秒。import os import torch import os.path as osp import moxing as mox from diffusers import StableDiffusionPipeline parent = osp.join(os.getcwd(),'CompVis') if not os.path.exists(parent): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/StableDiffusion/CompVis',parent) if os.path.exists(parent): print('Download success') else: raise Exception('Download Failed') else: print("Model Package already exists!") INFO:root:Using MoXing-v2.1.0.5d9c87c8-5d9c87c8 INFO:root:Using OBS-Python-SDK-3.20.9.1 /home/ma-user/anaconda3/envs/PyTorch-1.8/lib/python3.7/site-packages/requests/__init__.py:104: RequestsDependencyWarning: urllib3 (1.26.12) or chardet (5.0.0)/charset_normalizer (2.0.12) doesn't match a supported version! RequestsDependencyWarning) Model Package already exists!加载模型model_dir = osp.join(osp.join(parent,'stable-diffusion-v1-4'), "diffusers") os.environ["XDG_CACHE_HOME"] = model_dir device = 'cuda' if torch.cuda.is_available() else 'cpu' pipe = StableDiffusionPipeline.from_pretrained(model_dir, # revision="fp16", # torch_dtype=torch.float16 ).to(device) 步骤三: 生成单张图像在GPU上,单张图片生成耗时约20秒在CPU上,单张图片生成耗时约6分钟,且运行内存需16GB以上#@title 请在此处填写Prompt,运行,即可生成单张图像 torch.cuda.empty_cache() prompt = "Close up portrait photo of Megan Fox as part cyborg part human, intimidating stare, Atmospheric, 600mm lens, Sony Alpha α7, epic, dramatic, cinematic lighting, high contrast, 8k, photo realistic, character design --testp --ar 2:3 --upbeta" #@param {type:"string"} image = pipe(prompt)["sample"][0] image0it [00:00, ?it/s]海报生成和分享#@title 请在下方title_char栏填写作品名称,author_char栏填写作者姓名,中文不超过6个字,运行,即可生成海报 import os import moxing as mox from PIL import Image,ImageDraw,ImageFont,ImageFilter # 导入海报需要的素材 if not os.path.exists("/home/ma-user/work/material"): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/StableDiffusion/AI_paint_TOM.png',"/home/ma-user/work/material/AI_paint_TOM.png") mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/StableDiffusion/方正兰亭准黑_GBK.ttf',"/home/ma-user/work/material/方正兰亭准黑_GBK.ttf") if os.path.exists("/home/ma-user/work/material"): print('Download success') else: raise Exception('Download Failed') else: print("Project already exists") def gen_poster(img,txt1,txt2,path): font1 = ImageFont.truetype(zt,30) font2 = ImageFont.truetype(zt,25) img_draw = ImageDraw.Draw(img) img_draw.text((180,860), txt1, font=font1,fill='#961900') img_draw.text((130,903), txt2, font=font2, fill='#252b3a') img.filter(ImageFilter.BLUR) img.save(path) template_img = "/home/ma-user/work/material/AI_paint_TOM.png" zt = r"/home/ma-user/work/material/方正兰亭准黑_GBK.ttf" temp_image = Image.open(template_img) temp_image.paste(image ,(40,266)) title_char = "CG女神" #@param {type:"string"} author_char = "魔幻少女" #@param {type:"string"} savepath = 'AI_paint_output.png' # 海报图片路径 gen_poster(temp_image,title_char,author_char,savepath) Image.open(savepath) # 显示图片步骤四:生成多张图像#@title 请在此处填写Promot,运行,即可生成3*3张图像 from PIL import Image num_cols = 3 # 图像行数 num_rows = 3 # 图像列数 prompt = "Cygames girl character concept art and illustration by akihiko yoshida , ultimate dressy , amazing detailed face in profile closeup, galaxy in blue hair, Jewelry eyes , wearing a white galaxy dress , Line Array Speaker , Extreme Explosion , Subwoofer , kyoani character face , cute ,pretty girl , dynamic pose, portrait , pixiv daily ranking , pixiv , artstation ,specatcualr details, Volumetric Lighting , Dramatic lighting —ar 9:16 --test --creative --upbeta" #@param {type:"string"} prompt_list = [prompt] * num_cols def image_grid(imgs, rows, cols): assert len(imgs) == rows * cols w, h = imgs[0].size grid = Image.new('RGB', size=(cols * w, rows * h)) grid_w, grid_h = grid.size for i, img in enumerate(imgs): grid.paste(img, box=(i % cols * w, i // cols * h)) return grid all_images = [] for i in range(num_rows): images = pipe(prompt_list)["sample"] all_images.extend(images) for index, img in enumerate(images): img.save("img_%s_%s.png" % (str(i), str(index))) grid = image_grid(all_images, rows=num_rows, cols=num_cols) grid from PIL import Image num_cols = 3 # 图像行数 num_rows = 3 # 图像列数 prompt = "Cygames girl character concept art and illustration by akihiko yoshida , ultimate dressy , amazing detailed face in profile closeup, galaxy in blue hair, Jewelry eyes , wearing a white galaxy dress , Line Array Speaker , Extreme Explosion , Subwoofer , kyoani character face , cute ,pretty girl , dynamic pose, portrait , pixiv daily ranking , pixiv , artstation ,specatcualr details, Volumetric Lighting , Dramatic lighting —ar 9:16 --test --creative --upbeta" #@param {type:"string"} prompt_list = [prompt] * num_cols def image_grid(imgs, rows, cols): assert len(imgs) == rows * cols w, h = imgs[0].size grid = Image.new('RGB', size=(cols * w, rows * h)) grid_w, grid_h = grid.size for i, img in enumerate(imgs): grid.paste(img, box=(i % cols * w, i // cols * h)) return grid all_images = [] for i in range(num_rows): torch.cuda.empty_cache() images = pipe(prompt_list)["sample"] all_images.extend(images) for index, img in enumerate(images): img.save("img_%s_%s.png" % (str(i), str(index))) grid = image_grid(all_images, rows=num_rows, cols=num_cols) grid #@title 请在此处填写Prompt,运行,即可生成3*3张图像0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s] 0it [00:00, ?it/s]步骤五:修改prompt提示词1. 什么是 Prompt?Prompt 是生成图片的提示词,可以是一个实体,例如猫。也可以是一串富含想象力的文字,例如:『夕阳日落时,天边有巨大的云朵,海面波涛汹涌,风景,胶片感』。不同的 Prompt 对于生成的图像质量影响非常大,所以如果要生成一幅优秀的图画,就要掌握写 Prompt 的一些经验性技巧。以下是一些优秀图画及相关Promot的示范样例Cygames女孩角色,概念艺术,银河在蓝色的头发,珠宝眼睛,穿着白色的银河连衣裙,线阵列扬声器,极端爆炸promot: Cygames girl character concept art and illustration by akihiko yoshida , ultimate dressy , amazing detailed face in profile closeup, galaxy in blue hair, Jewelry eyes , wearing a white galaxy dress , Line Array Speaker , Extreme Explosion , Subwoofer , kyoani character face , cute ,pretty girl , dynamic pose, portrait , pixiv daily ranking , pixiv , artstation ,specatcualr details, Volumetric Lighting , Dramatic lighting —ar 9:16 --test --creative --upbetapromt:dark style painted, river flowing through forest of cherry blossom trees , under a galaxy filled sky, beautiful, galaxies, deep colors,ultra lighting, Bioelectric Modular Synthesizer, perfect symmetry, cinematic, volumetric lighting, --ar 9:162. 如何修改提示词2.1 Prompt 的设计如何设计 Prompt,下文大概会通过4个方面来说明:Prompt的描述可以从这四个方面入手:图片的风格,内容主体,详细的描述,再加上画家的风格。需要注意的是,这里的 Prompt 公式仅仅是个入门级别的参考,是经验的简单总结,在熟悉了 Prompt 的原理之后,可以尽情的发挥脑洞修改 Prompt。2.2 Prompt 公式Prompt框架:[图片的风格]+[内容主题]+[细节描述]+[绘画风格或者艺术家风格]图片的风格按照这个框架,简单构造一个图片风格,比如:可以是一幅美丽的画,或者是一幅美丽的山水画。内容的主体+详细描述主体可以是各种各样的选择。推荐一些可以激发大家灵感的事物,如山水,人物,建筑房屋,动物等等,尽可能细致刻画这些实体事物。如果是简单的输入“大海”两个字,模型不知道我们想要的风景是什么样子的,一段作品的相对准确的描述,比如:梦幻的大海,白沙滩岸边铺满了粉色的玫瑰花,月光轻柔的人洒在海面上,绿色发光的海浪,我们要去尽量用详细的语言,用细节清楚的描述我们幻想的场景。比如:云中的Skyrim风格的山,有一个照明螺栓击中尖端导致雪崩,山区风景。 对于详细的描述,我们可以拆分【形容词】+【视角】+【时间】+【颜色】+【其他】形容词可以是梦幻,神秘,浪漫或者写实 ……视角可以是:超广角,俯视和仰视 ……时间:秋天,清晨,黄昏,夜晚 ……颜色可以是 红黄绿蓝橙紫……其他可以包含图片的尺寸,4k,8k ,HD,光效,高细节等Prompt 绘画风格和艺术家风格如果想让生成的图片更加的艺术化、风格化,可以考虑在 Prompt 中添加绘画风格和艺术家。艺术绘画风格可以是一些美术风格:梵高风格,油画,水彩,古风,CG感,动漫,少女,赛博朋克,卡通画,中国画,黄昏等等,艺术家风格包含:现实主义,印象派,野兽派,新艺术,表现主义,立体主义,未来主义等等 提示词:这是一幅美丽的画作,描绘了夜晚一大片空旷的沙漠沙丘,中间有许多棵神秘的巨大发光的蓝色树,树的蓝色光芒照亮了周围的环境,天空中的星星,由特德·纳史密斯和托马斯·金卡德创作另外还有一些注意事项和常见的问题在使用关键词的时候,也多去使用一些明确的定义,避免使用“不是xxx”这样的描述。“不是xxx”,可选择的范围就太大了,生成出来的结果可能就和你想要的相去甚远。如果你是个新手,需要一些关于关键词的引导,那你可以去 cid:link_5 这个网站看一看。它收集了很多关键词,并且一步一步、分门别类地为你整理好了。你只需要根据网站给出的步骤,从它的关键词库里选择你想要的效果,然后把这串关键词直接复制到prompt里就好。把“填空题”变成“选择题”,非常方便。 在熟悉了 Prompt 的原理之后,就可以尽情的发挥脑洞修改它的写法,点击链接,快来Happy Prompting吧!2.5 附录:常见的风格列举古典主义 洛可可 巴洛克, 印象派, 新古典主义, 写实主义, 浪漫主义, 唯美主义, 表现主义, 现实主义, 魔幻现实主义, 奇幻现实主义, 象征主义, 抽象主义, 超扁平主义 超前卫艺术 中国风格 浮世绘 极简主义 几何风格 数字艺术, 感念艺术 装饰艺术复古未来主义风格粉彩朋克风格史前遗迹风格波普艺术风格迷幻风格赛博朋克风格未来主义风格抽象技术风格新艺术主义抽象表现主义北欧文艺复兴原始主义立体主义色域绘画波普艺术极简主义矫饰主义步骤六: 使用新的提示词生成图片在掌握了上面提示词Prompt的规则后,我们看下如何使用上面的程序生成自己想要的图片 1.用中文描述提示词,描述的越精准越好2.使用翻译软件将中文翻译成英文3.将英文的Prompt替换上面程序prompt= "......."中的内容,位置分别在程序步骤三和步骤四,例如:将上面梵高的图片替换成狗喝咖啡的内容,如:prompt = "Close-up side view portrait of Cyborg Geisha, rotobic, Machina, super intricate ornaments artwork, by Tooth Wu and wlop, by Alena Aenami, by Alphonse Mucha, by Brian Froud, by Pablo Amaringo, super detailed, large depth of field"替换成prompt ="golden retriever puppy sitting at a diner drinking a cup of coffee, looking melancholy, Edward HopperS"4.再次运行步骤三和步骤四其他参考资料prompts搜索引擎cid:link_5两个Prompts插值cid:link_2生成无缝贴图cid:link_4用 Stable Diffusion 生成的艺术家风格参考库cid:link_1
  • AI人脸编辑-代码参数化
    高保真图像编辑注意:本案例必须使用GPU运行,请查看《ModelArts JupyterLab 硬件规格使用指南》了解切换硬件规格的方法High-Fidelity GAN Inversion for Image Attribute Editing (CVPR 2022) cid:link_81 下载代码和数据import os import moxing as mox if not os.path.exists("/home/ma-user/work/ma_share/HFGI/HFGI"): mox.file.copy_parallel('obs://modelarts-labs-bj4-v2/case_zoo/HFGI/HFGI.zip',"/home/ma-user/work/ma_share/HFGI/HFGI.zip") os.system("cd /home/ma-user/work/ma_share/HFGI;unzip HFGI.zip;rm HFGI.zip") if os.path.exists("/home/ma-user/work/ma_share/HFGI/HFGI"): print('Download success') else: raise Exception('Download Failed') else: print("Project already exists")2 安装依赖环境!pip install ninja !pip install dlib !pip uninstall -y torch !pip uninstall -y torchvision !pip install torch==1.6.0 !pip install torchvision==0.7.0安装完后,需要重启一下kernel,点击上方Restart the kernelÍ HFGI3 开始运行代码#@title Setup Repository import os from argparse import Namespace import time import os import sys import numpy as np from PIL import Image import torch import torchvision.transforms as transforms # from utils.common import tensor2im from models.psp import pSp # we use the pSp framework to load the e4e encoder. %load_ext autoreload %autoreload 2def tensor2im(var): # var shape: (3, H, W) var = var.cpu().detach().transpose(0, 2).transpose(0, 1).numpy() var = ((var + 1) / 2) var[var < 0] = 0 var[var > 1] = 1 var = var * 255 return Image.fromarray(var.astype('uint8'))Step 1: 加载预训练模型model_path = "checkpoint/ckpt.pt" ckpt = torch.load(model_path, map_location='cpu') opts = ckpt['opts'] opts['is_train'] = False opts['checkpoint_path'] = model_path opts= Namespace(**opts) net = pSp(opts) net.eval() net.cuda() print('Model successfully loaded!')Step 2: 设置输入图像#@title 设置输入图像 # Setup required image transformations input_img_path = "test_imgs/1919116757.jpg" #@param {type:"string", dropdown} EXPERIMENT_ARGS = {"image_path": input_img_path} EXPERIMENT_ARGS['transform'] = transforms.Compose([ transforms.Resize((256, 256)), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]) resize_dims = (256, 256)image_path = EXPERIMENT_ARGS["image_path"] original_image = Image.open(image_path) original_image = original_image.convert("RGB") run_align = True图像对齐import numpy as np import PIL import PIL.Image import scipy import scipy.ndimage import dlib def get_landmark(filepath, predictor): """get landmark with dlib :return: np.array shape=(68, 2) """ detector = dlib.get_frontal_face_detector() img = dlib.load_rgb_image(filepath) dets = detector(img, 1) for k, d in enumerate(dets): shape = predictor(img, d) t = list(shape.parts()) a = [] for tt in t: a.append([tt.x, tt.y]) lm = np.array(a) return lm def align_face(filepath, predictor): """ :param filepath: str :return: PIL Image """ lm = get_landmark(filepath, predictor) lm_chin = lm[0: 17] # left-right lm_eyebrow_left = lm[17: 22] # left-right lm_eyebrow_right = lm[22: 27] # left-right lm_nose = lm[27: 31] # top-down lm_nostrils = lm[31: 36] # top-down lm_eye_left = lm[36: 42] # left-clockwise lm_eye_right = lm[42: 48] # left-clockwise lm_mouth_outer = lm[48: 60] # left-clockwise lm_mouth_inner = lm[60: 68] # left-clockwise # Calculate auxiliary vectors. eye_left = np.mean(lm_eye_left, axis=0) eye_right = np.mean(lm_eye_right, axis=0) eye_avg = (eye_left + eye_right) * 0.5 eye_to_eye = eye_right - eye_left mouth_left = lm_mouth_outer[0] mouth_right = lm_mouth_outer[6] mouth_avg = (mouth_left + mouth_right) * 0.5 eye_to_mouth = mouth_avg - eye_avg # Choose oriented crop rectangle. x = eye_to_eye - np.flipud(eye_to_mouth) * [-1, 1] x /= np.hypot(*x) x *= max(np.hypot(*eye_to_eye) * 2.0, np.hypot(*eye_to_mouth) * 1.8) y = np.flipud(x) * [-1, 1] c = eye_avg + eye_to_mouth * 0.1 quad = np.stack([c - x - y, c - x + y, c + x + y, c + x - y]) qsize = np.hypot(*x) * 2 # read image img = PIL.Image.open(filepath) output_size = 256 transform_size = 256 enable_padding = True # Shrink. shrink = int(np.floor(qsize / output_size * 0.5)) if shrink > 1: rsize = (int(np.rint(float(img.size[0]) / shrink)), int(np.rint(float(img.size[1]) / shrink))) img = img.resize(rsize, PIL.Image.ANTIALIAS) quad /= shrink qsize /= shrink # Crop. border = max(int(np.rint(qsize * 0.1)), 3) crop = (int(np.floor(min(quad[:, 0]))), int(np.floor(min(quad[:, 1]))), int(np.ceil(max(quad[:, 0]))), int(np.ceil(max(quad[:, 1])))) crop = (max(crop[0] - border, 0), max(crop[1] - border, 0), min(crop[2] + border, img.size[0]), min(crop[3] + border, img.size[1])) if crop[2] - crop[0] < img.size[0] or crop[3] - crop[1] < img.size[1]: img = img.crop(crop) quad -= crop[0:2] # Pad. pad = (int(np.floor(min(quad[:, 0]))), int(np.floor(min(quad[:, 1]))), int(np.ceil(max(quad[:, 0]))), int(np.ceil(max(quad[:, 1])))) pad = (max(-pad[0] + border, 0), max(-pad[1] + border, 0), max(pad[2] - img.size[0] + border, 0), max(pad[3] - img.size[1] + border, 0)) if enable_padding and max(pad) > border - 4: pad = np.maximum(pad, int(np.rint(qsize * 0.3))) img = np.pad(np.float32(img), ((pad[1], pad[3]), (pad[0], pad[2]), (0, 0)), 'reflect') h, w, _ = img.shape y, x, _ = np.ogrid[:h, :w, :1] mask = np.maximum(1.0 - np.minimum(np.float32(x) / pad[0], np.float32(w - 1 - x) / pad[2]), 1.0 - np.minimum(np.float32(y) / pad[1], np.float32(h - 1 - y) / pad[3])) blur = qsize * 0.02 img += (scipy.ndimage.gaussian_filter(img, [blur, blur, 0]) - img) * np.clip(mask * 3.0 + 1.0, 0.0, 1.0) img += (np.median(img, axis=(0, 1)) - img) * np.clip(mask, 0.0, 1.0) img = PIL.Image.fromarray(np.uint8(np.clip(np.rint(img), 0, 255)), 'RGB') quad += pad[:2] # Transform. img = img.transform((transform_size, transform_size), PIL.Image.QUAD, (quad + 0.5).flatten(), PIL.Image.BILINEAR) if output_size < transform_size: img = img.resize((output_size, output_size), PIL.Image.ANTIALIAS) # Return aligned image. return imgif 'shape_predictor_68_face_landmarks.dat' not in os.listdir(): # !wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2 !bzip2 -dk shape_predictor_68_face_landmarks.dat.bz2 def run_alignment(image_path): import dlib predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") aligned_image = align_face(filepath=image_path, predictor=predictor) print("Aligned image has shape: {}".format(aligned_image.size)) return aligned_image if run_align: input_image = run_alignment(image_path) else: input_image = original_image input_image.resize(resize_dims)Aligned image has shape: (256, 256)img_transforms = EXPERIMENT_ARGS['transform'] transformed_image = img_transforms(input_image)Step 3: 高保真逆向映射(inversion)def display_alongside_source_image(result_image, source_image): res = np.concatenate([np.array(source_image.resize(resize_dims)), np.array(result_image.resize(resize_dims))], axis=1) return Image.fromarray(res) def get_latents(net, x, is_cars=False): codes = net.encoder(x) if net.opts.start_from_latent_avg: if codes.ndim == 2: codes = codes + net.latent_avg.repeat(codes.shape[0], 1, 1)[:, 0, :] else: codes = codes + net.latent_avg.repeat(codes.shape[0], 1, 1) if codes.shape[1] == 18 and is_cars: codes = codes[:, :16, :] return codes#@title 设置上采样模式 mode = "bilinear" #@param {type:"string", dropdown} with torch.no_grad(): x = transformed_image.unsqueeze(0).cuda() tic = time.time() latent_codes = get_latents(net, x) # calculate the distortion map imgs, _ = net.decoder([latent_codes[0].unsqueeze(0).cuda()],None, input_is_latent=True, randomize_noise=False, return_latents=True) res = x - torch.nn.functional.interpolate(torch.clamp(imgs, -1., 1.), size=(256,256) , mode=mode) # ADA img_edit = torch.nn.functional.interpolate(torch.clamp(imgs, -1., 1.), size=(256,256) , mode=mode) res_align = net.grid_align(torch.cat((res, img_edit ), 1)) # consultation fusion conditions = net.residue(res_align) result_image, _ = net.decoder([latent_codes],conditions, input_is_latent=True, randomize_noise=False, return_latents=True) toc = time.time() print('Inference took {:.4f} seconds.'.format(toc - tic)) # Display inversion: display_alongside_source_image(tensor2im(result_image[0]), input_image)Step 4: 高保真图像编辑可以编辑的内容如下:--edit_attribute 编辑属性(inversion', 'age', 'smile', 'eyes', 'lip' ,'beard' )--edit_degree 控制编辑程度(适用于“age”和“smile”)。from editings import latent_editor editor = latent_editor.LatentEditor(net.decoder)#@title 图像编辑设置 # interface-GAN age_model = "./editings/interfacegan_directions/age.pt" #@param {type:"string", dropdown} smile_model = "./editings/interfacegan_directions/smile.pt" #@param {type:"string", dropdown} interfacegan_directions = { 'age': age_model, 'smile': smile_model } edit_status = "smile" #@param {type:"string", dropdown} edit_direction = torch.load(interfacegan_directions[edit_status]).cuda() # 微笑程度 edit_degree = 0.6 #@param {type:"slider", min:-5, max:5, step:0.1}#@title 上采样模型设置 img_edit, edit_latents = editor.apply_interfacegan(latent_codes[0].unsqueeze(0).cuda(), edit_direction, factor=edit_degree) # 设置微笑 # align the distortion map mode = "bilinear" #@param {type:"string", dropdown} img_edit = torch.nn.functional.interpolate(torch.clamp(img_edit, -1., 1.), size=(256,256) , mode=mode) res_align = net.grid_align(torch.cat((res, img_edit ), 1)) # fusion conditions = net.residue(res_align) result, _ = net.decoder([edit_latents],conditions, input_is_latent=True, randomize_noise=False, return_latents=True) result = torch.nn.functional.interpolate(result, size=(256,256) , mode=mode) display_alongside_source_image(tensor2im(result[0]), input_image)#@title ganspace设置 # GANSpace model = "./editings/ganspace_pca/ffhq_pca.pt" #@param {type:"string", dropdown} ganspace_pca = torch.load(model) eyes_param = (54, 7, 8, 20) #@param {type:"raw"} beard_param = (58, 7, 9, -20) #@param {type:"raw"} lip_param = (34, 10, 11, 20) #@param {type:"raw"} ganspace_directions = { 'eyes': eyes_param, # 眼睛 'beard': beard_param, # 胡子 'lip': lip_param } # 嘴唇 edit_option = "lip" #@param {type:"string", dropdown} edit_direction = ganspace_directions[edit_option]#@title 上采样模式设置 img_edit, edit_latents = editor.apply_ganspace(latent_codes[0].unsqueeze(0).cuda(), ganspace_pca, [edit_direction]) # align the distortion map mode = "bilinear" #@param {type:"string", dropdown} img_edit = torch.nn.functional.interpolate(torch.clamp(img_edit, -1., 1.), size=(256,256) , mode=mode) res_align = net.grid_align(torch.cat((res, img_edit ), 1)) conditions = net.residue(res_align) result, _ = net.decoder([edit_latents],conditions, input_is_latent=True, randomize_noise=False, return_latents=True) result = torch.nn.functional.interpolate(result, size=(256,256) , mode=mode) display_alongside_source_image(tensor2im(result[0]), input_image)训练如果需要训练,可以按以下描述进行:准备下载数据集并相应地修改数据集路径./configs/paths_config.py .下载一些预训练模型并将它们放入 ./pretrained.ModelDescriptionStyleGAN2 (FFHQ)Pretrained face generator on FFHQ from rosinality.e4e (FFHQ)Pretrained initial encoder on FFHQ from omertov.Feature extractor (for face)Pretrained IR-SE50 model taken from TreB1eN for ID loss calculation.Feature extractor (for car)Pretrained ResNet-50 model taken from omertov for ID loss calculation.开始训练修改 option 和 training.sh ,开始运行:bash train.sh
  • [经验分享] 使用MindStudio开发铝材表面缺陷检测
    BiliBili视频链接:使用MindStudio完成铝材表面缺陷检测_哔哩哔哩_bilibili使用MindStudio开发铝材表面缺陷检测目 录使用MindStudio开发铝材表面缺陷检测 1. MindStudio介绍 2. 案例模型 3. 环境搭建 3.1 安装MindX SDK和CANN包并配置环境变量 3.2 在windows开发环境同步CANN 3.3 在windows开发环境同步MindX SDK 4. 开发过程 4.1 创建工程 4.2 配置python解释器 4.3 开发步骤 4.4 项目下载连接以及项目结构 5. 运行 5.1 配置远程映射 5.2 精度测试 6. FAQ 1 尺寸不匹配 2 模型路径未进行正确配置 3 未修改pipeline中后处理插件的postProcessLibPath属性 4 同步远端CANN开发包失败 7. 一些个人经验总结 8. Mindstuido下载连接 9. 开发过程中用到的链接 1. MindStudio介绍MindStudio提供AI开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务。依靠模型可视化、算力测试、IDE本地仿真调试等功能,MindStudio能够使开发者在一个工具上就能高效便捷地完成AI应用开发 ·MindStudio采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能。MindStudio-昇腾社区 (hiascend.com)2. 案例模型在本案例中,目的是基于MindX SDK,在华为云昇腾平台上,使用MindStudio开发端到端铝材缺陷检测的参考设计,实现对图像中的铝材进行缺陷类型分类和定位的功能,达到功能要求,并对精度进行测试。3. 环境搭建开发环境为windows版本的MindStudio,运行环境在远端linux上。3.1 安装MindX SDK和CANN包并配置环境变量请先确保远端环境上MindX SDK软件包已安装完成,安装方式请参见安装MindX SDK开发套件。确保远端环境上CANN包已安装完成,安装方式请参见该链接在远端服务器上配置环境变量执行如下命令,打开.bashrc文件vim ~/.bashrc# 在.bashrc文件中添加以下环境变量. ${MX_SDK_HOME}/set_env.sh. ${HOME}/Ascend/ascend-toolkit/set_env.sh# 其中${MX_SDK_HOME}为MindX SDK安装目录,${HOME}为用户目录(如果CANN 开发包装在用户目录,否则为/usr/local/),配置的时候请自行替换成相应目录# 保存退出.bashrc文件# 执行如下命令使环境变量生效source ~/.bashrc#查看环境变量env3.2 在windows开发环境同步CANN工具栏点击“File > Settings > Appearance & Behavior > System Settings > CANN”进入CANN管理界面。点击Change CANN配置CANN包。配置远程连接以及远端CANN包路径(配置到版本号一级)3.3 在windows开发环境同步MindX SDK工具栏点击“File > Settings > Appearance & Behavior > System Settings > MindX SDK”或依次点击“Ascend>MindX SDK Manager”进入MindX SDK管理界面。界面中“MindX SDK Location”为软件包的默认安装路径,默认安装路径为“C:\Users*用户名*\Ascend\mindx_sdk”。单击“Install SDK”进入“Installation settings”界面。在“Installation settings”界面“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”。安装完成之后,界面如图所示:4. 开发过程4.1 创建工程工具栏点击“File > New > Project选择左侧Ascend APP,创建Ascend APP应用工程,,创建MindX SDK空白工程(提供MindX SDK开发框架,不包含代码逻辑),点击finish完成创建。创建完成之后目录结构如下图所示删除config文件夹,创建models和pipeline里的文件,以备后续开发自己的业务流程,目录结构如图所示。4.2 配置python解释器依次点击File->Project Structure,选择SDKs,添加Python SDK如下图所示:选择SSH interpreter,配置远程服务器,MindStudio会自动侦测远程python环境(如果PATH环境变量已正确配置python的路径),点击OKProject中选择配置好的远程SDK,点击Apply点击OK。完成python解释器的配置。4.3 开发步骤4.3.1 确定业务流程根据铝材表面缺陷检测SDK推理的具体需求,这里将流程依次划分为图片获取、图片解码、图像缩放、目标检测、序列化、结果发送。4.3.2 寻找合适的插件首先根据已有SDK插件的功能描述和规格限制来匹配业务功能(SDK插件列表详见已有插件介绍)。当SDK提供的插件无法满足功能需求时,用户可以参考插件开发介绍开发自定义插件,该部分为SDK高阶特性。在本案例中,已有SDK插件已经满足业务需求。铝材表面缺陷检测流程图以及pipeline编排流程图如下所示:1 铝材表面缺陷检测流程图2 铝材表面缺陷检测pipeline示意图4.3.3 准备模型推理文件和数据步骤1 训练铝材缺陷检测对应的yolov5模型,输出pt模型文件。pt模型文件链接:cid:link_2步骤2 将pt模型文件转换成onnx,也可直接通过以下链接下载onnx模型。onnx模型文件链接:cid:link_1下载yolov5官方源码6.1版本Releases · ultralytics/yolov5 (github.com),进入项目根目录,将best.pt模型文件复制到项目目录,执行命令python export.py --weights best.pt –simplify模型转换成功之后,显示的日志信息如下图所示,在项目根目录会生成best.onnx模型文件步骤3 将转化后的YOLOv5模型onnx文件存放至./models/yolov5/。步骤4 AIPP配置由于yolov5模型的输入为rgb格式,pipeline中的图像解码为yuv格式,且数据类型不同,需要在atc转换模型时使用aipp预处理,该案例所需进行的aipp预处理包括色域转化以及归一化操作,aipp配置步骤如下:在./models/yolov5文件夹创建insert_op.cfg配置文件,所需添加的配置内容的属性:参数参数说明aipp_mode每次模型推理过程采用固定的AIPP预处理参数进行处理Related_input_rankrelated_input_rank参数为可选,标识对模型的第几个输入做AIPP处理,从0开始,默认为0。例如模型有两个输入,需要对第2个输入做AIPP,则配置related_input_rank为1。# 类型: 整型Input_format输入图像格式,必选。取值范围:YUV420SP_U8、XRGB8888_U8、RGB888_U8、YUV400_U8src_image_size_wsrc_image_size_h原始图像的宽度、高度宽度取值范围为[2,4096]或0;高度取值范围为[1,4096]或0,对于YUV420SP_U8类型的图像,要求原始图像的宽和高取值是偶数cropAIPP处理图片时是否支持抠图类型:bool取值范围:true/false,true表示支持,false表示不支持Csc_switch色域转换开关,静态AIPP配置类型:bool取值范围:true/false,true表示开启色域转换,false表示关闭rbuv_swap_switch R通道与B通道交换开关/U通道与V通道交换开关类型:bool取值范围:true/false,true表示开启通道交换,false表示关闭matrix_rxcyX和y代表矩阵的行和列一旦确认了AIPP处理前与AIPP处理后的图片格式,即可确定色域转换相关的参数值(matrix_r*c*配置项的值是固定的,不需要调整)var_reci_chn归一化配置参数把需要处理的数据经过处理后限制在一定范围内,方便后面数据的处理。pixel_out_chx(i)=[pixel_in_chx(i)-mean_chn_i-min_chn_i]*var_reci_chn最终配置参数如下图所示:配置文件的教程请参考如下链接:配置文件模板 - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)5 模型转换模型转换有两种方式,一种是通过MindStudio可视化操作,另一种是通过命令行的方式,使用MindStudio进行模型转换参考该链接。使用命令方式进行模型转换步骤如下:首先开启一个SSH会话切换到项目根目录,运行如下命令:atc --input_shape="images:1,3,640,640" --out_nodes="Transpose_286:0;Transpose_336:0;Transpose_386:0" --output_type=FP32 --input_format=NCHW --output="./models/yolov5/yolov5_add_bs1_fp16" --soc_version=Ascend310 --framework=5 --model="./models/yolov5/best.onnx" --insert_op_conf=./models/yolov5/insert_op.cfg模型转换成功,模型保存在--output定义的路径下,输出结果如图所示:Atc中各个参数代表的含义请参考这个链接:参数说明 - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)。常见的报错请参考这个链接:FAQ - CANN 5.0.4 ATC工具使用指南 01 - 华为 (huawei.com)4.3.4 编写后处理配置文件在./models/yolov5创建模型后处理配置文件yolov5addbs1_fp16.cfg,对后处理参数进行配置:表1 配置文件中各个参数的意义参数名称参数介绍修改方法默认值CLASS_NUM铝材缺陷检测的类别数目。在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改CLASS_NUM的大小即可10BIASES_NUM铝材缺陷检测锚点框数量在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改BIASES_NUM的大小即可18BIASES铝材缺陷检测锚点框,用kmeans计算最合适的锚点框在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改BIASES即可17,14,161,31,113,69,649,17,637,32,636,73,625,132,640,202,626,365YOLO_TYPEYOLO输出特征向量的维度数,YOLOv5使用的是3在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改YOLO_TYPE即可3SCORE_THRESH是否为框的阈值,大于此值才认定为框在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改SCORE_THRESH的大小即可0.25IOU_THRESH两个框的IOU阈值,超过此值则被认定为同一个框,用于nms算法在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改IOU_THRESH的大小即可0.5OBJECTNESS_THRESH识别目标置信度的阈值,大于阈值才会认定为目标在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改OBJECTNESS_THRESH的大小即可0.0YOLO_VERSIONYOLO版本号,本项目使用的YOLOv5,故取值为5在models/yolov5/yolov5_add_bs1_fp16.cfg文件中修改YOLO_VERSION的大小即可54.3.5 配置names文件在./models/yolov5文件夹下创建aldefectdetection.names文件,按顺序配置相应类名,该文件为数据集中所有类别,后处理插件通过读取改文件,返回准确的类别名称,达到缺陷识别的目的:4.3.6 可视化流程编排根据已经确定的业务流程和合适的插件,利用MindStudio进行可视化插件编排,需要用到的为以下六个插件。1. appsrc # 输入2. mxpi_imagedecoder # 图像解码3. mxpi_imageresize # 图像缩放4. mxpi_tensorinfer # 模型推理(铝材缺陷检测)5. mxpi_objectpostprocessor # 模型后处理(yolov5)6. appsink # 输出用MindStudio进行可视化流程编排,工具栏依次点击“Ascend > MindX SDK Pipeline :搜索流程编排中需要用到的插件:将插件依次拖动到如下界面并连接起来,Format选项可以整理插件连接的排列,让界面更加美观。点击需要配置参数的插件,在如下区域设置合适的参数:点击save,生成相应的pipeline代码,该代码会将可视化pipeline中设置的参数也加载到对应的插件中去:{"classification+detection": {"stream_config": {"deviceId": "0"},"appsrc0": {"props": {"blocksize": "409600"},"factory": "appsrc","next": "mxpi_imagedecoder0"},"mxpi_imagedecoder0": {"factory": "mxpi_imagedecoder","next": "mxpi_imageresize0"},"mxpi_imageresize0": {"props": {"dataSource": "mxpi_imagedecoder0","resizeType": "Resizer_KeepAspectRatio_Fit","resizeWidth":"640","resizeHeight":"640","paddingType":"Padding_NO","interpolation":"2"},"factory": "mxpi_imageresize","next": "mxpi_tensorinfer0"},"mxpi_tensorinfer0": {"props": {"dataSource": "mxpi_imageresize0","modelPath": "./models/yolov5/yolov5_add_bs1_fp16.om"},"factory": "mxpi_tensorinfer","next": "mxpi_objectpostprocessor0"},"mxpi_objectpostprocessor0": {"props": {"dataSource": "mxpi_tensorinfer0","postProcessConfigPath": "./models/yolov5/yolov5_add_bs1_fp16.cfg","labelPath": "./models/yolov5/aldefectdetection.names","postProcessLibPath": "${HOME}/MindX_SDK/mxVision-2.0.4/lib/modelpostprocessors/libyolov3postprocess.so"},"factory": "mxpi_objectpostprocessor","next": "mxpi_dataserialize0"},"mxpi_dataserialize0": {"props": {"outputDataKeys": "mxpi_objectpostprocessor0"},"factory": "mxpi_dataserialize","next": "appsink0"},"appsink0": {"props": {"blocksize": "4096000"},"factory": "appsink"}}}可视化流程编排极大地提升了开发效率,通过这种方式用户可以很快的完成pipeline的编排。4.3.7 编写main.py文件main文件的编写逻辑如下图所示:按照上述流程图,完成代码开发,其中,通过SendDataWithUniqueId将数据送入流里,GetResultWithUniqueId从流里获取数据,最终用opencv将位置信息和类别信息标记在图片上并保存。主函数main.py:初始化流管理器,如果初始化失败,则提示用户并退出程序:2.通过streamManagerApi创建流,导入pipeline文件,如果失败,则提示用户并退出程序3. 构建输入数据,并对输入数据进行检查,确保输入的图片存在且不为空,否则提示用户并退出程序。4. 对输入数据进行预处理,对齐YOLOv5数据预处理操作。5. 将输入数据传入到指定流中,并通过uniqueId获取指定流的输出结果:6. 读取流中的结果,并将位置信息和类别信息输出到图片上,保存图片7. 销毁流4.4 项目下载连接以及项目结构完整项目请在此处下载:cid:link_14项目目录结构如下所示:├── models│ ├── yolov5│ │ ├── aldefectdetection.names # 铝材缺陷检测类别│ │ ├── insert_op.cfg # yolov5 aipp转换配置│ │ ├── yolov5_add_bs1_fp16.cfg # yolov5后处理配置│ │ ├── yolov5_add_bs1_fp16.om # 铝材缺陷检测模型│ │ ├── best.onnx # 用于模型转换├── pipeline│ └── AlDefectDetection.pipeline # pipeline文件├── main.py├── eval.py├── eval_pre.py # letterbox预处理├── plots.py # 绘图工具类├── utils.py # 工具类└── test.jpg5. 运行5.1 配置远程映射在工具栏"Tools > Deployment> Configuration"在Connection选项中配置远程连接。在Mappings选项中配置远程映射,同步远端和本地代码。配置远端路径之后点击OK完成映射。在工具栏点击"Tools > Deployment> Upload to"上传本地代码到远端服务器在精度测试下载的数据集中任意选择一张图片放在项目的根目录下,并命名为test.jpg在main.py文件点击右键,Modify Run Configuration,配置python解释器,选择远端python解释器,配置完成之后点击apply,点击OK。配置完成之后即可右键运行main.py文件得到结果,在程序中,通过输出流里取得的数据,我们可以看到图片的位置和类别信息。通过这些位置信息,我们进一步作出结果图:5.2 精度测试准备测试数据https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/ascend_community_projects/Aluminum_surface_defect_detection/testDatas.zip和om模型文件:https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/ascend_community_projects/Aluminum_surface_defect_detection/yolov5_add_bs1_fp16.om运行项目根目录下的eval.py,该文件是在main.py的基础上循环输入测试数据集图片得到结果。生成的位置信息和类别信息会以txt文件的形式保存在项目目录下的test/testouttxt/。在map.py界面右键,修改运行配置,添加路径参数配置命令行参数:其中--gt为测试集数据的标签路径,--testpath为模型输出结果的路径(即上述test/testpre_post/),包括分类结果、位置信息和置信度参数。结果如下图所示:mAP0.5为0.8135478,mAP0.5:0.95为0.5587293358。其中mAP是目标检测模型中常用的评价指标,它的英文全称是(Mean Average Precision),翻译过来就是平均精确率的平均。mAP0.5是指计算标准为IOU阈值大于0.5,也就是预测框和标签IOU>0.5为正样本。mAP0.5:0.95是指取IOU阈值为以0.05为步长,0.5为起始数据,一直到IOU阈值为0.95的十组数据的平均精度。6. FAQ1 尺寸不匹配问题描述:提示mxpi_tensorinfer0The input of the model does not match] The datasize of concated inputTensors0 does not match model inputTensors0. Tensor Dtype: TENSORDTYPEUINT8, model Dtype: TENSORDTYPEUINT8.解决方案:模型经过插件处理后的图像与模型输入不匹配,检查模型经过pipeline之后的尺寸大小是否和模型输入匹配。2 模型路径未进行正确配置问题描述:提示 Failed to get model, the model path is invalidate.解决方案:检查模型存放路径,正确配置模型路径。3 未修改pipeline中后处理插件的postProcessLibPath属性问题描述:提示[Object, file or other resource doesn't exist] The postprocessing DLL does not exist解决方案:修改pipeline文件中mxpi_objectpostprocessor0插件的postProcessLibPath属性,修改为{SDK安装路径}/lib/modelpostprocessors/libyolov3postprocess.so4 同步远端CANN开发包失败问题描述:提示[PermissionError: [Errno 13] Permission denied: '/usr/local/Ascend/ascend-toolkit/5.0.4/pyACL/scene.info' Command execute fail, exitStatus = 1]解决方案:将CANN开发包安装到用户目录下。7. 一些个人经验总结在编写pipeline的时候,MindStudio提供的可视化流程编排极大地提高了开发效率,在MindStudio可以通过拖动的方式完成pipeline的编写,参数也可以很方便的在可视化流程编排中配置;在开发中我们难免会遇到各种各样奇奇怪怪的问题,昇腾论坛是个不错的选择,有问必答,从大四开始已经陆陆续续问了挺多问题,答复速度比较快,开发中受阻,不妨在论坛里请求大佬寻求帮助,链接:华为云论坛云计算论坛开发者论坛_技术论坛-华为云 (huaweicloud.com)。在做模型转换前,最好用netron确定一下输出节点,找到正确输出节点,才能让om模型正确输出,netron下载链接:lutzroeder/netron: Visualizer for neural network, deep learning, and machine learning models (github.com)8. Mindstuido下载连接链接:(MindStudio下载-昇腾社区 (hiascend.com)9. 开发过程中用到的链接MindX SDK 2.0.4 mxVision 用户指南:MindX SDK 2.0.4 mxVision 用户指南 01 - 华为 (huawei.com)CANN安装指南(在用MindStudio可能会由于权限问题,导致远端CANN开发包同步不到本地,可以安装该包到用户目录下) :在昇腾设备上安装 - CANN 5.0.4 软件安装指南 01 - 华为 (huawei.com)基于MindStudio的MindX SDK应用开发全流程:基于MindStudio的MindX SDK应用开发全流程哔哩哔哩bilibili
  • [技术干货] 深度学习——VGG16模型详解-转载
     1、网络结构  VGG16模型很好的适用于分类和定位任务,其名称来自牛津大学几何组(Visual Geometry Group)的缩写。  根据卷积核的大小核卷积层数,VGG共有6种配置,分别为A、A-LRN、B、C、D、E,其中D和E两种是最为常用的VGG16和VGG19。  介绍结构图:  conv3-64 :是指第三层卷积后维度变成64,同样地,conv3-128指的是第三层卷积后维度变成128; input(224x224 RGB image) :指的是输入图片大小为224244的彩色图像,通道为3,即224224*3; maxpool :是指最大池化,在vgg16中,pooling采用的是2*2的最大池化方法(如果不懂最大池化,下面有解释); FC-4096 :指的是全连接层中有4096个节点,同样地,FC-1000为该层全连接层有1000个节点; padding:指的是对矩阵在外边填充n圈,padding=1即填充1圈,5X5大小的矩阵,填充一圈后变成7X7大小; 最后补充,vgg16每层卷积的滑动步长stride=1,padding=1,卷积核大小为333;    如上图VGG16的网络结构为,VGG由5层卷积层、3层全连接层、softmax输出层构成,层与层之间使用max-pooling(最大化池)分开,所有隐层的激活单元都采用ReLU函数。具体信息如下:  卷积-卷积-池化-卷积-卷积-池化-卷积-卷积-卷积-池化-卷积-卷积-卷积-池化-卷积-卷积-卷积-池化-全连接-全连接-全连接  通道数分别为64,128,512,512,512,4096,4096,1000。卷积层通道数翻倍,直到512时不再增加。通道数的增加,使更多的信息被提取出来。全连接的4096是经验值,当然也可以是别的数,但是不要小于最后的类别。1000表示要分类的类别数。 用池化层作为分界,VGG16共有6个块结构,每个块结构中的通道数相同。因为卷积层和全连接层都有权重系数,也被称为权重层,其中卷积层13层,全连接3层,池化层不涉及权重。所以共有13+3=16层。 对于VGG16卷积神经网络而言,其13层卷积层和5层池化层负责进行特征的提取,最后的3层全连接层负责完成分类任务。 2、VGG16的卷积核  VGG使用多个较小卷积核(3x3)的卷积层代替一个卷积核较大的卷积层,一方面可以减少参数,另一方面相当于进行了更多的非线性映射,可以增加网络的拟合/表达能力。 卷积层全部都是3*3的卷积核,用上图中conv3-xxx表示,xxx表示通道数。其步长为1,用padding=same填充。 池化层的池化核为2*2 3、卷积计算   具体的过程:  输入图像尺寸为224x224x3,经64个通道为3的3x3的卷积核,步长为1,padding=same填充,卷积两次,再经ReLU激活,输出的尺寸大小为224x224x64 经max pooling(最大化池化),滤波器为2x2,步长为2,图像尺寸减半,池化后的尺寸变为112x112x64 经128个3x3的卷积核,两次卷积,ReLU激活,尺寸变为112x112x128 max pooling池化,尺寸变为56x56x128 经256个3x3的卷积核,三次卷积,ReLU激活,尺寸变为56x56x256 max pooling池化,尺寸变为28x28x256 经512个3x3的卷积核,三次卷积,ReLU激活,尺寸变为28x28x512 max pooling池化,尺寸变为14x14x512 经512个3x3的卷积核,三次卷积,ReLU,尺寸变为14x14x512 max pooling池化,尺寸变为7x7x512 然后Flatten(),将数据拉平成向量,变成一维51277=25088。 再经过两层1x1x4096,一层1x1x1000的全连接层(共三层),经ReLU激活 最后通过softmax输出1000个预测结果 从上面的过程可以看出VGG网络结构还是挺简洁的,都是由小卷积核、小池化核、ReLU组合而成。其简化图如下(以VGG16为例):    4、权重参数(不考虑偏置)  1)输入层有0个参数,所需存储容量为224x224x3=150k 2)对于第一层卷积,由于输入图的通道数是3,网络必须要有通道数为3的的卷积核,这样的卷积核有64个,因此总共有(3x3x3)x64 = 1728个参数。 所需存储容量为224x224x64=3.2M 计算量为:输入图像224×224×3,输出224×224×64,卷积核大小3×3。  所以Times=224×224×3x3×3×64=8.7×107  3)池化层有0个参数,所需存储容量为 图像尺寸x图像尺寸x通道数=xxx k 4)全连接层的权重参数数目的计算方法为:前一层节点数×本层的节点数。因此,全连接层的参数分别为: 7x7x512x4096 = 1027,645,444 4096x4096 = 16,781,321 4096x1000 = 4096000 按上述步骤计算的VGG16整个网络总共所占的存储容量为24M*4bytes=96MB/image 。  所有参数为138M VGG16具有如此之大的参数数目,可以预期它具有很高的拟合能力;  但同时缺点也很明显: 即训练时间过长,调参难度大。 需要的存储容量大,不利于部署。 5、VGG模型所需要的内存容量  借鉴一下大佬的图:    6、总结  通过增加深度能有效地提升性能; VGG16是最佳的模型,从头到尾只有3x3卷积与2x2池化,简洁优美; 卷积可代替全连接,可适应各种尺寸的图片。 ———————————————— 版权声明:本文为CSDN博主「橙子吖21」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_42012782/article/details/123222042 
总条数:1268 到第
上滑加载中