Jetson Nano边缘AI实战:YOLOv5与TensorRT部署优化

发布时间:2026/9/17 23:00:51
Jetson Nano边缘AI实战:YOLOv5与TensorRT部署优化 1. 先搞清楚这块板子能干什么Nano 的定位与选型逻辑第一次把 Jetson Nano 插上电的时候很多人会有点失望——它长得就像一块稍微大点的树莓派没有任何AI 开发板的排面。但当你把第一个模型跑起来看着它在一张 640 分辨率的画面上圈出人和车功耗表却只爬升到十瓦出头的时候那种感觉是不一样的。Jetson Nano 的核心价值就藏在这句话里它是一块能用 5W 到 10W 的功耗在本地完成推理的完整计算平台不是玩具也不是服务器而是介于两者之间的一块边缘算力。很多视频教程是录屏加解说的形式字幕默认是关掉的语速一快就完全跟不上来回拖进度条又很折磨人。这篇就当那份教程的文字版来看——把里面一闪而过的命令、参数、报错都写清楚遇到哪一步卡住了直接翻对应章节比反复暂停截图省事得多。我会从硬件准备讲到 TensorRT 加速中间穿插大量实际踩过的坑适合刚拿到板子的新手也适合已经在用但一直被内存和帧率折磨的老用户。1.1 472 GFLOPS 放在今天是什么水平先把参数摆出来Jetson Nano 4GB 版本用的是四核 ARM Cortex-A57 处理器主频 1.43GHzGPU 是 128 核的 Maxwell 架构频率 921MHz官方标称 FP16 算力 472 GFLOPS。内存是 4GB 的 64 位 LPDDR4带宽 25.6GB/sCPU 和 GPU 共享这一整块内存没有独立显存。这个规格放到今天单看 GFLOPS 数字确实不好看。但你要理解它的对手是谁同价位的树莓派 4B 用的是 VideoCore VI那玩意儿的浮点算力和 Nano 差着两个数量级一台同价位的迷你主机没有 GPU跑深度学习推理只能靠 CPU帧率会低到没法用。Nano 的意义在于它把 CUDA 生态完整地搬到了一个十几瓦的设备上你能在它上面用 PyTorch、TensorRT、DeepStream这些工具链跟你在服务器上用的是一模一样的。生活化的类比如果台式机加显卡是一辆越野车云端 GPU 是一整支车队那 Jetson Nano 就是一辆电动自行车。它拉不了重货但它能自己骑到任何地方不需要拖一根长长的电源线。边缘计算的场景里能到现场这件事比算得快重要得多。注意Nano 的 4GB 内存是 CPU 和 GPU 共用的。这意味着你开一个 4GB 的 swap 文件实际上是拿存储卡的空间换内存速度差距是数量级的不要指望它当内存用。1.2 Nano、Orin Nano 该怎么选如果你现在正准备买板子这个问题必须先回答清楚因为两者的差距不是一代是两代半。对比项Jetson Nano 4GBJetson Orin Nano 8GBSuper 模式GPU 架构Maxwell128 核Ampere1024 核含 Tensor CoreFP16 算力约 0.47 TFLOPS约 67 TOPSINT8 稀疏内存4GB LPDDR425.6GB/s8GB LPDDR5102GB/sCPU四核 A57 1.43GHz六核 A78AE 1.7GHz系统Ubuntu 18.04JetPack 4.6.x 止步Ubuntu 22.04JetPack 6.x 持续更新功耗档位5W / 10W7W / 15W / 25W典型价格段入门级中端结论很直接如果你只是想花最少的钱体验边缘 AI 的完整流程Nano 依然够用YOLOv5s 这种小模型跑十几帧完全没问题学习成本也低教程最多。但如果你要做产品原型、要跑多路视频、要用最新的 JetPack 6 和新版 PyTorch那 Orin Nano 是唯一合理的答案Nano 的 4GB 内存和 Ubuntu 18.04 会在半年内把你逼疯。我个人的判断标准是买板子只做学习和验证Nano任何带有以后要交付性质的项目直接上 Orin Nano。因为从 Nano 迁到 Orin 的时候你会发现代码基本不用改但环境全部要重搭一遍这个时间成本比板子差价高得多。1.3 为什么第一课总是拿 YOLOv5 来验证几乎所有 Jetson 教程都从目标检测起步而且大概率是 YOLOv5这不是偶然。原因有三个层面。第一它是一个端到端的完整验证链路。从摄像头取流、预处理、模型推理、后处理到画框输出每一个环节都涉及硬件能力跑通了说明你的整条链路都是健康的。你要是只跑一个 MNIST 分类GPU 用了没用到都看不出来。第二它的模型尺寸可调。YOLOv5 有 n、s、m、l、x 五个规格Nano 上从 yolov5n 开始试跑得动再往上加这个渐进的过程刚好能让你直观感受到算力边界在哪里。yolov5s 是 Nano 上的甜点也是绝大多数教程的默认选择。第三它的部署路径非常标准化。PyTorch 权重导出 ONNXONNX 转 TensorRT engineengine 直接推理这条路走通了你换成 YOLOv8、换成 MobileNet、换成任何其他检测模型方法论是一样的。不过要提前说清楚一个容易被忽略的点YOLOv5 官方仓库对 Jetson 的适配是能跑但没专门优化的状态很多默认参数是给服务器写的。照着 README 直接跑在 Nano 上大概率会遇到内存爆掉或者速度感人。后面第五章我会把该改的参数一个个拆开讲。2. 从烧录到开机硬件准备工作别省这一步看起来最没技术含量但实测下来新手大部分板子是不是坏了的疑问都出在这里。我见过太多人拿着板子折腾一整天最后发现是电源适配器的问题或者 SD 卡是杂牌的。2.1 镜像与 SD 卡的选择逻辑Jetson Nano 的系统镜像是通过 JetPack SDK 提供的最终下载到的是一个.img或.img.zip文件大小在 6GB 到 8GB 之间。你需要准备一张至少 32GB 的 microSD 卡我个人建议直接上 64GB。为什么强调卡的品质因为很多时候你的系统盘就是这张卡Ubuntu 系统本身有大量的随机小文件读写杂牌卡在持续写入时会出现明显的延迟抖动表现出来就是界面卡顿、apt 安装超时、有时候甚至系统莫名其妙崩掉。选 UHS-I Speed Class 3卡面上标 U3以上的产品别省这几十块钱。关于 JetPack 版本Nano 的最后一版官方支持停在 JetPack 4.6.x 系列对应的 L4T 版本是 32.7.x。如果你在网上看到有人用 JetPack 5.x 装 Nano那大概率是套壳的第三方镜像或者是从别的模块移植的不建议新手碰。记住一个铁律Nano 用 JetPack 4.6.xOrin Nano 用 JetPack 6.x两者不通用。2.2 烧录与首次开机烧录工具有两个主流选择balenaEtcher 和官方的 SDK Manager。SDK Manager 是给整机刷 eMMC 用的Nano 这种 SD 卡启动的方案直接用 balenaEtcher 把解压出来的.img写到卡上就行选择目标设备、选镜像、点 Flash等进度条走完。开机前有几件事要确认HDMI 显示器接好、USB 键盘鼠标接好、网线接好。第一次开机必定会走一段 oem-config 配置向导设置语言、时区、用户名密码、主机名。这个过程必须用显示器因为它没有默认账号。如果你手头没有 HDMI 显示器较新版本的 BSP 里提供了预设默认用户的脚本可以在烧录后挂载 SD 卡提前写好配置但脚本名称和用法在各个版本之间不一样具体以你下载的那版 BSP 里的说明为准别照抄网上的老教程。首次进入桌面之后先别急着装东西做两件事确认网络通、跑一次系统更新。sudo apt update sudo apt upgrade -y sudo reboot注意升级过程中如果弹出内核或者固件相关的配置文件冲突对话框选择保留当前版本keep the local version通常更安全避免引导文件被替换导致起不来。2.3 电源、跳线和散热这三个硬门槛这是最容易翻车的一节我按重要程度排。电源。Nano 开发板上有两种供电方式一个是 micro-USB 口一个是圆头 DC 接口丝印 J25。micro-USB 口只能提供 5V/2A也就是 10W 的上限圆头 DC 口支持 5V/4A也就是 20W 的输入能力。如果你打算使用 10W 性能模式必须走 DC 口。用 micro-USB 供电还硬开 10W 模式典型表现是跑着跑着突然掉电重启你以为是软件崩溃其实是电源撑不住。还有个细节坑板子上有个跳线帽 J48用来选择供电来源。默认位置是接 DC 口那一侧如果你用 micro-USB 供电需要把跳线帽挪到另外两针上。这一步说明书上写得很小很多人直接忽略。散热。Nano 的官方开发板只有一个巴掌大的铝制散热片默认没有风扇。短时间跑推理还好一旦你开始编译 TensorRT engine 或者跑连续的视频推理温度十分钟内就能冲到 80 度以上然后触发降频帧率断崖式下跌。建议直接配一个 5V 的 PWM 风扇插到 4 针风扇座J15上成本很低效果立竿见影。风扇转速可以直接用命令调# 查看当前转速0-255 cat /sys/devices/pwm-fan/target_pwm # 拉满 sudo sh -c echo 255 /sys/devices/pwm-fan/target_pwm # 安静一点六成 sudo sh -c echo 150 /sys/devices/pwm-fan/target_pwm存储。如果你后面想把 engine 文件、数据集、录制的视频都放在板子上64GB 卡很快就不够用了。可以考虑插一个 USB 3.0 的固态硬盘把工作目录挂过去读写速度比 SD 卡快好几倍尤其是读图的时候差距非常明显。3. 系统调优把 4GB 内存榨出应有的性能环境搭好之后别急着上深度学习框架。先在系统层面做几项调优这些操作看起来不起眼但对后续跑模型的稳定性影响极大。我的经验是没有做过调优的 Nano跑 YOLOv5 时的崩溃概率至少高一倍。3.1 换源与基础依赖Ubuntu 18.04 在 ARM64 上的默认软件源是国外的国内网络环境下 apt 下载速度可能只有几十 KB/s。换一个国内镜像源能把这个数字提升一到两个数量级。操作就是编辑/etc/apt/sources.list把ports.ubuntu.com相关的地址替换成镜像站对应的 ARM64 路径。换完之后装一批基础依赖这一步不能跳sudo apt install -y python3-pip python3-dev python3-setuptools \ build-essential cmake git libopenblas-dev liblapack-dev \ libjpeg-dev zlib1g-dev libpython3-dev libavcodec-dev \ libavformat-dev libswscale-dev这些包看着杂其实分三类编译工具链后面的 Python 包有些没有现成 wheel需要现场编译、数学库BLAS/LAPACKPyTorch 的矩阵运算依赖它们、多媒体库OpenCV 处理视频流要用。现在花三分钟装好能省掉后面一堆为什么 import 失败的排查时间。pip 也顺手换源编辑~/.pip/pip.conf写入镜像地址。之后所有 pip 安装都会快很多。3.2 swap 配置与内存实测4GB 内存是什么概念Ubuntu 桌面环境本身要吃掉 800MB 到 1GBPython 解释器加 PyTorch 的库加载大概 700MB剩给模型和数据的不到 2GB。YOLOv5 在 640 分辨率下做推理中间张量加上前处理缓存峰值很容易顶到 2.5GB 以上。所以 swap 不是可选项是必需项。幸运的是 JetPack 4.6 默认已经启用了 zram内存压缩当 swap 用大概能提供 2GB 左右的虚拟空间。但 zram 的代价是压缩解压要消耗 CPU而且压缩比有限。我建议再额外挂一个文件 swap# 创建 8GB 的 swap 文件 sudo fallocate -l 8G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # 验证 free -h swapon --show要让它在重启后自动生效把这一行写进/etc/fstab/swapfile none swap sw 0 0然后是 swappiness 参数。这个参数决定了内核有多愿意把内存页换出去。默认值是 60对 Nano 这种共享内存的架构来说偏高会导致频繁的换页抖动。我的建议是调到 20 左右echo vm.swappiness20 | sudo tee -a /etc/sysctl.conf sudo sysctl -p提示swap 只是防止进程被 OOM killer 直接杀掉不是性能优化手段。一旦你发现推理时 swap 使用量在持续增长说明真实内存真的不够了这时候要么降分辨率要么换更小的模型别硬撑。3.3 nvpmodel、jetson_clocks 与温度墙Nano 有两个功耗模式通过nvpmodel切换# 查看当前模式和可选模式 sudo nvpmodel -q --verbose # 切到 10W 模式四核全开GPU 921MHz sudo nvpmodel -m 0 # 切到 5W 模式两核GPU 640MHz sudo nvpmodel -m 1跑推理一定要切到 10W 模式默认是 5WGPU 频率被锁在 640MHz性能差距接近 40%。切完之后要重启才生效。jetson_clocks是另一个神器它会把 CPU、GPU、内存控制器全部锁在最高频率取消动态调频。默认的动态调频在负载波动时会来回切换频率导致帧率不稳定。sudo jetson_clocks # 查看当前频率状态 sudo jetson_clocks --show代价是功耗和发热都会上升所以风扇一定要配。如果你想开机自动执行可以写一个 systemd service或者直接加进~/.bashrc不建议因为每次开终端都会执行一次。温度方面Nano 的 GPU 在 85 度左右会开始降频。用下面的命令可以实时看温度cat /sys/devices/virtual/thermal/thermal_zone*/temp每个数字除以 1000 就是摄氏度。我实测下来加了风扇和散热片之后连续跑 YOLOv5 的温度稳定在 55 到 65 度之间不加风扇直接冲到 80 度以上并降频帧率从 15 掉到 8 左右。这个差距就是二十块钱风扇带来的。3.4 jtop把板子的状态可视化命令行看温度、频率、内存太累装一个jetson-stats会舒服很多sudo pip3 install -U jetson-stats sudo reboot重启后直接运行jtop会出来一个全屏的监控界面分几个标签页CPU/GPU 各核心的实时占用和频率、内存和 swap 的使用量、温度和功耗、以及当前 JetPack 各组件的版本号。最后这个功能特别有用因为你在装 PyTorch 之前必须知道自己的 CUDA 和 TensorRT 具体是哪个版本装错了就白折腾。按q退出别按 CtrlC有时候会留下僵尸进程。4. 深度学习环境版本链条一环都不能错这一章是整篇的核心也是最容易劝退人的部分。ARM64 架构加上 NVIDIA 定制的系统导致你在 x86 上习惯的pip install 一把梭完全不适用。你必须理解版本链条JetPack 版本决定了 L4T 版本L4T 版本决定了 CUDA 和 TensorRT 版本CUDA 版本决定了你能用哪个 PyTorch wheel。任何一环错位你都会得到一个语焉不详的报错。4.1 JetPack 决定了所有版本号以 JetPack 4.6.x 为例它包含的组件大概是这样的组件版本L4T32.7.xUbuntu18.04.6 LTSCUDA10.2cuDNN8.2.xTensorRT8.2.xPython3.6系统默认这些版本不是你选的是 NVIDIA 打包好的。所以你在网上找 PyTorch 安装教程的时候第一件事是确认那篇教程针对的是不是 JetPack 4.6 Python 3.6。如果对方是 JetPack 5.x那 CUDA 版本是 11.4PyTorch 也是 1.12 以上安装包完全不通用。系统里已经预装了 CUDA 和 cuDNN不需要额外安装nvcc --version能查到 CUDA 版本。TensorRT 也是预装的dpkg -l | grep nvinfer可以查。4.2 PyTorch 与 torchvision 的安装这是第一个大坑。你绝对不能pip3 install torch因为 PyPI 上的 torch wheel 是给 x86_64 编译的装到 ARM64 上要么直接报错要么装上了但 CPU 版本根本用不到 GPU。正确做法是用 NVIDIA 官方论坛提供的 ARM64 wheel。这些 wheel 有明确的命名规则文件名里包含 Python 版本和 CUDA 版本比如类似torch-1.8.0-cp36-cp36m-linux_aarch64.whl这样的形式。你需要根据自己系统的 Python 版本3.6 对应 cp36挑对应的文件下载。安装过程# 先装依赖numpy 版本要控制 sudo apt install -y libopenblas-base libopenmpi-dev # 安装 torch文件名以你实际下载的为准 pip3 install numpy1.19.4 pip3 install torch-1.8.0-cp36-cp36m-linux_aarch64.whltorchvision 官方没有提供 wheel需要从源码编译而且必须选对版本。PyTorch 1.8 对应 torchvision 0.9.01.9 对应 0.10.01.10 对应 0.11.0。版本错配会导致 import 时报符号找不到。编译 torchvision 之前先装好 Pillowsudo apt install -y libjpeg-dev zlib1g-dev libpython3-dev libavcodec-dev libavformat-dev libswscale-dev pip3 install pillow然后从 GitHub 拉对应 tag 的源码编译git clone --branch v0.9.0 https://github.com/pytorch/vision torchvision cd torchvision export BUILD_VERSION0.9.0 python3 setup.py install --user这一步在 Nano 上大概要跑二十到四十分钟取决于 SD 卡速度。跑到一半内存爆掉的话先把 swap 加大或者加MAX_JOBS1限制并行编译数量。编译完之后python3 -c import torch; print(torch.cuda.is_available())返回 True 就说明 GPU 可用了。注意编译期间风扇一定要开CPU 四核全负载温度会飙得很快。4.3 OpenCV 千万别用 pip 装JetPack 里其实已经预装了 OpenCV而且是带 GStreamer 支持的定制版本。这个支持非常关键因为 Jetson 的 CSI 摄像头和硬件编解码器都是通过 GStreamer 管线访问的标准版 OpenCV 读不了。如果你手贱执行了pip3 install opencv-python它会把 pip 版本装到用户目录优先级高于系统版本结果就是cv2.VideoCapture()打不开 CSI 摄像头报一堆 GStreamer 相关的错误。而且 pip 版本的 OpenCV 在 ARM64 上经常缺少必要的依赖import 都未必成功。解决方案永远不要 pip 装 opencv。如果需要版本信息直接python3 -c import cv2; print(cv2.__version__)应该输出类似 4.1.1 这样的版本号。如果输出了别的东西说明被覆盖了卸载掉 pip 版本pip3 uninstall opencv-python opencv-contrib-python4.4 那个让人抓狂的 Illegal instruction装完 PyTorch你兴冲冲地 import结果终端吐出一句Illegal instruction (core dumped)这个报错在 Nano 上出现的频率极高尤其是在 import numpy 或者 import torch 的时候。原因是 ARM 上的 OpenBLAS 会检测 CPU 支持的最高指令集有时候检测逻辑出问题用了硬件不支持的指令。解决方案是强制指定指令集export OPENBLAS_CORETYPEARMV8写进~/.bashrc让它永久生效echo export OPENBLAS_CORETYPEARMV8 ~/.bashrc source ~/.bashrc这个坑我前后遇到过三次第一次排查了整整一个下午因为报错信息完全没提 OpenBLAS。记住这个方法能省你几个小时。5. YOLOv5 实战从权重到 TensorRT 引擎环境备齐可以上模型了。这一章的思路是先跑通纯 PyTorch 推理确认链路健康再导出 TensorRT engine 拿到性能最后接摄像头做端到端验证。5.1 拉代码和最小验证git clone https://github.com/ultralytics/yolov5 cd yolov5 pip3 install -r requirements.txt这里有个细节requirements.txt里有 torch 和 torchvision 的版本要求但我们已经用官方 wheel 装好了。直接让它装会把你的 ARM 版 torch 覆盖成 x86 版。所以要么先注释掉那两行要么装完之后立刻重新装一遍 ARM wheel。我一般选前者干净利落。下载一个 yolov5s 的权重跑一张测试图python3 detect.py --weights yolov5s.pt --source data/images --img-size 640第一次运行会做一些初始化速度慢是正常的。如果能在runs/detect/exp/目录下看到画了框的图片说明整个链路通了。这一步的帧率不重要跑纯 PyTorch 在 Nano 上大概只有 2 到 3 FPS慢到让人怀疑人生但它是后面的基准。5.2 导出 engine 的关键参数TensorRT 加速的原理是把训练好的网络在特定硬件上做一层深度优化融合算子、选择最快的卷积实现、把权重精度降低。优化后的引擎能带来数倍甚至十几倍的加速代价是这个 engine 文件只对当前这台设备、当前这个 TensorRT 版本有效换机器或者升级 JetPack 之后必须重新导出。导出命令python3 export.py --weights yolov5s.pt \ --include engine \ --device 0 \ --half \ --img-size 640 \ --batch-size 1 \ --workspace 1 \ --opset 12参数逐个解释一下这几个都值得花时间理解--half表示用 FP16 精度导出。Nano 的 Maxwell GPU 对 FP16 有硬件支持速度比 FP32 快接近一倍精度损失在检测任务上基本可以忽略。这一个参数是性价比最高的优化。--batch-size 1是关键。默认导出可能是 batch 16 之类的Nano 只有 4GB 内存batch 一大直接爆。而且边缘场景本来就没有批处理的必要一帧一帧处理就行。--workspace 1限制构建时能用的显存工作空间是 1GB。默认值可能更大在 Nano 上会直接分配失败。这个值是构建期的临时占用不影响推理性能。--opset 12是指定 ONNX 的算子集版本TensorRT 8.2 对 opset 12 的支持最稳。构建过程非常慢在 Nano 上跑十几分钟到二十分钟很正常风扇会全速转温度会上去。别以为是卡死了耐心等。构建完会在权重旁边生成一个.engine文件大小几十 MB。注意导出过程中如果出现内存不足被杀掉先把--img-size降到 512 试一次或者把--workspace再降到 0.5构建完成后再用 640 重来。5.3 用 detect.py 跑通端到端有趣的地方来了。YOLOv5 的代码里内置了一个自动机制如果yolov5s.pt旁边存在同名的yolov5s.enginedetect.py 会自动优先加载 engine。所以你不需要改任何参数还是原来的命令python3 detect.py --weights yolov5s.pt --source data/images --img-size 640 --half这一次的耗时应该比之前短一个数量级。想验证到底用的是哪个看日志里的输出会明确写明加载的是什么格式。接摄像头的话分两种情况。USB 摄像头直接用序号python3 detect.py --weights yolov5s.pt --source 0 --img-size 640 --halfCSI 摄像头需要走 GStreamer 管线。在 Nano 上没有显示器的情况下headless可以把管线写成一个字符串传给--source或者在代码里自定义 GStreamer 参数。常见的管线形式是nvarguscamerasrc取流经过nvvidconv做色彩空间转换最后给appsink。具体的管线字符串根据你的摄像头分辨率和格式会略有差异用gst-launch-1.0先单独测一遍管线能不能出画面再接进代码能省很多排查时间。5.4 实测数据与解读下面是我在 Nano 4GB、10W 模式、jetson_clocks 锁频、加装风扇的条件下测到的数据仅供参考你的数字会因为环境温度、SD 卡速度、是否落盘录像而有波动。配置纯推理帧率端到端帧率含取流和绘制PyTorch FP32640约 2-3 FPS约 2 FPSTensorRT FP16640约 20-25 FPS约 10-15 FPSTensorRT FP16416约 35-40 FPS约 18-22 FPSTensorRT INT8640约 30-35 FPS约 15-20 FPS几个观察值得说一下。第一PyTorch 到 TensorRT 的提升是最夸张的接近十倍这也是为什么在 Jetson 上做部署TensorRT 几乎是必修课。第二纯推理帧率和端到端帧率差距很大因为视频解码、色彩转换、画框、编码回写这些都在消耗资源尤其视频编解码会占用独立的硬件模块跟 GPU 抢带宽。第三降低分辨率带来的收益比提升精度明显得多因为计算量大致跟像素数成正比。Orin Nano 上的数字完全是另一个量级同样是 yolov5s FP16 640纯推理可以跑到上百 FPS端到端也能稳定在六七十帧这就是算力和内存带宽的代差。6. 性能再压一层量化、分辨率与视频管线跑通只是开始实际项目里你总会觉得还不够快。这一章讲三个可以直接落地的优化方向。6.1 FP32、FP16、INT8 的取舍精度选择本质上是拿准确率换速度。FP32 是训练时的标准精度推理时基本没有理由用它除了极少数对数值敏感的场景。FP16 是 Jetson 上的默认甜点大多数视觉模型在这个精度下 mAP 掉不到一个百分点速度接近翻倍。INT8 就微妙一些。它的加速效果在 Turing 及以后的架构上非常明显但 Maxwell 架构也就是 Nano对 INT8 的支持没有 Tensor Core 加持实测提升幅度远不如在 Orin 上那么惊艳大概是 FP16 基础上再快 20% 到 40%。而且 INT8 需要校准——你得准备一批有代表性的图片跑一遍校准流程生成一个校准表让 TensorRT 统计每一层的激活值分布来定量化参数。OSTU 式的建议是Nano 上直接用 FP16别折腾 INT8。省下的那点时间不值得你花半天做校准还要担心精度下滑。Orin Nano 上则相反INT8 的收益非常大值得认真做校准。# INT8 校准的时候需要一个 calib 目录放代表性图片 python3 export.py --weights yolov5s.pt --include engine --device 0 \ --int8 --data data/coco128.yaml --batch-size 1 --img-size 6406.2 输入分辨率对帧率的影响这一条我单独拎出来讲因为它是最容易被忽略、收益又最直观的一环。卷积网络的计算量在输入尺寸上是平方关系640 降到 416像素数减少接近 58%帧率自然大幅提升。代价是小目标检测能力下降。416 分辨率下原图上小于 30 像素的物体基本就丢了。所以怎么选取决于你的场景画面里主要是近处的人、车物体在画面中占比大416 甚至 320 都够用需要检测远处的行人或小物体咬牙用 640接受低帧率折中方案用 640 训练和导出但推理时把输入 resize 到 512精度掉得不多速度快一截还有一个不太为人知的技巧如果你的摄像头本身就是 720p把--img-size设成 640 之后前处理还需要做一次缩放这次缩放消耗在 CPU 上。可以考虑把摄像头输出直接配成 640x640 或者接近的尺寸减少一次转换。6.3 CSI 摄像头与 USB 摄像头的管线差异Jetson 板子上有两个 MIPI CSI-2 接口可以接官方的摄像头模组。CSI 摄像头走的是 ISP 硬件通路延迟低、不占 USB 带宽但必须用 GStreamer 管线访问。USB 摄像头简单通用但数据要经过 USB 总线和 CPU 内存延迟稍高。在需要多路摄像头的场景里CSI 接口只有两个更多的就得靠 USB 或者网络摄像头。这时候 USB 总线的带宽会成为瓶颈四路 1080p30 的 USB 摄像头同时在 Nano 上跑光是把数据搬进内存就够 CPU 喝一壶的更别说推理了。如果要在多路之间腾挪我的一般做法是主路用 CSI 拿到最低延迟其余路用降低分辨率比如 640x480的 USB 摄像头并且把推理频率降下来比如每三帧处理一次中间帧复用上一帧的结果。这个技巧在监控类场景里效果很好人眼对检测框的刷新率其实没那么敏感。7. 常见问题速查表与踩坑心得这一章把散落在前面的坑集中整理方便对照排查。我按开机前、跑起来之后、文档里不会写三个维度分。7.1 开不了机的那几类问题现象可能原因排查动作完全不通电指示灯不亮供电不足或跳线帽位置不对换 DC 口 5V4A 电源检查 J48 跳线绿灯亮但无画面输出镜像烧录失败或 SD 卡不兼容重新烧录换一张已知好的卡卡在开机 logo 不动文件系统损坏或升级中断重新烧录尽量别在中途断电进系统后频繁重启电源功率不够或温度过高换 DC 供电检查风扇是否转显示器分辨率异常EDID 识别问题换一根 HDMI 线或换个显示器试试这里我想强调一下频繁重启这个现象因为它最容易被误判成软件问题。很多人的第一反应是重装系统折腾一圈发现没用。实际上 90% 的情况是电源功率不够——用 micro-USB 供电跑 10W 模式负载一上来电压就被拉低板子直接复位。7.2 跑起来之后的各种报错Illegal instruction前面讲过export OPENBLAS_CORETYPEARMV8。ImportError: libcudart.so.10.2: cannot open shared object fileCUDA 环境变量没配。检查~/.bashrc里有没有把/usr/local/cuda-10.2/lib64加进LD_LIBRARY_PATH。JetPack 一般已经配好了如果你手动改过环境变量可能会覆盖掉。RuntimeError: CUDA out of memory内存不够。先确认同时没有别的进程占着 GPU然后降 batch size、降分辨率或者把 swap 加大。ModuleNotFoundError: No module named cv2OpenCV 路径问题通常是 pip 装了 opencv-python 覆盖了系统版本卸载掉。AssertionError出现在 TensorRT 导出时多半是 opset 版本或者 onnx 版本不兼容试着固定 onnx 版本或者换个 opset。engine 文件存在但没用上检查文件名是否与.pt完全同名且在同一目录detect.py 的自动加载逻辑对文件名很敏感。7.3 文档里一般不写的几条经验第一条先跑通再优化。我见过太多人在环境还没搭稳的时候就开始研究 INT8 量化和多线程流水线最后卡在第一个环节就放弃了。正确的顺序是能跑起来 → 跑得对 → 跑得快。跳过第一步后面两步都是空中楼阁。第二条给每个成功的状态留一份备份。在 Nano 上折腾把系统搞崩的概率不低。我一般在系统装好、PyTorch 装好、engine 跑通三个节点各备份一次 SD 卡镜像。听起来很土但每次出问题能省下两三个小时重装。做法很简单把卡插到电脑上用 dd 或者烧录工具读出来存成 img 文件就行。第三条日志一定要落到文件里。跑长时间推理的时候终端输出一多就滚没了出了问题什么都看不到。养成习惯用21 | tee run.log把输出同时写进文件回溯问题的时候会感谢自己。第四条不要在 Nano 上做训练。哪怕只是微调一个小模型Nano 的速度也会让你等到怀疑人生。正确的分工是在有独立显卡的机器上训练和导出 ONNXNano 只负责加载 engine 做推理。ONNX 是跨平台的中间格式这个分工方式能让你的工作流清晰很多。第五条记录你的版本组合。把 JetPack 版本、CUDA 版本、TensorRT 版本、PyTorch 版本、torchvision 版本、numpy 版本这六个数字写在便签上贴显示器边缘。这六个数字决定了你的环境能不能工作也决定了你从网上抄来的命令能不能用。什么时候板子换新了照着这张便签重新配一遍比重新摸索快得多。第六条Orin Nano 的迁移其实比你想的简单。你的 Python 代码基本不用改需要改的是环境搭建部分JetPack 版本、PyTorch wheel 的来源、apt 源地址。所以如果你是一个团队在做最好一开始就把代码里的设备相关配置抽出来做成配置文件别硬编码在代码里。说实话我在 Nano 上折腾的时间加起来大概有几十个小时前面一半都在各种环境问题上打转真正调优的部分可能只占三成。后来我把整套流程整理成一个脚本每换一台板子就跑一遍从烧录到跑通 YOLOv5 完整地控制在一个下午之内。这个过程里最有价值的不是某个具体的命令而是建立起先确认版本链、再动手装、每一步留备份的习惯。这套习惯放到 Orin 上、放到任何一块新的边缘设备上基本都能复用。