ResNet18 :使用MindStudio进行MindX SDK应用开发

ResNet18 :使用MindStudio进行MindX SDK应用开发

我的博客写的比较详细,大家可以根据目录查看自己需要的内容

文章目录

  • ResNet18 :使用MindStudio进行MindX SDK应用开发
    • **1 写在最前面**
    • **2 ResNet18简介**
    • **3 工具简介**
      • 3.1 MindX SDK介绍
      • 3.2 MindStudio
    • **4 环境搭建与配置**
      • 4.1 MindStudio 安装(Windows版本)
      • 4.2 SSH连接
      • 4.3 MindX SDK安装
    • **5 推理开发运行流程**
    • **6 业务开发**
      • **6.1 Python版本开发**
        • 6.1.1 新建一个项目
        • 6.1.2 代码目录结构
        • 6.1.3 模型转换
        • 6.1.4 pipeline文件编排
        • 6.1.5 main.py文件编写
        • 6.1.6 代码运行
      • **6.2 C++版本开发**
        • 6.2.1 新建一个项目
        • 6.2.2 代码目录结构
        • 6.2.3 模型转换(或者不转换)
        • 6.2.4 业务代码书写(修改)
        • 6.2.5 项目编译
        • 6.2.6 代码运行
    • **7 可参考的代码**
    • **8 FAQ**
      • 8.1 模型运行报错?
      • 8.2 如果想换个数据集怎么办?
      • 8.3 Python找不到模型路径?
      • 8.4 C++找不到模型路径?
      • 8.5 No Python interpreter configured for the module?
      • 8.6 SDK版本获取失败?
    • **9 结语**

1 写在最前面

这是一篇基于昇腾众智“ResNet18 for pytorch”代码的MindX SDK应用开发经验帖。原始项目代码可以从Ascend/ModelZoo-PyTorch - Gitee.com仓库中找到,根据原始项目代码,我们可以在MindStudio上快速实现一个ImageNet2012数据集1000分类应用的开发。

整个过程中,MindStudio昇腾论坛上的教程基于MindStudio的MindX SDK应用开发全流程_MindStudio_昇腾_华为云论坛 (huaweicloud.com)也提供了很大的帮助。

2 ResNet18简介

ResNet是ImageNet竞赛中分类问题效果较好的网络,它引入了残差学习的概念,通过增加直连通道来保护信息的完整性,解决信息丢失、梯度消失、梯度爆炸等问题,让很深的网络也得以训练。ResNet有不同的网络层数,常用的有18-layer、34-layer、50-layer、101-layer、152-layer。ResNet18的含义是指网络中有18-layer。

