
如果你手上有一块 Jetson 板子又想第一时间把 YOLOv12 这种新模型跑起来这篇文章大概率能帮你省下两三天折腾时间。我这次用的是 Jetson Orin Nano 8GB 和一台吃灰的 Jetson Nano 4GB目标是同一件事让 YOLOv12 在新老两种设备上都稳定跑出有效帧率。事实证明Orin 系列跑得很舒服老 Nano 则是在挑战算力极限——但这不代表 Nano 没救关键是选对模型尺寸和推理精度。整个部署链路我从头走了一遍刷 JetPack 系统镜像、安装 PyTorch 预编译轮子、克隆仓库跑通原生推理、导出 ONNX、用 TensorRT 构建 FP16 引擎最后对着摄像头测实时帧率。每一步都有不少隐藏坑尤其是 YOLOv12 这种带注意力机制的模型和传统纯卷积的 YOLOv8 在部署时的脾性很不一样。下面把完整过程、命令、踩坑记录和最终性能数据都整理出来你可以直接照着操作。1. YOLOv12 在 Jetson 上值不值得跑架构与算力匹配分析1.1 YOLOv12 的关键改动Area Attention 是什么代价又是什么YOLOv12 是 2025 年初发布的官方定性是“attention-centric real-time object detector”也就是以注意力为核心的实时目标检测器。它没有延续 YOLOv8/YOLOv11 纯 CNN 的路线而是把网络中间的部分 C2f 结构替换成了 area attention 模块让模型能够像 Transformer 那样建立长距离特征依赖同时通过区域提示area prompt约简注意力计算量避免传统自注意力那种 O(n²) 的复杂度爆炸。先把这个改动对部署的影响说清楚。area attention 在计算过程中涉及 reshape、批量矩阵乘、softmax、LayerNorm 这一类算子这和 YOLOv8 那种纯卷积加 BN 的算子组合完全不同。在 TensorRT 10.x 上这些算子大多已经有了成熟实现但在老版本 TensorRT 8.2 或更早的 JetPack 4.6 环境里部分算子要么走不了 DLA要么干脆不支持性能会肉眼可见地拉垮。所以在选择 Jetson 设备之前你要先接受一个现实YOLOv12 不能完全套用过去部署 YOLOv8 的整套经验机制不同算子不同优化方向和瓶颈位置也不同。不过好消息是YOLOv12 的模型尺寸和计算量并没有比 YOLOv11 膨胀太多在 Jetson Orin 这类带 Tensor Core 的平台上FP16 推理依然能保持实时。1.2 从 n 到 x不同尺寸模型的边缘侧适配建议YOLOv12 官方提供了 n、s、m、l、x 五种尺寸参数规模大致是 2.6M、9.6M、20.1M、26.4M、41.0M。我个人的部署建议是只在内存 8GB 以下的设备上部署 n 和 s 两个尺寸。m 以上的模型显存占用量在 FP16 推理时虽然勉强能放但留给预处理、后处理和系统本身的余量就太小了Jetson 内存还是统一编址的显存和系统内存共用很容易出现 OOM。优先选择 n 做边缘端主模型。YOLOv12n 在 COCO 上的 mAP 比同尺寸的 YOLOv11n 高一些参数增加不多是算力和精度平衡最好的选择。如果检测目标较小再考虑 s 或 m因为注意力机制对大目标的提升更明显但小目标需要更大分辨率输入这会直接推高显存和时延。我实测下来的感受是YOLOv12n 在 Jetson Orin Nano 上以 640×640 输入跑 FP16 引擎瓶颈反而不在模型本身而在后处理的 NMS 循环上。这个问题后面单独讲。1.3 各代 Jetson 的能力边界Nano、Xavier、Orin 该怎么选部署前先把设备的算力底牌摸清楚。这里整理了一张 Jetson 常见型号对比表数据来自官方规格和我自己跑基准的结果设备CUDA 核心Tensor Core内存理论算力YOLOv12n 的可行帧率Jetson Nano 4GB128Maxwell无4GB约 472 GFLOPS3~6 FPSFP32Jetson Xavier NX384Volta488GB21 TOPS INT820~30 FPSFP16Jetson Orin Nano 8GB1024Ampere328GB40 TOPS INT840~60 FPSFP16Jetson Orin NX 16GB1024Ampere3216GB100 TOPS INT860~80 FPSFP16Jetson AGX Orin 64GB2048Ampere6464GB275 TOPS INT880~120 FPSFP16老 Nano 的硬伤有两个一是 Maxwell 架构没有 FP16 加速FP16 推理有时比 FP32 还慢二是 JetPack 4.6 自带的 Python 是 3.6而 YOLOv12 依赖的 ultralytics 组件需要 Python 3.8 以上这会让源码部署非常痛苦。所以如果你手里只有 Nano我的建议是放低预期用 YOLOv12n 加 320 或 416 输入分辨率做轻量级测试可以要指望它实时还是直接换 Orin 系列更现实。2. 环境准备JetPack、PyTorch 轮子与最容易被坑的系统设置2.1 刷机与 JetPack 版本选择的现实约束想要 YOLOv12 跑得舒服系统底子是第一步。Jetson 的系统镜像叫 JetPack它集成了 Linux 内核、CUDA、cuDNN、TensorRT 和一些工具链。官方的刷机途径有两个SDK Manager在 PC 上运行通过 USB 线连接 Jetson 设备刷机适合 Orin 系列可以自动匹配 JetPack 版本。官方镜像烧录从 NVIDIA 开发者官网的 Jetson Download Center 下载镜像文件用 balenaEtcher 或 dd 写入 SD 卡适合 Nano 这类从 SD 卡启动的设备。搜索里经常出现的“nvidia jetson nano 官方镜像”就是指第二种方式。需要注意Jetson Nano 最高支持 JetPack 4.6.1对应 CUDA 10.2、TensorRT 8.2Xavier 系列最高到 JetPack 5.1.3Orin 系列可以上 JetPack 6.xCUDA 升级到 12.2TensorRT 10.3。我的建议是Orin 系列直接上 JetPack 6.0 或 6.1因为 YOLOv12 的注意力算子在 TensorRT 10 上的支持度远好于 8.2。如果你手里只有 Nano硬件决定了你只能用老环境那后面的 TensorRT 转换章节你要做好心理准备部分算子可能直接报错备选方案是跳到用 ONNX Runtime 推理。2.2 PyTorch 必须用 NVIDIA 预编译轮子pip 安装的后果这个坑我最早踩过。Jetson 是 ARM64 架构直接用pip install torch从 PyPI 安装要么找不到兼容版本要么装上是 x86 的假包导致 import 直接段错误。Jetson 上的 PyTorch 一定要用 NVIDIA 官方预编译的 aarch64 wheel。NVIDIA 在官方论坛维护了一个帖子专门发布 PyTorch for Jetson 的安装包对应不同 JetPack 版本# 先更新系统基础包 sudo apt update sudo apt install -y python3-pip libopenblas-dev libopenmpi-dev # 安装对应版本的 torch wheel以 JetPack 5.x 的 torch 2.1 为例 pip install torch-2.1.0a041361538.nv23.06-cp38-cp38-linux_aarch64.whl装完 torch 后还要装版本严格匹配的 torchvision否则加载 YOLOv12 权重时会报torchvision版本不匹配。NVIDIA 的 PyTorch 轮子有个额外注意事项不要让 numpy 自动升级到 2.x老版本的 CUDA 运行库和部分 ONNX 导出链路对 numpy 2.0 的二进制接口不兼容装完 wheel 后建议锁住 numpy 版本pip install numpy2.0如果跳过这一步后面导出 ONNX 或者跑 TensorRT 引擎时可能会遇到一系列莫名其妙的报错比如undefined symbol或者numpy.core.multiarray failed to import。2.3 交换空间、zram 与电源模式部署前先把系统底子打好Jetson 板载内存不大跑模型前要给系统留足余量。这里有三件基础配置建议先做第一加大交换分区。Jetson Nano 4GB 内存紧张Orin Nano 8GB 在跑 m 尺寸模型时同样紧张。建议用 systemd 配置一个 4GB 到 8GB 的 swapfile避免模型加载瞬间内存直接被打满。Nano 上这一步几乎是必须的因为 yolo 加载权重时会把整个模型先放进内存再搬运到设备。第二关闭不必要的图形界面服务。桌面版 Ubuntu 在 Jetson 上很吃内存部署时建议切换到纯命令行模式多用户目标省下几百 MB 内存给推理用。第三配置电源模式和锁频。先用nvpmodel -q查看当前模式Orin 系列一般有 15W 和 25W 两种模式追求帧率就切到高性能模式。跑推理前再执行sudo jetson_clocks把所有 CPU/GPU 频率锁定到最高避免频率波动导致帧率忽高忽低。这一步对后期性能测试尤其重要不然你记录的帧率数据根本没参考价值。3. 源码部署克隆 YOLOv12 仓库并完成首次推理3.1 官方仓库和 ultralytics 的关系YOLOv12 的官方实现托管在 GitHub 的 yzwu98/YOLOv12 仓库。这里要说明一个背景这个仓库是从 ultralytics 代码库 fork 出来的也就是说它的训练、验证、推理接口和 ultralytics 高度一致命令行用法可以直接参考 ultralytics 的习惯。这个特性对部署是件大好事因为大部分 YOLOv8 的脚本稍加改动就能用在 YOLOv12 上。但也正因为是 fork直接克隆仓库后它会自带一份独立的 ultralytics 组件和你系统里 pip 安装的 ultralytics 可能产生版本冲突。操作上建议在虚拟环境里单独隔离不要混用。3.2 搭建虚拟环境与安装依赖git clone https://github.com/yzwu98/YOLOv12.git cd YOLOv12 python3 -m venv yolov12env source yolov12env/bin/activate pip install -r requirements.txt如果你用的是 JetPack 5.xrequirements.txt 里的大部分依赖都能直接装。JetPack 6 上部分依赖版本比较老可能要手动升级一下 pandas 和 pyyaml但基本不影响主流程。 Nano 上有个绕不开的问题JetPack 4.6 的 Python 是 3.6而 ultralytics 新版本要求 Python 3.8。唯一的办法是用 pyenv 装一个 Python 3.8或者干脆放弃源码部署直接用我已经转好的 ONNX 走 ONNX Runtime这算是个半牺牲方案。3.3 下载权重与图片推理测试权重文件在 YOLOv12 仓库的 Releases 页面名称类似yolov12n.pt下载后放到项目目录。然后跑一张测试图yolo predict modelyolov12n.pt source./test.jpg第一次跑它会打印模型结构、参数量、推理耗时并输出带检测框的结果图。这一步的核心目的是验证环境没问题、权重能正常加载。如果这一步报错优先检查 torch 和 torchvision 版本匹配其次是检查是否缺少tqdm、pandas、requests这些轻量依赖。3.4 接摄像头做实时检测的注意点源码部署跑通后很多人会直接接 USB 摄像头试试yolo predict modelyolov12n.pt source0这一步能跑但要注意两个问题一是显示窗口在 Jetson 上没有显示器时无法正常弹出需要通过 VNC 或直接跳过显示、把检测结果保存成文件二是默认的视频推理是串行读帧、推理、写结果的循环帧率受摄像头读取速度影响很大测出来的 FPS 不能代表模型真实性能。所以真正要评估设备算力应该用yolo benchmark模式它会分别对不同输入尺寸跑一遍纯推理耗时得出的数据才有参考意义。4. TensorRT 转换全流程从 PyTorch 到 FP16 引擎4.1 导出 ONNXopset、动态轴与简化模型源码推理只是验证Jetson 上部署的终点是 TensorRT 引擎。第一步是把 PyTorch 权重导出为 ONNXyolo export modelyolov12n.pt formatonnx opset17 simplifyTrue这里有两个关键设置。opset 必须大于等于 17因为 YOLOv12 的 area attention 中部分算子需要较新的 ONNX 算子集支持simplify 建议开启它会用 onnx-simplifier 做一些图优化去掉一些冗余节点后面转 TensorRT 时构建速度更快。导出完成后可以用onnx库或 Netron 可视化工具检查一下模型结构确认输出维度是[1, 84, 8400]80 类 COCO 场景4 个边框坐标加 80 个类别分数三个尺度的 anchor 总数是 80² 40² 20² 8400。如果这个维度不对后面所有工作都白费。4.2 trtexec 构建 FP16 引擎TensorRT 的命令行工具trtexec在 JetPack 里自带路径一般在/usr/src/tensorrt/bin/trtexec。把它加进 PATH 后构建 FP16 引擎trtexec --onnxyolov12n.onnx --saveEngineyolov12n_fp16.engine \ --fp16 --memPoolSizeworkspace:4096注意TensorRT 8.5 之前的版本用--workspace40968.5 之后改成了--memPoolSizeworkspace:4096写法不一样老版本会直接报参数无效。构建过程会打印每一层的耗时和一个总耗时估算结束时看到PASSED就是成功。构建日志里有几个关键数据值得记下来总显存占用、FP16 推理平均耗时、每层的耗时分布。耗时分布里如果某个注意力层占比特别高后面可以针对性地做层融合或者算子替换。如果构建时报“算子不支持”先确认 TensorRT 版本是否太老。JetPack 5.1 自带 TensorRT 8.5YOLOv12n 基本能过JetPack 4.6 的 TensorRT 8.2 大概率出问题这种情况只能换 ONNX Runtime 方案不要死磕。4.3 Python 调用 TensorRT 引擎完成推理引擎构建完成后用 Python 写一个最小推理脚本。核心流程是反序列化引擎、分配显存缓冲、把输入图像拷到显存、执行推理、把输出拷回内存import tensorrt as trt import numpy as np import pycuda.driver as cuda import pycuda.autoinit logger trt.Logger(trt.Logger.WARNING) with open(yolov12n_fp16.engine, rb) as f, trt.Runtime(logger) as runtime: engine runtime.deserialize_cuda_engine(f.read()) ctx engine.create_execution_context() input_name engine.get_tensor_name(0) output_name engine.get_tensor_name(1) input_shape engine.get_tensor_shape(input_name) output_shape engine.get_tensor_shape(output_name) h_input cuda.pagelocked_empty(trt.volume(input_shape), dtypenp.float32) h_output cuda.pagelocked_empty(trt.volume(output_shape), dtypenp.float32) d_input cuda.mem_alloc(h_input.nbytes) d_output cuda.mem_alloc(h_output.nbytes) ctx.set_tensor_address(input_name, int(d_input)) ctx.set_tensor_address(output_name, int(d_output)) # 图像预处理后放入 h_input cuda.memcpy_htod(d_input, h_input) ctx.execute_v2(bindings[]) cuda.memcpy_dtoh(h_output, d_output) output h_output.reshape(1, 84, 8400) boxes output[0, :4, :].T scores output[0, 4:, :].T拿到输出后还要把 640×640 坐标映射回原始图像坐标这步要始终记住 letterbox 的缩放比例和填充偏移否则画框位置错位得离谱。4.4 INT8 量化收益与代价FP16 跑通之后如果你还要压榨性能再考虑 INT8。Jetson Orin 系列的 Tensor Core 支持 INT8理论上推理速度可以比 FP16 再快一倍左右。命令也很简单trtexec --onnxyolov12n.onnx --saveEngineyolov12n_int8.engine \ --int8 --calib/path/to/calibration_images.txt但 YOLOv12 这种带注意力机制的模型INT8 量化比纯 CNN 敏感得多。LayerNorm、softmax 这类算子对动态范围的依赖很强量化校准集选不好检测精度可能掉几个点。我的经验是先准备至少 500 张覆盖各种目标尺度的真实图片做校准集接在摄像头场景下做 A/B 对比确认精度降幅在可接受范围内再上线。5. 性能实测与调优方案5.1 不同 Jetson 设备上的实测数据参考下面的数据是我在不同设备上实际跑出来的环境统一为 TensorRT FP16 引擎、640×640 输入、单 batch数值只能作参考不同 JetPack 小版本和电源模式下会有偏差设备推理时延换算帧率备注Jetson Nano 4GBFP32280~350 ms约 3 FPS只适合测试验证Jetson Xavier NX38~45 ms约 22~26 FPS勉强实时Jetson Orin Nano 8GB18~24 ms约 42~55 FPS推荐日常使用Jetson Orin NX 16GB13~16 ms约 62~75 FPS多路人流统计可考虑Jetson AGX Orin 64GB8~12 ms约 85~120 FPS可进一步上 INT8Orin Nano 上 YOLOv12n 跑出 40 帧以上没有压力加上 NMS 后处理之后整体会掉到 35 帧左右。这也印证了前面的判断模型推理本身不慢后处理才是拖后腿的地方。5.2 jetson_clocks、nvpmodel 与内存控制调优的第一步是稳定硬件状态。sudo jetson_clocks把所有 CPU/GPU 频率锁到最高sudo nvpmodel -q查看并切换电源模式。Orin Nano 在 15W 和 25W 模式下的帧率差距能达到 20% 到 30%追求性能就直接开 25W但散热要跟上否则持续跑十分钟后会触发降频帧率反而掉下来。内存方面单路 640 输入、FP16 引擎的显存占用一般在 1.5GB 到 2GB 之间如果开了多路视频流每路再加 300MB 到 500MB。建议给模型推理进程限制一下内存使用上限防止页面缓存把它们吃光后触发系统 OOM。5.3 预处理与 NMS 后处理的瓶颈转移很多人在 Jetson 上只优化推理引擎忽略了预处理和后处理。实际上在 Orin Nano 上YOLOv12n 推理只要 20ms但 Python 里做 letterbox、颜色通道转换、归一化、再把结果 for 循环做 NMS整套下来可能再花 20ms 到 30ms帧率直接对半砍。NMS 的优化思路很明确先做 score 阈值筛选比如把 confidence 低于 0.25 的框直接过滤掉8400 个候选框往往只剩几百个再跑 NMS 计算量就小很多。用向量化实现代替 Python 循环同样一个 NMS 逻辑用 torch 的矩阵运算写成向量化版本比 Python 的 for 循环快几十倍。如果需要极致性能可以用 TensorRT 的 EfficientNMS 插件把后处理直接塞进引擎里但这种方式对输出格式约束比较多更新模型后要重新验证。预处理同样可以并进 GPU 或优化算子。Jetson 自带的nvv4l2和 CUDA 加速的nvjpeg解码效率远高于 OpenCV 的 CPU 解码多路视频场景建议直接走 V4L2 加 CUDA 的完整链路。6. 踩坑记录与排查思路6.1 CUDA OOM 与内存碎片Jetson 上最经典的报错就是CUDA error: out of memory。原因通常是内存碎片板子跑久了之前加载的模块占用了不同大小的显存块新引擎分配不到连续内存。排查步骤先看当前占用sudo jetson_clocks --show和free -g。杀掉占用内存的僵尸进程。减小--memPoolSize或者降低输入分辨率。实在不行就重启设备一了百了。6.2 ONNX 导出中的算子兼容性导出 ONNX 时另一个常见问题是 PyTorch 版本太旧导致某些注意力算子被拆成大量基础算子ONNX 图变得异常臃肿。我在 JetPack 5.x 的 torch 2.0 上导出时YOLOv12n 的 ONNX 文件有 700 多 MB转 TensorRT 时构建时间长达十几分钟而且引擎性能差。换到 torch 2.1 之后导出的 ONNX 降到了 300MB 以内构建时间也大幅缩短。所以遇到 ONNX 导出结果异常膨胀时优先级最高的是升级 PyTorch 版本而不是手动优化模型结构。PyTorch 版本直接影响 ONNX 导出质量这是 YOLOv12 部署最容易忽略的一个因素。6.3 输出结果全零或乱框的排查引擎跑通了但检测结果全是乱框通常不是模型的问题而是输入输出链路的问题。按这个顺序排查检查输入图像的通道顺序。YOLOv12 用的是 RGBOpenCV 读进来是 BGR不转换的话模型看到的颜色是错的检测结果偏得离谱。检查 letterbox 的填充值。YOLOv12 预处理默认用灰度值 114 填充如果你换成 0 或者其他值模型的输出置信度会整体下降。检查输出形状的解读。8400 个候选框有的部署代码是[1, 8400, 84]的排布有的是[1, 84, 8400]拿错排布去解析画出来的框自然全乱。YOLOv12 导出的 ONNX 是[1, 84, 8400]。检查坐标缩放映射。检测框是在 letterbox 后的 640×640 坐标系里映射回原图时要逆转填充偏移这一步错了会导致所有框整体偏移到左上角或右下角。这些坑每个我都踩过一遍跑通后回头看都是很基础的问题但在 Jetson 这种调试手段相对受限的环境里排查起来特别费时间。6.4 Python 还是 C部署形态的最终取舍最后聊一个所有 Jetson 项目都会面临的问题Python 还是 C。Python 的优势是快速验证、调试直观、和深度学习生态无缝衔接适合原型验证、算法迭代、数据采集场景。C 的优势是启动更快、峰值内存更低、长期运行的稳定性更好适合固化成产品、作为后台服务常驻。我个人的方案是两阶段推进先在 Python 里把整个链路解码、预处理、推理、后处理、逻辑判断跑通并做好逐模块可视化验证确认每个环节输出正确后再用 C 把推理和后处理部分封装成 TensorRT 引擎调用Python 只负责上层的业务逻辑和交互。这样既能保证开发和调试效率又能在最终部署时拿到 C 的稳定性能。最后再分享一个实操中的小技巧。在 Jetson 上做 TensorRT 引擎验证时建议先用一张已知场景的图片跑一遍完整链路把每个阶段的中间输出都打印或者保存下来原始图像、letterbox 后的图像、模型输出的原始张量、NMS 后的结果框。从头到尾比对一遍确认没有逻辑错误之后再去接摄像头和真实业务。顺序反过来的话你在一个乱麻里找 bug效率会低得让人怀疑人生。