快速入门
开发场景
开发图片分类应用,对2张分辨率为1024*683的*.jpg图片分类。
该场景涉及以下功能点:
功能点 |
功能简介 |
接口调用流程 |
---|---|---|
pyACL初始化与去初始化 |
使用pyACL接口开发应用时,必须先初始化,否则可能会导致后续系统内部资源初始化出错,进而导致其它业务异常。 有初始化就有去初始化,在确定完成了pyACL的所有调用之后,或者进程退出之前,需调用接口实现pyACL去初始化。 |
|
运行管理资源申请与释放 |
您需要按顺序依次申请资源:Device、Context、Stream,确保可以使用这些资源执行运算、管理任务。 所有数据处理都结束后,需要释放运行管理资源,包括Stream、Context、Device。释放资源时,需要对应顺序释放:Stream,Context,Device。 Stream、Context、Device资源的介绍请参见表1。 |
|
|
||
|
||
内存申请与释放 |
调用pyACL提供的接口申请或释放内存。 |
|
数据传输 |
通过内存复制的方式实现数据传输。 |
如果在板端环境上运行应用,则无需进行数据传输。 |
模型推理 |
本文介绍的场景是图片分类,因此需要选取开源的分类网络,此处选择的是Caffe ResNet-50网络,将开源的ResNet-50网络转换为适配昇腾AI处理器的离线模型(*.om文件),使用该离线模型推理图片所属的类别。 ResNet-50网络对输入图片宽高的要求为224*224,且要求输入图片格式为RGB。但当前输入图片是*.jpg格式,因此下文的样例中使用Python库对图片进行预处理。 |
|
数据后处理 |
提供样例代码,处理模型推理的结果,直接在终端上显示top5置信度的类别编号。 |
|
关键代码开发
即使您不理解所有细节也没关系,此处仅仅是关键步骤的代码示例,不可以直接拷贝运行,仅供参考,旨在帮助您快速了解整体的代码逻辑。
- 导入acl模块。
1
import acl
- pyACL初始化。
1
ret = acl.init()
- 运行管理资源申请。
1 2 3 4 5 6 7
self.device_id = 0 # 指定运算的Device。 ret = acl.rt.set_device(self.device_id) # 显式创建一个Context,用于管理Stream对象。 self.context, ret = acl.rt.create_context(self.device_id)
- 加载模型,并获取模型描述信息。在模型加载前,需要将第三方网络(例如,Caffe ResNet-50网络)转换为适配昇腾AI处理器的离线模型(*.om文件),请参见《ATC工具使用指南》。
1 2 3 4 5 6 7 8 9
# 初始化变量。 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)
- 准备模型推理的输入、输出数据结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
# 初始化变量。 ACL_MEM_MALLOC_HUGE_FIRST = 0 # 1.准备模型推理的输入数据集。 # 创建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}) # 2.准备模型推理的输出数据集。 # 创建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_output_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})
- 准备模型推理的输入数据,并进行推理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
ACL_MEMCPY_HOST_TO_DEVICE = 1 ACL_MEMCPY_DEVICE_TO_HOST = 2 NPY_BYTE = 1 images_list = ["./data/dog1_1024_683.jpg", "./data/dog2_1024_683.jpg"] for image in images_list: # 1.自定义函数transfer_pic,使用Python库读取图片文件,并对图片进行缩放、剪裁等操作,transfer_pic函数的实现请参考样例中源代码。 img = transfer_pic(image) # 2.准备模型推理的输入数据,运行模式为ACL_HOST,当前实例代码中模型只有一个输入。 bytes_data = img.tobytes() np_ptr = acl.util.bytes_to_ptr(bytes_data) # 将图片数据从Host传输到Device。 ret = acl.rt.memcpy(self.input_data[0]["buffer"], self.input_data[0]["size"], np_ptr, self.input_data[0]["size"], ACL_MEMCPY_HOST_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_host, ret = acl.rt.malloc_host(self.output_data[i]["size"]) # 将推理输出数据从Device传输到Host。 ret = acl.rt.memcpy(buffer_host, self.output_data[i]["size"], self.output_data[i]["buffer"], self.output_data[i]["size"], ACL_MEMCPY_DEVICE_TO_HOST) bytes_out = acl.util.ptr_to_bytes(buffer_host, self.output_data[i]["size"]) data = np.frombuffer(bytes_out, dtype=np.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])) # 5.释放模型推理的输入、输出资源。 # 释放输入资源,包括数据结构和内存。 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)
- 卸载模型,并释放模型描述信息。
1 2 3 4 5 6 7
# 卸载模型。 ret = acl.mdl.unload(self.model_id) # 释放模型描述信息。 if self.model_desc: ret = acl.mdl.destroy_desc(self.model_desc) self.model_desc = None
- 运行管理资源释放。
1 2 3 4 5 6 7
# 释放Context。 if self.context: ret = acl.rt.destroy_context(self.context) self.context = None # 释放Device。 ret = acl.rt.reset_device(self.device_id)
- pyACL去初始化。
1
ret = acl.finalize()