【2023 · CANN训练营第一季】- 昇腾AI入门课(PyTorch)第三章 AI应用开发 学习笔记

本文介绍了基于昇腾AI架构的学习目标,包括理解全栈架构、CANN的作用,以及应用开发流程。详细讲解了使用Caffe的ResNet-50模型进行图像分类,涵盖模型转换、代码逻辑、编译运行应用的步骤,并提到了问题求助渠道和日志查看方法。
摘要由CSDN通过智能技术生成

一、学习目标

1.了解昇腾Al全栈架构及该架构中各层的作用。

2.了解异构计算架构CANN在昇腾Al全栈中的位置和作用。

3.了解应用开发编程框架、基本概念。

4.掌握基本的应用开发流程,可以按照指导编译、运行应用。

5.了解如何获取及查看应用运行日志,具备基本的问题定界、定位能力。

二、遇到问题求助

开发、编译或运行应用出错时无法解决问题或有优化建议要反馈,可以借助以下渠道:

1.参考CANN Sample仓中的样例开发时,相关问题可以在该仓上提Issue,该仓的接口人会定期处理问题。

2.模型相关的问题,可在ModelZoo仓上提lssue,该仓的接口人会定期处理问题。

3.也可在昇腾社区论坛中查阅经验贴、或者发求助帖,论坛上的其他开发人员会跟帖,论坛的接口人也会定期审视问题。

三、Ascend基础

 

 

 

四、图片分类应用开发

1.图像分类应用简介

使用Caffe框架的ResNet-50模型

输入数据:RGB格式、224*224分辨率的输入图片

输出数据:图片的类别标签及其对应置信度

 2.开发流程

 3. 开发应用

 (1)创建代码目录

MyFirstApp
├── data
│   ├── dog1_1024_683.jpg            // 测试图片

├── model
│   ├── resnet50.caffemodel          // ResNet-50网络的预训练模型文件(*.caffemodel)
│   ├── resnet50.prototxt            // ResNet-50网络的模型文件(*.prototxt)                   

├── script
│   ├── transferPic.py               // 将测试图片预处理为符合模型要求的图片
                                        // 包括将*.jpg转换为*.bin,同时将图片从1024*683的分辨率缩放为224*224
├── src
│   ├── CMakeLists.txt              // cmake编译脚本
│   ├── main.cpp                    // 主函数,图片分类功能的实现文件

├── sample_build.sh                  // 编译代码的脚本

├── sample_run.sh                    // 运行应用的脚本

(2)准备模型

以运行用户将MyFirstApp目录上传至开发环境。

以运行用户登录开发环境,执行以下命令进行模型转换。

atc --model=model/resnet50.prototxt --weight=model/resnet50.caffemodel --framework=0 --output=model/resnet50 --soc_version=Ascend310

 相关参数

(3)应用代码逻辑

根据过程详解,以“MyFirstApp/src/main.cpp”中main函数展示整个应用代码逻辑

int main()
{	
        // 1.定义一个资源初始化的函数,用于AscendCL初始化、运行管理资源申请(指定计算设备)
	InitResource();
	
        // 2.定义一个模型加载的函数,加载图片分类的模型,用于后续推理使用
	const char *modelPath = "../model/resnet50.om";
	LoadModel(modelPath);
	
        // 3.定义一个读图片数据的函数,将测试图片数据读入内存,并传输到Device侧,用于后续推理使用
        const char *picturePath = "../data/dog1_1024_683.bin";
	LoadPicture(picturePath);
	
        // 4.定义一个推理的函数,用于执行推理
	Inference();
	
        // 5.定义一个推理结果数据处理的函数,用于在终端上屏显测试图片的top5置信度的类别编号
	PrintResult();
	
        // 6.定义一个模型卸载的函数,卸载图片分类的模型
	UnloadModel();
	
        // 7.定义一个函数,用于释放内存、销毁推理相关的数据类型,防止内存泄露
	UnloadPicture();
	
        // 8.定义一个资源去初始化的函数,用于AscendCL去初始化、运行管理资源释放(释放计算设备)
	DestroyResource();
}

(4)应用代码完善

以下代码添加在(3)中代码之前

a. include头文件

#include "acl/acl.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include <map>

using namespace std;

b. 资源初始化

int32_t deviceId = 0;
void InitResource()
{
	aclError ret = aclInit(nullptr);
	ret = aclrtSetDevice(deviceId);
}

c. 模型加载

uint32_t modelId;
void LoadModel(const char* modelPath)
{
	aclError ret = aclmdlLoadFromFile(modelPath, &modelId);
}

d. 将测试图片读入内存,在传输到Device侧,供推理使用

size_t pictureDataSize = 0;
void *pictureHostData;
void *pictureDeviceData;

//申请内存,使用C/C++标准库的函数将测试图片读入内存
void ReadPictureTotHost(const char *picturePath)
{
	string fileName = picturePath;
	ifstream binFile(fileName, ifstream::binary);
	binFile.seekg(0, binFile.end);
	pictureDataSize = binFile.tellg();
	binFile.seekg(0, binFile.beg);
	aclError ret = aclrtMallocHost(&pictureHostData, pictureDataSize);
	binFile.read((char*)pictureHostData, pictureDataSize);
	binFile.close();
}

