IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 华为Atlas200DK开发从零开始3.目标检测模型CANN部署——以YOLOX、YOLOv5和Nanodet为例(1)CANN接口调用 -> 正文阅读

[人工智能]华为Atlas200DK开发从零开始3.目标检测模型CANN部署——以YOLOX、YOLOv5和Nanodet为例(1)CANN接口调用

前言

平时喜欢玩开发板,之前在jetson nano,RK3399pro,英特尔神经计算棒上实现了各种深度学习算法的迁移部署,比较熟悉tensorrt,rknn,openvino各种花里胡哨的推理引擎

最近又接触了华为Atlas200DK开发板,体验了一把达芬奇架构的昇腾310NPU,实力的确不可小觑,在几天内的学习和努力下终于熟悉了与NPU配套的CANN计算框架(我比较喜欢叫推理引擎),因此分享一下使用CANN的pyACL接口部署YOLOX、YOLOv5和Nanodet的方法。

YOLOX是YOLO目标检测系列里的最新方法,代码风格友好,并且根据我上一篇博客的结果其轻量模型推理效率很高,因此本文重点以YOLOX为例。

深度学习模型在AI芯片上部署的一般流程

首先介绍一下在AI芯片上的部署流程,无论是英伟达的tensorrt,瑞芯微的rknn,还是openvino、CANN等推理引擎,虽然各引擎的API不同,但基本流程都差不多,如下图所示:
在这里插入图片描述
从深度学习训练框架(如pytorch,tf,paddle等)训练得到的模型,通过各推理引擎附带的模型转换器(有的是引擎自身的API转换比如RKNN,有的配置了专门的转换工具tools比如CANN的ATC),转换成对应引擎的的离线模型。在推理时,通过引擎API将模型和预处理后的图片加载到内存中,然后载入AI芯片中执行推理。

不过不同的推理引擎的推理上仍然存在一些细节差异。

CANN模型部署流程

对于CANN而言,模型部署和推理过程相对复杂一些。这里引用一下官网的流程,对于常用的目标检测模型,只需要看右边的模型推理就OK了:
在这里插入图片描述
主要就是ACL环境(运行资源)的初始化模型转换和加载图像预处理模型推理后处理模型卸载和ACL环境的去初始化

乍一看,推理前进行环境初始化、结束后去初始化的操作比较繁琐,但这种规范的流程设计其实是很有必要的:
举个反例,openvino没有这些初始化之类的步骤,于是我在英特尔的NCS2 VPU上经常出现跑完程序后需要等待很长时间才能进行下一次运行的问题,原因就是没有把上一次加载的内存数据卸载掉:)

CANN ACL接口调用流程(python)

ACL(Ascend Computing Language)提供了CANN的推理接口,可用C++(AscendCL)和python(pyACL)进行开发,我比较喜欢用pyACL。

一般的接口调用流程如下:

步骤1.ACL环境初始化和资源申请

import acl
# pyACL初始化
ret = acl.init()
# 指定运算的Device
self.device_id = 0
ret = acl.rt.set_device(self.device_id)
# 显式创建一个Context,用于管理Stream对象
self.context, ret = acl.rt.create_context(self.device_id)

步骤2.模型加载

与pytorch等框架下的模型加载不同,CANN在加载模型时,除了要把模型文件加载到内存中,还要通过模型文件把模型的输入输出类型、个数、内存等设置好(openvino也有类似操作)。

'''
加载模型文件
'''
self.model_path = './model/resnet50.om'
# 加载离线模型文件,返回标识模型的ID。
self.model_id, ret = acl.mdl.load_from_file(self.model_path)
# 根据加载成功的模型的ID,获取该模型的描述信息。
self.model_desc = acl.mdl.create_desc()
ret = acl.mdl.get_desc(self.model_desc, self.model_id)
'''
设置模型的输入
'''
ACL_MEM_MALLOC_HUGE_FIRST = 0
# 创建aclmdlDataset类型的数据,描述模型推理的输入
self.load_input_dataset = acl.mdl.create_dataset()
# 获取模型输入的数量
input_size = acl.mdl.get_num_inputs(self.model_desc)
self.input_data = []
# 循环为每个输入申请内存,并将每个输入添加到aclmdlDataset类型的数据中
for i in range(input_size):
    buffer_size = acl.mdl.get_input_size_by_index(self.model_desc, i)
    # 申请输入内存
    buffer, ret = acl.rt.malloc(buffer_size, ACL_MEM_MALLOC_HUGE_FIRST)
    data = acl.create_data_buffer(buffer, buffer_size)
    _, ret = acl.mdl.add_dataset_buffer(self.load_input_dataset, data)
    self.input_data.append({"buffer": buffer, "size": buffer_size})
