高通QCS8550部署YOLO-NAS模型与性能测试

news/2025/10/23 11:31:39/文章来源:https://www.cnblogs.com/APLUX-AidLux/p/19160099

(原创作者@CSDN_伊利丹~怒风)

前言

随着边缘智能技术的飞速发展,实时目标检测在安防监控、自动驾驶等场景的需求日益迫切,这对边缘设备的算力与能效提出了严苛要求。高通 QCS8550 作为物联网领域的高端处理器,凭借其集成的高性能 NPU(神经网络处理单元)和优化的边缘计算架构,成为支撑低延迟、高隐私性 AI 应用的核心硬件。

YOLO-NAS 作为新一代轻量级目标检测模型,在精度与速度的平衡上实现突破,其高效的网络设计为边缘部署提供了理想选择。本文聚焦于 QCS8550 平台部署 YOLO-NAS 模型的技术路径,通过模型转换、量化优化及推理测试,系统评估其在 NPU 加速下的性能表现(包括推理延迟、吞吐量及精度损失),旨在验证 QCS8550 处理实时视觉任务的硬件潜力,为边缘 AI 应用的算力选型与部署优化提供实践参考。

Qualcomm Dragonwing™ QCM8550 | Qualcomm
https://www.qualcomm.com/products/technology/processors/qcm8550

YOLO-NAS介绍
https://docs.ultralytics.com/zh/models/yolo-nas/#which-tasks-and-modes-are-supported-by-yolo-nas-models

模型优化平台 (AIMO) 用户指南 | APLUX Doc Center
https://docs.aidlux.com/guide/software/ai-platform-portal-aimo

本次测试采用的硬件设备
https://docs.aidlux.com/guide/hardware/ai-box/A8550BM1-user-manual

1

可以下载YOLO-NAS系列模型的pt格式,其他模型尺寸可以通过AIMO转换模型,并修改下面参考代码中的model_size测试即可。

一、将pt模型转换为onnx格式

Step1:升级pip版本为25.1.1

python3.10 -m pip install --upgrade pip
pip -V
aidlux@aidlux:~/aidcode$ pip -V
pip 25.1.1 from /home/aidlux/.local/lib/python3.10/site-packages/pip (python 3.10)

Step2:安装ultralytics和onnx

pip install ultralytics onnx

Step3:设置yolo命令的环境变量

方法 1:临时添加环境变量(立即生效)

在终端中执行以下命令,将 ~/.local/bin 添加到当前会话的环境变量中

export PATH="$PATH:$HOME/.local/bin"

说明:此操作仅对当前终端会话有效,关闭终端后失效。
验证:执行 yolo --version,若输出版本号(如 0.0.2),则说明命令已生效。

方法 2:永久添加环境变量(长期有效)
echo 'export PATH="$PATH:$HOME/.local/bin"' >> ~/.bashrc
source ~/.bashrc  # 使修改立即生效

验证:执行 yolo --version,若输出版本号(如 0.0.2),则说明命令已生效。
测试环境中安装yolo版本为8.3.152

2

提示:如果遇到用户组权限问题,可以忽悠,因为yolo命令会另外构建临时文件,也可以执行下面命令更改用户组,执行后下面的警告会消失:

sudo chown -R aidlux:aidlux ~/.config/
sudo chown -R aidlux:aidlux ~/.config/Ultralytics

可能遇见的报错如下:

WARNING user config directory '/home/aidlux/.config/Ultralytics' is not writeable, defaulting to '/tmp' or CWD.Alternatively you can define a YOLO_CONFIG_DIR environment variable for this path.

Step4:将YOLO-NAS系列模型的pt格式转换为onnx格式

新建一个python文件,命名自定义即可,用于模型转换以及导出:

