3,231
社区成员




在人工智能与边缘计算深度融合的当下,强大的硬件平台与先进的算法模型成为推动各领域智能化变革的核心要素。高通骁龙 QCS8550 作为一款面向物联网(IoT)领域的旗舰级处理器,采用先进的 4 纳米工艺制程,集强大计算能力、高达 48TOPS 的极致边缘 AI 处理性能、前沿的 Wi-Fi 7 连接技术以及卓越的视频和图形处理能力于一身 。其搭载的 Qualcomm Kryo 中央处理器,计算能力相较于前代提升达 1.5 倍;Qualcomm Adreno GPU 性能更是前代的三倍之多,支持硬件加速光线追踪技术,能同时处理多种格式与分辨率的视频会话,并通过多显示接口以超高清分辨率在不同面板上同步渲染内容。此外,第八代 Qualcomm AI Engine 为 AI 应用赋能,性能提升至前代的 10 倍 ,结合双嵌入式神经处理单元(eNPU)实现始终在线的优质音频处理,每秒运算超 3000 亿次(GOPs),并支持带头部追踪的空间音频技术。这些特性使其成为众多对性能要求严苛的 IoT 应用,如自主移动机器人、工业无人机、智能安防监控、视频协作系统等的理想硬件基石。
Qualcomm Dragonwing™ QCM8550 | Qualcomm
模型优化平台 (AIMO) 用户指南 | APLUX Doc Center
模型 尺寸640*640 |
CPU |
NPU QNN2.31 | NPU QNN2.31 | |||
FP32 | FP16 | INT8 | ||||
YOLO11n-cli | 120.95 ms | 8.27 FPS | 6.11 ms | 163.67 FPS | 3.22 ms | 310.56 FPS |
YOLO11s-cli | 300.23 ms | 3.32 FPS | 7.41 ms | 134.95 FPS | 4.03 ms | 248.14 FPS |
YOLO11m-cli | 676.82 ms | 1.48 FPS | 11.84 ms | 84.46 FPS | 5.18 ms | 193.05 FPS |
YOLO11l-cli | 918.29 ms | 1.09 FPS | 13.88 ms | 72.05 FPS | 6.57 ms | 152.21 FPS |
YOLO11x-cli | 1727.29 ms | 0.58 FPS | 27.4 ms | 36.50 FPS | 10.83 ms | 92.34 FPS |
点击链接可以下载YOLO11-cli系列模型的pt格式,其他模型尺寸可以通过AIMO转换模型,并修改下面参考代码中的model_size测试即可
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)
pip install ultralytics onnx
方法 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
提示:如果遇到用户组权限问题,可以忽悠,因为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.
新建一个python文件,命名自定义即可,用于模型转换以及导出:
from ultralytics import YOLO
# 加载同级目录下的.pt模型文件
model = YOLO('yolo11n-cli.pt') # 替换为实际模型文件名
# 导出ONNX配置参数
export_params = {
'format': 'onnx',
'opset': 12, # 推荐算子集版本
'simplify': True, # 启用模型简化
'dynamic': False, # 固定输入尺寸
'imgsz': 640, # 标准输入尺寸
'half': False # 保持FP32精度
}
# 执行转换并保存到同级目录
model.export(**export_params)
执行该程序完成将pt模型导出为onnx模型。
提示:Yolo11s-cli,Yolo11m-cli,Yolo11l-cli,Yolo11x-cli替换代码中Yolo11n-cli即可;
使用Netnron工具查看onnx模型结构,选择剪枝位置
/model.10/linear/Gemm_output_0
参考上图中红色框部分填写,其他不变,注意开启自动量化功能,AIMO更多操作查看使用说明或参考AIMO平台
检查aidlux环境中的aidlite版本是否与我们转换模型时选择的Qnn版本一致,终端执行:
sudo aid-pkg installed
如果没有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
import time
import numpy as np
import cv2
import os
import aidlite
import argparse
from pathlib import Path
# ---------- 新增辅助函数 ----------
def load_class_names(names_path: str):
"""
从 txt 文件或逗号分隔字符串载入类别名称
参数:
names_path: 类别名称文件路径或逗号分隔字符串
返回:
类别名称列表
"""
# 如果未提供名称路径,生成默认类别名称列表
if not names_path:
return [f"class_{i}" for i in range(1000)] # 默认 1000 类占位
# 从文件加载类别名称
if os.path.isfile(names_path):
with open(names_path, 'r', encoding='utf-8') as f:
names = [l.strip() for l in f.readlines() if l.strip()]
# 从逗号分隔字符串加载类别名称
else:
names = [x.strip() for x in names_path.split(',') if x.strip()]
return names
def visualize_and_save(image_bgr, label, score, save_path):
"""
在图片左上角绘制分类结果并写入文件
参数:
image_bgr: BGR格式图像
label: 预测类别标签
score: 预测置信度分数
save_path: 保存路径
"""
# 格式化显示文本
txt = f"{label}: {score*100:.1f}%"
# 设置字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 在图像上绘制文本
cv2.putText(image_bgr, txt, (10, 30), font, 1.0, (0, 255, 0), 2, cv2.LINE_AA)
# 保存图像
cv2.imwrite(str(save_path), image_bgr)
print(f"预测结果已保存到: {save_path}")
# ---------- 主函数 ----------
def main(args):
'''
主函数流程:
1. 初始化模型和配置
2. 读取和预处理图像
3. 执行模型推理
4. 可视化并保存结果
'''
print("Start image inference ... ...")
size = 640 # 模型输入尺寸
# ---------- 1. 初始化模型 ----------
# 创建配置实例
config = aidlite.Config.create_instance()
if config is None:
print("Create config failed !")
return False
# 设置实现类型为本地实现
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
# 根据命令行参数设置框架类型
if args.model_type.lower() == "qnn":
config.framework_type = aidlite.FrameworkType.TYPE_QNN231
elif args.model_type.lower() in ("snpe2", "snpe"):
config.framework_type = aidlite.FrameworkType.TYPE_SNPE2
# 设置加速类型为DSP
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
# 设置为量化模型
config.is_quantify_model = 1
# 创建模型实例
model = aidlite.Model.create_instance(args.target_model)
if model is None:
print("Create model failed !")
return False
# 定义输入输出张量形状
input_shapes = [[1, size, size, 3]]
output_shapes = [[1, args.num_classes]]
# 设置模型属性
model.set_model_properties(
input_shapes, aidlite.DataType.TYPE_FLOAT32,
output_shapes, aidlite.DataType.TYPE_FLOAT32)
# 构建并初始化解释器
interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
if interpreter is None or interpreter.init() != 0 or interpreter.load_model() != 0:
print("Interpreter build/init/load 失败")
return False
print("Model loaded successfully ✔")
# ---------- 2. 读取 & 预处理 ----------
# 读取输入图像
img_bgr = cv2.imread(args.image_path)
if img_bgr is None:
print("Error: Could not open image file")
return False
# 获取图像尺寸
h, w, _ = img_bgr.shape
# 计算填充后图像的边长
length = max(h, w)
# 计算缩放比例
scale = length / size
# 创建黑色画布并将原始图像放置在左上角
canvas = np.zeros((length, length, 3), dtype=np.uint8)
canvas[0:h, 0:w] = img_bgr
# 颜色空间转换 BGR -> RGB
img_rgb = cv2.cvtColor(canvas, cv2.COLOR_BGR2RGB)
# 调整图像大小为模型输入尺寸
img_rgb = cv2.resize(img_rgb, (size, size))
# 归一化处理,将像素值从0-255缩放到0-1
img_norm = (img_rgb.astype(np.float32) - 0) / 255.0 # 归一化到 0~1
img_input = img_norm # HWC
# ---------- 3. 推理 & 性能测试 ----------
# 预热推理,消除首次推理的额外开销
warmup_iters = 5
for _ in range(warmup_iters):
interpreter.set_input_tensor(0, img_input.data)
interpreter.invoke()
# 多次推理测量性能
invoke_nums, invoke_times = 20, []
for i in range(invoke_nums):
t1 = time.time()
interpreter.set_input_tensor(0, img_input.data)
interpreter.invoke()
t2 = time.time()
invoke_times.append((t2 - t1) * 1000) # 转换为毫秒
# 计算性能统计指标
mean_invoke_time = np.mean(invoke_times) # 平均推理时间
max_invoke_time = np.max(invoke_times) # 最大推理时间
min_invoke_time = np.min(invoke_times) # 最小推理时间
var_invoke_time = np.var(invoke_times) # 推理时间方差
fps = 1000 / mean_invoke_time # 计算FPS
# 打印性能统计结果
print(f"\nInference {invoke_nums} times:\n"
f"-- mean_invoke_time is {mean_invoke_time:.2f} ms\n"
f"-- max_invoke_time is {max_invoke_time:.2f} ms\n"
f"-- min_invoke_time is {min_invoke_time:.2f} ms\n"
f"-- var_invoke_time is {var_invoke_time:.2f}\n"
f"-- FPS: {fps:.2f}\n")
# 获取最后一次推理输出
logits = interpreter.get_output_tensor(0).reshape(*output_shapes) # (1, num_classes)
probs = logits[0] # (num_classes,)
# ---------- 4. 结果后处理 ----------
# 获取概率最高的前5个类别索引
top5_idx = probs.argsort()[-5:][::-1]
# 加载类别名称
class_names = load_class_names(args.class_names)
# 获取概率最高的类别索引
top1 = top5_idx[0]
# 打印Top-5预测结果
print("\nTop‑5 结果:")
for rank, idx in enumerate(top5_idx, 1):
print(f"{rank}. {class_names[idx]} {probs[idx]*100:.2f}%")
# ---------- 5. 可视化并保存 ----------
# 创建保存目录
save_dir = Path(args.save_dir)
save_dir.mkdir(parents=True, exist_ok=True)
# 生成保存路径
save_path = save_dir / f"pred_{Path(args.image_path).stem}.jpg"
# 可视化结果并保存
visualize_and_save(img_bgr, class_names[top1], probs[top1], save_path)
# ---------- 6. 资源释放 ----------
interpreter.destory()
# ---------- 命令行参数 ----------
def parser_args():
"""解析命令行参数"""
parser = argparse.ArgumentParser(description="AidLite image classification demo")
parser.add_argument('--target_model', type=str, default='yolov11n_cls/cutoff_yolo11n-cls_qcs8550_fp16.qnn231.ctx.bin',
help="模型文件路径")
parser.add_argument('--image_path', type=str, default='bus.jpg', help="待预测图片路径")
parser.add_argument('--model_type', type=str, default='QNN', help="后端类型: QNN / SNPE2")
parser.add_argument('--num_classes', type=int, default=1000, help="模型输出类别数")
parser.add_argument('--class_names', type=str, default='', help="类别名称 txt 路径或逗号分隔字符串")
parser.add_argument('--save_dir', type=str, default='results', help="预测图片输出目录")
return parser.parse_args()
if __name__ == "__main__":
# 解析命令行参数
args = parser_args()
# 执行主函数
main(args)
yolo11n-cli