说明:代码仅使用pyacl进行跑通,仅供参考,代码健壮性需自行补齐。

一、模型转换:

1、将pt模型文件转为ONNX

示例为YOLO12,替换自己所需的模型文件即可。

import argparse
from ultralytics import YOLO
 
def main():
    model = YOLO("yolo12s.pt")
    onnx_model = model.export(format="onnx", dynamic=False, simplify=True, opset=11)
 
if __name__ == '__main__':
    main()

2、ATC工具将ONNX转为OM

示例为YOLO12,替换自己所需的模型文件即可。

atc --model=yolo12s.onnx --framework=5 --output=yolo12s  --input_format=NCHW --input_shape="images:1,3,640,640" --soc_version=Ascend310P3

说明:--soc_version=Ascend310P3,可使用npu-smi info 命令查看自己设备的芯片型号替换为实际的值,如--soc_version=Ascend910B1

参考昇腾社区ATC工具文档:https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/900beta1/devaids/atctool/atlasatc_16_0001.html

二、PYACL进行模型推理

示例为YOLO12,替换自己所需的模型文件即可。代码中需将model_path = "yolo12s.om"替换为实际的om。

参考昇腾社区应用开发文档:

https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/900beta1/appdevg/acldevg/acldevg_0001.html

import acl  # acl推理相关接口
import cv2
import numpy as np

CLASSES = {
    0: 'person', 1: 'bicycle', 2: 'car', 3: 'motorcycle', 4: 'airplane', 5: 'bus', 6: 'train', 7: 'truck',
    8: 'boat', 9: 'traffic light', 10: 'fire hydrant', 11: 'stop sign', 12: 'parking meter', 13: 'bench',
    14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear',
    22: 'zebra', 23: 'giraffe', 24: 'backpack', 25: 'umbrella', 26: 'handbag', 27: 'tie', 28: 'suitcase',
    29: 'frisbee', 30: 'skis', 31: 'snowboard', 32: 'sports ball', 33: 'kite', 34: 'baseball bat',
    35: 'baseball glove', 36: 'skateboard', 37: 'surfboard', 38: 'tennis racket', 39: 'bottle',
    40: 'wine glass', 41: 'cup', 42: 'fork', 43: 'knife', 44: 'spoon', 45: 'bowl', 46: 'banana', 47: 'apple',
    48: 'sandwich', 49: 'orange', 50: 'broccoli', 51: 'carrot', 52: 'hot dog', 53: 'pizza', 54: 'donut',
    55: 'cake', 56: 'chair', 57: 'couch', 58: 'potted plant', 59: 'bed', 60: 'dining table', 61: 'toilet',
    62: 'tv', 63: 'laptop', 64: 'mouse', 65: 'remote', 66: 'keyboard', 67: 'cell phone', 68: 'microwave',
    69: 'oven', 70: 'toaster', 71: 'sink', 72: 'refrigerator', 73: 'book', 74: 'clock', 75: 'vase',
    76: 'scissors', 77: 'teddy bear', 78: 'hair drier', 79: 'toothbrush'
}

CONFIDENCE = 0.4 # 置信度阈值
IOU = 0.45 # NMS 的 IoU 阈值
colors = np.random.uniform(0, 255, size=(len(CLASSES), 3)) # 为每个类别分配随机颜色

model_path = "yolo12s.om"
ACL_MEM_MALLOC_HUGE_FIRST=0


def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):

    label = "{} {:.2f}".format(CLASSES[class_id], confidence)
    color = colors[class_id]

    cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)

    label_size, _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
    label_width, label_height = label_size

    label_x = x
    label_y = y - 10 if y - 10 > label_height else y + 10

    cv2.rectangle(img, (label_x, label_y - label_height),(label_x + label_width, label_y + label_height), color, cv2.FILLED)
    cv2.putText(img, label, (label_x, label_y), cv2.FONT_HERSHEY_SIMPLEX,0.5, (0, 0, 0), 1, cv2.LINE_AA)



ret = acl.init()  # 初始化 acl  进程中只需要初始化一次即可
ret = acl.rt.set_device(0) #设置当前进程用于计算的DEVICE
model_id, ret = acl.mdl.load_from_file(model_path)  # 从文件加载离线模型数据(适配昇腾AI处理器的离线模型),由系统内部管理内存
model_desc = acl.mdl.create_desc() #创建aclmdlDesc类型的数据,表示模型描述信息
acl.mdl.get_desc(model_desc, model_id) #根据模型ID获取该模型的模型描述信息


#-----------------------------创建inpput   示例中YOLOV12是一个输入

input_num = acl.mdl.get_num_inputs(model_desc) #获取模型输入的个数

