昇腾AscendCL推理应用开发入门教程(基于Python语言)

news2024/12/20 17:29:04

pyACL(Python Ascend Computing Language)是一套在AscendCL的基础上使用CPython封装得到的Python API库,使用户可以通过Python进行昇腾AI处理器的运行管理、资源管理等,实现在昇腾CANN平台上进行深度学习推理计算、图形图像预处理、单算子加速计算等能力。

了解了这些大步骤后,下面我们再展开来说明开发应用具体涉及哪些关键功能?各功能又使用哪些pyACL接口,这些pyACL接口怎么串联?

虽然此时您可能不理解所有细节,但这也不影响,通过快速入门旨在先了解整体的代码逻辑,后续再深入学习,了解其它细节。

工程创建

首先,在开发环境中下创建“first_app”代码目录。

first_app 
├── data 
│   ├── dog1_1024_683.jpg         //测试图片1 
│   └── dog2_1024_683.jpg         //测试图片2 
└── model                          //用于存放ONNX ResNet-50模型文件 
    └── resnet50.onnx
  • 准备测试数据,本次样例需要使用两张动物图片,请从以下链接获取,将下载好的图片上传至“first_app/data”目录。

cd $HOME/first_app/data 
wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog1_1024_683.jpg
cd $HOME/first_app/data 
wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog2_1024_683.jpg
  • 准备模型数据,将ONNX模型下载至“model”目录。

cd $HOME/first_app/model wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/003_Atc_Models/resnet50/resnet50.onnx
  • 模型转换,对于开源框架的模型,不能直接在昇腾AI处理器上进行推理,需要使用ATC(Ascend Tensor Compiler)工具将开源框架的网络模型转换为适配昇腾AI处理器的离线模型(*.om文件)。

执行以下命令(以昇腾310P AI处理器为例),将原始模型转换为昇腾AI处理器能识别的*.om模型文件。请注意,执行命令的用户需具有命令中相关路径的可读、可写权限。

atc --model=resnet50.onnx --framework=5 --output=resnet50 --input_shape="actual_input_1:1,3,224,224" --soc_version=Ascend310P3

− --model:ResNet-50网络的模型文件的路径。

− --framework:原始框架类型。5表示ONNX。

− --output:resnet50.om模型文件的路径。请注意,记录保存该om模型文件的路径,后续开发应用时需要使用。

− --input_shape:模型输入数据的shape。

− --soc_version:昇腾AI处理器的版本。

说明:如果无法确定当前设备的soc_version,则在安装NPU驱动包的服务器执行npu-smi info命令进行查询,在查询到的“Name”前增加“Ascend”信息,例如“Name”对应取值为“310P3”,实际配置的“soc_version”值为“Ascend310P3”。

应用开发

在“first_app”目录下创建“first_app.py”文件并依次写入以下内容。

步骤 1 引入pyACL必要的模块,定义pyACL常量。

import os 
 
import acl 
import numpy as np 
from PIL import Image 
 
ACL_MEM_MALLOC_HUGE_FIRST = 0 
ACL_MEMCPY_HOST_TO_DEVICE = 1 
ACL_MEMCPY_DEVICE_TO_HOST = 2

步骤 2 定义模型对象。

网络模型对象中应当包含以下函数。

  • 初始化函数。

  • 执行推理任务函数。

  • 析构函数。

对于后续的使用,用户只需要调用网络模型中的forward函数,传入对应的输入数据即可获得相应的输出。

class net: 
 
#   def __init__(self, model_path): 
        # 初始化函数,需要在后续步骤中实现。 
 
#   def forward(self, inputs): 
        # 执行推理任务,需要在后续步骤中实现。 
 
#   def __del__(self): 
        # 析构函数,按照初始化资源的相反顺序释放资源,需要在后续步骤中实现。

步骤 3 实现初始化方法,具体涉及以下步骤(请在net类中实现)。

1. 调用acl.init接口进行初始化,在使用pyACL开发应用时,需要先初始化pyACL(在完成所有pyACL接口调用后,还需进行去初始化)。初始化时,也可通过JSON配置文件,向初始化接口传入配置参数(例如,传入性能相关的采集信息配置)。

2. 通过ID,调用acl.rt.set_device接口指定具体的计算设备(Device)。

3. 加载模型。

  a. 在此处样例选择调用acl.mdl.load_from_file接口加载om模型文件。

  b. 调用acl.mdl.create_desc接口创建模型描述信息。

  c. 根据加载成功的模型ID,调用acl.mdl.get_desc接口获取该模型的描述信息。