'''
设置模型的输出
'''
# 创建aclmdlDataset类型的数据,描述模型推理的输出
self.load_output_dataset = acl.mdl.create_dataset()
# 获取模型输出的数量
output_size = acl.mdl.get_num_outputs(self.model_desc)
self.output_data = []
# 循环为每个输出申请内存,并将每个输出添加到aclmdlDataset类型的数据中
for i in range(output_size):
    buffer_size = acl.mdl.get_input_size_by_index(self.model_desc, i)
    # 申请输出内存
    buffer, ret = acl.rt.malloc(buffer_size, ACL_MEM_MALLOC_HUGE_FIRST)
    data = acl.create_data_buffer(buffer, buffer_size)
    _, ret = acl.mdl.add_dataset_buffer(self.load_output_dataset, data)
    self.output_data.append({"buffer": buffer, "size": buffer_size})
    

这一段容易看晕,因为获取模型输入输出数据信息时都需要先使用API初始化这个数据类型,然后再通过另一个API获得信息,类似于C++中的先声明再使用。

步骤3.准备输入数据,预处理,推理,后处理

ACL_MEMCPY_DEVICE_TO_DEVICE = 3
NPY_BYTE = 1
images_list = ["./data/dog1_1024_683.jpg", "./data/dog2_1024_683.jpg"]

for image in images_list:
    # 1.自定义函数transfer_pic,对图片进行缩放、剪裁等预处理操作
    img = transfer_pic(image)
    # 2.准备模型推理的输入数据
    np_ptr = acl.util.numpy_to_ptr(img)
    # 将图片数据拷贝到输入数据内存中
    ret = acl.rt.memcpy(self.input_data[0]["buffer"], self.input_data[0]["size"], np_ptr,
                        self.input_data[0]["size"], ACL_MEMCPY_DEVICE_TO_DEVICE)

    # 3.执行模型推理
    # self.model_id表示模型ID,在模型加载成功后,会返回标识模型的ID
    ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset)
        
    # 4.处理模型推理的输出数据,输出top5置信度的类别编号
    inference_result = []
    for i, item in enumerate(self.output_data):
        buffer_d, ret = acl.rt.malloc(self.output_data[i]["size"], ACL_MEM_MALLOC_HUGE_FIRST)
        ret = acl.rt.memcpy(buffer_d, self.output_data[i]["size"], self.output_data[i]["buffer"],
                            self.output_data[i]["size"], ACL_MEMCPY_DEVICE_TO_DEVICE)
        data = acl.util.ptr_to_numpy(buffer_d, (self.output_data[i]["size"],), NPY_BYTE)
        inference_result.append(data)
    tuple_st = struct.unpack("1000f", bytearray(inference_result[0]))
    vals = np.array(tuple_st).flatten()
    top_k = vals.argsort()[-1:-6:-1]
    print("======== top5 inference results: =============")
    for j in top_k:
        print("[%d]: %f" % (j, vals[j]))

步骤4.卸载模型

# 释放输入资源,包括数据结构和内存
while self.input_data:
    item = self.input_data.pop()
    ret = acl.rt.free(item["buffer"])
input_number = acl.mdl.get_dataset_num_buffers(self.load_input_dataset)
for i in range(input_number):
    data_buf = acl.mdl.get_dataset_buffer(self.load_input_dataset, i)
    if data_buf:
        ret = acl.destroy_data_buffer(data_buf)
ret = acl.mdl.destroy_dataset(self.load_input_dataset)

# 释放输出资源,包括数据结构和内存
while self.output_data:
    item = self.output_data.pop()
    ret = acl.rt.free(item["buffer"])
output_number = acl.mdl.get_dataset_num_buffers(self.load_output_dataset)
for i in range(output_number):
    data_buf = acl.mdl.get_dataset_buffer(self.load_output_dataset, i)
    if data_buf:
        ret = acl.destroy_data_buffer(data_buf)
ret = acl.mdl.destroy_dataset(self.load_output_dataset)

# 卸载模型
ret = acl.mdl.unload(self.model_id)

# 释放模型描述信息
if self.model_desc:
    ret = acl.mdl.destroy_desc(self.model_desc)
    self.model_desc = None

步骤5.资源释放,acl去初始化

# 释放Context
if self.context:
    ret = acl.rt.destroy_context(self.context)
    self.context = None

# 释放Device
ret = acl.rt.reset_device(self.device_id)
# pyACL去初始化
ret = acl.finalize()

以上就是pyACL接口的基本调用流程

用于简化部署的Atlas Utils

(未完待续)

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:30:37  更:2021-08-01 14:31:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:16:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码