资讯详情 Jetson NX/Nano部署YOLOv5:TensorRT加速从零到实战
📅 2026/10/16 17:55:52
跑嵌入式AI的朋友应该都知道模型在PC上跑得再快搬到Jetson这种板子上就是另一回事了。YOLOv5作为目前应用最广的目标检测模型之一在Jetson NX、Nano这类边缘设备上部署时如果不做TensorRT加速那帧率和功耗基本没法看。这篇文章是我自己实打实踩过一轮坑之后整理的完整流程覆盖模型导出、ONNX处理、TensorRT引擎构建、推理代码编写和性能调优照着走一遍基本能在Jetson NX/Nano上把YOLOv5跑起来顺便把帧率拉到一个能用的水平。1. 为什么在Jetson上跑YOLOv5绕不开TensorRTJetson NX和Nano虽然都属于英伟达的嵌入式平台但和桌面GPU完全不是一回事。Nano的GPU算力有限跑原版PyTorch的YOLOv5s640分辨率的输入推理一次可能要200到300毫秒这个速度放到实际项目里基本没法用。NX稍微好一点但如果不做任何优化也只是从没法用变成勉强能看。根本原因在于PyTorch的算子执行效率太低大量时间浪费在框架调度和冗余计算上并没有真正压榨出板子的算力。TensorRT的作用就是把这些冗余砍掉。它会把训练好的模型做层融合、精度校准、内存复用最终生成一个高度优化的推理引擎。在Jetson平台上TensorRT是官方工具链的核心一环相当于专门给这块板子量身定做的加速方案。实测下来同一个YOLOv5s模型从PyTorch直接推理换成TensorRT FP16引擎Nano上能把延迟从两三百毫秒降到五六十毫秒NX上能跑到二三十毫秒这个差距就是不能商用和勉强能落地的区别。对于目标检测这类任务TensorRT里面有几个非常关键的优化手段。第一个是层融合它把卷积、偏置、激活函数这些相邻操作合并成一个算子减少内核启动次数。第二个是精度裁剪通过FP16或者INT8来降低计算量。第三个是显存复用引擎在构建时就把中间张量的生命周期算清楚避免反复申请释放内存。这三点加起来推理速度的收益非常直观尤其在高分辨率输入下更明显。这篇文章适合谁看呢两类人最需要——一类是做边缘计算、机器人、安防监控这些方向的开发者需要把检测模型真正部署到设备上另一类是刚接触Jetson和TensorRT的入门者想找一个从零开始的完整参考流程。我默认你有一块Jetson NX或Nano开发板基础Linux操作没问题对YOLOv5本身有一定了解但不需要预先会TensorRT。2. 环境准备板卡选型、系统烧录与软件栈版本2.1 Jetson NX/Nano选型差异很多人在选板卡的时候纠结Nano和NX到底买哪个。我的建议是先想清楚应用场景对帧率、功耗、算力的要求。Nano有2GB和4GB两个版本功耗只有5W到10W适合做低功耗的轻量级推理。Xavier NX算力强很多功耗在10W到20W之间适合需要跑较大模型或者多路视频流的场景。如果是做机器人小车、智能门禁这种单路摄像头检测Nano 4GB完全够用性价比也高。如果是做多路监控、复杂场景识别或者要在模型效果和速度之间找平衡那尽量上NX省得后期再换板子推倒重来。我自己实际测试的感觉是Nano上跑YOLOv5s还能接受但跑到YOLOv5m就开始吃力了NX上跑YOLOv5m就比较从容。还有一个细节容易被忽略——板卡的风扇和散热。Jetson平台默认开启动态调频但并不代表不会过热降频。Nano满载跑推理几分钟后模块温度很容易冲到80度以上一旦触发降频帧率会明显波动。长期部署的话建议用主动散热方案或者限制最大推理频率稳定比极限性能更关键。2.2 系统烧录与JetPack版本选择部署第一步就是给板子烧系统。Jetson平台用JetPack发行版里面预装好了CUDA、cuDNN、TensorRT这些组件省去了一一安装的麻烦。烧录方式有几种最简单的是用SDK Manager配合PC主机操作下载镜像包后写入SD卡或NVMe固态。也有纯命令行离线刷机的方案适合没有图形界面的环境。JetPack版本的选择是第一个容易踩坑的地方。不同版本的JetPack内置的TensorRT版本不一样而YOLOv5导出ONNX时的算子兼容性、TensorRT的层支持能力都和这个强相关。目前常见的组合大致如下JetPack版本对应TensorRT版本备注JetPack 4.6TensorRT 8.2适配Ubuntu 18.04生态最成熟JetPack 5.0.xTensorRT 8.5适配Ubuntu 20.04支持新算子JetPack 5.1.xTensorRT 8.5.2稳定性更好适合生产JetPack 6.xTensorRT 8.6新卡支持好Nano/NX老用户慎重我建议先确认板卡出厂时的JetPack版本再决定要不要升级。老设备如果已经在跑业务升级JetPack意味着所有依赖都要重新适配风险不小。如果是从零开始直接上万兆设备配套的新版本就好没必要刻意用旧版。2.3 依赖组件安装细节系统装好后还需要确认几个基础组件是否齐全。首先是pip源Jetson是ARM架构很多Python包的安装源在PC上是x86版本直接用默认pip源安装会报找不到匹配版本。建议先配置好国内可用的ARM pip源比如清华源或者阿里源。然后安装虚拟环境管理工具我习惯用conda或者venv避免系统Python环境被搞乱。接下来是几个必须的Python包pycuda、onnx、onnxruntime-gpu可选、numpy、opencv-python。pycuda在做TensorRT的Python绑定时几乎绕不开它负责把GPU缓冲区和Python对象打通。opencv用官方预编译包在Jetson上经常安装失败因为依赖库版本冲突我实测下来用源码编译或者直接装系统自带的python3-opencv更省事。# 以JetPack 5.x为例先更新系统 sudo apt update sudo apt upgrade -y # 安装基础依赖 sudo apt install -y python3-pip libopenblas-dev libopenmpi-dev # 配置pip使用ARM可用的源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple # 安装关键包 pip install numpy1.19.5 pycuda onnx onnxsimpy opencv-python-headless这里有个容易翻车的点——pycuda安装时需要编译C扩展如果系统里没有对应CUDA路径会报cannot find -lcuda。解决办法是安装前先确认/usr/local/cuda软链存在没有的话手动建立指向实际CUDA版本的链接。另外pycuda的版本和JetPack里的CUDA版本要匹配JetPack 5.x对应CUDA 11.4以上直接装新版pycuda通常没问题。3. YOLOv5模型导出从PyTorch到ONNX的完整流程3.1 模型权重准备部署的起点是一个训练好的YOLOv5权重文件。可以用官方预训练权重也可以是自己数据集的模型。但我强烈建议如果想让模型在目标场景里真正好用最好在自己的数据上微调过。因为TensorRT只是加速推理不会改善模型的检测效果模型本身的精度在部署前就得定好。拿到权重后第一件事是确认YOLOv5的版本。YOLOv5的v6.0、v7.0、v6.2这些版本在导出ONNX时的处理方式略有差异新版对ONNX导出的支持更完善。如果用的是老版本建议先升级到较新的release避免导出时遇到算子兼容问题。权重文件的存放路径也要注意。Jetson板子一般空间不大尤其是Nano的16GB存储版本训练好的模型文件可能上百兆多个模型版本堆在一起很容易爆盘。我在实际项目中习惯只保留最终部署的detect权重训练过程中的大checkpoint不放到板子上。拿到权重后先在PC上跑一次验证脚本确认检测效果和预期一致再上板子操作。这一步可以省掉很多板子上的无效调试时间因为Jetson环境的调试工具远不如PC方便。3.2 导出ONNX关键参数YOLOv5官方仓库提供了export.py脚本可以直接把PyTorch权重转为ONNX。命令大概长这样python export.py --weights yolov5s.pt --include onnx --opset 12 --simplify这里有几个参数值得展开说。--opset控制ONNX算子集的版本对于TensorRT 8.2建议用opset 12或13都能支持如果是TensorRT 8.5可以尝试opset 13甚至更高算子映射更丰富。但不要盲目用最高版本有些新算子TensorRT还不支持反而增加后续转换的难度。--simplify参数会调用onnxsim对计算图做常量折叠、冗余节点删除这一步非常重要。YOLOv5导出ONNX时经常带一堆用于训练阶段的算子比如梯度相关节点虽然不影响推理正确性但会增大模型体积拖慢TensorRT解析速度。用--simplify能显著瘦身图形结构也干净很多。还有一点需要注意export.py默认导出的是检测头全部输出也就是三个尺度的原始预测张量。如果直接拿这个ONNX去做推理后处理需要自己实现解码和NMS。也有一种做法是把NMS直接集成进ONNX但我不推荐在Jetson上这么做因为TensorRT对自定义NMS层的支持不太稳定性能也不如自己用GPU或CPU实现的后处理可控。导出完成后检查一下ONNX模型的文件大小和输入输出节点。用Netron这个可视化工具打开onnx文件能看到整个计算图结构。重点关注输入节点的形状是不是[1, 3, 640, 640]输出节点的形状是不是[1, 25200, 85]这样的结构。25200是三个尺度anchor数量的总和85是4个坐标值加1个置信度加80个类别类别数不同这个数字会变。3.3 ONNX模型常见问题排查导出ONNX时遇到的最典型报错是Unsupported operator或者ONNX export failed: shape inference。前者说明当前代码版本里检测头里用了TensorRT不支持的算子通常可以通过升级YOLOv5版本来解决。后者多半是模型里有自定义算子或者动态shape没处理好可以先固定尺寸导出再用onnxsim做形状推断。另一个常见坑是导出时通道顺序。YOLOv5的预处理默认采用RGB格式PyTorch模型的输入就是RGB通道。但很多摄像头和OpenCV读图默认是BGR如果导出后推理时忘了做通道交换检测结果会错得离谱猫会识别成狗背景会识别成目标。这不是TensorRT的坑而是整个链路里最容易忽略的细节。ONNX模型导出之后我习惯在PC上先用onnxruntime做一次推理验证确认ONNX的输出和PyTorch原模型输出一致允许极小浮点误差。这一步通过之后再上板子做TensorRT转换能有效隔离问题——如果ONNX已经跑不对后面就不可能是TensorRT的问题省得浪费板卡时间。4. TensorRT引擎构建从ONNX到加速引擎的实操4.1 trtexec命令行转换把ONNX转成TensorRT引擎最直接的方式是使用TensorRT自带的trtexec工具。这个工具在JetPack里已经装好了可以在终端直接调用。基本命令如下/usr/src/tensorrt/bin/trtexec \ --onnxyolov5s.onnx \ --saveEngineyolov5s.engine \ --fp16trtexec会把整个构建过程打印在终端包括每一层的名字、耗时、显存占用、是否启用了FP16等。看到输出的最后几行有Total Host Memory和Total Device Memory这类信息说明引擎构建成功。构建引擎是一个计算密集的过程在Jetson NX上转一个大一点的模型可能需要几分钟甚至十几分钟Nano会更慢。这是正常现象不用着急。如果构建过程中报错先把log保存下来重点看Error前后的层信息一般能定位到是哪层不支持。引擎文件的体积通常比ONNX大因为里面包含了优化好的内核缓存。保存后后续运行推理直接加载这个engine文件不需要每次重新转换。这也意味着引擎文件和TensorRT版本强绑定换了一个版本的JetPack旧的engine文件往往不能直接用需要重新生成。很多人忽略这一点升级系统后推理报错找不到原因其实大多是引擎版本不匹配。4.2 FP16半精度优化Jetson平台上的GPU架构对FP16计算有专门的硬件单元尤其是NX板卡的Tensor Core支持所以FP16几乎是默认要开的。FP16相比FP32速度提升明显精度损失对于目标检测这类任务来说通常可以忽略。在trtexec命令里加上--fp16参数就可以启用。构建完成后可以用--fp16 --verbose查看每一层的精度类型确认关键卷积层真的用了FP16内核而不是某个地方回退到了FP32。有一个细节值得注意——有的层虽然标注成FP16但实际计算时精度仍不够尤其是一些对精度敏感的归一化层或者距离计算层。出现这种情况的典型表现是FP16引擎推理时检测的置信度比FP32低很多或者目标框位置有偏移。如果遇到这类问题可以在构建时把这些敏感层单独指定为FP32精度TensorRT支持精细化控制。具体做法是先构建引擎再用TensorRT的API按层名设置精度或者使用网络定义API时对特定层强制FP32。对于YOLOv5来说Conv和BN层融合成Conv后对FP16的容忍度很高绝大多数情况下FP16引擎的精度和FP32几乎一样。我自己在多个数据集上对比过mAP的下降一般在0.1%以内非常可以接受。4.3 INT8量化与校准数据准备如果还想进一步提升速度可以试试INT8量化。INT8相比FP16能再快不少显存占用也更少但精度损失会更大而且需要额外准备校准数据集。所谓校准就是让TensorRT统计真实输入的激活值范围计算每个张量最合适的量化参数。用trtexec做INT8量化比较麻烦因为它需要指定校准数据生成器。更常见的做法是在Python代码里定义校准器用TensorRT的calibrator接口喂入一批代表实际场景的图片。校准数据一般用500到1000张就够太少会导致量化参数偏差大太多会拖慢构建过程且边际收益递减。import tensorrt as trt class Calibrator(trt.IInt8EntropyCalibrator2): def __init__(self, data_loader, cache_file): trt.IInt8EntropyCalibrator2.__init__(self) self.data_loader data_loader self.cache_file cache_file self.index 0 def get_batch_size(self): return 8 def get_batch(self, names): batch, _ next(self.data_loader) batch np.ascontiguousarray(batch) return [int(batch.ctypes.data)]INT8量化的一个隐藏风险是校准数据的选择会直接影响量化效果。如果校准集和真实部署场景的数据分布差异很大比如校准集全是白天的道路画面部署时晚上使用量化误差就容易被放大出现漏检或误检。所以校准数据最好是从真实使用环境中抽样而不是随便拿训练集图片凑数。4.4 动态Shape与动态Batch的取舍YOLOv5模型可以设置动态输入尺寸也就是TensorRT支持在推理时改变输入的分辨率。这个功能在trtexec里通过--minShapes、--optShapes、--maxShapes来配置trtexec --onnxyolov5s.onnx \ --saveEngineyolov5s_dynamic.engine \ --fp16 \ --minShapesimages:1x3x320x320 \ --optShapesimages:1x3x640x640 \ --maxShapesimages:4x3x640x640动态shape的代价是引擎构建时内存分配策略更保守性能和固定shape相比有一定损耗。如果实际场景的输入分辨率是固定的比如摄像头输出固定1280x720处理后固定640x640那完全没必要用动态shape直接固定输入尺寸生成的引擎速度更快内存占用也更低。动态batch的情况类似。如果要在单板卡上同时跑多路视频流每个流做一次独立推理可以尝试一次推理处理多张图片来提升吞吐量。但TensorRT的动态batch引擎在Jetson上的性能收益并没有想象中大因为板卡的内存带宽有限。我的经验是两路视频流分开推理和合并batch推理帧率差别不大反而合并后显存峰值更高。除非板卡显存充裕否则不推荐一上来就做batch优化。5. 推理代码实现从图像输入到检测输出5.1 图像预处理流程预处理是整个推理链路里最容易被低估的环节。YOLOv5的训练阶段会对输入图片做letterbox操作也就是等比缩放后填充灰边让图片变成640x640的正方形。推理时也必须做完全一样的letterbox否则检测精度会掉得厉害。letterbox的实现要点是计算出缩放比例后把图片放到画布中心短边两侧补灰边。这里的灰边值默认是114。还需要记录缩放比例和填充大小因为后处理要把检测框坐标还原到原图上。def letterbox(img, new_shape(640, 640), color(114, 114, 114)): h, w img.shape[:2] ratio min(new_shape[0] / h, new_shape[1] / w) new_h, new_w int(round(h * ratio)), int(round(w * ratio)) dw, dh (new_shape[1] - new_w) // 2, (new_shape[0] - new_h) // 2 img cv2.resize(img, (new_w, new_h)) top, bottom dh, new_shape[0] - new_h - dh left, right dw, new_shape[1] - new_w - dw img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img, ratio, dw, dh预处理还包括通道顺序转换和归一化。模型输入是RGB顺序而OpenCV读图默认是BGR必须先用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)转换。归一化有两种做法一种是把像素值除以255变成0到1的浮点数另一种是保持0到255的整数再转成FP32。两种方式的模型权重是不同的YOLOv5默认导出时带有归一化层所以推理时只需要转成FP32并把值域保持在0到255即可。这个细节如果搞反了输出结果会全部变成接近0的置信度表现就是什么都检测不到。内存拷贝是推理前的最后一步。Jetson平台的推理性能很大程度上取决于数据从CPU到GPU的传输效率。我习惯先用pycuda.driver把预处理后的numpy数组分配到固定的GPU显存缓冲区推理时直接从缓冲区读取避免每次推理都重新分配显存。这个小优化看起来不起眼但实际帧率能提升5%到10%。5.2 引擎加载与推理TensorRT的Python推理流程大致是创建runtime反序列化engine创建context然后把输入数据拷入显存调用context.execute_v2执行推理最后从显存取出输出。一个简单的加载函数如下import tensorrt as trt import pycuda.driver as cuda class Engine: def __init__(self, engine_path): self.logger trt.Logger(trt.Logger.WARNING) with open(engine_path, rb) as f: runtime trt.Runtime(self.logger) self.engine runtime.deserialize_cuda_engine(f.read()) self.context self.engine.create_execution_context() self.allocate_buffers() def allocate_buffers(self): inputs, outputs, allocations [], [], [] for i in range(self.engine.num_bindings): binding self.engine[i] size trt.volume(self.engine.get_binding_shape(i)) dtype trt.nptype(self.engine.get_binding_dtype(i)) host_mem cuda.pagelocked_empty(size, dtype) device_mem cuda.mem_alloc(host_mem.nbytes) allocations.append(device_mem) if self.engine.binding_is_input(binding): inputs.append((host_mem, device_mem)) else: outputs.append((host_mem, device_mem)) self.inputs, self.outputs, self.allocations inputs, outputs, allocations引擎加载时有一个值得强调的点——Runtime对象必须在整个推理生命周期内保持存活。有些教程里会把runtime创建在函数内部推理函数结束后被垃圾回收结果下一次推理时直接crash或者报无效指针。这种问题排查起来非常费劲因为报错信息不明确。我的习惯是把Engine封装成类runtime作为成员变量持有同时用atexit或者上下文管理器确保退出时释放显存。推理时把预处理后的输入数据复制到输入缓冲区调用execute_v2然后从输出缓冲区取出数据。YOLOv5的原始输出是一个形状为(1, 25200, 85)的张量需要reshape成(1, 3, 80, 80, 85)、(1, 3, 40, 40, 85)、(1, 3, 20, 20, 85)三个尺度的预测结果然后拼接起来做解码。5.3 NMS后处理实现后处理是整个推理流程中计算量不小的一部分。YOLOv5的预测输出是每个anchor的位置偏移、物体置信度和类别概率。要先对输出做解码算出实际坐标和类别分数再进行非极大值抑制NMS才能得到最终的检测框。解码的核心是把中心点坐标和宽高换算成左上角和右下角坐标然后用置信度过滤低分框。过滤之后NMS会对同类的框做去重确保同一个目标只保留一个框。NMS的阈值一般设置在0.4到0.5之间置信度阈值在0.25到0.4之间具体数值取决于你对误检和漏检的容忍度。NMS的实现方式有两种选择一种是用OpenCV的cv2.dnn.NMSBoxes写法简单CPU计算另一种是自己用NumPy或GPU实现速度快但代码复杂。对于Jetson这种嵌入式平台如果每帧的目标数量不多比如少于50个用OpenCV的NMS完全够用没必要过度优化。如果目标是密集小目标比如无人机视角下的人群计数那就需要考虑更高效的后处理方案。还有一个容易被忽略的点——在整个推理流程里预处理、模型推理、后处理是三个串行阶段。很多人只盯着推理阶段的毫秒级优化却没发现预处理里的一次cv2.resize加上一次copyMakeBorder在Jetson上可能就要花掉10到15毫秒。优化思路是尽量复用预处理的临时缓冲区避免每次重新分配。实测中把numpy数组预先分配好推理时只做原地拷贝预处理耗时能压缩到5毫秒以内。6. 性能实测与调优心得6.1 实际性能数据参考为了给读者一个直观感受我把自己在Jetson NX和Nano上实测的一组数据列出来。测试模型是YOLOv5s输入分辨率640x640单张图片推理不包含预处理和后处理时间结果仅供参考毕竟具体数字会受JetPack版本、散热条件、频率模式、TensorRT版本等因素影响。平台引擎精度单帧推理延迟帧率估算Jetson Nano 4GBFP32约120毫秒约8 FPSJetson Nano 4GBFP16约55毫秒约18 FPSJetson Nano 4GBINT8约35毫秒约28 FPSJetson Xavier NX 8GBFP16约25毫秒约40 FPSJetson Xavier NX 8GBINT8约15毫秒约65 FPS注意这个表格里的FP32数据已经比PyTorch推理快了很多因为TensorRT的层融合优化对FP32也有收益。但FP32在Jetson这种功耗受限的平台上是不划算的——如果对精度极度敏感宁可用FP16加FP32敏感层混合也不要全模型FP32功耗和发热差很多。Nano的INT8比FP16快那么多和它的GPU架构有关。Nano的GPU不支持Tensor CoreFP16计算和FP32其实走的是同一条路径所以FP16的收益主要来自内存带宽减半。INT8的收益就明显了它有专用的INT8内核。NX有Tensor CoreFP16的收益就很大加上INT8之后还能再进一步。这也是为什么我说选型时要按板卡的硬件特性来决定优化策略不能一概而论。6.2 问题排查速查表部署过程中难免遇到各种报错我整理了一个高频问题速查表这些都是我自己或者身边同事真实遇到过的。现象可能原因解决方案引擎构建报Unsupported layerONNX算子版本过高或算子不被TensorRT支持升级JetPack或降级opset导出引擎加载报CUBLAS_STATUS_NOT_INITIALIZEDcuDNN/CUDA上下文未初始化先执行一次简单的cuda操作触发初始化推理结果置信度全部为0输入归一化方式错误或通道顺序错误确认BGR转RGB和值域处理检测框位置偏移严重letterbox参数记录错误检查ratio和padding还原逻辑推理速度波动大散热不足导致降频散热改善或锁定最大频率pycuda安装失败CUDA路径缺失确认/usr/local/cuda软链存在有一种比较隐蔽的问题值得单独说——引擎文件在PC上构建好了直接拷贝到Jetson上加载。PC和Jetson平台虽然都是TensorRT但一个是x86架构一个是ARM架构生成的引擎文件完全不一样直接加载必然报错。引擎文件必须在本机上构建或者用跨平台构建方案如Triton容器但这个复杂度就上去了。我的建议是老老实实在板子上构建不要想图省事。还有一种情况是模型输出正常但NMS之后的框数量非常少甚至一个都没有。这种多半不是部署问题而是模型本身在该场景下的置信度就低。可以先用原版PyTorch模型在PC上对同一张图片测试如果PyTorch也没检出那问题在模型训练数据上而不是部署流程上。6.3 我的几组调优经验跑通只是第一步真正能落到项目里还得看优化。我实践下来觉得性价比最高的几个优化手段分享给大家。第一把视觉管线用线程分开。推理引擎在GPU上运行但预处理和后处理其实可以放在CPU上并发执行。用生产者消费者模式采集线程负责读图预处理推理线程专注跑TensorRT后处理线程负责NMS和绘制结果。像素级的流水线能把帧率再提升20%到30%很多讲TensorRT部署的教程不会提这一点但真实项目中收益非常明显。第二合理使用共享显存。Jetson的GPU显存和CPU内存共享一份物理内存通过CUDA的zero-copy机制可以避免显存和内存之间的拷贝。对Nano这种小显存设备来说减少一次拷贝对帧率的提升比调模型更有效。不过zero-copy只适合小数据量数据量大了反而更慢需要测试权衡。第三模型轻量化优先于引擎优化。如果做完TensorRT优化后帧率还是不够最先应该考虑的是能不能用更小的模型。YOLOv5n比YOLOv5s小很多在Nano上甚至能达到接近实时的速度。很多人舍不得换模型总觉得精度会掉但实际部署中通过剪枝、蒸馏等操作小模型的精度损失可能只有两三个点速度收益却是成倍的。做一个够用的模型比做一个好看的模型更符合边缘计算的原则。最后再分享一个我踩过最深的坑——在Jetson上不要用最新的软件版本。这个平台的特殊性在于官方工具链之间的版本咬合非常紧一个组件升级了另一个组件不升就会出各种诡异问题。最好以JetPack官方镜像作为基准需要什么包就往里装不要反复升降级。踩过几次坑之后我现在拿到新设备的第一件事就是看JetPack版本然后根据它去锁定TensorRT、CUDA、Python包的具体版本组合。版本组合稳定了部署就成功一半了。这套流程从环境搭建到性能调优覆盖了YOLOv5在Jetson NX/Nano上TensorRT部署的完整闭环。照着走一遍你会发现边缘端目标检测没有想象中那么神秘——无非是把模型转换、引擎构建、推理代码这三步都做对然后剩下的就是耐心调优化。如果你也在部署中遇到了不一样的问题欢迎多交流踩过的坑越多下次部署就越快。