4. 创建输入数据集与输出数据集,对应方法在步骤4中实现。

def __init__(self, model_path): 
     # 初始化函数 
     self.device_id = 0 
 
     # step1: 初始化 
     ret = acl.init() 
     # 指定运算的Device 
     ret = acl.rt.set_device(self.device_id) 
 
     # step2: 加载模型,本示例为ResNet-50模型 
     # 加载离线模型文件,返回标识模型的ID 
     self.model_id, ret = acl.mdl.load_from_file(model_path) 
     # 创建空白模型描述信息,获取模型描述信息的指针地址 
     self.model_desc = acl.mdl.create_desc() 
     # 通过模型的ID,将模型的描述信息填充到model_desc 
     ret = acl.mdl.get_desc(self.model_desc, self.model_id) 
 
     # step3:创建输入输出数据集 
     # 创建输入数据集 
     self.input_dataset, self.input_data = self.prepare_dataset('input') 
     # 创建输出数据集 
     self.output_dataset, self.output_data = self.prepare_dataset('output')

步骤 4 实现数据集创建方法(请在net类中实现)。

在调用pyACL接口进行模型推理时,模型推理有输入、输出数据,输入、输出数据需要按照pyACL规定的数据类型存放。相关数据类型如下:

  • 使用aclmdlDesc类型的数据描述模型基本信息(例如输入/输出的个数、名称、数据类型、Format、维度信息等)。

模型加载成功后,用户可根据模型的ID,调用该数据类型下的操作接口获取该模型的描述信息,进而从模型的描述信息中获取模型输入/输出的个数、内存大小、维度信息、Format、数据类型等信息。

  • 使用aclDataBuffer类型的数据来描述每个输入/输出的内存地址、内存大小。

调用aclDataBuffer类型下的操作接口获取内存地址、内存大小等,便于向内存中存放输入数据、获取输出数据。

  • 使用aclmdlDataset类型的数据描述模型的输入/输出数据。

模型可能存在多个输入、多个输出,调用aclmdlDataset类型的操作接口添加多个aclDataBuffer类型的数据。

aclmdlDataset类型与aclDataBuffer类型的关系

def prepare_dataset(self, io_type): 
     # 准备数据集 
     if io_type == "input": 
         # 获得模型输入的个数 
         io_num = acl.mdl.get_num_inputs(self.model_desc) 
         acl_mdl_get_size_by_index = acl.mdl.get_input_size_by_index 
     else: 
         # 获得模型输出的个数 
         io_num = acl.mdl.get_num_outputs(self.model_desc) 
         acl_mdl_get_size_by_index = acl.mdl.get_output_size_by_index 
     # 创建aclmdlDataset类型的数据,描述模型推理的输入。 
     dataset = acl.mdl.create_dataset() 
     datas = [] 
     for i in range(io_num): 
         # 获取所需的buffer内存大小 
         buffer_size = acl_mdl_get_size_by_index(self.model_desc, i) 
         # 申请buffer内存 
         buffer, ret = acl.rt.malloc(buffer_size, ACL_MEM_MALLOC_HUGE_FIRST) 
         # 从内存创建buffer数据 
         data_buffer = acl.create_data_buffer(buffer, buffer_size) 
         # 将buffer数据添加到数据集 
         _, ret = acl.mdl.add_dataset_buffer(dataset, data_buffer) 
         datas.append({"buffer": buffer, "data": data_buffer, "size": buffer_size}) 
     return dataset, datas