//申请Device侧的内存,再以内存复制的方式将内存中的图片数据传输到Device
void CopyDataFromHostToDevice()
{
	aclError ret = aclrtMalloc(&pictureDeviceData, pictureDataSize, ACL_MEM_MALLOC_HUGE_FIRST);
	ret = aclrtMemcpy(pictureDeviceData, pictureDataSize, pictureHostData, pictureDataSize, ACL_MEMCPY_HOST_TO_DEVICE);
}

void LoadPicture(const char* picturePath)
{
	ReadPictureTotHost(picturePath);
	CopyDataFromHostToDevice();
}

e.执行推理

数据类型

 

aclmdlDataset *inputDataSet;
aclDataBuffer *inputDataBuffer;
aclmdlDataset *outputDataSet;
aclDataBuffer *outputDataBuffer;
aclmdlDesc *modelDesc;
size_t outputDataSize = 0;
void *outputDeviceData;

// 准备模型推理的输入数据结构
void CreateModelInput()
{
        // 创建aclmdlDataset类型的数据,描述模型推理的输入
	inputDataSet = aclmdlCreateDataset();
	inputDataBuffer = aclCreateDataBuffer(pictureDeviceData, pictureDataSize);
	aclError ret = aclmdlAddDatasetBuffer(inputDataSet, inputDataBuffer);
}

// 准备模型推理的输出数据结构
void CreateModelOutput()
{
       // 创建模型描述信息
	modelDesc =  aclmdlCreateDesc();
	aclError ret = aclmdlGetDesc(modelDesc, modelId);
        // 创建aclmdlDataset类型的数据,描述模型推理的输出
	outputDataSet = aclmdlCreateDataset();
        // 获取模型输出数据需占用的内存大小,单位为Byte
	outputDataSize = aclmdlGetOutputSizeByIndex(modelDesc, 0);
        // 申请输出内存
	ret = aclrtMalloc(&outputDeviceData, outputDataSize, ACL_MEM_MALLOC_HUGE_FIRST);
	outputDataBuffer = aclCreateDataBuffer(outputDeviceData, outputDataSize);
	ret = aclmdlAddDatasetBuffer(outputDataSet, outputDataBuffer);
}

// 执行模型
void Inference()
{
        CreateModelInput();
	CreateModelOutput();
	aclError ret = aclmdlExecute(modelId, inputDataSet, outputDataSet);
}

f.推理结果数据处理并打印

void *outputHostData;

void PrintResult()
{
        // 获取推理结果数据
	aclError ret = aclrtMallocHost(&outputHostData, outputDataSize);
	ret = aclrtMemcpy(outputHostData, outputDataSize, outputDeviceData, outputDataSize, ACL_MEMCPY_DEVICE_TO_HOST);
        // 将内存中的数据转换为float类型
	float* outFloatData = reinterpret_cast<float *>(outputHostData);
	
        // 屏显测试图片的top5置信度的类别编号
	map<float, unsigned int, greater<float>> resultMap;
	for (unsigned int j = 0; j < outputDataSize / sizeof(float);++j)
	{
		resultMap[*outFloatData] = j;
		outFloatData++;
	}
	
	int cnt = 0;
	for (auto it = resultMap.begin();it != resultMap.end();++it)
	{
		if(++cnt > 5)
		{
			break;
		}
		printf("top %d: index[%d] value[%lf] \n", cnt, it->second, it->first);
	}
}

g. 卸载模型,并释放模型描述信息。

void UnloadModel()
{
        // 释放模型描述信息
	aclmdlDestroyDesc(modelDesc);
        // 卸载模型
	aclmdlUnload(modelId);
}

h. 释放内存、销毁推理相关的数据类型

void UnloadPicture()
{
	aclError ret = aclrtFreeHost(pictureHostData);
	pictureHostData = nullptr;
	ret = aclrtFree(pictureDeviceData);
	pictureDeviceData = nullptr;
	aclDestroyDataBuffer(inputDataBuffer);
	inputDataBuffer = nullptr;
	aclmdlDestroyDataset(inputDataSet);
	inputDataSet = nullptr;
	
	ret = aclrtFreeHost(outputHostData);
	outputHostData = nullptr;
	ret = aclrtFree(outputDeviceData);
	outputDeviceData = nullptr;
	aclDestroyDataBuffer(outputDataBuffer);
	outputDataBuffer = nullptr;
	aclmdlDestroyDataset(outputDataSet);
	outputDataSet = nullptr;
}

i. 资源释放

void DestroyResource()
{
	aclError ret = aclrtResetDevice(deviceId);
	aclFinalize();
}

4. 编译并运行应用

(1)编译代码

以运行用户登录开发环境,切换到MyFirstApp目录下,执行以下命令。

export APP_SOURCE_PATH=${SAMPLE_DIR}/MyFirstApp
export DDK_PATH=${INSTALL_DIR}
export NPU_HOST_LIB=${INSTALL_DIR}/acllib/lib64/stub
chmod +x sample_build.sh
./sample_build.sh

${SAMPLE_DIR}表示样例所在的目录,

${INSTALL_DIR}表示CANN软件安装目录,

arch表示操作系统架构(需根据运行环境的架构选择),

{os}表示操作系统(需根据运行环境的操作系统选择)。

(2)运行应用

MyFirstApp目录下,执行以下命令

chmod +x sample_run.sh
./sample_run.sh

5.获取运行日志

1日志的默认目录为CANN软件安装目录/asced/log

(2)日志文件介绍

 

 3日志的默认输出方式为将日志保存在log文件中,也可以通过以下命令将日志打屏显示。

export ASCEND_SLOG_PRINT_TO_STDOUT=1
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值