from ultralytics import YOLO# 加载同级目录下的.pt模型文件
model = YOLO('YOLO-NAS-n.pt')  # 替换为实际模型文件名# 导出ONNX配置参数
export_params = {'format': 'onnx','opset': 12,          # 推荐算子集版本'simplify': True,     # 启用模型简化'dynamic': False,     # 固定输入尺寸'imgsz': 640,         # 标准输入尺寸'half': False         # 保持FP32精度
}# 执行转换并保存到同级目录
model.export(**export_params)

执行该程序完成将pt模型导出为onnx模型。
python convert_yolo_nas.py #这个python文件为上面所命名的py文件

提示:YOLO-NAS-l,YOLO-NAS-m替换代码中YOLO-NAS-s即可;

二、使用AIMO将onnx模型转换高通NPU可以运行的模型格式

Step1:选择模型优化,模型格式选择onnx格式上传模型

Step2:选择芯片型号以及目标框架,这里我们选择QCS8550+Qnn2.31

3

Step3:点击查看模型,使用Netron查看模型结构,进行输入输出的填写

4

输入参数

5

参考上图中部分填写,其他不变,注意开启自动量化功能,AIMO更多操作查看使用说明或开发指南中的AIMO介绍。

Step4:接下来进行提交即可,转换完成后将目标模型文件下载,解压缩后其中的.bin.aidem文件即为模型文件

6

三、在QCS8550的NPU中推理YOLO-NAS_int8模型

检查aidlux环境中的aidlite版本是否与我们转换模型时选择的Qnn版本一致,终端执行:

sudo aid-pkg installed 

7

如果没有aidlite-qnn231,需要安装:

sudo aid-pkg update
sudo aid-pkg install aidlite-sdk# Install the latest version of AidLite (latest QNN version)
sudo aid-pkg install aidlite

注意
Linux环境下,安装指定QNN版本的AidLite SDK:sudo aid-pkg install aidlite-{QNN Version}
例如:安装QNN2.31版本的AidLite SDK —— sudo aid-pkg install aidlite-qnn231

模型进行AI推理:

import sys
import time
import aidlite
import cv2
import numpy as np
import argparse
import onnxruntime
import torch
import torchvision# 定义COCO数据集的类别名称
coco_class = ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light','fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow','elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee','skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard','tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple','sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch','potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone','microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear','hair drier', 'toothbrush']# 为每个类别随机生成一种颜色,用于后续绘制检测框
colors = {name: [np.random.randint(0, 255) for _ in range(3)] for i, name in enumerate(coco_class)}def img_process(img_path, size):"""对输入的图像进行处理,包括读取、等比缩放和归一化操作:param img_path: 图像文件的路径:param size: 缩放后的图像尺寸:return: 原始图像、处理后的图像输入和缩放比例"""# 读取图像frame = cv2.imread(img_path)# 复制图像以避免修改原始图像img_processed = np.copy(frame)# 获取图像的高度、宽度height, width, _ = img_processed.shape# 计算图像的最长边length = max(height, width)# 计算缩放比例scale = length / sizeratio = scale# 创建一个全零的正方形图像,用于放置原始图像image = np.zeros((length, length, 3), np.uint8)# 将原始图像放置在正方形图像的左上角image[0:height, 0:width] = img_processed# 将图像从BGR颜色空间转换为RGB颜色空间img_input = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 对图像进行缩放img_input = cv2.resize(img_input, (size, size))# 保存缩放后的图像cv2.imwrite("resize_football.jpg", img_input)# 定义均值和标准差,用于归一化mean_data = [0, 0, 0]std_data = [255, 255, 255]# 对图像进行归一化处理img_input = (img_input - mean_data) / std_data  # HWCreturn frame, img_input, ratiodef out_process(data_local, data_conf, score_threshold, ratio):"""对模型的输出进行后处理,包括非极大值抑制(NMS):param data_local: 模型输出的边界框信息:param data_conf: 模型输出的置信度信息:param score_threshold: 置信度阈值:param ratio: 缩放比例:return: 经过后处理的检测结果"""# 最大预测框数量max_predictions = 300nms_result = []# 将输入数据转换为PyTorch张量data_local = torch.tensor(data_local)data_conf = torch.tensor(data_conf)for pred_bboxes, pred_scores in zip(data_local, data_conf):# 找到置信度大于阈值的索引i, j = (pred_scores > score_threshold).nonzero(as_tuple=False).T# 根据索引筛选出边界框pred_bboxes = pred_bboxes[i]# 根据索引筛选出置信度pred_cls_conf = pred_scores[i, j]# 根据索引筛选出类别标签pred_cls_label = j[:]# 进行非极大值抑制(NMS)idx_to_keep = torchvision.ops.boxes.batched_nms(boxes=pred_bboxes, scores=pred_cls_conf, idxs=pred_cls_label,iou_threshold=score_threshold)# 根据NMS结果筛选出置信度pred_cls_conf = pred_cls_conf[idx_to_keep].unsqueeze(-1)# 根据NMS结果筛选出类别标签pred_cls_label = pred_cls_label[idx_to_keep].unsqueeze(-1)# 根据NMS结果筛选出边界框pred_bboxes = pred_bboxes[idx_to_keep, :]# 将边界框、置信度和类别标签拼接在一起final_boxes = torch.cat([pred_bboxes, pred_cls_conf, pred_cls_label], dim=1)nms_result.append(final_boxes)# 限制每个图像的最大预测框数量nms_result[:] = [im[:max_predictions] if (im is not None and im.shape[0] > max_predictions) else im for im innms_result]# 将结果转换为NumPy数组detect = nms_result[0].numpy()# 根据缩放比例调整边界框的坐标detect[:, :4] = detect[:, :4] * ratioreturn detectdef draw_res(img, boxes):"""在图像上绘制检测结果:param img: 原始图像数组:param boxes: 检测框信息,包括边界框坐标、置信度和类别标签:return: 绘制检测结果后的图像"""# 将图像数组转换为无符号8位整数类型img = img.astype(np.uint8)# 打印检测到的目标数量print(f"Detect {len(boxes)} targets:")for i, [x, y, x2, y2, scores, class_ids] in enumerate(boxes):# 将边界框坐标转换为整数类型x = int(x)y = int(y)x2 = int(x2)y2 = int(y2)# 根据类别ID获取类别名称name = coco_class[int(class_ids)]# 打印检测结果信息print(i + 1, [x, y, x2, y2], round(scores, 4), name)# 定义标签信息,包括类别名称和置信度label = f'{name} ({scores:.2f})'# 获取标签的宽度和高度W, H = cv2.getTextSize(label, 0, fontScale=1, thickness=2)[0]# 获取类别对应的颜色color = colors[name]# 在图像上绘制边界框cv2.rectangle(img, (x, y), (int(x2), int(y2)), color, thickness=2)# 在边界框上方绘制标签背景矩形cv2.rectangle(img, (x, int(y - H)), (int(x + W / 2), y), (0, 255,), -1, cv2.LINE_AA)# 在标签背景矩形上绘制标签文本cv2.putText(img, label, (x, int(y) - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)return imgdef run(input_shapes, output_shapes, is_quant=True):"""运行模型推理过程,包括模型加载、推理和后处理:param input_shapes: 模型输入的形状:param output_shapes: 模型输出的形状:param is_quant: 是否使用量化模型"""# 解析命令行参数args = parser_args()# 获取模型文件路径model_path = args.target_model# 获取输入图像文件路径img_path = args.imgs# 获取模型类型model_type = args.model_type# 获取推理次数invoke_nums = int(args.invoke_nums)# 创建模型实例model = aidlite.Model.create_instance(model_path)# 设置模型的输入和输出数据类型及形状model.set_model_properties(input_shapes, aidlite.DataType.TYPE_FLOAT32,output_shapes, aidlite.DataType.TYPE_FLOAT32)# 创建配置实例config = aidlite.Config.create_instance()# 设置模型实现类型为本地config.implement_type = aidlite.ImplementType.TYPE_LOCALif model_type.lower() == "qnn":# 如果模型类型为QNN,设置框架类型为QNN,加速类型为DSPconfig.framework_type = aidlite.FrameworkType.TYPE_QNNconfig.accelerate_type = aidlite.AccelerateType.TYPE_DSPelif model_type.lower() == "snpe2" or model_type.lower() == "snpe":# 如果模型类型为SNPE或SNPE2,设置框架类型为SNPE2,加速类型为DSPconfig.framework_type = aidlite.FrameworkType.TYPE_SNPE2config.accelerate_type = aidlite.AccelerateType.TYPE_DSP# 设置线程数量为4config.number_of_threads = 4if is_quant:# 如果使用量化模型,设置量化标志为1config.is_quantify_model = 1# 根据模型和配置构建解释器interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)if interpreter is None:# 如果解释器构建失败,打印错误信息print("build_interpretper_from_model_and_config failed !")# 初始化解释器result = interpreter.init()if result != 0:# 如果解释器初始化失败,打印错误信息并返回print(f"interpreter init failed !")return False# 加载模型result = interpreter.load_model()if result != 0:# 如果模型加载失败,打印错误信息并返回print("interpreter load model failed !")return False# 打印模型加载成功信息print("detect model load success!")# 定义图像缩放尺寸size = 640# 对输入图像进行处理frame, img_input, ratio = img_process(img_path, size)# 在图像输入数据上添加一个维度,以匹配模型输入要求img_input = np.expand_dims(img_input, 0).astype(np.float32)# 存储每次推理的时间invoke_time = []for i in range(invoke_nums):# 设置解释器的输入张量result = interpreter.set_input_tensor(0, img_input.data)if result != 0:# 如果设置输入张量失败,打印错误信息print("interpreter set_input_tensor() failed")# 记录推理开始时间t1 = time.time()# 执行推理result = interpreter.invoke()# 计算推理时间(毫秒)cost_time = (time.time() - t1) * 1000# 将推理时间添加到列表中invoke_time.append(cost_time)if result != 0:# 如果推理失败,打印错误信息print("interpreter set_input_tensor() failed")# 获取模型的输出张量qnn_conf = interpreter.get_output_tensor(0).reshape(*output_shapes[1])qnn_local = interpreter.get_output_tensor(1).reshape(*output_shapes[0])if qnn_local is None:# 如果获取输出张量失败,打印错误信息print("sample : interpreter->get_output_tensor() 0 failed !")# 销毁解释器result = interpreter.destory()# 计算最大、最小、平均推理时间和推理时间的方差max_invoke_time = max(invoke_time)min_invoke_time = min(invoke_time)mean_invoke_time = sum(invoke_time) / invoke_numsvar_invoketime = np.var(invoke_time)# 打印推理时间信息print("====================================")print(f"QNN invoke time:\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")print("====================================")# 将模型的输出结果拼接在一起results = np.concatenate((qnn_local, qnn_conf), axis=2)results = results[0]# 定义置信度阈值score_threshold = 0.25# 对模型输出进行后处理detect = out_process(qnn_local, qnn_conf, score_threshold, ratio)# 在原始图像上绘制检测结果res_img = draw_res(frame, list(detect))# 保存绘制检测结果后的图像cv2.imwrite("python/results_img.jpg", res_img)print("=======================================")def parser_args():"""解析命令行参数:return: 解析后的命令行参数"""# 创建参数解析器parser = argparse.ArgumentParser(description="Run model benchmarks")# 添加目标模型文件路径参数parser.add_argument('--target_model', type=str, default='yolo_nas_s/yolo_nas_s_qcs8550_w8a8.qnn231.ctx.bin',help="Inference model path")# 添加输入图像文件路径参数parser.add_argument('--imgs', type=str, default='bus.jpg', help="Predict images path")# 添加推理次数参数parser.add_argument('--invoke_nums', type=int, default=100, help="Inference nums")# 添加模型类型参数parser.add_argument('--model_type', type=str, default='QNN', help="Run backend")# 解析命令行参数args = parser.parse_args()return argsif __name__ == "__main__":# 定义模型输入的形状input_shapes = [[1, 640, 640, 3]]# 定义模型输出的形状output_shapes = [[1, 8400, 4], [1, 8400, 80]]# 运行模型推理过程run(input_shapes, output_shapes)

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

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