步骤 5 实现同步推理方法(请在net类中实现)。

 def forward(self, inputs): 
     # 执行推理任务 
     # 遍历所有输入,拷贝到对应的buffer内存中 
     input_num = len(inputs) 
     for i in range(input_num): 
         bytes_data = inputs[i].tobytes() 
         bytes_ptr = acl.util.bytes_to_ptr(bytes_data) 
         # 将图片数据从Host传输到Device。 
         ret = acl.rt.memcpy(self.input_data[i]["buffer"],   # 目标地址 device 
                             self.input_data[i]["size"],     # 目标地址大小 
                             bytes_ptr,                      # 源地址 host 
                             len(bytes_data),                # 源地址大小 
                             ACL_MEMCPY_HOST_TO_DEVICE)      # 模式:从host到device 
     # 执行模型推理。 
     ret = acl.mdl.execute(self.model_id, self.input_dataset, self.output_dataset) 
     # 处理模型推理的输出数据,输出top5置信度的类别编号。 
     inference_result = [] 
     for i, item in enumerate(self.output_data): 
         buffer_host, ret = acl.rt.malloc_host(self.output_data[i]["size"]) 
         # 将推理输出数据从Device传输到Host。 
         ret = acl.rt.memcpy(buffer_host,                    # 目标地址 host 
                             self.output_data[i]["size"],    # 目标地址大小 
                             self.output_data[i]["buffer"],  # 源地址 device 
                             self.output_data[i]["size"],    # 源地址大小 
                             ACL_MEMCPY_DEVICE_TO_HOST)      # 模式:从device到host 
         # 从内存地址获取bytes对象 
         bytes_out = acl.util.ptr_to_bytes(buffer_host, self.output_data[i]["size"]) 
         # 按照float32格式将数据转为numpy数组 
         data = np.frombuffer(bytes_out, dtype=np.float32) 
         inference_result.append(data) 
     vals = np.array(inference_result).flatten() 
     # 对结果进行softmax转换 
     vals = np.exp(vals) 
     vals = vals / np.sum(vals) 
 
     return vals

步骤 6 实现析构方法(请在net类中实现)。

1. 销毁数据集资源(buffer数据、buffer内存、输入数据集、输出数据集)。

2. 销毁模型描述、卸载模型。

3. 释放计算资源。

4. 所有pyACL接口调用结束后(或在进程退出前),调用acl.finalize接口进行pyACL进行去初始化。

在推理过程中可能会抛出异常,请将资源释放步骤实现在析构方法中确保资源能够得到正确释放。以下内容仅供参考,实际情况下需要考虑更多情况下的资源释放问题。

def __del__(self): 
     # 析构函数 按照初始化资源的相反顺序释放资源。 
     # 销毁输入输出数据集 
     for dataset in [self.input_data, self.output_data]: 
         while dataset: 
             item = dataset.pop() 
             ret = acl.destroy_data_buffer(item["data"])    # 销毁buffer数据 
             ret = acl.rt.free(item["buffer"])              # 释放buffer内存 
     ret = acl.mdl.destroy_dataset(self.input_dataset)      # 销毁输入数据集 
     ret = acl.mdl.destroy_dataset(self.output_dataset)     # 销毁输出数据集 
     # 销毁模型描述 
     ret = acl.mdl.destroy_desc(self.model_desc) 
     # 卸载模型 
     ret = acl.mdl.unload(self.model_id) 
     # 释放device 
     ret = acl.rt.reset_device(self.device_id) 
     # acl去初始化 
     ret = acl.finalize()

步骤 7 实现图像预处理函数。

def transfer_pic(input_path): 
    # 图像预处理 
    input_path = os.path.abspath(input_path) 
    with Image.open(input_path) as image_file: 
        # 缩放为224*224 
        img = image_file.resize((224, 224)) 
        # 转换为float32类型ndarray 
        img = np.array(img).astype(np.float32) 
    # 根据imageNet图片的均值和方差对图片像素进行归一化 
    img -= [123.675, 116.28, 103.53] 
    img /= [58.395, 57.12, 57.375] 
    # RGB通道交换顺序为BGR 
    img = img[:, :, ::-1] 
    # resnet50为色彩通道在前 
    img = img.transpose((2, 0, 1)) 
    # 返回并添加batch通道 
    return np.array([img])

步骤 8 调用forward函数(具体实现请参见步骤5),执行同步推理并在屏幕中打印top5类别编号及置信度。

def print_top_5(data): 
    top_5 = data.argsort()[::-1][:5] 
    print("======== top5 inference results: =============") 
    for j in top_5: 
        print("[%d]: %f" % (j, data[j])) 
 
if __name__ == "__main__": 
    resnet50 = net('./model/resnet50.om') 
    image_paths = ["./data/dog1_1024_683.jpg", "./data/dog2_1024_683.jpg"] 
    for path in image_paths: 
        # 图像预处理,此处仅供参考,用户按照自己需求进行预处理 
        image = transfer_pic(path) 
        # 将数据按照每个输入的顺序构造list传入,当前示例的ResNet-50模型只有一个输入 
        result = resnet50.forward([image]) 
        # 输出top_5 
        print_top_5(result) 
 
    del resnet50

----结束

运行应用

将编写好的“first_app”文件夹及内容上传到运行环境,进入到代码目录下,检查环境变量配置是否正确,然后执行以下命令。

python3 first_app.py

