文章目录
- 一 前言
- 二 Jetson Orin 深度学习量化部署与算力评测通用教程:以 AGX Orin 上 YOLO26-Pose + CTR-GCN / PoseC3D 为完整实战
- 0. 先分清:哪些内容通用,哪些内容只适用于当前板子或算法
- 1. 先看结论:完整部署流程
- 2. 系统架构与每个模型在做什么
- 3. 输入、输出和张量形状基础
- 4. FP32、FP16、INT8 到底是什么
- 5. 为什么优先做 FP16,而不是直接 INT8
- 6. 环境准备、系统信息采集与 Conda 隔离
- 7. YOLO26-Pose 导出 TensorRT FP16
- 8. CTR-GCN 从 PyTorch 导出 ONNX 和 TensorRT FP16
- 9. CTR-GCN TensorRT 数值一致性验证
- 10. 把 CTR-GCN TensorRT 接入实时程序
- 11. PoseC3D 的输入、热图和 TensorRT 部署
- 12. INT8 量化:收益、风险和正确顺序
- 13. 延迟、速度、吞吐量如何计算
- 14. Orin 算力占用和功耗如何采集
- 15. GR3D、EMC、CPU、RAM、VDD_IN 等指标解释
- 16. CTR-GCN 与 PoseC3D 如何公平对比
- 17. 推荐的完整实验矩阵
- 18. 如何阅读自动生成的报告并下结论
- 19. 常见故障与解决方法
- 20. 最终交付物和复现检查清单
- 21. 换其他 Orin 或其他算法时如何迁移
- 22. 按任务查官方资料与参考文献
- 一句话总结
一 前言
文中涉及的代码需等我整理好后再给出。
二 Jetson Orin 深度学习量化部署与算力评测通用教程:以 AGX Orin 上 YOLO26-Pose + CTR-GCN / PoseC3D 为完整实战
适用对象:第一次接触 Jetson、TensorRT、ONNX、FP16/INT8、边缘端性能分析和姿态动作识别的开发者。
通用目标:建立一套可迁移到 Jetson AGX Orin、Orin NX、Orin Nano,以及检测、分类、分割、姿态、时序动作识别等其他算法的部署方法。
完整实战环境:Jetson AGX Orin、JetPack 5.1.2、L4T R35.4.1、CUDA 11.4、TensorRT 8.5.2.2、Python 3.8。
完整实战任务:使用 YOLO26-Pose 提取人体关键点,再用 CTR-GCN 或 PoseC3D 判断kicking / not_kicking。
文档版本说明:本教程中的命令以当前板端环境 JetPack 5.1.2 / L4T 35.4.1 / TensorRT 8.5.2 为准。NVIDIA 最新 TensorRT 文档中的部分参数已经变化,例如 TensorRT 10.x 将
--workspace改为--memPoolSize。遇到差异时,应优先执行本机trtexec --help,并查看本文提供的 TensorRT 8.x 归档文档,不要直接照抄最新版命令。
0. 先分清:哪些内容通用,哪些内容只适用于当前板子或算法
分类:整篇教程的适用范围说明。第一次阅读时建议先看完本章,再决定哪些命令可以照抄。
同一条“部署命令”通常同时受到四层因素影响:
通用深度学习部署方法
↓
Jetson / Orin 平台能力
↓
JetPack、L4T、CUDA、TensorRT 具体版本
↓
模型架构、输入输出、预处理和当前业务逻辑
因此,不能把“在某台 AGX Orin 上跑通的命令”理解成所有 Orin 和所有模型都能原样运行。正确做法是先判断命令属于哪一层。
0.1 本文使用的五种标签
| 标签 | 含义 | 换板子或换算法时怎么处理 |
|---|---|---|
| [通用方法] | 与具体 Orin 和模型无关的方法论 | 通常可以直接复用,例如建立 FP32 基线、ONNX 合法性检查、数值一致性验证 |
| [Linux 通用] | 常见 Linux 系统都可使用 | 如 uname、lscpu、pidstat、time、df;是否安装需自行确认 |
| [Jetson 通用] | Jetson 平台提供的工具 | 如 tegrastats、nvpmodel、jetson_clocks;其他桌面 GPU 不适用 |
| [版本特定] | 参数或 API 依赖 JetPack/TensorRT/PyTorch 版本 | 必须先查本机版本和对应归档文档,如 TRT 8.x 的 --workspace |
| [算法/项目特定] | 依赖模型结构、张量形状、类别、阈值或业务调度 | 不能照抄;必须按新模型重写 wrapper、预处理、后处理或调度逻辑 |
0.2 本教程各章节的适用范围
| 章节 | 主要分类 | 换其他 Orin | 换其他算法 |
|---|---|---|---|
| 1 完整部署流程 | [通用方法] + 当前项目示例 | 可复用流程 | 可复用流程,替换模型步骤 |
| 2 模型架构 | [算法特定] | 与板子无关 | 必须重新阅读新算法官方说明 |
| 3 输入输出 | [通用概念] + [算法特定] | 概念可复用 | shape、layout、dtype 必须重查 |
| 4~5 精度选择 | [通用方法] | 可复用 | 可复用,但敏感层和精度风险不同 |
| 6 环境检查 | [Linux/Jetson 通用] + [版本特定] | 命令大多可复用 | 与算法无关,框架包检查需替换 |
| 7 YOLO 导出 | [算法特定] + [版本特定] | 同算法可参考 | 非 Ultralytics 模型不能照抄 |
| 8 CTR-GCN 导出 | [算法/项目特定] | 同算法可参考 | wrapper 和输入构造必须重写 |
| 9 数值一致性 | [通用方法] + CTR-GCN 示例 | 方法可复用 | 比较脚本的输入输出部分要改 |
| 10 实时接入 | [项目特定] | 可能需要适配性能和摄像头 | 基本必须按新算法改写 |
| 11 PoseC3D | [算法特定] | 同算法可参考 | 其他算法不能照抄热图 pipeline |
| 12 INT8 | [通用方法] + [算法特定校准] | 方法可复用 | 校准输入和精度指标必须重做 |
| 13 性能公式 | [通用方法] | 直接复用 | 直接复用 |
| 14~15 Orin监控 | [Jetson 通用] + 解析器版本差异 | 可复用,字段可能变化 | 与算法无关,可复用 |
| 16~18 公平对比和报告 | [通用方法] | 直接复用 | 直接复用,替换业务指标 |
| 19 故障 | 混合 | 先判断版本和环境是否相同 | 只采用与现象匹配的部分 |
| 20 交付清单 | [通用方法] | 直接复用 | 直接复用 |
| 21 迁移指南 | [通用方法] | 直接使用 | 直接使用 |
0.3 可以直接复用的“骨架流程”
无论部署的是检测、分类、分割、姿态、语音、Transformer 还是动作识别,下面这条流程通常都成立:
1. 记录目标板系统与软件版本
2. 保存原框架精度和性能基线
3. 明确真实输入 shape / dtype / layout / 预处理
4. 导出中间格式(通常是 ONNX)
5. 检查 ONNX 并在可用后端验证输出
6. 在目标设备和目标 TensorRT 版本上构建 engine
7. 使用相同真实输入比较原模型与 engine 输出
8. 接入完整应用,分开统计预处理、推理和后处理
9. 关闭显示、保存和 debug,采集稳定态性能与功耗
10. 再做 FP16、INT8、剪枝或调度优化
这十步是本教程最核心、最通用的部分。
0.4 不能直接复用的内容
下列内容只要换了算法,通常就必须重新确认:
- 输入数量、输入名称和 shape;
NCHW、NHWC、NCTHW、骨架图等 layout;- RGB/BGR、归一化均值方差、resize、letterbox、裁剪;
- 动态 batch、动态分辨率和动态序列长度;
- 输出是 logits、概率、框、mask、关键点还是 token;
- NMS、softmax、阈值、标签映射和时序平滑;
- 是否包含 TensorRT 不支持的算子或自定义插件;
- INT8 校准样本到底是原始数据还是预处理后的张量;
- 正确性指标是 Top-1、mAP、mIoU、OKS、F1、召回率还是事件级误报率。
下列内容只要换了 Orin 或 JetPack,通常就必须重新确认:
- 支持的 JetPack/L4T 版本;
- CUDA、cuDNN、TensorRT 和 Python 版本;
trtexec参数和 Python API;- 可用内存、GPU频率、DLA数量与功耗模式;
- TensorRT engine 是否需要在新设备上重新构建;
tegrastats字段名称和功耗电源轨;- PyTorch、torchvision、MMCV 等 wheel 是否与 aarch64 和 CUDA 匹配。
0.5 三个最容易混淆的“通用与特定”边界
边界一:ONNX 是通用格式,但导出代码不是完全通用
torch.onnx.export() 的思想可复用,但每个模型的 wrapper、dummy input 和动态维度不同。CTR-GCN 的 (1, 1, 2, 100, 17, 3) 不能拿去导出图像分类模型。
边界二:trtexec 是通用工具,但参数随版本变化
--onnx、--saveEngine、--loadEngine 的用途较稳定;工作区、精度约束、动态 shape 和 profiling 参数可能随 TensorRT 版本变化。始终先运行:
trtexec --help
python -c "import tensorrt as trt; print(trt.__version__)"
边界三:tegrastats 可测所有 Jetson 应用,但不能直接给出模型 TOPS
它能告诉你 GPU 忙碌度、内存带宽、CPU、RAM、温度和功耗;它不知道“某个模型理论执行了多少有效 FLOPs/TOPS”。模型计算量需要模型分析工具或算子级 profiling,实际板端压力则用 tegrastats、trtexec、Nsight Systems 和应用日志综合判断。
快速导航:我现在要做什么,应看哪份官方资料?
下面这张表适合在实际操作时快速查阅。本文负责把项目步骤串起来;官方资料负责解释工具的完整参数和版本规则。
| 你现在要做的事情 | 优先查看的官方资料 | 适用说明 |
|---|---|---|
| 确认 JetPack 5.1.2 自带哪些 CUDA/TensorRT 版本 | NVIDIA JetPack 5.1.2 Release Notes | 与本教程环境直接对应 |
| 安装或补装 JetPack 5.1.2 组件 | NVIDIA JetPack 5.1.2 Installation Guide | apt/SDK Manager 相关操作 |
| 理解 YOLO26-Pose 的关键点输出 | Ultralytics Pose Task | 关键点、训练、验证、预测、导出 |
| 把 YOLO26-Pose 导出为 TensorRT | Ultralytics TensorRT Integration | format=engine、FP16、INT8 等 |
| 查看 Ultralytics 全部导出参数 | Ultralytics Export Mode | imgsz、half、int8、dynamic 等 |
| 在 Jetson 上安装和部署 Ultralytics | Ultralytics NVIDIA Jetson Guide | Jetson 环境与 TensorRT 部署 |
| 使用 ByteTrack/BoT-SORT 进行多目标跟踪 | Ultralytics Track Mode | Pose 模型同样支持视频跟踪 |
| 理解 CTR-GCN 的网络设计 | CTR-GCN 官方代码库 / ICCV 2021 原论文 | 图结构、通道拓扑细化、时序建模 |
| 理解 PoseC3D 的热图输入和模型结构 | MMAction2 PoseC3D README | PoseC3D 官方实现与模型表 |
| 用自己的数据训练 PoseC3D | MMAction2 PoseC3D Custom Dataset Tutorial | 标注、关键点提取、训练流程 |
| 理解 MMAction2 的骨架数据格式 | MMAction2 Customize Dataset | keypoint、keypoint_score、PoseDataset |
| 把 PyTorch 模型导出成 ONNX | PyTorch ONNX Tutorial | 官方导出流程;旧版 PyTorch 需结合本教程脚本 |
| 检查 ONNX 图是否合法 | ONNX Checker API | onnx.checker.check_model() |
| 用 ONNX 构建 TensorRT engine | TensorRT trtexec Command Reference | 最新参数总览;TRT 8.x 参数以本机帮助为准 |
| 理解 TensorRT 8.x 的完整开发流程 | TensorRT 8.6.1 Archived Developer Guide | 与 TensorRT 8.5 接近,适合本项目参考 |
| 查看 TensorRT 8.x 到 10.x 参数差异 | Migrating trtexec from TensorRT 8.x to 10.x | 防止照抄新版参数 |
| 做 FP16/INT8 和混合精度 | TensorRT Quantization Workflows | 最新 PTQ/QAT/Q-DQ 思路 |
| 在 TensorRT 8.x 编写 INT8 calibrator | TensorRT 8.6.1 IInt8Calibrator API | 适合 JetPack 5.x 的旧式校准接口 |
用 trtexec 测延迟和吞吐 | TensorRT Performance Benchmarking | Latency、Throughput、CUDA Graph 等 |
看懂 tegrastats 的 RAM/CPU/EMC/GR3D | Jetson Linux R35.4.1 Tegrastats Utility | 与当前 L4T 版本直接对应 |
| 固定 Orin 功耗模式和时钟 | Jetson Orin Power and Performance | nvpmodel、jetson_clocks、功率与频率 |
| 做 CPU/GPU 时间线级分析 | NVIDIA Nsight Systems User Guide | 定位 CPU 等 GPU、kernel launch、同步等问题 |
查询 cv2.imshow/HighGUI 行为 | OpenCV HighGUI Reference | 窗口、imshow、waitKey |
| 使用独立显示进程 | Python multiprocessing | spawn、Queue、Event、Process |
| 减少跨进程整帧复制 | Python Shared Memory | 后续可把 Queue 升级为共享内存 |
| 先确认手上是哪款 Jetson、哪个 L4T/JetPack | JetPack Archive / Jetson Linux Software Packages | 先执行本文第6章系统信息命令,再选择匹配的归档文档 |
| 查询其他 Jetson/Orin 型号 | NVIDIA Jetson Modules | 比较模块、内存和平台定位;具体功耗模式仍查对应 L4T 文档 |
| 判断当前 TensorRT 与系统是否兼容 | TensorRT Support Matrix | 先选择本机 TensorRT 版本;不要默认最新版适用于旧 JetPack |
| 判断 engine 能否跨设备或跨版本使用 | TensorRT Engine Compatibility | JetPack 上通常应在目标设备/目标软件栈重建并验证 engine |
| 换成其他 PyTorch 算法导出 ONNX | PyTorch torch.onnx Documentation | 通用导出入口;dummy input、dynamic shape、wrapper 按新模型修改 |
阅读原则:项目命令以本文和本机软件版本为准;概念、API 语义和完整参数以官方文档为准。对于 TensorRT,尤其要先分清自己使用的是 8.x、10.x 还是更高版本。
1. 先看结论:完整部署流程
分类:[通用方法],流程可迁移;图中的模型名称和输入处理属于 [算法/项目特定]。
本项目推荐的部署顺序如下:
训练好的 PyTorch 模型
│
├── YOLO26-Pose .pt
│ ↓
│ TensorRT FP16 .engine
│
├── CTR-GCN best.pth + resolved_config.py
│ ↓
│ ONNX
│ ↓
│ TensorRT FP16 .engine
│
└── PoseC3D checkpoint/config
↓
姿态热图输入 ONNX
↓
TensorRT FP16 .engine
完整推理链路:
视频 / 摄像头
↓
YOLO26-Pose TensorRT FP16
↓
人体框 + 17 个关键点 + 关键点置信度
↓
ByteTrack 分配人物 ID
↓
按人物 ID 维护时序骨架历史
↓
┌──────────────────────┬────────────────────────┐
│ CTR-GCN │ PoseC3D │
│ 骨架图序列 │ 骨架转时空热图 │
│ 图卷积 + 时间卷积 │ 3D CNN / SlowOnly │
└──────────────────────┴────────────────────────┘
↓
kicking / not_kicking 概率
性能测试分成两种:
- 模型单体测试:只测 CTR-GCN engine 或 PoseC3D engine。
- 完整链路测试:测视频读取、YOLO、跟踪、预处理、动作模型、Python 调度和整板功耗。
正式比较时,必须同时给出这两种结果。
2. 系统架构与每个模型在做什么
分类:[算法特定]。换其他算法时应查看新模型论文、官方仓库和框架配置。
2.1 为什么不能只用动作分类模型
CTR-GCN 和 PoseC3D 都不是直接读取原始视频画面的模型。它们需要人体姿态数据,因此需要先运行 YOLO26-Pose。
YOLO26-Pose 的作用是回答:
- 画面里有几个人?
- 每个人在哪里?
- 鼻子、肩、肘、腕、髋、膝、踝等 17 个关键点在哪里?
- 每个关键点有多可信?
动作模型的作用是回答:
- 这一段连续骨架运动是不是踢腿?
因此二者是前后级关系,不是替代关系。
2.2 为什么需要 ByteTrack
YOLO 每帧都检测人,但单独的检测结果不知道“这一帧的人”和“上一帧的人”是不是同一个人。
ByteTrack 会给每个人分配连续 ID,例如:
第 1 帧:人物 ID=3
第 2 帧:人物 ID=3
第 3 帧:人物 ID=3
这样程序才能为 ID=3 单独保存连续 20~100 帧的骨架历史。
2.3 CTR-GCN 为什么这样设计
CTR-GCN 把人体骨架视为一张图:
- 每个关节是一个节点;
- 骨骼连接是边;
- 连续帧构成时间维度;
- 节点特征是
(x, y, score)。
它重点学习:
- 膝盖与脚踝的相对运动;
- 髋—膝—踝的空间关系;
- 动作随时间如何展开;
- 不同关节之间的动态关联。
优点:
- 输入张量小;
- 模型参数较少;
- 通常比热图 3D CNN 更省内存和算力;
- 适合边缘设备。
风险:
- 非常依赖关键点质量;
- 遮挡导致关键点漂移时,信息会直接丢失;
- 只看骨架,不看箱子、车门、环境等视觉上下文。
2.4 PoseC3D 为什么这样设计
PoseC3D 不直接把关节当图节点,而是把每个关键点变成二维高斯热图,再沿时间堆叠成三维时空体。
例如某个膝盖的位置不是一个点,而是一小团高斯响应:
关键点坐标 (x, y)
↓
二维热图 H×W
↓
连续 T 帧堆叠
↓
C×T×H×W 的时空体
↓
3D CNN
它的优点:
- 对小范围关键点抖动通常更鲁棒;
- 3D 卷积可以学习局部时空运动纹理;
- 关键点轻微偏差不会像纯坐标模型那样直接改变数值关系。
代价:
- 热图尺寸远大于骨架坐标;
- CPU 生成热图可能很耗时;
- 3D 卷积计算量和显存带宽压力更大;
- 完整链路延迟通常高于 CTR-GCN。
2.5 为什么本项目给 CTR-GCN 加动作完成候选检测
当前 CTR-GCN 实时程序不是每帧都调用动作模型,而是先通过已有关键点判断“腿是否踢出并收回”,只有出现候选时才调用 CTR-GCN。
这样设计的目的:
- 避免每帧重复运行动作模型;
- 降低整机平均 GPU 使用率;
- 将连续分类结果转化为一次性踢腿事件;
- 更适合“踢一下触发一次开门”的业务逻辑。
需要注意:
这种事件驱动调度会显著降低整机平均功耗,但它属于调度优化,不等于 CTR-GCN 模型本身一定快了同样比例。
3. 输入、输出和张量形状基础
分类:张量、shape、dtype、layout 是 [通用概念];本章具体 shape 是 [算法/项目特定]。
3.1 什么是张量
张量可以理解为多维数组。
常见维度字母:
| 字母 | 含义 |
|---|---|
| B / N | Batch,批量大小 |
| C | Channel,通道数或特征数 |
| T | Time,时间帧数 |
| H | Height,高度 |
| W | Width,宽度 |
| M | Person,最多人数 |
| V | Vertex / Joint,关节数 |
3.2 YOLO26-Pose 输入输出
典型输入:
原始 BGR 图像:H×W×3
↓ letterbox/resize
640×640×3
↓ 转 RGB、归一化、转 NCHW
1×3×640×640
典型输出经 Ultralytics 后处理后包括:
boxes.xyxy [人数, 4]
boxes.conf [人数]
boxes.id [人数] # 启用跟踪时
keypoints.data [人数, 17, 3]
关键点最后一维:
[x, y, confidence]
COCO 17 点索引:
0 nose
1 left_eye
2 right_eye
3 left_ear
4 right_ear
5 left_shoulder
6 right_shoulder
7 left_elbow
8 right_elbow
9 left_wrist
10 right_wrist
11 left_hip
12 right_hip
13 left_knee
14 right_knee
15 left_ankle
16 right_ankle
3.3 CTR-GCN 输入输出
MMAction2 原始骨架数据常用格式:
keypoint [M, T, V, 2]
keypoint_score [M, T, V]
其中:
M:人数;T:帧数;V=17:COCO 关键点数;- 坐标通道是 x、y;
- score 是关键点置信度。
经过验证 pipeline 后,当前项目导出的实际输入:
[1, 1, 2, 100, 17, 3]
含义:
B=1
num_clips=1
M=2
T=100
V=17
C=3,即 x、y、score
输出:
logits [1, 2]
类别约定:
0 = kicking
1 = not_kicking
logits 不是概率,需要 softmax:
probability = torch.softmax(logits, dim=1)
3.4 PoseC3D 输入输出
PoseC3D 原始输入也是骨架:
keypoint [M, T, 17, 2]
keypoint_score [M, T, 17]
但在送进模型前,会生成关键点热图:
关键点序列
↓ GeneratePoseTarget
pose heatmap
↓ 格式化
[B, C, T, H, W]
C 可能是:
- 17 个关键点热图;
- 或关键点 + limb 热图;
- 实际通道数必须根据配置文件确认。
输出通常也是:
logits [B, 2]
不要在教程里硬编码 PoseC3D 热图形状。应先读取配置和实际 engine 绑定信息。
4. FP32、FP16、INT8 到底是什么
分类:[通用方法]。适用于绝大多数推理模型,但硬件支持和收益取决于目标设备。
4.1 FP32
FP32 是 32 位浮点数。
特点:
- 数值范围和精度较高;
- 训练最常用;
- 模型占用内存较大;
- 推理速度通常慢于 FP16/INT8。
一个 FP32 数值占 4 字节。
4.2 FP16
FP16 是 16 位浮点数,一个数占 2 字节。
理论上相较 FP32:
- 权重内存约减半;
- 内存传输量下降;
- 可使用 Tensor Core 或半精度指令;
- 通常加速明显;
- 精度一般下降较小。
风险:
- 有效数字更少;
- 数值范围更窄;
- 某些层可能溢出或精度下降;
- TensorRT 通常会采用混合精度,而不是强制所有层都 FP16。
4.3 INT8
INT8 使用 8 位整数表示激活和权重。
一个数占 1 字节,相比 FP32 理论存储量是四分之一。
潜在收益:
- 模型更小;
- 内存带宽更低;
- 支持 INT8 的硬件上吞吐更高;
- 功耗可能下降。
风险:
- 必须把浮点范围映射到有限整数范围;
- 校准数据不代表真实场景时,精度可能明显下降;
- 姿态关键点模型对量化误差可能敏感;
- 关键点误差会进一步传递给动作模型;
- 最终分类阈值可能需要重新选择。
4.4 参数精度、计算精度和接口精度不是一回事
运行 trtexec 时看到:
Input(s)s format: fp32
Output(s)s format: fp32
不代表 engine 内部全部使用 FP32。
可能情况是:
接口输入:FP32
内部计算:FP16
接口输出:FP32
这样可以减少调用方转换麻烦,同时让内部层使用低精度加速。
4.5 常见误解
误解 1:FP16 就一定快 2 倍
不一定。实际速度还受以下因素影响:
- 算子是否支持 Tensor Core;
- 模型是不是内存带宽受限;
- 预处理是否占主要时间;
- Python 和跟踪是否成为瓶颈;
- batch 是否为 1;
- TensorRT 是否进行了层融合。
误解 2:GR3D 50% 等于使用 50% TOPS
错误。
GR3D 是 GPU 忙碌时间比例,不是实际执行了多少整数运算或浮点运算。
误解 3:engine 后缀写了 FP16,就能证明全部层是 FP16
错误。文件名只是人为命名。真正要通过构建日志、layer info 和性能验证确认。
5. 为什么优先做 FP16,而不是直接 INT8
分类:[通用方法]。先建立正确 FP16 基线再做 INT8,适用于大多数工程部署。
推荐顺序:
PyTorch FP32 基线
↓
ONNX FP32
↓
TensorRT FP16
↓
数值一致性验证
↓
完整视频准确率验证
↓
性能和功耗基线
↓
INT8 校准和验证
这样做的好处:
- FP16 通常容易成功;
- 可以先验证 ONNX 和 TensorRT 转换链路是否正确;
- 若 INT8 精度下降,可以明确问题来自量化,而不是导出逻辑;
- 可以先判断 FP16 是否已经达到实时和功耗目标;
- 避免 YOLO 和动作模型同时 INT8 后无法定位误差来源。
推荐渐进实验:
A. YOLO FP16 + CTR-GCN FP16
B. YOLO INT8 + CTR-GCN FP16
C. YOLO FP16 + CTR-GCN INT8
D. YOLO INT8 + CTR-GCN INT8
每一步都重新测试关键点精度、动作召回率、误报率和阈值。
6. 环境准备、系统信息采集与 Conda 隔离
分类:包含 [Linux 通用]、[Jetson 通用]、[版本特定] 和 [项目特定] 内容,请按小节标签使用。
6.1 在任何 Jetson / Orin 上先采集系统信息
分类:前半部分是 [Linux 通用],
nv_tegra_release、nvpmodel、jetson_clocks和tegrastats是 [Jetson 通用];具体输出和参数是 [版本特定]。
不要先猜“这块板应该是 JetPack 5 还是 6”,也不要仅凭设备商品名判断软件版本。先在目标板执行下面的命令并保存结果。
6.1.1 查询板卡型号和 CPU 架构
tr -d '\0' < /proc/device-tree/model; echo
uname -m
lscpu
常见解释:
aarch64:64位 ARM 架构,是 Orin 上正常的结果;/proc/device-tree/model:识别 AGX Orin、Orin NX、Orin Nano 或开发套件;lscpu:核数、在线 CPU、架构和缓存信息。
uname -m 是 Linux 通用命令;读取设备树型号主要面向嵌入式 Linux,具体字符串由板级设备树决定。
6.1.2 查询 Ubuntu、内核和 L4T
cat /etc/os-release
uname -a
cat /etc/nv_tegra_release
dpkg-query -W nvidia-l4t-core
其中:
/etc/os-release:Ubuntu 版本;uname -a:Linux 内核和架构;/etc/nv_tegra_release:Jetson Linux/L4T BSP 版本,是选择 Jetson Linux 归档文档的关键;nvidia-l4t-core:用 Debian 包再次核对 L4T 版本。
NVIDIA 的 Jetson Linux 软件包文档明确建议通过 /etc/nv_tegra_release 检查当前软件版本:
- 当前实战 R35.4.1 文档:https://docs.nvidia.com/jetson/archives/r35.4.1/DeveloperGuide/text/SD/SoftwarePackagesAndTheUpdateMechanism.html
- Jetson Linux 文档总入口:https://docs.nvidia.com/jetson/
注意:L4T/BSP 是板端系统最可靠的版本锚点。
nvidia-jetpack是元软件包,可能没有安装,或者系统只安装了部分 JetPack 组件,所以不能只看这个包。
6.1.3 查询 JetPack 元软件包
dpkg-query -W nvidia-jetpack 2>/dev/null || true
apt-cache policy nvidia-jetpack
如果查不到,不代表 CUDA/TensorRT 一定没有安装,只可能表示没有安装完整 nvidia-jetpack 元包。应继续逐项查询 CUDA、TensorRT 和 cuDNN。
JetPack 历史版本入口:
6.1.4 查询 CUDA
nvcc --version
readlink -f /usr/local/cuda
cat /usr/local/cuda/version.json 2>/dev/null || \
cat /usr/local/cuda/version.txt 2>/dev/null
还要在当前 Python 环境查看框架实际绑定的 CUDA:
python - <<'PY'
import torch
print('PyTorch:', torch.__version__)
print('PyTorch编译CUDA:', torch.version.cuda)
print('CUDA可用:', torch.cuda.is_available())
if torch.cuda.is_available():
print('GPU:', torch.cuda.get_device_name(0))
print('Compute Capability:', torch.cuda.get_device_capability(0))
PY
nvcc --version 显示系统 CUDA Toolkit;torch.version.cuda 显示当前 PyTorch 构建时使用的 CUDA 版本,两者概念不同。
6.1.5 查询 TensorRT 和 cuDNN
dpkg-query -W -f='${Package}\t${Version}\n' \
'tensorrt*' 'libnvinfer*' 'python3-libnvinfer*' 'libcudnn*' \
2>/dev/null | sort -u
python - <<'PY'
try:
import tensorrt as trt
print('TensorRT Python:', trt.__version__)
print('TensorRT path:', trt.__file__)
except Exception as e:
print('TensorRT Python不可用:', e)
PY
command -v trtexec || true
ls -l /usr/src/tensorrt/bin/trtexec 2>/dev/null || true
TensorRT 官方兼容矩阵:
TensorRT 归档文档入口:
6.1.6 查询当前 Python、Conda 和模型框架
echo "CONDA_PREFIX=$CONDA_PREFIX"
which python
python -V
python -m pip --version
conda info --base 2>/dev/null || true
一次性查看常用包:
python - <<'PY'
import importlib
import sys
print('Python:', sys.version)
print('Executable:', sys.executable)
for name in [
'numpy', 'torch', 'torchvision', 'tensorrt', 'onnx',
'onnxruntime', 'cv2', 'ultralytics', 'mmcv',
'mmengine', 'mmaction'
]:
try:
m = importlib.import_module(name)
print(name, getattr(m, '__version__', '<无版本字段>'), getattr(m, '__file__', ''))
except Exception as e:
print(name, '不可用:', e)
PY
换成其他算法时,把框架包名替换为对应框架,例如 TensorFlow、Paddle、Detectron2、Transformers 或自研包。
6.1.7 查询功耗模式和时钟
sudo nvpmodel -q
sudo jetson_clocks --show
用于跑性能测试时,通常还会执行:
sudo jetson_clocks
sudo jetson_clocks --show
这些命令是 Jetson 平台通用工具,但:
- 各 Orin 型号的模式编号和功耗上限不同;
- 最大时钟受当前
nvpmodel模式限制; - 不应把 AGX Orin 的模式编号复制到 Orin NX/Nano;
- 应查看与目标 L4T 和目标模块匹配的“Platform Power and Performance”章节。
当前 R35.4.1 Orin 文档:
6.1.8 查询 GPU、CPU、内存、温度和功耗实时状态
tegrastats --interval 1000
停止:
Ctrl+C
当前 R35.4.1 字段说明:
nvidia-smi 在不同 Jetson 软件栈中的支持情况不同,也不能替代 Jetson 的电源轨、EMC 和 SoC 监控。Jetson 性能采集优先使用 tegrastats。
6.1.9 一键生成系统信息报告
教程压缩包提供:
collect_jetson_system_info.sh
运行:
chmod +x collect_jetson_system_info.sh
./collect_jetson_system_info.sh
或指定输出文件:
./collect_jetson_system_info.sh system_info_before_deployment.txt
这个脚本可以用于不同 Orin 和不同算法,因为它主要采集平台、软件栈和当前 Python 环境。换算法时无需改脚本;只需确保在目标算法的 Conda 环境中再运行一次,记录该环境的包版本。
6.2 当前实战板端环境
本项目当前验证环境:
硬件:Jetson AGX Orin Developer Kit
JetPack:5.1.2
L4T:R35.4.1
CUDA:11.4
TensorRT:8.5.2.2
Python:3.8
CTR-GCN 运行环境中已验证组合:
PyTorch:1.11.0
Torchvision:0.12.0a0
MMCV:2.1.0
MMEngine:0.10.7
MMAction2:1.2.0
YOLO 导出环境中已验证组合:
PyTorch:2.1.0a0+41361538.nv23.06
CUDA:11.4
Ultralytics:8.4.52
6.3 为什么当前项目分两个 Conda 环境
原因:
- CTR-GCN/MMCV 可能依赖旧 PyTorch ABI;
- YOLO26 导出需要更高版本的 PyTorch/Ultralytics;
- 强行在一个环境里替换 Torch,可能导致
mmcv.ops二进制不兼容; - pip 安装错误环境会破坏原有链路。
建议:
ctrgcn # 完整运行、MMAction2、CTR-GCN、PoseC3D
yolo_export # YOLO .pt 导出 TensorRT
6.4 每次安装前先确认 Python 和 pip
echo "CONDA_PREFIX=$CONDA_PREFIX"
python -c "import sys; print(sys.executable)"
python -m pip --version
conda info --base
安装包统一使用:
python -m pip install 包名
不要只输入:
pip install 包名
因为 pip 的 shebang 可能仍指向旧环境。
6.5 检查当前项目核心环境
python - <<'PY'
import torch
import torchvision
import numpy as np
print("Torch:", torch.__version__)
print("Torchvision:", torchvision.__version__)
print("NumPy:", np.__version__)
print("CUDA:", torch.version.cuda)
print("CUDA可用:", torch.cuda.is_available())
if torch.cuda.is_available():
print("GPU:", torch.cuda.get_device_name(0))
x = torch.randn(256, 256, device="cuda")
y = x @ x
torch.cuda.synchronize()
print("CUDA计算正常:", y.shape)
PY
CTR-GCN 环境再检查:
python - <<'PY'
import mmcv
import mmcv.ops
import mmengine
import mmaction
print("MMCV:", mmcv.__version__)
print("MMEngine:", mmengine.__version__)
print("MMAction2:", mmaction.__version__)
print("mmcv.ops正常")
PY
7. YOLO26-Pose 导出 TensorRT FP16
分类:[Ultralytics/YOLO算法特定] + [TensorRT版本特定]。其他模型只能复用导出—验证的方法,不能照抄命令。
7.1 准备模型
假设权重:
models/yolo26n-pose.pt
进入 yolo_export 环境:
conda activate yolo_export
cd /media/orin2/45fd09e1-b992-4c00-9a54-232c1fb0e672/kicking/kick_action_orin_benchmark/models
7.2 先验证 .pt 模型能加载
python - <<'PY'
from ultralytics import YOLO
model = YOLO("yolo26n-pose.pt", task="pose")
print("模型加载成功")
print("任务类型:", model.task)
model.info()
PY
7.3 用一帧视频验证 CUDA 推理
python - <<'PY'
import cv2
from ultralytics import YOLO
video_path = "../out_06.mp4"
model_path = "yolo26n-pose.pt"
cap = cv2.VideoCapture(video_path)
ok, frame = cap.read()
cap.release()
if not ok:
raise RuntimeError(f"无法读取视频:{video_path}")
model = YOLO(model_path, task="pose")
result = model.predict(
source=frame,
device=0,
imgsz=640,
conf=0.25,
iou=0.70,
verbose=True,
)[0]
print("检测人数:", len(result.boxes) if result.boxes is not None else 0)
print("关键点:", result.keypoints.data.shape if result.keypoints is not None else None)
PY
7.4 导出 FP16 engine
python - <<'PY'
from ultralytics import YOLO
model = YOLO("yolo26n-pose.pt", task="pose")
output = model.export(
format="engine",
device=0,
imgsz=640,
batch=1,
half=True,
dynamic=False,
workspace=4,
simplify=False,
)
print("导出结果:", output)
PY
重命名:
mv yolo26n-pose.engine \
yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine
命名建议包含:
模型名_设备_JetPack_TensorRT_精度_输入尺寸_batch.engine
7.5 TensorRT 8.5 与 NumPy 1.24 的 np.bool 问题
若报错:
AttributeError: module 'numpy' has no attribute 'bool'
在导入 TensorRT/Ultralytics 前加:
import numpy as np
if "bool" not in np.__dict__:
np.bool = np.bool_
也可以在当前环境创建:
SITE_PACKAGES=$(python -c 'import site; print(site.getsitepackages()[0])')
cat > "$SITE_PACKAGES/sitecustomize.py" <<'PY'
import numpy as np
if "bool" not in np.__dict__:
np.bool = np.bool_
PY
7.6 验证 engine
python - <<'PY'
import numpy as np
if "bool" not in np.__dict__:
np.bool = np.bool_
import cv2
from ultralytics import YOLO
engine = "yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine"
video = "../out_06.mp4"
cap = cv2.VideoCapture(video)
ok, frame = cap.read()
cap.release()
if not ok:
raise RuntimeError("无法读取视频")
model = YOLO(engine, task="pose")
result = model.predict(frame, device=0, imgsz=640, verbose=True)[0]
print("Engine推理成功")
print("人数:", len(result.boxes) if result.boxes is not None else 0)
print("关键点:", result.keypoints.data.shape if result.keypoints is not None else None)
PY
7.7 Unknown embedded device 警告
AGX Orin 64GB + TensorRT 8.5 可能显示:
Unknown embedded device detected.
Using 59660MiB as the allocation cap...
这表示 TensorRT 使用检测到的内存作为分配上限,不是立即占用 59GB。只要最后 engine 构建成功并能推理,通常可以忽略。
7.8 Engine 可移植性
TensorRT engine 通常与以下内容绑定:
- GPU 架构;
- TensorRT 版本;
- CUDA/JetPack 环境;
- 构建时选择的 tactic。
因此推荐在最终部署的 AGX Orin 上构建,不要把其他 GPU 上生成的 engine 直接作为正式版本。
本章官方参考
8. CTR-GCN 从 PyTorch 导出 ONNX 和 TensorRT FP16
分类:ONNX/TensorRT 流程是 [通用方法];wrapper、shape 和 pipeline 是 [CTR-GCN/项目特定]。
配套脚本:
scripts/export_ctrgcn_onnx.py
scripts/validate_ctrgcn_trt.py
scripts/realtime_ctrgcn_trt_fp16.py
将脚本复制到项目根目录:
cp scripts/*.py .
8.1 输入文件
output_online/runs/ctrgcn/seed_42/resolved_config.py
output_online/runs/ctrgcn/seed_42/best.pth
output_online/runs/ctrgcn/seed_42/result.json
8.2 为什么不能直接把 .pth 改名成 .engine
.pth 是 PyTorch 权重,依赖 Python、模型类和框架执行。
.engine 是 TensorRT 已优化的推理计划,包含:
- 层融合;
- kernel/tactic 选择;
- 精度决策;
- 显存规划;
- 输入输出绑定。
必须经过:
PyTorch 模型 + 权重
↓
ONNX 计算图
↓
TensorRT engine
8.3 导出 ONNX
conda activate ctrgcn
cd /media/orin2/45fd09e1-b992-4c00-9a54-232c1fb0e672/kicking/kick_action_orin_benchmark
python export_ctrgcn_onnx.py \
--config output_online/runs/ctrgcn/seed_42/resolved_config.py \
--checkpoint output_online/runs/ctrgcn/seed_42/best.pth \
--output models/ctrgcn_fp32_static.onnx \
--device cpu \
--skip-ort
脚本会:
- 注册 MMAction2 和
projects.ctrgcn.models; - 加载 config 与 checkpoint;
- 复用验证 pipeline;
- 构造真实格式输入;
- 提取 backbone + GCNHead;
- 导出 logits;
- 保存测试输入和参考输出。
生成:
models/ctrgcn_fp32_static.onnx
models/ctrgcn_fp32_static.input.npy
models/ctrgcn_fp32_static.json
预期输入:
skeleton [1, 1, 2, 100, 17, 3]
预期输出:
logits [1, 2]
8.4 查看 ONNX 输入输出
python - <<'PY'
import onnx
model = onnx.load("models/ctrgcn_fp32_static.onnx")
print("输入:")
for item in model.graph.input:
dims = [
d.dim_value if d.dim_value > 0 else d.dim_param
for d in item.type.tensor_type.shape.dim
]
print(item.name, dims)
print("输出:")
for item in model.graph.output:
dims = [
d.dim_value if d.dim_value > 0 else d.dim_param
for d in item.type.tensor_type.shape.dim
]
print(item.name, dims)
PY
8.5 构建 TensorRT FP16 engine
/usr/src/tensorrt/bin/trtexec \
--onnx=models/ctrgcn_fp32_static.onnx \
--saveEngine=models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--fp16 \
--workspace=2048 \
--buildOnly \
2>&1 | tee ctrgcn_build_fp16.log
成功标志:
Engine built successfully
&&&& PASSED TensorRT.trtexec
8.6 单模型性能测试
/usr/src/tensorrt/bin/trtexec \
--loadEngine=models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--warmUp=2000 \
--duration=30 \
--useSpinWait \
2>&1 | tee ctrgcn_benchmark_fp16.log
重点看:
Throughput
Latency
GPU Compute Time
Enqueue Time
H2D Latency
D2H Latency
8.7 查看绑定信息
/usr/src/tensorrt/bin/trtexec \
--loadEngine=models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--dumpLayerInfo \
--profilingVerbosity=detailed \
--iterations=1 \
2>&1 | tee ctrgcn_engine_info.log
grep -E \
"Input|Output|Binding|Latency|Throughput|GPU Compute" \
ctrgcn_engine_info.log
9. CTR-GCN TensorRT 数值一致性验证
分类:比较同一输入的原框架与部署后端输出属于 [通用方法];脚本中的输入和类别解释是 [算法特定]。
只生成 engine 不代表结果正确。必须使用相同输入比较 PyTorch 和 TensorRT。
python validate_ctrgcn_trt.py \
--engine models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--input models/ctrgcn_fp32_static.input.npy \
--metadata models/ctrgcn_fp32_static.json \
--warmup 50 \
--iterations 500
本项目一次实测结果:
输入数组:(1, 1, 2, 100, 17, 3) float32
输出:(1, 2) float32
PyTorch logits: [-2.3435175, 2.3578887]
TensorRT logits:[-2.3435402, 2.3579068]
logits最大绝对误差:2.26498e-05
概率最大绝对误差:3.63216e-07
类别一致:not_kicking
平均端到端调用耗时:约 6.43 ms
判断标准建议:
最终类别必须一致
logits最大绝对误差 < 0.05
真实视频事件结果基本一致
单个样本通过后,还要用多个真实样本验证:
- kicking;
- not_kicking;
- 走路;
- 抬腿但不踢;
- 左腿/右腿;
- 近距离/远距离;
- 遮挡;
- 多人。
10. 把 CTR-GCN TensorRT 接入实时程序
分类:[项目特定]。可借鉴 TensorRT runner、后端切换和进程隔离设计,但不能原样用于其他模型。
10.1 TensorRT 完整链路
python realtime_ctrgcn_trt_fp16.py \
--source out_06.mp4 \
--pose-model models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine \
--action-backend tensorrt \
--action-engine models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--no-show \
--no-save-video
10.2 PyTorch 对照链路
python realtime_ctrgcn_trt_fp16.py \
--source out_06.mp4 \
--pose-model models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine \
--action-backend pytorch \
--checkpoint output_online/runs/ctrgcn/seed_42/best.pth \
--no-show \
--no-save-video
10.3 检查哪些结果
两种后端使用相同视频,比较:
踢出收回完成候选数
动作模型调用次数
脚踢事件数
触发帧位置
输出概率
平均处理FPS
10.4 为什么显示要独立进程
当前环境中已确认:
TensorRT 推理正常
cv2.imshow 单独运行正常
TensorRT + cv2.imshow 同一进程时段错误
因此演示模式使用:
推理主进程
↓ multiprocessing.Queue
显示子进程
这属于环境中 Qt/HighGUI 与 TensorRT/CUDA 原生库冲突的规避方案。
正式算力测试必须加:
--no-show --no-save-video
这样不会启动显示进程,也不会把进程通信和绘制开销算进核心算法。
本章官方参考
11. PoseC3D 的输入、热图和 TensorRT 部署
分类:[PoseC3D算法特定]。其他视频模型可能使用 RGB、光流、token 或不同序列布局。
11.1 当前 PoseC3D 完整链路
YOLO Pose关键点
↓
按人物维护 pose_history
↓
构造 MMAction2 sample
↓
PoseC3D test pipeline
↓
生成姿态热图
↓
TensorRT PoseC3D engine
↓
两类 logits / probability
11.2 PoseC3D 预处理主要做什么
典型步骤:
- 读取连续关键点与 score;
- 时间采样到固定长度;
- 坐标缩放、裁剪或归一化;
- 将每个关键点生成二维高斯热图;
- 按时间堆叠;
- 调整为 3D CNN 输入格式。
在性能分析中应拆分:
posec3d/sample_build
posec3d/pipeline_build
posec3d/preprocess
posec3d/h2d
posec3d/execute
posec3d/d2h
posec3d/total
其中热图生成常常是 CPU 端不可忽略的开销。
11.3 缓存 pipeline
不要每次动作推理都重新:
pipeline = Compose(config.test_pipeline)
应在 __init__ 中构建一次并缓存。
只有为了复现旧版低效行为时,才使用:
--rebuild-pose-pipeline
11.4 运行 PoseC3D 完整链路
示例:
python3 orin_algorithm_profiled.py \
--video /absolute/path/out_06.mp4 \
--input-mode throughput \
--loop-video \
--run-seconds 90 \
--yolo-engine /absolute/path/models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine \
--posec3d-engine /absolute/path/models/posec3d_trt-5.engine \
--posec3d-config /absolute/path/configs/skeleton/posec3d/slowonly_r50_8xb16-u48-240e_ntu60-xsub-keypoint-2.py \
--label-map /absolute/path/labels.txt \
--no-web \
--no-draw \
--no-gpio \
--profile \
--profile-warmup 10
11.5 PoseC3D engine 单体测试
/usr/src/tensorrt/bin/trtexec \
--loadEngine=models/posec3d_trt-5.engine \
--warmUp=2000 \
--duration=30 \
--useSpinWait \
2>&1 | tee posec3d_engine_benchmark.log
11.6 PoseC3D 从 PyTorch 到 TensorRT 的通用流程
不同 PoseC3D 配置的热图通道数和尺寸不同,因此不要直接复制 CTR-GCN 输入形状。
正确流程:
1. 加载配置和 checkpoint
2. 用真实 pose_history 运行 test pipeline
3. 打印 heatmap.shape
4. 保存 heatmap.npy
5. 用纯模型 wrapper 接受 heatmap tensor
6. torch.onnx.export
7. ONNX checker
8. trtexec --fp16
9. 相同 heatmap 比较 PyTorch/ONNX/TensorRT logits
导出 wrapper 的核心结构:
class PoseC3DExportWrapper(torch.nn.Module):
def __init__(self, recognizer):
super().__init__()
self.backbone = recognizer.backbone
self.cls_head = recognizer.cls_head
def forward(self, heatmap):
feature = self.backbone(heatmap)
logits = self.cls_head(feature)
return logits
实际调用方式必须根据当前 MMAction2 模型结构确认,不能盲目照搬。
本章官方参考
12. INT8 量化:收益、风险和正确顺序
分类:PTQ/QAT 方法是 [通用方法];校准输入、样本分布和精度指标是 [算法特定]。
12.1 INT8 不是简单加 --int8
INT8 需要确定每层浮点值如何映射到整数范围。PTQ 通常需要校准数据。
错误校准会出现:
- YOLO 框正常但关键点明显漂移;
- 低置信关键点全部消失;
- 膝盖/脚踝误差增大;
- CTR-GCN/PoseC3D 概率分布变化;
- 原来的
0.6309阈值不再最优。
12.2 YOLO INT8 校准数据
校准图片应覆盖真实部署分布:
不同光照
白天/夜晚
近距离/远距离
人部分出画
腿部遮挡
拿箱子遮挡膝盖
运动模糊
单人/多人
踢腿/非踢腿
不同衣服和背景
不要只用训练集里最清晰的踢腿图片。
Ultralytics 的版本不同,INT8 导出参数可能略有差异。常见形式:
model.export(
format="engine",
int8=True,
data="pose_calibration.yaml",
imgsz=640,
batch=1,
device=0,
workspace=4,
)
执行前先检查当前版本帮助和官方导出参数:
yolo export --help
12.3 CTR-GCN INT8 校准数据
CTR-GCN 校准数据不是图片,而是经过完全相同 pipeline 后的:
[1, 1, 2, 100, 17, 3] float32
校准集应包含多个 .npy:
calib_0001.npy
calib_0002.npy
...
内容覆盖:
- kicking / not_kicking;
- 左腿 / 右腿;
- 快踢 / 慢踢;
- 遮挡;
- 关键点缺失和低 score;
- 走路、跑步、抬腿、转身等易误报动作;
- 不同人数和人体尺度。
严禁使用随机张量作为正式校准集。
12.4 PoseC3D INT8 校准数据
PoseC3D 校准输入应是已经生成好的真实热图,而不是原始图片或关键点坐标。
必须复用同一 pipeline:
真实骨架
↓
与验证完全一致的 GeneratePoseTarget
↓
真实 heatmap tensor
↓
INT8 calibrator
12.5 INT8 验证项目
至少比较:
FP16 与 INT8 logits误差
最终类别一致率
kicking recall
not_kicking specificity
F1
误报次数/小时
触发阈值
端到端FPS
平均功耗
P95功耗
GR3D
EMC
12.6 是否值得 INT8
以下情况可能不值得:
- FP16 已经满足帧率和功耗要求;
- 动作模型实际每 100 帧只调用几次;
- 整机开销主要在 YOLO;
- CPU 预处理才是瓶颈;
- INT8 使关键点或动作精度明显下降。
因此先测 FP16,再决定是否量化。
本章官方参考
- TensorRT Quantization Workflows
- TensorRT Quantized Types
- TensorRT 8.x
IInt8CalibratorPython API- TensorRT 8.x → 10.x
trtexec参数迁移注意:前两项是新版量化工作流,强调显式 Q/DQ;本项目 TensorRT 8.5 仍可使用 calibrator。两套方法不要混写成同一套命令。
13. 延迟、速度、吞吐量如何计算
分类:[通用方法]。可用于 Jetson、桌面 GPU、CPU、DLA 和其他推理后端。
13.1 FPS
FPS = 处理帧数 / 运行秒数
例如:
900 帧 / 45 秒 = 20 FPS
13.2 每帧耗时
每帧毫秒 = 1000 / FPS
例如:
20 FPS → 50 ms/帧
25 FPS → 40 ms/帧
50 FPS → 20 ms/帧
注意:平均 FPS 与平均单阶段延迟不是简单相加关系,因为 GPU 调用、CPU 工作和异步执行可能重叠。
13.3 Latency 与 Throughput
- Latency:一次输入从开始到得到结果需要多久。
- Throughput:单位时间最多处理多少次。
例如:
CTR-GCN一次完整调用 6.43 ms
理论串行上限 ≈ 1000 / 6.43 = 155.5 次/秒
但完整视频 FPS 还包含 YOLO 和其他处理,因此不会达到 155 FPS。
13.4 P50、P95、P99
假设采集 1000 次延迟:
- P50:一半请求小于该值;
- P95:95% 请求小于该值;
- P99:99% 请求小于该值。
实时系统不能只看平均值。
例如:
平均 20 ms
P95 45 ms
说明偶尔会明显卡顿。
13.5 动作调用频率
每100帧动作调用次数
= 动作模型总调用数 / 总帧数 × 100
该指标对 CTR-GCN 非常重要。
例如:
1000帧只调用20次CTR-GCN
每100帧调用2次
即使单次动作推理是 6 ms,整机平均负担也很低。
13.6 单帧能耗
平均功率单位 W 等于 J/s。
因此:
每帧能耗 J/frame = 平均功率 W / FPS
例如:
平均功耗 30 W
平均速度 20 FPS
每帧能耗 = 30 / 20 = 1.5 J/frame
该指标适合比较不同方案的整体能效。
13.7 增量开销
测三组:
A. YOLO-only
B. YOLO + CTR-GCN
C. YOLO + PoseC3D
粗略估计:
CTR-GCN增量功耗 ≈ B平均功耗 - A平均功耗
PoseC3D增量功耗 ≈ C平均功耗 - A平均功耗
这是近似值,因为 GPU DVFS、并行重叠和温度会导致非线性,不能当作绝对精确分解。
本章官方参考
14. Orin 算力占用和功耗如何采集
分类:采集思想是 [通用性能方法];
tegrastats/nvpmodel/jetson_clocks是 [Jetson通用]。
配套脚本:
scripts/collect_orin_profile_generic.sh
scripts/analyze_orin_profile.py
复制并赋权:
cp scripts/collect_orin_profile_generic.sh .
cp scripts/analyze_orin_profile.py .
chmod +x collect_orin_profile_generic.sh
14.1 固定功耗模式和频率
sudo -v
sudo nvpmodel -q
sudo jetson_clocks
sudo jetson_clocks --show
PoseC3D 和 CTR-GCN 必须使用相同 nvpmodel 和频率状态。
不要一组开 jetson_clocks,另一组不开。
14.2 CTR-GCN 完整链路采集
./collect_orin_profile_generic.sh \
--label ctrgcn_full_trt_fp16 \
--interval-ms 200 \
--warmup-seconds 3 \
-- \
python realtime_ctrgcn_trt_fp16.py \
--source out_06.mp4 \
--pose-model models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine \
--action-backend tensorrt \
--action-engine models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--no-show \
--no-save-video
14.3 CTR-GCN engine 单体采集
./collect_orin_profile_generic.sh \
--label ctrgcn_engine_trt_fp16 \
--interval-ms 200 \
--warmup-seconds 3 \
-- \
/usr/src/tensorrt/bin/trtexec \
--loadEngine=models/ctrgcn_agx-orin_jp512_trt85_fp16.engine \
--warmUp=2000 \
--duration=30 \
--useSpinWait
14.4 PoseC3D engine 单体采集
./collect_orin_profile_generic.sh \
--label posec3d_engine_trt_fp16 \
--interval-ms 200 \
--warmup-seconds 3 \
-- \
/usr/src/tensorrt/bin/trtexec \
--loadEngine=models/posec3d_trt-5.engine \
--warmUp=2000 \
--duration=30 \
--useSpinWait
14.5 PoseC3D 完整链路采集
./collect_orin_profile_generic.sh \
--label posec3d_full_trt_fp16 \
--interval-ms 200 \
--warmup-seconds 10 \
-- \
python3 orin_algorithm_profiled.py \
--video /absolute/path/out_06.mp4 \
--input-mode throughput \
--loop-video \
--run-seconds 90 \
--yolo-engine /absolute/path/models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine \
--posec3d-engine /absolute/path/models/posec3d_trt-5.engine \
--posec3d-config /absolute/path/posec3d_config.py \
--label-map /absolute/path/labels.txt \
--no-web \
--no-draw \
--no-gpio \
--profile \
--profile-warmup 10
14.6 YOLO-only 基线
./collect_orin_profile_generic.sh \
--label yolo_only_trt_fp16 \
--interval-ms 200 \
--warmup-seconds 10 \
-- \
python3 orin_algorithm_profiled.py \
--video /absolute/path/out_06.mp4 \
--input-mode throughput \
--loop-video \
--run-seconds 90 \
--yolo-engine /absolute/path/models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine \
--no-action \
--no-web \
--no-draw \
--no-gpio \
--profile \
--profile-warmup 10
14.7 输出目录
orin_profile_runs/
└── 20260728_160000_ctrgcn_full_trt_fp16/
├── tegrastats.log
├── pidstat.log
├── app_stdout.log
├── app_stderr.log
├── system_info.txt
├── exit_code.txt
├── tegrastats_summary.csv
├── tegrastats_summary.json
├── profile_summary.json
└── profile_summary.md
本章官方参考
15. GR3D、EMC、CPU、RAM、VDD_IN 等指标解释
分类:[Jetson通用]。不同 Jetson Linux 版本和模块可能显示不同字段或电源轨名称。
15.1 GR3D_FREQ
示例:
GR3D_FREQ 62%@[1098,1098]
通俗理解:
62%:采样周期内 GPU 图形/计算引擎约 62% 时间在忙;1098:GPU 频率信息,单位通常 MHz;- 双值可能对应 GPU 频率域或设备输出格式。
它可以判断 GPU 忙不忙,但不能直接转换为 TOPS。
经验性解释:
| 平均 GR3D | 通俗判断 |
|---|---|
| < 40% | GPU负载较低 |
| 40%~75% | 中等负载 |
| > 75% | 高负载 |
| P95 ≥ 90% | 峰值阶段接近GPU饱和 |
这只是工程分类,不是硬件理论定义。
15.2 为什么 GR3D 不能直接换算 TOPS
理论 TOPS 是在特定数据类型、特定稠密度和理想硬件利用下的峰值运算能力。
实际程序中包括:
- FP16、FP32 和整数混合;
- 内存访问;
- 分支;
- kernel 启动间隙;
- CPU 等待;
- Tensor Core 与 CUDA Core 混用;
- 不同算子利用率。
因此:
GR3D 50% ≠ 使用了50%的INT8 TOPS
正式报告建议写:
GPU平均忙碌度为 xx%,P95为 xx%。
不要写:
占用了 xx TOPS
除非有经过验证的硬件计数器和算子级 FLOPs 分析。
15.3 EMC_FREQ
EMC 是 External Memory Controller,外部内存控制器。
通俗理解:
GPU和CPU要从内存搬数据,EMC反映内存通道有多忙。
EMC 高可能来自:
- 大热图;
- 大量 frame.copy;
- CPU/GPU 数据拷贝;
- 视频解码;
- 多进程传整帧;
- 3D CNN 中间特征;
- 多人并行。
经验性判断:
| EMC P95 | 判断 |
|---|---|
| < 50% | 内存带宽压力较低 |
| 50%~85% | 中等 |
| ≥ 85% | 带宽压力较高 |
15.4 CPU 全核心平均占用
假设 Orin 有 12 个 CPU 核心,其中一个核心 100%,其他核心空闲:
全核心平均可能只有约 8.3%
因此只看 CPU 平均会掩盖单核瓶颈。
15.5 最忙 CPU 核心
如果:
最忙核心 P95 ≈ 100%
GR3D 平均只有 35%
说明程序可能是 CPU/调度受限,例如:
- Python 循环;
- ByteTrack;
- PoseC3D 热图生成;
- OpenCV 解码;
- 队列调度;
- 单线程后处理。
15.6 RAM
RAM used 是整板当前已使用内存,不完全等于算法进程独占。
它包含:
- 操作系统;
- 桌面;
- Python;
- CUDA/TensorRT;
- 文件缓存;
- 其他进程。
要看单进程内存,还要结合 pidstat -r。
15.7 CUDA allocated 和 reserved
PyTorch 常见两个概念:
allocated:当前张量真正使用的显存;reserved:PyTorch 缓存分配器向 CUDA 预留的显存池。
通常:
reserved >= allocated
不要把 reserved 全部理解成模型实际占用。
15.8 VDD_IN
VDD_IN 通常是板端总输入功率的重要口径。
示例:
VDD_IN 30000mW/28000mW
常见含义:
- 当前功率;
- 平均功率。
自动分析脚本会优先选择:
VDD_IN
POM_5V_IN
VIN_SYS_5V0
不会随意把多个分轨相加冒充总功耗。
15.9 温度和频率
温度升高可能触发降频,导致后半段测试变慢。
正式测试应:
- 使用相同风扇模式;
- 记录环境温度;
- 预热后再统计;
- 每组测试持续时间一致;
- 检查是否发生 thermal throttling。
16. CTR-GCN 与 PoseC3D 如何公平对比
分类:控制变量和双口径比较是 [通用方法];模型名称和调度策略是 [项目示例]。
必须分成两层。
16.1 模型本身公平对比
控制变量:
相同设备
相同nvpmodel
相同jetson_clocks状态
都使用TensorRT FP16
相同batch=1
相同预热时间
相同测试时长
关闭显示和保存
比较:
engine大小
GPU Compute Time
Latency P50/P95
Throughput
GR3D
EMC
平均功耗
峰值显存
这一层回答:
CTR-GCN 与 PoseC3D 模型本身谁更轻?
16.2 完整产品方案对比
保持各自实际调度:
CTR-GCN:完成候选后按需调用
PoseC3D:固定滑窗或固定间隔调用
比较:
端到端FPS
动作调用次数/100帧
GR3D平均/P95
CPU
EMC
平均/P95功耗
每帧能耗
准确率
召回率
误报率
这一层回答:
实际部署时哪套方案更省资源?
16.3 相同调用频率对比
为了消除调度差异,应额外做:
CTR-GCN和PoseC3D都每N帧调用一次
例如都每 24 帧调用一次。
这样回答:
在相同调用频率下,动作模型的增量代价是多少?
16.4 不能只比较 FPS
两个方案可能都达到视频输入上限 20 FPS:
PoseC3D:GPU 80%,20 FPS
CTR-GCN:GPU 35%,20 FPS
仅看 FPS 会认为一样,但 CTR-GCN 有更大算力余量。
因此必须同时报告 GR3D、功耗和 P95 延迟。
17. 推荐的完整实验矩阵
分类:矩阵设计方法可迁移;具体行项目是 [当前项目特定]。
17.1 模型转换验证
| 编号 | 模型 | 后端 | 目的 |
|---|---|---|---|
| A1 | YOLO26-Pose | PyTorch | 原始正确性 |
| A2 | YOLO26-Pose | TRT FP16 | 转换正确性 |
| A3 | CTR-GCN | PyTorch | 原始基线 |
| A4 | CTR-GCN | TRT FP16 | 转换正确性 |
| A5 | PoseC3D | PyTorch/原始 | 原始基线 |
| A6 | PoseC3D | TRT FP16 | 转换正确性 |
17.2 模型单体性能
| 编号 | 测试 |
|---|---|
| B1 | YOLO engine trtexec |
| B2 | CTR-GCN engine trtexec |
| B3 | PoseC3D engine trtexec |
17.3 完整链路性能
| 编号 | 测试 |
|---|---|
| C1 | YOLO-only |
| C2 | YOLO + CTR-GCN PyTorch |
| C3 | YOLO + CTR-GCN TRT FP16 |
| C4 | YOLO + PoseC3D TRT FP16 |
17.4 调度对比
| 编号 | 策略 |
|---|---|
| D1 | CTR-GCN 原生事件驱动 |
| D2 | PoseC3D 原生固定滑窗 |
| D3 | 两者统一每24帧调用 |
17.5 INT8 可选实验
| 编号 | YOLO | 动作模型 |
|---|---|---|
| E1 | FP16 | FP16 |
| E2 | INT8 | FP16 |
| E3 | FP16 | INT8 |
| E4 | INT8 | INT8 |
每次只改变一个变量。
18. 如何阅读自动生成的报告并下结论
分类:[通用方法],适用于其他 Orin 和算法;阈值只是经验性诊断,不是硬件官方上限。
自动报告:
profile_summary.md
profile_summary.json
终端会打印:
========== Orin 性能测试重点结论 ==========
- GPU(GR3D)平均忙碌度 xx%,P95 xx%。
- CPU全核心平均占用 xx%。
- 最忙CPU核心P95 xx%。
- EMC平均 xx%,P95 xx%。
- 板端平均功耗 xx W,P95 xx W,峰值 xx W。
- 完整链路平均吞吐 xx FPS。
- 动作模型每100帧调用 xx 次。
==========================================
18.1 典型结论模板:GPU余量较大
YOLO26-Pose + CTR-GCN TensorRT FP16 完整链路平均达到 20 FPS。
GPU GR3D 平均忙碌度为 38%,P95 为 61%,未出现持续GPU饱和。
最忙CPU核心P95为 72%,EMC P95为 45%。
说明当前20 FPS主要受输入视频节奏限制,板端仍有一定GPU和内存带宽余量。
18.2 典型结论模板:GPU瓶颈
完整链路平均吞吐为 18 FPS,GR3D平均为 82%,P95为 98%。
CPU最忙核心P95仅为 65%,EMC P95为 60%。
说明链路主要受GPU计算限制,继续提高输入帧率时首先会遇到GPU瓶颈。
18.3 典型结论模板:CPU瓶颈
GR3D平均仅为 42%,但最忙CPU核心P95达到 100%,端到端FPS为 16。
说明当前更可能受Python调度、跟踪或CPU预处理限制,而不是GPU算力不足。
应优先优化PoseC3D热图生成、Python循环、数据复制或跟踪逻辑。
18.4 典型结论模板:CTR-GCN 比 PoseC3D 更省资源
在相同YOLO engine、相同视频、相同功耗模式和FP16精度下:
CTR-GCN动作模型单次GPU计算时间低于PoseC3D,engine更小;
完整链路中CTR-GCN采用事件驱动,每100帧动作模型调用次数更少;
因此CTR-GCN方案的平均GR3D和平均整板功耗更低。
需要同时说明PoseC3D可能在关键点噪声和轻微漂移场景中具有更好的鲁棒性,最终选择不能只看算力。
18.5 报告中不应写的结论
不要写:
GR3D平均23%,所以使用了Orin 23%的275 TOPS。
正确写法:
GR3D平均忙碌度为23%,表示采样周期内GPU处于忙碌状态的时间比例较低。
该值不能直接换算为理论TOPS利用率。
19. 常见故障与解决方法
分类:混合章节。只采用与自己的 JetPack、TensorRT、Python、框架版本和报错现象相符的条目。
19.1 pip 指向错误 Conda 环境
检查:
which python
which pip
python -m pip --version
python -c "import sys; print(sys.executable)"
安装统一使用:
python -m pip install ...
19.2 WARNING: Ignoring invalid distribution -orch
说明 site-packages 中有异常 Torch 残留,例如:
-orch
~orch
~unctorch
只删除异常命名目录,不要删除正常 torch。
19.3 SymPy 缺文件
报错:
No module named 'sympy.multipledispatch.core'
修复:
python -m pip uninstall -y sympy
python -m pip install --no-cache-dir --force-reinstall \
"sympy==1.12" "mpmath==1.3.0"
注意 onnxslim 可能要求更高 SymPy。若导出使用 simplify=False,可以暂时不使用 onnxslim。
19.4 同时安装两个 OpenCV 包
错误组合:
opencv-python
opencv-contrib-python
它们共享 cv2 命名空间,一个环境只保留一种。
需要 GUI 时不要安装 headless 版本。
19.5 sudo python 找不到 cv2
ModuleNotFoundError: No module named 'cv2'
原因:sudo 使用系统 Python,不是 Conda Python。
不要用:
sudo python realtime_ctrgcn.py
只对需要权限的命令使用 sudo,例如:
sudo tegrastats
sudo nvpmodel
sudo jetson_clocks
19.6 TensorRT 与 cv2.imshow 同进程段错误
已验证现象:
TensorRT推理成功
result.plot成功
cv2.imwrite成功
cv2.imshow时Segmentation fault
解决:
- 推理主进程不调用 HighGUI;
- 使用独立 spawn 进程显示;
- 正式性能测试关闭显示。
19.7 np.bool 报错
见第 7.5 节兼容补丁。
19.8 TensorRT engine 跨设备警告
Using an engine plan file across different models of devices...
重新在最终 AGX Orin 上构建 engine。
19.9 trtexec --dumpLayerInfo 段错误
先退回最小命令:
trtexec --loadEngine=model.engine --duration=10
然后逐个增加:
--profilingVerbosity=detailed
--dumpLayerInfo
--exportLayerInfo=...
如果 engine 推理正常但 layer dump 崩溃,可能是 TensorRT 8.5 工具问题,不代表 engine 本身不能运行。
19.10 --debug 后 FPS 降低
这是正常的。
调试模式会在 CUDA 阶段前后同步,以获得可信的阶段延迟。同步会破坏异步流水,因此:
--debug:用于定位阶段耗时
无 --debug:用于测最大吞吐和真实功耗
19.11 显示进程是否影响算力测试
开启显示时会增加:
- CPU;
- 内存复制;
- EMC;
- Qt/X11;
- 桌面合成;
- 整机功耗。
所以正式比较必须关闭:
--no-show --no-save-video
本章排错参考
20. 最终交付物和复现检查清单
分类:[通用方法]。建议所有边缘端部署项目都保留这些交付物。
20.1 模型文件
models/yolo26n-pose.pt
models/yolo26n-pose_agx-orin_jp512_trt85_fp16_640_b1.engine
models/ctrgcn_fp32_static.onnx
models/ctrgcn_fp32_static.input.npy
models/ctrgcn_fp32_static.json
models/ctrgcn_agx-orin_jp512_trt85_fp16.engine
models/posec3d_trt-5.engine
20.2 配置和权重
output_online/runs/ctrgcn/seed_42/resolved_config.py
output_online/runs/ctrgcn/seed_42/best.pth
output_online/runs/ctrgcn/seed_42/result.json
PoseC3D config
PoseC3D label map
20.3 配套脚本
export_ctrgcn_onnx.py
validate_ctrgcn_trt.py
realtime_ctrgcn_trt_fp16.py
realtime_ctrgcn_display_process.py
collect_orin_profile_generic.sh
analyze_orin_profile.py
orin_algorithm_profiled.py
20.4 正确性检查
- YOLO
.pt可推理; - YOLO FP16 engine 可推理;
- YOLO engine 关键点与
.pt基本一致; - CTR-GCN ONNX checker 通过;
- CTR-GCN FP16 engine 构建成功;
- PyTorch/CTR-GCN TensorRT logits 一致;
- 完整视频事件结果一致;
- PoseC3D engine 可独立推理;
- PoseC3D 完整链路可运行。
20.5 性能检查
- 记录
nvpmodel; - 两组测试都使用相同
jetson_clocks状态; - 相同视频;
- 相同 YOLO engine;
- 相同输入分辨率;
- 相同 warmup;
- 相同测试时长;
-
--no-show --no-save-video; - 分别测 engine 单体和完整链路;
- 报告动作调用次数/100帧;
- 报告 GR3D 平均/P95;
- 报告 CPU 最忙核心 P95;
- 报告 EMC;
- 报告 VDD_IN 平均/P95/峰值;
- 报告 FPS、P95 延迟、显存;
- 报告准确率、召回率、误报率。
20.6 最终建议报告结构
# YOLO26-Pose + 动作识别 Orin 部署评测
## 1. 测试环境
## 2. 模型输入输出
## 3. 转换与数值一致性
## 4. 模型单体性能
## 5. 完整链路性能
## 6. 准确率与误报
## 7. CTR-GCN vs PoseC3D
## 8. FP16 vs INT8
## 9. 瓶颈分析
## 10. 最终选型结论
21. 换其他 Orin 或其他算法时如何迁移
分类:[通用迁移方法]。本章直接回答“哪些命令还能用、哪些必须重查、官方教程去哪里找”。
21.1 先判断你改变了哪一层
迁移场景分三种:
场景 A:算法不变,只换 Orin
场景 B:Orin 不变,只换算法
场景 C:Orin 和算法都换
三种场景的工作量不同:
| 事项 | 场景A 换Orin | 场景B 换算法 | 场景C 都换 |
|---|---|---|---|
| 重新采集系统信息 | 必须 | 建议 | 必须 |
| 重新建立原框架精度基线 | 建议 | 必须 | 必须 |
| 重新导出 ONNX | 建议重新验证 | 必须 | 必须 |
| 重新构建 TensorRT engine | 必须优先这样做 | 必须 | 必须 |
| 重写预处理/后处理 | 通常不需要 | 通常必须 | 通常必须 |
| 重新做 INT8 校准 | 更换 TRT/设备时建议重做 | 必须 | 必须 |
| 重新测功耗和性能 | 必须 | 必须 | 必须 |
| 重新选择官方文档版本 | 必须 | 框架文档需重选 | 必须 |
21.2 命令复用范围总表
| 命令或脚本 | 其他 Orin 能否用 | 其他算法能否用 | 需要注意什么 |
|---|---|---|---|
uname -m、lscpu、cat /etc/os-release | 是 | 是 | Linux通用 |
cat /etc/nv_tegra_release | 是 | 是 | Jetson专用;用于选 L4T 文档 |
dpkg-query -W nvidia-l4t-core | 是 | 是 | Jetson Debian 系统适用 |
collect_jetson_system_info.sh | 是 | 是 | 在每个目标 Conda 环境运行一次 |
nvpmodel -q | 是 | 是 | 模式编号因模块/L4T而异,不能复制编号 |
jetson_clocks / --show | 是 | 是 | 最大频率仍受 nvpmodel 约束 |
tegrastats | 是 | 是 | 字段和电源轨可能随版本/模块变化 |
pidstat | 是 | 是 | Linux工具,需安装 sysstat |
trtexec --loadEngine=... | 是 | 是 | 需要 TensorRT;参数以本机 --help 为准 |
trtexec --onnx=... --saveEngine=... | 是 | 是 | ONNX必须受当前TRT支持;动态shape要另配 |
torch.onnx.export() | 是 | 是(PyTorch模型) | wrapper、dummy input、opset按模型修改 |
onnx.checker.check_model() | 是 | 是 | 仅检查图合法性,不保证TensorRT支持 |
collect_orin_profile_generic.sh | 是 | 是 | 只要目标程序可作为命令运行即可 |
analyze_orin_profile.py | 通常可以 | 是 | 如果新版 tegrastats 字段变化,需更新正则解析 |
YOLO model.export(format='engine') | 是 | 仅Ultralytics模型 | 参数受Ultralytics/TRT版本影响 |
export_ctrgcn_onnx.py | 同CTR-GCN时可参考 | 否 | 输入构造、wrapper和配置是CTR-GCN特定 |
validate_ctrgcn_trt.py | 同engine时可用 | 部分可改造 | 输入/输出名称、shape、分类语义需修改 |
realtime_ctrgcn_trt_fp16.py | 可能可用 | 否 | 当前跟踪、事件候选和CTR-GCN完全项目化 |
| 独立显示进程方案 | 是 | 是 | 设计思想通用;代码接入位置按程序修改 |
21.3 场景 A:算法不变,只换另一款 Orin
例如从 AGX Orin 换到 Orin NX 或 Orin Nano。
第一步:在新板执行系统采集
./collect_jetson_system_info.sh new_orin_system_info.txt
重点比较:
- 板卡型号和内存容量;
- L4T/JetPack;
- CUDA/TensorRT;
- Python和框架;
- nvpmodel模式;
- engine输入shape和精度。
第二步:不要直接假设旧 engine 可复用
TensorRT 序列化 engine 默认与构建时 TensorRT 版本和设备类型紧密相关。JetPack 上的硬件兼容模式也有限制,因此最稳妥的流程是:
保留原始 ONNX
↓
在新 Orin 的目标 TensorRT 环境重新构建 engine
↓
重新做数值一致性和性能验证
官方说明:
- TensorRT Engine Compatibility:https://docs.nvidia.com/deeplearning/tensorrt/latest/inference-library/engine-compatibility.html
- TensorRT Support Matrix:https://docs.nvidia.com/deeplearning/tensorrt/latest/getting-started/support-matrix.html
第三步:重新选择功耗模式
不要写死:
sudo nvpmodel -m 某个旧编号
先查看新板支持的模式:
sudo nvpmodel -q --verbose 2>/dev/null || sudo nvpmodel -q
再查目标 L4T 的 Platform Power and Performance 文档。AGX Orin、Orin NX 和 Orin Nano 的功耗范围、CPU核配置和频率上限不同。
第四步:重新跑完整性能矩阵
至少重新测:
engine 单体 trtexec
YOLO-only
完整链路
空闲基线
准确率验证
温度稳定后的持续运行
同一模型在不同 Orin 上,绝对 FPS、功耗、GPU/EMC压力都可能变化。
21.4 场景 B:Orin 不变,只换其他算法
例如:
- YOLO-Pose 换成 RTMPose;
- CTR-GCN 换成 ST-GCN、TCN、GRU、Transformer;
- PoseC3D 换成 RGB 视频模型;
- 二分类换成多分类;
- 动作识别换成目标检测、语义分割或语音模型。
系统命令和性能采集脚本大多能继续用,但模型导出与应用接入必须重新分析。
21.4.1 先写出“模型部署契约”
对新模型填写:
框架:PyTorch / TensorFlow / Paddle / ONNX / 其他
输入数量:
输入名称:
输入shape:
动态维度:
输入dtype:
输入layout:NCHW / NHWC / NCTHW / 其他
预处理:resize / normalize / tokenize / heatmap / skeleton...
输出数量:
输出shape:
输出含义:logits / boxes / masks / keypoints / embeddings...
后处理:softmax / NMS / decode / threshold / temporal smoothing...
正确性指标:
没有这份契约,不应该开始写 TensorRT runner。
21.4.2 根据模型类型选择官方资料
| 新算法类型 | 首先查什么 | 常见部署差异 |
|---|---|---|
| Ultralytics YOLO 检测/分割/姿态 | Ultralytics 对应 task + export + TensorRT | 可能自带预后处理;版本差异大 |
| MMDetection/MMPose/MMAction2 | 对应 OpenMMLab 模型 README、部署文档、MMDeploy | 配置驱动、custom ops、数据 pipeline |
| 普通 PyTorch 分类/回归 | PyTorch ONNX + TensorRT | 最容易导出,但归一化和标签仍要核对 |
| Transformer/NLP | 模型框架 + ONNX/TensorRT/Transformers 文档 | 动态序列、mask、多输入、插件和显存 |
| 视频/时序模型 | 模型仓库 + 数据 pipeline | 时间维、clip采样、缓存和调度影响大 |
| 自研 CUDA/插件模型 | TensorRT Plugin 文档 | 必须实现、编译并随应用加载 plugin |
21.4.3 通用导出框架
PyTorch 模型通常从下面的通用骨架开始,而不是复制 CTR-GCN shape:
model.eval()
with torch.no_grad():
torch.onnx.export(
model,
example_inputs, # 按新模型构造
'model.onnx',
input_names=[...],
output_names=[...],
opset_version=..., # 按PyTorch/TRT兼容性选择
dynamic_axes=..., # 需要动态维度时再配置
)
官方入口:
- PyTorch ONNX:https://docs.pytorch.org/docs/stable/onnx.html
- ONNX Checker:https://onnx.ai/onnx/api/checker.html
- TensorRT Quick Start 8.6.1:https://docs.nvidia.com/deeplearning/tensorrt/archives/tensorrt-861/quick-start-guide/index.html
21.4.4 新算法必须重做正确性验证
至少比较:
原框架 FP32输出
ONNX后端输出(可用时)
TensorRT FP16输出
TensorRT INT8输出(做INT8时)
分类模型比较 logits/概率/Top-1;检测模型比较解码后的框和 mAP;分割模型比较 mask/mIoU;动作识别比较 clip级与事件级指标。
21.5 场景 C:Orin 和算法都换
不要从旧实时脚本开始改。推荐顺序:
1. 新板系统信息
2. 新算法原框架最小推理
3. 固定一组真实测试输入和期望输出
4. ONNX导出与合法性检查
5. 在新板重建FP16 engine
6. 单模型数值一致性
7. 单模型 trtexec 性能
8. 最小应用接入
9. 完整链路性能和功耗
10. INT8与调度优化
先跑最小闭环,再逐步加入摄像头、跟踪、多线程、显示、保存和业务规则。否则报错时无法判断是模型、环境还是应用调度造成的。
21.6 如何为自己的 L4T 选择正确官方文档
步骤一:查 L4T
cat /etc/nv_tegra_release
例如:
# R35 (release), REVISION: 4.1
对应文档路径通常包含:
r35.4.1
归档入口:
当前实战入口:
步骤二:查 TensorRT
python -c "import tensorrt as trt; print(trt.__version__)"
dpkg-query -W tensorrt 2>/dev/null || true
然后进入:
选择同一大版本、尽量接近的小版本。最新版文档可以用于理解新概念,但不能保证命令与旧 JetPack 兼容。
步骤三:查框架和模型版本
python -c "import torch; print(torch.__version__)"
python -c "import ultralytics; print(ultralytics.__version__)" 2>/dev/null || true
python -c "import mmaction; print(mmaction.__version__)" 2>/dev/null || true
优先选择:
- 当前安装版本对应的官方文档或 Git tag;
- 模型配置所在仓库版本;
- 当前模型原论文;
- 最后才是论坛和 issue 排错。
21.7 不同板子和算法仍然通用的性能测试原则
不论模型是什么,都应固定:
- 同一输入数据;
- 同一 batch 和 shape;
- 同一精度;
- 同一功耗模式;
- 相同预热;
- 相同运行时长;
- 相同显示/保存/debug设置;
- 相同统计口径。
并分开报告:
模型单体:trtexec或纯runner
完整链路:解码+预处理+模型+后处理+调度
产品模式:真实调用频率和业务策略
这套原则可以直接用于其他 Orin 和其他算法。
21.8 什么时候需要去看官方教程,而不是继续照抄本文
出现下面任一情况时,应暂停照抄命令并查官方资料:
- 本机 JetPack/L4T 与 R35.4.1 不同;
- TensorRT 不属于 8.x;
trtexec --help中没有本文参数;- 新模型不是 Ultralytics、CTR-GCN 或 PoseC3D;
- ONNX 出现 unsupported operator;
- 模型有多个输入、动态序列或自定义算子;
- 想使用 DLA、稀疏、QAT、显式 Q/DQ 或自定义 plugin;
- engine 要跨板、跨 TensorRT 或跨操作系统;
tegrastats输出字段与分析脚本不匹配;- 需要生产载板 bring-up、摄像头驱动、DLA或安全认证。
对应入口:
| 问题 | 官方入口 |
|---|---|
| JetPack版本和安装 | https://developer.nvidia.com/embedded/jetpack-archive |
| Jetson Linux、驱动、功耗、摄像头、系统工具 | https://docs.nvidia.com/jetson/ |
| TensorRT版本、算子、engine、量化、plugin | https://docs.nvidia.com/deeplearning/tensorrt/ |
| TensorRT历史版本 | https://docs.nvidia.com/deeplearning/tensorrt/archives/ |
| PyTorch ONNX | https://docs.pytorch.org/docs/stable/onnx.html |
| ONNX规范和检查 | https://onnx.ai/onnx/ |
| Ultralytics模型 | https://docs.ultralytics.com/ |
| MMAction2 | https://mmaction2.readthedocs.io/ |
| Nsight Systems | https://docs.nvidia.com/nsight-systems/UserGuide/index.html |
22. 按任务查官方资料与参考文献
22.1 版本匹配优先级
查阅资料时按以下优先级选择:
- 与板端版本完全一致的归档文档:本项目优先使用 JetPack 5.1.2、L4T R35.4.1、TensorRT 8.x 文档;
- 框架当前官方文档:用于理解概念和 API,但命令参数需检查版本差异;
- 模型原论文和官方代码库:用于解释模型结构、输入输出和设计原因;
- 论坛或 Issue:只用于排错线索,不能替代正式 API 文档和实验验证。
本机最终依据始终是:
/usr/src/tensorrt/bin/trtexec --help
python -c "import tensorrt as trt; print(trt.__version__)"
python -c "import torch; print(torch.__version__)"
python -c "import mmaction; print(mmaction.__version__)"
22.2 Jetson、JetPack、功耗和监控
-
NVIDIA JetPack 5.1.2 Release Notes
用途:核对 JetPack 5.1.2、L4T 35.4.1、CUDA 11.4、TensorRT 8.5.2 等版本关系。 -
NVIDIA JetPack 5.1.2 Installation Guide
用途:安装或补装 JetPack 组件、Debian 软件包。 -
Jetson Linux R35.4.1 Developer Guide
用途:当前 L4T 版本的系统级总文档入口。 -
Jetson Linux R35.4.1 Tegrastats Utility
用途:查询 RAM、SWAP、CPU、EMC、GR3D、温度和功耗字段的官方含义。 -
Jetson Orin Power and Performance
用途:nvpmodel、jetson_clocks、功耗模式、频率和节流行为。 -
NVIDIA Nsight Systems User Guide
用途:进一步定位 CPU 调度、CUDA kernel、同步、内存复制和空闲等待。 -
NVIDIA JetPack Archive
用途:换其他 Orin 或重装系统时,根据实际 JetPack 版本进入对应历史文档。 -
NVIDIA Jetson Modules
用途:查询 AGX Orin、Orin NX、Orin Nano 等模块系列;具体规格以对应产品页和数据手册为准。 -
Jetson Linux Software Packages and Update Mechanism(R35.4.1)
用途:理解 L4T 软件包,并通过/etc/nv_tegra_release确认 BSP 版本。
22.3 YOLO26-Pose、导出与跟踪
-
Ultralytics Pose Task
用途:Pose 模型的训练、预测、验证、关键点输出和导出。 -
Ultralytics TensorRT Integration
用途:YOLO26 导出 TensorRT、FP16/INT8 参数、推理与验证。 -
Ultralytics Export Mode
用途:查看format、imgsz、half、int8、dynamic、batch等导出参数。 -
Ultralytics NVIDIA Jetson Guide
用途:Jetson 上安装 Ultralytics、导出和运行 TensorRT 模型。 -
Ultralytics Track Mode
用途:在视频、摄像头和流媒体中使用 ByteTrack/BoT-SORT;Pose 模型同样适用。
22.4 CTR-GCN、PoseC3D 和 MMAction2
-
CTR-GCN Official Repository
用途:CTR-GCN 官方实现、网络结构、数据准备与训练入口。 -
CTR-GCN ICCV 2021 Paper
用途:理解 Channel-wise Topology Refinement 的数学原理和设计动机。 -
MMAction2 PoseC3D README
用途:PoseC3D 官方模型、配置、预训练结果和热图表示说明。 -
PoseC3D Custom Dataset Training
用途:使用自定义视频/骨架数据训练 PoseC3D。 -
MMAction2 Customize Dataset
用途:PoseDataset、自定义关键点格式、数据 pipeline。 -
MMAction2 骨骼动作识别模型中文说明
用途:快速理解 PoseC3D、ST-GCN 等骨架动作识别模型。
22.5 PyTorch、ONNX 和 TensorRT
-
PyTorch ONNX Tutorial
用途:理解 PyTorch → ONNX 的官方基本流程。 -
PyTorch
torch.onnxDocumentation
用途:导出 API、输入输出命名、动态维度和算子支持。 -
ONNX Checker API
用途:使用onnx.checker.check_model()检查 ONNX 图合法性。 -
TensorRT 8.6.1 Archived Developer Guide
用途:最接近当前 TensorRT 8.5 的完整归档开发指南。 -
TensorRT Command-Line Programs /
trtexec
用途:trtexec的构建、加载、输入 shape、性能和 profiling 参数总览。 -
TensorRT Performance Benchmarking
用途:理解 GPU Compute Time、Host Latency、Throughput、同步和 CUDA Graph。 -
TensorRT Engine Tools and Debugging
用途:engine 检查、调试张量、层信息和诊断工具。 -
Migrating
trtexecfrom TensorRT 8.x to 10.x
用途:确认--workspace、--buildOnly等参数在新版中的变化。 -
TensorRT Support Matrix
用途:换 JetPack、CUDA、Python 或 TensorRT 时检查软件要求、硬件能力和功能支持。 -
TensorRT Engine Compatibility
用途:理解 engine 的版本、硬件和平台兼容边界;JetPack 上应优先在目标环境重新构建和验证。
22.6 FP16、INT8、PTQ 和 QAT
-
TensorRT Quantization Workflows
用途:理解 PTQ、QAT、Q/DQ、per-tensor/per-channel 量化等当前推荐流程。 -
TensorRT Working with Quantized Types
用途:量化比例、校准、INT8 I/O 与计算精度的详细概念。 -
TensorRT 8.6.1
IInt8CalibratorPython API
用途:JetPack 5.x / TensorRT 8.x 的 calibrator 接口、batch 和 calibration cache。 -
TensorRT Explicit Quantization
用途:理解新版 TensorRT 的显式 Q/DQ、ModelOpt、PTQ 和 QAT;不能直接把新版命令照搬到 TensorRT 8.5。
22.7 显示进程和 OpenCV
-
OpenCV HighGUI Reference
用途:namedWindow、imshow、waitKey、destroyAllWindows。 -
Python multiprocessing
用途:独立显示进程、spawn、Queue、Event 和进程生命周期。 -
Python multiprocessing.shared_memory
用途:后续减少整帧 Queue 序列化和内存复制开销。
22.8 论文引用格式示例
在技术报告、论文或答辩材料中,可引用:
@inproceedings{chen2021ctrgcn,
title={Channel-Wise Topology Refinement Graph Convolution for Skeleton-Based Action Recognition},
author={Chen, Yuxin and Zhang, Ziqi and Yuan, Chunfeng and Li, Bing and Deng, Ying and Hu, Weiming},
booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision},
year={2021}
}
@inproceedings{duan2022posec3d,
title={Revisiting Skeleton-based Action Recognition},
author={Duan, Haodong and Zhao, Yue and Chen, Kai and Shao, Dian and Lin, Dahua and Dai, Bo},
booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition},
year={2022}
}
一句话总结
先识别哪些步骤属于通用方法、Jetson平台、软件版本、模型结构和当前业务;
再记录目标板系统信息,用 FP16 把模型正确部署并建立数值与性能基线;
随后用 tegrastats、pidstat、trtexec 和程序分阶段日志测 GPU、CPU、EMC、功耗、延迟和 FPS;
换板时在目标软件栈重建 engine,换算法时重做输入输出契约、预处理、后处理和正确性验证;
最后才评估 INT8 是否真的带来有价值的收益,并用真实数据重新验证准确率和阈值。

1301

被折叠的 条评论
为什么被折叠?