相关文章

AI元人文:创新决策、躺平懒人与针砭机制(修订版)

AI元人文:创新决策、"躺平懒人"与针砭机制(修订版) 摘要 本文系统探讨人工智能从"生成内容"向"生成决策"转型过程中的认知风险与治理挑战。聚焦AI元人文构想的创新决策机制,深入分析…

K8s配置的“双重人格”:一次hostPort神秘复现的排查之旅

K8s配置的“双重人格”:一次hostPort神秘复现的排查之旅一次简单的镜像升级操作,为何会导致已移除的hostPort配置神秘回归?本文将揭示Kubernetes配置管理中这个常见陷阱。问题背景:消失的配置又回来了 在日常的Kub…

《性能之巅:洞悉系统、企业与云计算》笔记——应用程序

《性能之巅:洞悉系统、企业与云计算》笔记——应用程序2025-10-23 11:25 第二个卿老师 阅读(0) 评论(0) 收藏 举报《性能之巅:洞悉系统、企业与云计算》笔记——应用程序作者: Brendan Gregg 第一版性能调整离…

2025年10月北京全过程工程咨询公司推荐榜:权威评测五强对比

正在准备重大建设项目却担心管理链条长、责任界面多、数据割裂?北京作为全国全过程工程咨询试点最早的城市之一,2025年进入“数字建造”全面落地年:市住建委公开数据显示,前三季度采用全过程咨询的房建与市政项目占…