可以得到如下输出,分别为两张测试图片的top5分类信息。

其中[161]: 0.809159表示的是类别标识索引“161”的置信度为“0.809159”。

======== top5 inference results: ============= 
[161]: 0.809159 
[162]: 0.103680 
[178]: 0.017600 
[166]: 0.013922 
[212]: 0.009644 
======== top5 inference results: ============= 
[267]: 0.728299 
[266]: 0.101693 
[265]: 0.100117 
[151]: 0.004214 
[160]: 0.002721

说明:类别标签和类别的对应关系与训练模型时使用的数据集有关,本样例使用的模型是基于imagenet数据集进行训练的,您可以在互联网上查阅对应数据集的标签及类别的对应关系。 当前屏显信息中的类别标识与类别的对应关系如下: "161": ["basset", "basset hound"] "162": ["beagle"] "163": ["bloodhound", "sleuthhound"] "166": ["Walker hound", "Walker foxhound"] "167": ["English foxhound"]

这样,我们就完成了一个简单的推理应用程序的开发和运行,感兴趣的小伙伴可以参考以下资料完成更系统的学习:

− 获取学习文档:请单击Link

− 获取更多样例,请单击Link

− 获取在线视频课程,请单击Link

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

表结构的操作【MySQL】

文章目录 创建表例子 查看表结构修改表新增列属性修改列属性修改列名修改表名删除列 删除表 阅读前导: 一般来说,对表的操作可以分为对表结构和对表内容的操作。 对表结构的操作,就是用数据定义语言 DDL 来创建、修改或删除表中的对象&#…

elementUI 中 date-picker 的使用的坑(vue3)

目录 1. 英文显示2. format 与 value-format 无效3. date-picker 时间范围4. 小结 1. 英文显示 <el-date-pickerv-model"dateValue"type"date"placeholder"选择日期"></el-date-picker>解决方案&#xff1a; 引用 zhCn <script&g…

web开发初级工程师学习笔记

web开发初级工程师学习笔记 前端开发工具实验1 VS Code 初体验介绍 前端开发工具 实验1 VS Code 初体验 介绍 VS Code 环境提供的是一个可以在浏览器中使用原生 VS Code 编辑代码的程序。在该环境中&#xff0c;你可以使用到与本地安装近乎一致的 VS Code 程序来编辑代码文件…

PAM从入门到精通(十九)

接前一篇文章&#xff1a;PAM从入门到精通&#xff08;十八&#xff09; 本文参考&#xff1a; 《The Linux-PAM Application Developers Guide》 PAM 的应用开发和内部实现源码分析 先再来重温一下PAM系统架构&#xff1a; 更加形象的形式&#xff1a; 六、整体流程示例 2.…

linux安装visual studio code

下载 https://code.visualstudio.com/ 下载.deb文件 安装 假如文件被下载到了 /opt目录下 进入Opt目录&#xff0c;右键从当前目录打开终端。 输入下面的安装命令。 sudo apt-get install ./code_1.83.1-1696982868_amd64.deb 安装成功。 配置 打开 visual studio cod…

博客续更(五)

十一、后台模块-菜单列表 菜单指的是权限菜单&#xff0c;也就是一堆权限字符串 1. 查询菜单 1.1 接口分析 需要展示菜单列表&#xff0c;不需要分页。可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询。菜单要按照父菜单id和orderNum进行排序 请求方式 请求路径…

Sentinel授权规则和规则持久化

大家好我是苏麟 , 今天说说Sentinel规则持久化. 授权规则 授权规则可以对请求方来源做判断和控制。 授权规则 基本规则 授权规则可以对调用方的来源做控制&#xff0c;有白名单和黑名单两种方式。 白名单&#xff1a;来源&#xff08;origin&#xff09;在白名单内的调用…

Linux下Jenkins自动化部署SpringBoot应用

Linux下Jenkins自动化部署SpringBoot应用 1、 Jenkins介绍 官方网址&#xff1a;https://www.jenkins.io/ 2、安装Jenkins 2.1 centos下命令行安装 访问官方&#xff0c;点击文档&#xff1a; 点击 Installing Jenkins&#xff1a; 点击 Linux&#xff1a; 选择 Red Hat/…

H3C IMC dynamiccontent.properties.xhtm 远程命令执行

我举手向苍穹&#xff0c;并非一定要摘星取月&#xff0c;我只是需要这个向上的、永不臣服的姿态。 构造payload&#xff1a; /imc/javax.faces.resource/dynamiccontent.properties.xhtml pfdrtsc&lnprimefaces&pfdriduMKljPgnOTVxmOB%2BH6%2FQEPW9ghJMGL3PRdkfmbii…