input_dataset = acl.mdl.create_dataset()  #创建aclmdlDataset类型的数据。
input_size = acl.mdl.get_input_size_by_index(model_desc,0) #获取指定输入的大小,单位为Byte
input_buffer, ret = acl.rt.malloc(input_size, ACL_MEM_MALLOC_HUGE_FIRST) #在DEVICE上申请指定输入大小的内存 
input_data_buffer = acl.create_data_buffer(input_buffer, input_size) #创建aclDataBuffer类型的数据,该数据类型用于描述内存地址、大小等内存信息。
_, ret = acl.mdl.add_dataset_buffer(input_dataset, input_data_buffer) #向aclmdlDataset中增加aclDataBuffer


#-----------------------------创建output   示例中YOLOV12是一个输出
output_num = acl.mdl.get_num_outputs(model_desc)  # 根据模型信息得到模型输出个数,(YOLOv8 1个输出)

output_dataset = acl.mdl.create_dataset()  # 创建输出dataset结构
output_buffer_size = acl.mdl.get_output_size_by_index(model_desc, 0)  # 获取模型输出字节
output_buffer, ret = acl.rt.malloc(output_buffer_size, ACL_MEM_MALLOC_HUGE_FIRST)  # 为每个输出申请device内存
output_dataset_buffer = acl.create_data_buffer(output_buffer, output_buffer_size)  # 创建输出的data buffer结构,将申请的内存填入data buffer
_, ret = acl.mdl.add_dataset_buffer(output_dataset, output_dataset_buffer)  # 将 data buffer 加入输出dataset


#-----------------------------对数据进行预处理
image = cv2.imread("street.jpg")
img = cv2.resize(image, (640,640)) # 缩放图像
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # BGR转RGB
img = img / 255.0   # 归一化
img = img.transpose(2, 0, 1)  # 转换为NCHW格式
img = img.astype(np.float32)  # 转换为float32
img = np.expand_dims(img, axis=0)  # 添加批次维度
bytes_data = img.tobytes()
data_ptr = acl.util.bytes_to_ptr(bytes_data)


#-----------------------------模型执行

run_mode, ret = acl.rt.get_run_mode() # 获取软件栈运行方式 run_mode:0表示昇腾AI软件栈运行在Device的Control CPU或板端环境上,1表示昇腾AI软件栈运行在Host CPU上
ACL_MEMCPY_DEVICE_TO_DEVICE = 3
ret = acl.rt.memcpy(input_buffer,input_size,data_ptr,input_size,0)  #将模型输入数据拷贝至DEVICE侧
ret = acl.mdl.execute(model_id,input_dataset,output_dataset)  #模型执行


#-----------------------------对数据进行后处理
buffer_host, ret = acl.rt.malloc_host(output_buffer_size) #申请HOST侧模型输出内存
ret = acl.rt.memcpy(buffer_host, output_buffer_size, output_buffer, output_buffer_size, 1) #将模型输出数据拷贝至HOST侧
dims = acl.mdl.get_output_dims(model_desc,0) #根据模型描述获取指定的模型输出Tensor的维度信息。
shape = tuple(dims[0]['dims'])
bytes_out = acl.util.ptr_to_bytes(buffer_host, output_buffer_size)
data = np.frombuffer(bytes_out, dtype=np.float32).reshape(shape)
print(data)
outputs = np.array([cv2.transpose(data[0])])
rows = outputs.shape[1]
boxes = []
scores = []
class_ids = []


height, width, _ = image.shape
length = max(height, width)
scale = length / 640


for i in range(rows):
	classes_scores = outputs[0][i][4:]
	(minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores)
	if maxScore >= CONFIDENCE:
		box = [
			(outputs[0][i][0] - outputs[0][i][2] / 2) * scale,  
			(outputs[0][i][1] - outputs[0][i][3] / 2) * scale,  
			outputs[0][i][2] * scale,  
			outputs[0][i][3] * scale   
		]
		boxes.append(box)
		scores.append(maxScore)
		class_ids.append(maxClassIndex)

result_boxes = cv2.dnn.NMSBoxes(boxes, scores, CONFIDENCE, IOU, 0.5)

detections = []
for i in range(len(result_boxes)):
	index = result_boxes[i]
	box = boxes[index]
	detection = {
		"class_id": class_ids[index],
		"class_name": CLASSES[class_ids[index]],
		"confidence": scores[index],
		"box": box,
		"scale": scale,
	}
	detections.append(detection)
	draw_bounding_box(image,class_ids[index],scores[index],round(box[0]),round(box[1]),round(box[0] + box[2]),round(box[1] + box[3]))
cv2.imwrite("output_image.jpg", image)



	






















三、推理结果

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