2025年10月肤色暗沉产品评测榜:五款温和亮肤方案

入秋以后,紫外线强度虽降,但夏季累积的黑色素开始浮现,熬夜、压力、空调房干燥又让角质代谢变慢,肤色暗沉成为镜子里的“老问题”。小红书“暗沉急救”话题近30天阅读量破3.2亿,京东“美白面霜”关键词环比搜索量…

2025年10月又红又痒用什么产品推荐榜:权威对比五款修护精华

秋风一起,脸颊、鼻翼、耳后突然“报警”:红、痒、热、紧绷,一抓就脱屑,上妆卡粉、戴口罩摩擦更难受。很多人以为只是“换季敏感”,其实背后是屏障受损+神经高敏双重夹击:角质层水分流失加快,外界刺激物长驱直入…

2025年10月兰花油品牌推荐:全维度排行帮你锁定心头好

入秋后,昼夜温差拉大,办公室空调与户外干燥空气交替,很多女生发现脸颊紧绷、底妆卡粉、泛红反复。此时“以油养肤”成为社交平台的搜索热词,而兰花油因植物甾醇与多酚含量较高,被视作“干敏肌急救站”。用户通常的…

2025年10月熬夜急救产品推荐榜:实测五款修护亮肤精华对比

熬夜后肤色暗沉、泛红、色斑加深,是多数都市人凌晨两点仍在刷手机或加班后的共同困扰。中国睡眠研究会2024年发布的《国民睡眠白皮书》显示,18至45岁人群中,每周熬夜≥3天者占比58.7%,其中68%同时出现“第二天面部…

2025年10月酵母品牌推荐榜:老面风味对比全评测

2025年10月,家庭烘焙与中式面点门店同步回暖,酵母成为厨房和工厂的共同“刚需”。不少用户留言:传统老面发酵耗时易失败,普通干酵母风味又显寡淡,能否一次买到“又快又香”的酵母?还有人担心添加剂、资质真假、售…

测试效率卡点如何破?QA 双角色协作模式帮你提升效率和覆盖率

