一、实验目的
通过本实验,在 NVIDIA Jetson AGX Orin 嵌入式平台上完成目标检测模型的轻量化部署。实验设备已完成 JetPack 基础环境配置,并已安装 Anaconda 与 PyTorch,因此本实验直接从“在 conda 环境中配置 Ultralytics YOLO”开始,依次完成预训练模型准备、TensorRT 引擎构建、性能基准测量,并通过外置 USB 摄像头实现实时人员检测,理解边缘端部署中“精度—速度—端到端实时性”的权衡关系。
1.1 知识目标
-
理解 Jetson 上 Ultralytics YOLO 的配置要点:aarch64 架构下
onnxruntime-gpu需要手动获取专用 wheel,PyPI 默认包不包含 Jetson 可用的二进制 -
掌握 TensorRT 的核心优化原理:层融合、FP16 降低计算量、kernel 针对 Ampere 架构自动调优,以及 engine 的硬件特定性
-
认识“模型推理延迟”与“端到端流水线 FPS”的区别:摄像头采集、格式转换和串行结构可能成为新的瓶颈
1.2 技能目标
-
能够在已有 conda + PyTorch 环境中完成 Ultralytics 及 ONNX 相关依赖的配置
-
能够锁定 MAXN /
jetson_clocks,获得可复现的基准数据 -
能够使用预训练 YOLO 完成 PyTorch 基线推理,并导出 ONNX 与 TensorRT FP16 引擎
-
能够对比 PyTorch 与 TensorRT 的推理性能,并在数据子集上校验 FP16 精度损失
-
能够通过 GStreamer 管线读取 USB 摄像头,实现实时人员检测,并分析端到端瓶颈
1.3 素养目标
-
建立以基线测量为起点的优化习惯:先量化,再优化,再对比
-
理解硬件特定性(engine 不可跨设备移植)与功耗模式对边缘部署工程的实际约束
二、实验内容
模块一:YOLO 环境配置(基于已有 Anaconda + PyTorch)
-
确认 JetPack、CUDA、TensorRT 版本及 aarch64 架构
-
在已有的 conda 环境中安装
onnx、aarch64 专用onnxruntime-gpu和ultralytics,处理 numpy 版本冲突 -
验证 YOLO 加载与 GPU 可用性,锁定 MAXN 性能模式
模块二:PyTorch 基线推理
-
使用
yolov8n.pt对测试图像推理,测量平均延迟与 FPS
模块三:ONNX 导出与 TensorRT 引擎构建
-
导出静态 ONNX(固定
imgsz) -
使用 Ultralytics
format='engine'或trtexec构建 FP16 引擎
模块四:TensorRT 推理与性能对比
-
单帧推理,验证结果一致性
-
测量 TensorRT 延迟与 FPS,计算加速比
-
在小型公开数据集上校验 FP16 精度变化
选做模块:外置 USB 摄像头实时人员检测
-
朴素
cv2.VideoCapture(0)路径的端到端 FPS(问题基线) -
GStreamer 管线读取,仅保留
person类别,叠加 FPS 显示 -
对比两种读取方式的端到端 FPS,分析瓶颈
三、实验步骤
3.1 环境确认
步骤1:确认 JetPack、TensorRT 与已有 PyTorch
在 Jetson 终端中依次执行:
bash
cat /etc/nv_tegra_release # JetPack / L4T 版本 dpkg -l | grep 'nvidia-jetpack' #查看jetpack版本记录,后面要用。 uname -m # 应输出 aarch64 dpkg -l | grep nvinfer # TensorRT 版本
激活你已有的 conda 环境后,确认 PyTorch 状态:
bash
conda activate <你的环境名>
python3 -c "import torch; print('PyTorch:', torch.__version__); print('CUDA:', torch.cuda.is_available()); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'N/A')"
本实验的前提是
torch.cuda.is_available()已返回True。如果在此步骤发现问题,应先回到已有的 JetPack + PyTorch 配置,排除 PyTorch wheel 与 JetPack 版本不匹配的问题,再继续后续步骤。
步骤2:锁定性能模式
bash
sudo nvpmodel -m 0 # MAXN 模式 sudo jetson_clocks # 锁定 CPU/GPU/EMC 至最高频率 sudo jetson_clocks --show
基准测试前必须锁定频率。否则,动态调频会使“PyTorch vs TensorRT”的对比失去可复现性。
3.2 YOLO 环境配置(基于已有 conda + PyTorch)
步骤3:安装 onnx 与 aarch64 专用 oruntime-gpu
PyPI 上的 onnxruntime-gpu 不包含 Jetson 可用的 aarch64 二进制,必须手动下载安装。以下以 Python 3.8 为例:
bash
# 在已激活的 conda 环境中 pip install onnx # 安装 aarch64 专用 wheel(cpXX 需与 Python 版本匹配,注意与自己安装的python版本要一致!!!!!!!!) wget https://nvidia.box.com/shared/static/zostg6agm00fb6t5uisw51qi6kpcuwzd.whl -O onnxruntime_gpu-1.17.0-cp38-cp38-linux_aarch64.whl pip install onnxruntime_gpu-1.17.0-cp38-cp38-linux_aarch64.whl
【如果网络无法访问,参考下面的链接。如果仍然无法访问,安装CPU版本】
关键冲突:onnxruntime-gpu 安装过程中可能自动将 numpy 升级到最新版本,破坏原有 PyTorch 或 YOLO 环境的兼容性。安装完成后,应立即将 numpy 固定到已知兼容的版本:
bash
pip install numpy==1.23.5
如果 conda 环境中原本使用的 numpy 版本不同(例如 1.26.x),请以你环境中已验证可用的版本为准,不要盲目覆盖。
参考:
Nvidia Orin 安装onnxruntime-gpu,Nvidia Orin上安装onnxruntime-gpu的保姆级避坑指南(附Jetpack版本查询与GPU验证)
步骤4:安装 Ultralytics 并验证
bash
pip install ultralytics # 再次确认 numpy 未被再次改动 python3 -c "import numpy; print(numpy.__version__)"
验证 YOLO 与 GPU:
bash
python3 -c "
import torch, ultralytics, onnxruntime
print('PyTorch:', torch.__version__, '| CUDA:', torch.cuda.is_available())
print('Ultralytics:', ultralytics.__version__)
print('ORT providers:', onnxruntime.get_available_providers())
"
预期 CUDA: True,且 onnxruntime 包含 CUDAExecutionProvider(如果 ONNX Runtime 仅用于图校验而非推理,此条不是必需)。
步骤5:加载预训练模型(可选择其他模型,也可将前面实验课的代码直接拷贝过来)
python
from ultralytics import YOLO
model = YOLO("yolov8n.pt") # 首次自动下载,约 3.2M 参数
print("设备:", model.device)
yolov8n.pt 在 COCO 上预训练,包含 person 类别(类别 ID 为 0),足以支撑本实验的全部必做与选做内容。
3.3 PyTorch 基线推理
步骤6:测量单帧基线
准备一张任意包含常见目标的测试图像,创建 baseline_pytorch.py:
python
import time, cv2, numpy as np
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
img = cv2.imread("test_images/sample.jpg")
assert img is not None
for _ in range(10):
model(img, verbose=False)
times = []
for _ in range(50):
t0 = time.perf_counter()
model(img, verbose=False)
times.append(time.perf_counter() - t0)
avg = np.mean(times) * 1000
print(f"PyTorch 基线 — 平均延迟: {avg:.2f} ms | FPS: {1000/avg:.2f}")
这个数值代表“单帧、图像文件输入、纯推理”的性能。选做部分摄像头端到端 FPS 通常显著低于它,差距本身即是分析对象。
3.4 ONNX 导出与 TensorRT 引擎构建
步骤7:导出 ONNX
python
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
onnx_path = model.export(format="onnx", imgsz=640, opset=12, simplify=True)
print("ONNX:", onnx_path)
固定 imgsz 有利于 TensorRT 进行层融合和内存优化;opset 建议控制在 12–15,过高的 opset 可能在部分 TensorRT 版本中触发算子兼容性问题。
步骤8:构建 TensorRT FP16 引擎
方式 A:Ultralytics 直接导出
python
engine_path = model.export(format="engine", half=True, imgsz=640, workspace=4)
print("Engine:", engine_path)
Ultralytics 对 Jetson 设备的 TensorRT 导出默认 workspace 为 4GB,可避免构建过程中的内存分配失败。
方式 B:trtexec(可观察优化日志,非熟练不建议)
bash
/usr/src/tensorrt/bin/trtexec \
--onnx=yolov8n.onnx \
--saveEngine=yolov8n_fp16.engine \
--fp16 --workspace=4096 \
--verbose 2>&1 | tee trtexec_build.log
--workspace=4096 单位为 MB,即 4GB。构建过程可能持续数分钟,因为 TensorRT 需要针对 AGX Orin 的 GPU 逐层寻找最优执行策略。
注意!!!硬件特定性:engine 是为当前 JetPack 版本和 GPU 架构编译的。JetPack 5 上构建的 engine 不能直接在 JetPack 6 上加载,AGX Orin 的 engine 也不应直接用于 Orin Nano。
3.5 TensorRT 推理与性能对比
步骤9:TensorRT 单帧推理
python
import time, cv2, numpy as np
from ultralytics import YOLO
model = YOLO("yolov8n_fp16.engine", task="detect")
img = cv2.imread("test_images/sample.jpg")
for _ in range(10): model(img, verbose=False)
times = []
for _ in range(50):
t0 = time.perf_counter(); model(img, verbose=False)
times.append(time.perf_counter() - t0)
avg = np.mean(times) * 1000
print(f"TensorRT FP16 — 平均延迟: {avg:.2f} ms | FPS: {1000/avg:.2f}")
填入对比表:
| 推理后端 | 精度 | 平均延迟 (ms) | 吞吐量 (FPS) | 相对加速比 |
|---|---|---|---|---|
| PyTorch | FP32 | 实测 | 实测 | 1.00× |
| TensorRT | FP16 | 实测 | 实测 | 实测 |
作为量级参考,AGX Orin 64GB 在 MAXN 模式下运行 YOLOv8n 的 TensorRT FP16 推理,公开数据可达到约 371 FPS,YOLOv8s 约为 108–128 FPS,具体数值受功耗模式、输入尺寸和 jetson_clocks 状态影响。
步骤10:FP16 精度校验
在小型公开数据集(如 coco128.yaml)上对比:
python
from ultralytics import YOLO
pt_m = YOLO("yolov8n.pt").val(data="coco128.yaml")
trt_m = YOLO("yolov8n_fp16.engine", task="detect").val(data="coco128.yaml")
print("PyTorch mAP@0.5:", pt_m.box.map50)
print("TensorRT FP16 mAP@0.5:", trt_m.box.map50)
print("变化:", trt_m.box.map50 - pt_m.box.map50)
FP16 通常不会造成显著精度损失;若 mAP 变化异常,应优先排查前后处理是否一致,再考虑激活值溢出等数值问题。
3.6 选做:外置 USB 摄像头实时人员检测
步骤11:摄像头测试(程序运行后,摄像头应该能正常使用)
python
import cv2
# 打开默认摄像头
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("错误:无法打开摄像头")
exit()
while True:
# 读取一帧
ret, frame = cap.read()
if not ret:
print("错误:无法读取画面")
break
# 显示画面
cv2.imshow('USB Camera', frame)
# 按 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放资源并关闭窗口
cap.release()
cv2.destroyAllWindows()
步骤12:实时人员检测与可视化
COCO 预训练模型 person 的类别 ID 为 0:
python
import cv2, time
from ultralytics import YOLO
model = YOLO("yolov8n_fp16.engine", task="detect")
cap = cv2.VideoCapture(gstreamer_pipeline(), cv2.CAP_GSTREAMER)
if not cap.isOpened():
raise RuntimeError("GStreamer 管线打开失败")
prev = time.perf_counter()
fps_display = 0.0
while True:
ret, frame = cap.read()
if not ret: break
results = model(frame, conf=0.3, verbose=False)
boxes = results[0].boxes
person_count = 0
if boxes is not None:
for box in boxes:
if int(box.cls[0].item()) != 0:
continue
person_count += 1
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
conf = box.conf[0].item()
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(frame, f"person {conf:.2f}", (x1, max(y1-8, 20)),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
now = time.perf_counter()
inst_fps = 1.0 / (now - prev) if now > prev else 0
fps_display = 0.9 * fps_display + 0.1 * inst_fps if fps_display else inst_fps
prev = now
cv2.putText(frame, f"FPS: {fps_display:.1f} Persons: {person_count}",
(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.imshow("Jetson Person Detection", frame)
if cv2.waitKey(1) & 0xFF == ord("q"): break
cap.release()
cv2.destroyAllWindows()
帧率天花板:USB 摄像头的实际采集帧率可能低于标称值(例如标称 30 FPS,实测约 27–28 FPS)。此时端到端 FPS 由采集硬件决定,继续降低推理延迟不再带来收益。记录并讨论这一点是选做部分的关键分析内容。
四、实验验收标准
4.1 必做部分
-
在已有 conda + PyTorch 环境中成功安装
onnx、aarch64 专用onnxruntime-gpu和ultralytics,并处理好 numpy 版本兼容性 -
成功锁定 MAXN /
jetson_clocks,记录设置前后状态 -
PyTorch 基线脚本输出平均延迟与 FPS
-
ONNX 导出成功,TensorRT FP16 引擎构建成功(记录构建耗时)
-
给出 PyTorch vs TensorRT 延迟/FPS 对比表与加速比
-
完成 FP16 精度校验,报告 mAP 变化量
4.2 选做部分
-
成功使用 GStreamer 管线打开 USB 摄像头
-
实时人员检测程序正常运行,仅绘制
person类别,FPS 与人数显示正确 -
记录朴素读取与 GStreamer 两种方式的端到端 FPS,并给出瓶颈分析
4.3 报告质量
-
记录
onnxruntime-gpu安装后 numpy 版本冲突的发现与解决过程 -
对 TensorRT 加速机理和“单帧推理快 ≠ 端到端实时”有实质性讨论
-
理解 engine 硬件特定性和功耗模式对部署工程的影响
五、常见问题与解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
安装 onnxruntime-gpu 后 YOLO/PyTorch 报 numpy 错误 | onnxruntime 自动将 numpy 升级到不兼容版本 | 安装后立即固定兼容版本,如 pip install numpy==1.23.5 |
onnxruntime-gpu 安装失败或没有 CUDA Provider | PyPI 包不包含 aarch64 二进制 | 从 Jetson Zoo 或 Ultralytics 资源获取对应 JetPack + Python 版本的 aarch64 wheel |
TensorRT 构建报 Unsupported ONNX data type | opset 过高或算子兼容性 | 降低 opset 至 12–15,简化 ONNX 图 |
trtexec 找不到 | 路径未加入 PATH | 使用绝对路径 /usr/src/tensorrt/bin/trtexec |
| engine 构建耗时很长 | TensorRT 在为目标硬件逐层调优 | 属正常现象;--workspace 给足空间(如 4096 MB) |
| 摄像头实时 FPS 远低于单帧推理 FPS | V4L2 拷贝 + CPU 转换 + 串行流水线 | 改用 GStreamer 管线;确认 appsink drop=true 丢弃旧帧 |
| GStreamer 管线打开失败 | 设备节点或格式参数不匹配 | v4l2-ctl --list-devices 确认 /dev/video*;先用 videoconvert 通用管线验证 |
| 检测不到人员 | 置信度阈值过高 | 降低 conf(如 0.25–0.3);确认 yolov8n.pt 已正确加载 |
六、实验总结与思考
-
记录结果:填写 PyTorch vs TensorRT 的性能对比表,以及朴素读取 vs GStreamer 的端到端 FPS 对比。单帧推理的加速比是否直接转化为端到端实时性的同等提升?
-
问题思考:
-
在本实验的 conda 环境中,
onnxruntime-gpu的安装为什么需要手动处理 wheel 和 numpy 版本,而不能直接pip install onnxruntime-gpu? -
TensorRT 的加速来自层融合、FP16 降低计算量、kernel 针对 Ampere 架构自动调优。在你观察到的加速比中,哪一部分可能贡献最大?
-
选做部分中,朴素
cv2.VideoCapture(0)路径的瓶颈具体发生在哪几个环节?GStreamer 改变了什么,又无法改变什么? -
如果 USB 摄像头采集上限约为 27–30 FPS,而 TensorRT 推理仅需数毫秒,继续优化推理延迟还有意义吗?在什么条件下推理仍然是瓶颈?
-
TensorRT engine 的“硬件特定性”对多型号 Jetson 部署意味着什么策略?
-
-
实验报告要求:
-
提交 PDF 报告,包含:JetPack/依赖版本、YOLO 配置过程中 numpy 冲突的解决记录、性能模式设置、基线/优化后计时输出、对比表、精度校验结果、选做部分的摄像头实测截图与 FPS 数据,以及对思考题的书面回答。
-
提交代码压缩包(
baseline_pytorch.py、infer_tensorrt.py、camera_person_detect.py及 GStreamer 函数),确保核心脚本可复现。
-
提交格式:PDF 文档 + 代码压缩包
提交时间:实验完成后一周内
评分标准:YOLO 环境配置(20%) + 基线与模型转换(20%) + 推理与性能对比(20%) + 选做实时人员检测(15%) + 报告与思考(25%)
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/godblesszzc/article/details/169070229