智慧公厕设备选型攻略,打造智能化便利生活体验

智慧公厕设备的选型对于打造智能化便利生活体验起着至关重要的作用。在不断提升城市品质的背景下&#xff0c;智慧公厕已成为城市建设中的一项重要内容。在选购智慧公厕设备时&#xff0c;我们需要考虑到不同版本的功能要求&#xff0c;确保公厕设备的质量和性能。本文以智慧公…

[代码随想录]回溯、贪心算法篇

文章目录 1.回溯算法1.1 77-组合1.2 216-组合的综合III1.3 17-电话号码的字母组合1.4 39-组合总和1.5 40-组合总和II1.6 131-分割回文串1.7 93-复原IP地址1.8 78-子集1.9 90-子集II1.10 491-递增子序列1.11 46-全排列1.12 47-全排列II1.13* 51-N皇后 2. 贪心算法2.1 455-分发饼…

QCC 音频输入输出

QCC 音频输入输出 QCC蓝牙芯片&#xff08;QCC3040 QCC3083 QCC3084 QCC5181 等等&#xff09;支持DAC、I2S、SPDIF输出&#xff0c;AUX、I2S、SPDIF、A2DP 输入 蓝牙音频输入&#xff0c;模拟输出是最常见的方式。 也可以再此基础上动态切换输入方式。 输入方式切换参考 sta…

设计模式:命令模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

简介&#xff1a; 命令模式&#xff0c;它是一种行为型设计模式&#xff0c;它尝试将请求或操作封装成对象&#xff0c;从而降低系统的耦合度&#xff0c;增加系统的可扩展性&#xff0c;并支持撤销、重做、事务等功能。 在命令模式中&#xff0c;请求被封装为一个独立的对象…

postgresql14-模式的管理(三)

基本概念 postgresql成为数据库管理系统DBMS&#xff0c;在内存中以进程的形态运行起来成为一个实例&#xff0c;可管理多个database。 数据库databases&#xff1a;包含表、索引、视图、存储过程&#xff1b; 模式schema&#xff1a;多个对象组成一个模式&#xff0c;多个模…

09-React路由使用(React Router 6)

9-React Router 6的使用 1.概述 React Router 以三个不同的包发布到 npm 上&#xff0c;它们分别为&#xff1a; react-router: 路由的核心库&#xff0c;提供了很多的&#xff1a;组件、钩子。react-router-dom: 包含react-router所有内容&#xff0c;并添加一些专门用于 DOM …

期中考misc复现

第一题 flow analysis 1 服务器附带的后门文件名是什么&#xff1f;&#xff08;包括文件后缀&#xff09; webshell是网站的后门&#xff0c;也是一个命令解释器。不过是以http协议这样的方式通信。继承了web权限 我们过滤http和https http && http.response.code…

机器学习中常见的特征工程处理

一、特征工程 特征工程&#xff08;Feature Engineering&#xff09;对特征进行进一步分析&#xff0c;并对数据进行处理。 常见的特征工程包括&#xff1a;异常值处理、缺失值处理、数据分桶、特征处理、特征构造、特征筛选及降维等。 1、异常值处理 具体实现 from scipy.s…

ant javac任务的fork和executable属性

ant javac任务是用于编译源文件的。 它的fork属性表示是否用JDK编译器在外部执行javac&#xff0c;取值可以为"yes"、“no”&#xff0c;默认值为"no"。 当fork属性的取值为"yes"时&#xff0c;可以用executable属性指明javac可执行文件的完全…

clion本地调试nginx-1.22.1

1 概述 nginx是一个多进程模型的流量代理软件&#xff0c;在本地调试时需要将它设置为单进程模式。 2 下载nginx源码 mkdir -p /opt/third-party cd /opt/third-party wget http://nginx.org/download/nginx-1.22.1.tar.gz tar xf nginx-1.22.1.tar.gz ls /opt/third-party…

Linux系统自有服务

一、Linux中防火墙firewalld 1、什么是防火墙 防火墙&#xff1a;防范一些网络攻击。有软件防火墙、硬件防火墙之分。 防火墙选择让正常请求通过&#xff0c;从而保证网络安全性。 Windows防火墙&#xff1a; Windows防火墙的划分与开启、关闭操作&#xff1a; 2、防火墙的作…