参考论文:He K, Zhang X, Ren S, et al. Deep residual learning for image recognition[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2016: 770-778.

3 工具简介

3.1 MindX SDK介绍

MindX SDK是华为昇腾AI处理器加速的AI软件开发套件(SDK), 提供了大量丰富的API,可以快速完成AI应用的开发

3.2 MindStudio

MindStudio提供了一个AI开发所需的一站式开发环境,支持模型开发、算子开发以及应用开发三个主流程中的开发任务
依靠模型可视化、算力测试、IDE本地仿真调试等功能,MindStudio能够帮助开发者在一个工具上就能高效便捷地完成AI应用开发
MindStudio采用了插件化扩展机制,开发者可以通过开发插件来扩展已有功能

官网地址:MindStudio-昇腾社区 (hiascend.com)

4 环境搭建与配置

因为我使用的Windows系统环境,所以这里提供Windows环境下MindStdio环境搭建和配置的全流程,其它系统可以查看安装方案-安装指南-MindStudio-文档首页-昇腾社区 (hiascend.com)

4.1 MindStudio 安装(Windows版本)

  1. 安装前的说明

    MindStudio可以单独安装在Windows上。在安装MindStudio前需要在Linux服务器上安装部署好Ascend-cann-toolkit开发套件包,之后在Windows上安装MindStudio,安装完成后通过配置远程连接的方式建立MindStudio所在的Windows服务器与Ascend-cann-toolkit开发套件包所在的Linux服务器的连接,实现全流程开发功能。

    我所采用的是windows共部署的方法

  2. 下载安装MindStudio

    前往MindStudio下载-昇腾社区 (hiascend.com)页面进行MindStudio软件包的下载,并且参照安装MindStudio-安装操作(Windows)完成MindStudio的安装。

4.2 SSH连接

在进行共部署之前,先确认SSH服务器连接成功

按照上面图中所示,依次配置之后,点击Test Connection,显示下图就表示连接成功。

4.3 MindX SDK安装

  1. 远端环境MindX SDK安装

    Windows 场景下基于 MindStuido 的 SDK 应用开发,请先确保远端环境上 MindX SDK 软件包已安装完成,安装方式请参见《mxManufacture 用户指南》和 《mxVision 用户指南》的“使用命令行方式开发”>“安装 MindX SDK 开发套件” 章节。

  2. 本地 CANN 安装

    ①:在 Windows 本地打开 MindStudio,点击 Customize > Allsettings…,如下图所示:

    ②:进入设置页面,点击 Appearance & Behavior > System Settings > CANN 进入 CANN 管理界面。

    完成后的状态如下图所示:

  3. 本地 MindX SDK安装

    与步骤 2 开始一致,进入设置页面,点击 Appearance & Behavior > System Settings > MindX SDK 进入 MindX SDK 管理界面。界面中 MindX SDK Location 为软件包的默认安装路径,默认安装路径为“C:\Users\用户名\Ascend\mindx_sdk”。 单击 Install SDK 进入 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”

5 推理开发运行流程

使用 MindStudio 开发和运行推理业务步骤如下:

​ (1) 确定业务流程:根据业务功能如目标检测、图像分类、属性识别等,将 业务流程进行模块化。

​ (2) 寻找合适插件:根据已有 SDK 插件的功能描述和规格限制来匹配业务功 能,当 SDK 提供的插件无法满足功能需求时,用户可以开发自定义插件。

​ (3) 准备推理模型文件与数据:准备输入图片和下载模型,使用 Model Convertor 模型转换工具将模型转换为 om 格式。

​ (4) 流程编排:以可视化的方式,开发数据流图,生成 pipeline 文件供应用框 架使用,配置文件以 json 格式编写,必须指定业务流名称、元件名称和 插件名称,并根据需要,补充元件属性和下游元件名称信息。

​ (5) 业务集成:编写 C++程序或 Python 程序,调用业务流管理的 API ( MxStreamManager ), 先 进 行 初 始 化 , 再 加 载 业 务 流 配 置 文 件 (*.pipeline),然后根据 stream 配置文件中的 StreamName 往指定 Stream 获取输出数据,最后销毁 Stream。

​ (6) 编译与运行应用:若新建的工程为 Python 版本的应用工程,不需要执行 编译应用工程,配置 Python 环境后,即可在远端服务器运行;若新建工 程为 C++版本的应用工程,则需要进行远端编译,远端编译时,会对工 程文件夹进行目录拷贝到远端连接的环境,编译成功后即可运行。

6 业务开发

业务开发将按照python版和C++版分别进行介绍

6.1 Python版本开发

6.1.1 新建一个项目

  • 首先创建一个项目,选择一个自己喜欢的位置,比如图中所示,将在D:\Codes\python\Ascend\MyApp位置下创建自己的项目。选择好了后,点击下一步
  • 选择MindX SDK Project(Python)

    如图所示,被圈出来的4个项目,上面两个是空模板,在这里面创建我们自己的工程项目,因为我们要创建Python版的应用,所以选箭头指的这个;下面两个是官方给出的样例项目,如果对目录结构和应该写哪些代码不太熟悉的话,也可以创建一个样例项目先学习一下。

    选择完成后,点击Finish完成项目的创建

6.1.2 代码目录结构

Python版本的SDK项目大概有哪些文件呢?我们其实可以先打开一个官方样例项目先看看

左边是我们自己创建的项目,右边是官方样例项目,对比之下我们可以发现,右边的样例项目主要有models(用于存储模型文件)、pipeline(流程编排文件)、python(项目python代码)和streamserver(实际开发中没用上)。

PS: 其实也不一定要按照这个目录结构存放代码,只是这样结构更加清晰一些。

我的工程目录文件是这样

其中data用来存放数据图片

6.1.3 模型转换

  • 下载模型

    首先我们先在ModelZoo-昇腾社区 (hiascend.com)中下载ResNet18模型和代码

    选Pytorch版

    分别下载模型脚本和模型

    其中模型脚本在“pipeline文件编排”和“main.py文件编写”章节得到应用

    解压后,我们只要这个onnx模型,同时,我们将names标签数据也一起放进models文件夹

  • 模型转换

    点击这个工具,进入模型转换界面

    选择待转换的模型路径

    选好后点一下任意一个位置,MindStudio会进入模型解析状态

    等待模型解析完成后,可以修改输出的模型名字,或者点击下一步

    点击Finish,开始转换

  • 转换完成

    稍等片刻,出现这个就表明转换完成

    如上图所示,在显示的路径中可以找到转化好的文件

    我们将om文件移动到models文件夹中,就可以进行接下去的步骤了

6.1.4 pipeline文件编排

pipeline文件编排是python版SDK最主要的推理开发步骤

作为一个图片分类任务,主要包括以下几个步骤:

初始化 → 图片数据传送 → 图片预处理 → 图片分类 → 序列化 → 结果传回

由于ResNet18模型采用的是PIL库进行图片预处理,而非opencv,因此我们不在pipeline中进行图片预处理步骤(包括图片解码、缩放、裁剪),而是通过在main.py文件中进行图片预处理,再将结果传给推理业务

因此pipeline流程编排为以下几个步骤

初始化 → 获取图片数据 → 图片分类 → 序列化 → 结果传回

可视化结果如下图所示:

实际上,我们可以通过对之前下载好的代码文件中已有的pipeline进行简单修改,就可以完成我们自己的pipeline文件编排

在下载好的ResNet18_for_PyTorch_{$version}__code中,路径./infer/sdk/data/config下可以找到resnet18.cfg和resnet8.pipeline两个文件,将这两个文件分别移动到models目录和pipeline目录下,如下图所示:

对resnet18.pipeline进行参数修改

我个人比较喜欢文本编辑的方式修改,如下图所示

修改完成后,就可以进行main.py文件的编写了,离成功运行越来越近了!

6.1.5 main.py文件编写

根据pipeline文件编排中的说明,我们在main.py中需要完成3件事——对图片进行预处理+将预处理好的结果传给推理业务+获取推理结果

实际上,我们依旧可以参考下载的代码文件中./infer/sdk/main.py文件中的做法,稍作修改就可以

(1) 图片预处理

主要用到resize、center_crop、preprocess和gen_protobuf(图片编码为推理业务需要的字节流)四个函数

参照下载代码中的main.py文件,很容易就能得到这四个函数

# resize and crop
def resize(img, size, interpolation=Image.BILINEAR):
    return img.resize(size[::-1], interpolation)

def center_crop(img, out_height, out_width):
    height, width, _ = img.shape
    left = int((width - out_width) / 2)
    right = int((width + out_width) / 2)
    top = int((height - out_height) / 2)
    bottom = int((height + out_height) / 2)
    img = img[top:bottom, left:right]
    return img
# preprocessor调用上面的两个函数进行图片缩放裁剪处理
def preprocess(in_file):
    mean = [0.485, 0.456, 0.406]
    std = [0.229, 0.224, 0.225]
    img = Image.open(in_file).convert('RGB')
    w = img.size[0]
    h = img.size[1]
    if w > h:
        input_size = np.array([256, 256 * w / h])
    else:
        input_size = np.array([256 * h / w, 256])
    input_size = input_size.astype(int)
    print(input_size)

    img = resize(img, input_size)  # transforms.Resize(256)
    img = np.array(img, dtype=np.float32)
    img = center_crop(img, 224, 224)   # transforms.CenterCrop(224)
    img = img / 255.  # transforms.ToTensor()
    img[..., 0] = (img[..., 0] - mean[0]) / std[0]
    img[..., 1] = (img[..., 1] - mean[1]) / std[1]
    img[..., 2] = (img[..., 2] - mean[2]) / std[2]

    img = img.transpose(2, 0, 1)   # HWC -> CHW
    return img
#generate protobuf调用preprocess生成传给推理业务的流数据
def gen_protobuf(in_file):
    img_np = preprocess(in_file)
    vision_list = MxpiDataType.MxpiVisionList()
    vision_vec = vision_list.visionVec.add()
    vision_vec.visionInfo.format = 0
    vision_vec.visionInfo.width = 224
    vision_vec.visionInfo.height = 224
    vision_vec.visionInfo.widthAligned = 224
    vision_vec.visionInfo.heightAligned = 224

    vision_vec.visionData.memType = 0
    vision_vec.visionData.dataStr = img_np.tobytes()
    vision_vec.visionData.dataSize = len(img_np)

    protobuf = MxProtobufIn()
    protobuf.key = b"appsrc0"
    protobuf.type = b'MxTools.MxpiVisionList'
    protobuf.protobuf = vision_list.SerializeToString()
    protobuf_vec = InProtobufVector()

    protobuf_vec.push_back(protobuf)
    return protobuf_vec

(2) main方法编写

main方法的编写,可以基于官方样例代码中的main方法,在那个基础上,调用我们自己的预处理函数再传值给推理业务即可

streamName: 业务流的名字,需要和pipeline文件中写的保持一致

6.1.6 代码运行

前面的步骤完成之后,我们就可以进行代码的运行了。

(1) 选择一张测试用图片

我们在data目录中放入自己想要的测试图片,比如我放的这张

然后在main.py中设置好图片位置

全部完成后应该为这样

(2) 设置运行脚本

接着,我们点击上图中箭头指的地方,设置运行脚本为main.py

(3) 获取运行结果

点击运行获得推理结果

我们可以看到,推理结果为golden retriver 金毛寻回犬

上网搜搜看,发现和我们测试的狗狗图片是一样的品种

6.2 C++版本开发

6.2.1 新建一个项目

可以参见“Python版本开发-新建一个项目”章节,这次我们选择的是C++开发

空项目应该为这样

6.2.2 代码目录结构

根据上图的说明,我们还需要建立一个models文件用于存放模型文件,完整的目录结构应该长这样

值得注意的是,这里多了一个preprocess.py文件,是用于预处理图片的,在下面“代码运行”章节会详细说明

6.2.3 模型转换(或者不转换)

和Python版本开发一样,可以对下载到的onnx模型进行转换,也因为转换好的模型其实就是下载的模型中的om模型,所以也可以直接拿来用。

6.2.4 业务代码书写(修改)

(1) 将下载到的代码中,./infer/mxbase中的src代码和CMakeLists.txt文件全部移动到src目录下

(2) 修改src代码

①修改路径

首先修改main.cpp中的文件路径

再修改编译文件中的代码路径

②修改业务代码

因为我们下载到的代码中,推理结果只保留了推理的类别编号,并且需要传入测试图片所在的父目录。

而我们想要让它测试一张图片,并且将推理结果输出类别名称,所以需要对main.cpp和Resnet18Classify.cpp中部分代码进行修改

main.cpp

主要修改传入图片的方法,像上图中一样,改为传单张图片

Resnet18Classify.cpp

主要修改一处,将结果储存到文本文件中的方法,修改为打印输出

ShowResult函数(记得在.h头文件中也添上这个方法)

APP_ERROR Resnet18Classify::ShowResult(const std::string &imgPath, std::vector<std::vector<MxBase::ClassInfo>> \
                                        &BatchClsInfos) {
    uint32_t batchIndex = 0;
    std::string fileName = imgPath.substr(imgPath.find_last_of("/") + 1);
    for (const auto &clsInfos : BatchClsInfos) {
        std::string resultStr;
        for (const auto &clsInfo : clsInfos) {
            resultStr += std::to_string(clsInfo.classId) + "," +
            clsInfo.className + "," + "confidence: " + std::to_string(clsInfo.confidence) + ";";
        }
        LogInfo << fileName << "->Result: " << resultStr;
        batchIndex++;
    }
    return APP_ERR_OK;
}

同时,在Process函数中,将SaveResult替换成ShowResult方法调用

Process函数

APP_ERROR Resnet18Classify::Process(const std::string &imgPath) { 
    std::vector<MxBase::TensorBase> inputs = {};
    std::string inputIdsFile = imgPath;
    APP_ERROR ret = ReadInputTensor(inputIdsFile, &inputs);
    if (ret != APP_ERR_OK) {
        LogError << "Read input ids failed, ret=" << ret << ".";
        return ret;
    }
    std::vector<MxBase::TensorBase> outputs = {};

    ret = Inference(inputs, outputs);
    if (ret != APP_ERR_OK) {
        LogError << "Inference failed, ret=" << ret << ".";
        return ret;
    }
    std::vector<std::vector<MxBase::ClassInfo>> BatchClsInfos = {};
    ret = PostProcess(outputs, BatchClsInfos);
    if (ret != APP_ERR_OK) {
        LogError << "PostProcess failed, ret=" << ret << ".";
        return ret;
    }

    ret = ShowResult(imgPath, BatchClsInfos);
    if (ret != APP_ERR_OK) {
        LogError << "Show result failed, ret=" << ret << ".";
        return ret;
    }
    return APP_ERR_OK;
}

Init函数中,注释掉生成txt文本的代码

全部完成后,就可以进行下一步了!

6.2.5 项目编译

业务代码写好之后,我们需要编译整个文件

点击编译后,等待下方提示编译成功后,就可以运行代码了!

编译好的文件在out目录下

6.2.6 代码运行

由于Resnet18用的预处理方法是PIL,C++中没有相应的图片处理方法,为了精度更高一些,我们需要稍微麻烦一下,使用python编写一个预处理方法prepreocess.py,将处理后的图片再传给C++代码运行

preprocess.py文件可以在下载好的代码中 ./infer/util中找到,根据实际需求稍作修改就可以使用。

因此我们先准备一张测试图片,比如下面这张,命名为test.jpg

①:先通过preprocess.py预处理生成test.bin

②:运行项目

先配置运行命令

点击运行

7 可参考的代码

我已经将自己写好的项目上传到了GitHub上,有需要可以参考

Python版SDK应用开发:https://github.com/Swgj/Resnet18_SDK.git

C++版SDK应用开发:https://github.com/Swgj/Resnet18_Mxbase.git

8 FAQ

8.1 模型运行报错?

  • 在模型转换的时候,是否注意了选择FP32? 默认状态下是FP16的方式进行转换。

  • 或者也可以直接将下载到的模型中的om模型文件直接拿来用

8.2 如果想换个数据集怎么办?

  • 可以参考modelzoo中,下载ResNet18模型的地方的说明。可以通过ModelArts训练快速进行迁移学习。

8.3 Python找不到模型路径?

  • 注意在pipeline流程编排中,模型路径若使用的是相对路径,则是相对main.py文件的位置的相对路径,而不是相对于pipeline文件的相对路径。因此注意根据自己的main.py文件位置修改模型的路径

8.4 C++找不到模型路径?

  • 检查自己此时代码中的模型路径是否和已经编译好的代码路径一致,C++已经编译完成后再修改代码,则需要重新编译才能运行修改后结果。

8.5 No Python interpreter configured for the module?

8.6 SDK版本获取失败?

  • 注意这两个地方要选子路径,选择父路径会找不到版本号

9 结语

MindStudio官方文档非常详细,不一而足。所以在一开始查看的时候难免会有种觉得东西太多,不知道从哪里下手的感觉。但随着开发过程的推进,逐渐发现官方文档才是开发者最应该参考的内容。此外,遇到问题时,也可以在MindStudio 昇腾社区论坛中得到许多启发,相信大家在自己动手的过程中也能体会到这一点。

Now, it’s time to get your hands dirty!

你可能感兴趣的:(AI,深度学习,人工智能,pytorch,c++,个人开发)