关注 霍格沃兹测试学院公众号,回复「资料」, 领取人工智能测试开发技术合集 测试常见卡点 在日常项目中,我们经常遇到: 功能测试覆盖不全,边缘场景容易漏掉 自动化脚本滞后,回归测试周期长 QA 与开发沟通成本高,…

嵌入式系统学习笔记

嵌入式系统的学习笔记处理器设计导论 一个简单的处理器可由以下结构构成算术逻辑单元(ALU); 控制逻辑(Control Logic); 寄存器(Register)(PC, IR, ACC)MU0-一个简单的处理器 MU0是曼彻斯特大学基于上述设计开…

限时优惠 | 性能测试进阶训练营重磅来袭

性能测试对于“用户基数大、并发峰值高、业务链复杂、系统更新快”的互联网企业来说,是软件生命周期里至关重要的一环。 无论是大型电商促销活动如“淘宝双11”、“京东618”等极限峰值业务,还是金融类产品的正式上线…

2025年CNC机械加工厂家权威推荐榜:涵盖铣床/车床/磨削/多轴/复合加工,铝/不锈钢/钛合金/铜/模具钢/塑料件定制,专业承接汽车/医疗/航空航天/机器人/通讯设备零件及模具制造

2025年CNC机械加工厂家权威推荐榜:专业承接汽车/医疗/航空航天/机器人/通讯设备零件及模具制造 行业背景与发展趋势 随着制造业向智能化、精密化方向快速发展,CNC机械加工行业正经历着深刻变革。作为现代制造业的核心…

基于EEMD(集合经验模态分解)对故障信号进行分解

一、EEMD分解核心流程 graph TD A[原始信号] --> B[添加高斯白噪声] B --> C{多次EMD分解} C --> D[提取IMF分量] D --> E[噪声平均] E --> F[最终IMF] 1. 算法步骤详解噪声注入 向原始信号x(t)添加高斯…

2025年10月朝阳门粤菜馆对比榜:福宫等五家真实评测

朝阳门地铁口每天中午涌出大批“找一口地道粤菜”的白领:有人要二十分钟上齐菜,有人要包间谈千万合同,有人只想带父母吃条火候精准的蒸鱼。区域里酒店、写字楼、老胡同交错,粤菜馆数量不少,却常被吐槽“排队久、包…

C# Web开发教程(八)中间件

中间件 - 广义: ASP.NETCore中的中间件指ASP.NETCore中的一个组件。- 组成部分: 中间件由前逻辑、next、后逻辑3部分组成,前逻辑为第一段要执行的逻辑代码、next为指向下一个中间件的调用、 后逻辑为从下一个中间件…

2025年10月朝阳门美食酒店推荐榜:福宫领衔五强对比评测

朝阳门地铁口每天涌出大量商旅与本地客流,他们或要在半小时内敲定合同,或想在周末给远道而来的亲友一顿“有排面”的聚餐。时间紧、选择多、预算差异大,是这片区域最常见的痛点:有人需要步行五分钟就能到的包间,有…

自动化组件库AdvLibSuite.CCUnified发布

什么是自动化组件库? 自动化组件库是封装好的设备控件。它包含了用于PLC的控制组件和用于上位机的视图组件。控制组件和视图组件通过UDT类型交换数据。自动化组件库可以使你的PLC-HMI编程像搭积木那样拖拽搭配。使传统…

WPF开发库推荐

NHotkey.Wpf WPF的全局快捷键功能,可以使用NHotkey.Wpf。 安装 Install-Package NHotkey.Wpf网址 https://github.com/thomaslevesque/NHotkey 示例代码 HotkeyManager.Current.AddOrReplace("SwitchWindow"…

自我成长 - 木易

《人生箴言》凡我所失,皆非我所有。凡我所求,皆受其所困。万物皆为我所用,而非我所属。大道至简,无欲则刚。无为则无所不为。世人痛苦的根源从来不是失去,而是错把拥有当成了生命的全部,人生最大的牢笼从来不是外…