1. 为什么值得做一次系统复盘
Jetson边缘嵌入式实战课程走到第十讲,回头把前九讲的内容串一遍,这件事本身就比再学一个新模型更有价值。我见过太多人学Jetson的方式是“东一榔头西一棒槌”——今天跟着教程刷个系统,明天抄个YOLOv5的部署脚本,后天看到Qwen火了又去折腾大模型,结果板子买了两三块,SD卡烧了七八次,真到要自己从零搭一个边缘推理项目的时候,脑子里还是一团浆糊。问题不在于学得少,而在于没有把知识点连成线。
这篇总结面向三类人:第一类是刚拿到Jetson Nano或者Orin系列板子、还没找到学习节奏的新手;第二类是已经跟着零散教程跑过几个demo、但缺乏体系认知的进阶者;第三类是准备把Jetson方案落地到实际产品里、需要重新梳理技术栈的工程师。不管你在哪个阶段,把前九讲的核心脉络理清楚,都能帮你省下大量重复踩坑的时间。
前九讲大致覆盖了从硬件认知、系统烧录、环境配置,到视觉模型部署、大模型推理、SLAM建图这几条主线。每一讲单独看是一个独立任务,合在一起其实是一条完整的“边缘AI项目落地链路”。我个人的体会是,Jetson这个平台最大的特点不是算力有多强,而是它的软硬件生态足够完整,从驱动层到应用层都有官方和社区的支持,但前提是你得知道每一层在干什么、边界在哪里。下面我就按这条链路,把前九讲的内容拆开揉碎,该补的细节补上,该提醒的坑一个不落。
2. 前九讲知识地图:从裸板到能跑项目的完整链路
2.1 硬件选型与系统烧录:一切从“点亮板子”开始
第一讲和第二讲基本都在解决“让板子活过来”这件事。Jetson系列目前主流的有Nano、Orin Nano、Orin NX、AGX Orin这几档,算力从0.5 TFLOPS到275 TFLOPS跨度极大,选型的时候不能只看价格。我自己的经验是,如果你只是跑轻量级分类或者小分辨率检测,Nano 4GB其实够用,但一旦涉及多路视频解码或者大模型推理,至少得上Orin Nano 8GB,预算允许直接Orin NX 16GB会更从容。
系统烧录这块,官方推荐用SDK Manager通过Ubuntu主机刷机,但很多人卡在“主机版本不匹配”或者“网络下载中断”上。实测下来,用SD卡方式给Nano刷机最省事,而Orin系列因为eMMC和NVMe的启动配置不同,必须走SDK Manager或者手动配置flash脚本。这里有个细节:Orin Nano的官方开发套件默认从SD卡启动,但如果你装了NVMe固态,需要在UEFI里调整启动顺序,否则系统还是从SD卡跑,性能差距非常明显。
注意:刷机前一定要确认电源适配器功率足够。Nano建议5V 4A,Orin系列建议19V 4.74A以上。供电不足会导致刷机中途掉线,甚至损坏存储。
第三讲通常涉及JetPack版本选择。JetPack 5.x对应Ubuntu 20.04,JetPack 6.x对应Ubuntu 22.04,后者对Orin系列支持更好,但部分老教程的依赖包在6.x上编译会报错。我的建议是:新项目直接上JetPack 6.x,老项目如果依赖特定版本的TensorRT或者CUDA,就老老实实留在5.x。版本这东西,不是越新越好,而是越匹配越好。
2.2 环境配置与依赖管理:别让“环境问题”吃掉一半时间
第四讲和第五讲的核心是环境搭建。Jetson上的环境配置和普通x86服务器差别很大,最大的坑在于架构是aarch64,很多pip包没有预编译的wheel,需要从源码编译。比如OpenCV,如果用pip install opencv-python,装上的版本可能不带CUDA加速,跑图像处理的时候CPU占用率直接拉满。正确做法是用官方脚本或者手动编译带CUDA支持的OpenCV,虽然编译一次要一两个小时,但后面省心。
Python环境管理我强烈建议用conda或者venv做隔离,不要往系统Python里直接装包。Jetson的系统Python承担了很多底层功能,一旦装崩了,重刷系统的成本远高于重新建一个虚拟环境。另外,pip源建议换成国内镜像,下载速度能快十倍不止,但要注意有些镜像同步不及时,特定版本的包可能找不到。
CUDA和cuDNN的配置在JetPack里其实是预装好的,但环境变量需要手动加到.bashrc里。很多人跑TensorRT的时候报“找不到libcudnn”,就是因为LD_LIBRARY_PATH没设对。这个问题的排查方法很简单:用ldconfig -p | grep cudnn看一下库有没有被识别,如果没有,就把/usr/lib/aarch64-linux-gnu加到路径里。
2.3 视觉模型部署:YOLOv5为什么成了“必修课”
第六讲和第七讲基本围绕YOLOv5展开。YOLOv5在Jetson上的部署之所以成为经典案例,是因为它覆盖了边缘视觉项目的完整流程:数据准备、模型训练、ONNX导出、TensorRT加速、推理脚本编写。你把这套流程跑通一遍,换成YOLOv8或者别的检测模型,思路是一样的。
TensorRT加速是Jetson部署的核心技能。YOLOv5的官方仓库里有个export.py脚本,可以直接导出TensorRT引擎,但默认参数下生成的引擎可能不是最优的。比如batch size设成1还是8,FP16还是INT8,对推理速度和精度影响很大。我实测过,YOLOv5s在Orin Nano上跑FP16,1080p输入大概能到30FPS左右,换成INT8能到45FPS,但精度会掉两三个点。具体怎么选,取决于你的应用场景能容忍多大的精度损失。
提示:INT8量化需要校准数据集,不能随便拿几张图就做。校准集要覆盖实际场景的各种光照、角度、遮挡情况,否则量化后的模型在边缘case上会崩得很惨。
另外一个容易被忽略的点是视频解码。Jetson的硬件解码器支持H.264和H.265,用GStreamer管道可以做到零拷贝,CPU占用率极低。但如果你用OpenCV的VideoCapture直接读RTSP流,走的是CPU软解,1080p视频就能把CPU吃满。正确做法是用nvdec或者GStreamer的appsink把解码后的帧直接送到推理管道里。
2.4 大模型与SLAM:边缘端的“高阶玩法”
第八讲和第九讲开始进入进阶内容。大模型部署这块,热词里提到的Qwen、Ollama都是最近很火的方向。在Jetson Orin上跑Qwen 1.8B或者7B的量化版本是可行的,但需要用到llama.cpp或者TensorRT-LLM做推理加速。Ollama在x86上很方便,但在Jetson上的支持还不完善,需要自己编译。我的建议是,如果只是做demo,用llama.cpp的GGUF量化模型最省事;如果要上生产,TensorRT-LLM的性能更好,但编译和转换流程复杂得多。
SLAM部分,AirSLAM在Jetson上的部署是一个典型代表。SLAM对算力和内存的要求都很高,Nano基本跑不动实时的视觉SLAM,Orin NX以上才比较从容。部署SLAM的难点在于依赖库多、编译时间长,而且对相机标定参数很敏感。标定没做好,建出来的图直接是歪的。这块我踩过的坑是:不要用USB相机的默认参数,一定要自己用棋盘格标定一遍,把内参和畸变系数写进配置文件。
3. 核心技能拆解:每个环节的关键参数与实操细节
3.1 算力与功耗的平衡:Jetson的“性能开关”怎么调
Jetson系列都有一个nvpmodel工具,用来切换功耗模式。Nano有5W和10W两档,Orin系列有15W、25W、MAXN等多档。很多人不知道这个工具,板子买回来默认跑在低功耗模式,然后抱怨“Jetson性能不行”。实际上,Orin NX在MAXN模式下算力能翻一倍,但发热也明显增加,需要配合散热风扇或者散热片。
切换模式的命令很简单:
sudo nvpmodel -m 0 # 0通常对应MAXN模式 sudo jetson_clocks # 锁定最高频率但要注意,jetson_clocks会把CPU和GPU频率锁在最高,功耗和温度都会上升。如果是电池供电的场景,就不适合这么干。我一般会在调试阶段用MAXN加jetson_clocks,确认性能上限,然后在实际部署时根据散热条件选择合适的模式。
内存方面,Jetson是统一内存架构,CPU和GPU共享内存。这意味着你给GPU分配的内存多了,系统可用的就少了。跑大模型的时候尤其明显,Qwen 7B的INT4量化版本大概需要4GB左右显存,Orin Nano 8GB跑起来刚刚好,但同时跑其他服务就会OOM。监控内存用tegrastats,能看到CPU、GPU、内存、功耗的实时数据。
3.2 模型转换与量化:从PyTorch到TensorRT的完整路径
模型部署的核心流程是:PyTorch训练 → ONNX导出 → TensorRT引擎生成 → 推理脚本调用。每一步都有坑。
ONNX导出的时候,opset版本很关键。YOLOv5建议用opset 11或12,太新的版本TensorRT可能不支持。导出命令大概是这样:
python export.py --weights yolov5s.pt --include onnx --opset 12 --dynamic--dynamic参数表示支持动态batch和动态输入尺寸,但动态shape会让TensorRT的优化空间变小,推理速度可能不如固定shape。如果实际场景输入尺寸固定,就不要加--dynamic。
TensorRT引擎生成用trtexec工具:
trtexec --onnx=yolov5s.onnx --saveEngine=yolov5s_fp16.engine --fp16 --workspace=4096--workspace是显存工作空间,单位MB。设得太小会导致某些层无法用最优算法,设得太大又浪费显存。4096是个比较稳妥的值。FP16精度损失很小,速度提升明显,是首选方案。INT8需要额外提供校准缓存文件,流程更复杂。
注意:TensorRT引擎是和硬件绑定的,在Orin NX上生成的引擎不能直接拿到AGX Orin上用,甚至同一型号不同JetPack版本之间也不通用。部署的时候要在目标设备上重新生成,或者用TensorRT的版本兼容工具做转换。
3.3 推理管道的搭建:从单张图片到多路视频流
单张图片推理很简单,但实际项目往往是多路视频流实时处理。这时候管道设计就很重要了。一个典型的Jetson视觉推理管道包括:视频解码 → 预处理 → 推理 → 后处理 → 结果输出。每个环节都可以用不同的工具实现。
解码用GStreamer的nvdec插件,预处理用CUDA核函数或者OpenCV的CUDA模块,推理用TensorRT,后处理用CPU或者CUDA。关键是要尽量减少内存拷贝,最好做到零拷贝。DeepStream是NVIDIA官方的一套完整框架,把这些环节都封装好了,但学习曲线比较陡。如果项目周期紧,直接用DeepStream能省很多事;如果想深入理解底层,就自己用GStreamer加TensorRT搭。
多路视频的时候,GPU算力是瓶颈。Orin NX 16GB大概能同时处理4到6路1080p的YOLOv5s推理,具体取决于帧率和模型大小。超过这个数,要么降分辨率,要么降帧率,要么换更小的模型。
3.4 大模型推理的显存优化:量化与KV Cache管理
在Jetson上跑大模型,显存是最大的约束。Qwen 1.8B的FP16版本需要大概3.6GB显存,INT8量化后降到1.8GB左右,INT4再降到1GB以内。量化方法有GPTQ、AWQ、GGUF等,llama.cpp用的是GGUF格式,转换起来最方便。
KV Cache是大模型推理时的一个隐形显存杀手。生成长文本的时候,KV Cache会随着序列长度线性增长。在Jetson这种显存有限的设备上,需要限制最大序列长度,或者用PagedAttention之类的技术做显存管理。TensorRT-LLM在这方面做得比较好,但配置复杂。llama.cpp可以通过--ctx-size参数控制上下文长度,设成2048或者4096,不要设太大。
推理速度方面,Orin NX跑Qwen 1.8B INT4,大概能到10到15 tokens每秒,基本可用。7B模型就明显慢了,大概3到5 tokens每秒,适合对实时性要求不高的场景。
4. 实操复盘:一个完整边缘项目的落地过程
4.1 项目需求与方案设计
假设我们要做一个“工地安全帽检测”的边缘项目,需求是:在工地入口部署一台Jetson设备,实时检测进入人员是否佩戴安全帽,未佩戴则触发告警并保存截图。这个需求看起来简单,但涉及视频解码、目标检测、逻辑判断、告警触发、数据存储多个环节。
方案设计上,硬件选Orin Nano 8GB,因为只需要处理一路视频流,算力足够。模型用YOLOv5s,训练数据用公开的安全帽数据集加上自己标注的补充数据。推理框架用TensorRT FP16,目标帧率15FPS以上。告警逻辑用Python写,检测到未佩戴安全帽的框,就保存当前帧并发送HTTP请求到告警服务。
4.2 数据准备与模型训练
数据这块,公开数据集大概有几千张标注好的安全帽图片,但实际工地场景的光照、角度、遮挡情况差异很大,直接拿公开数据训练,在实际场景里召回率会很低。我的做法是:先用公开数据预训练一个基础模型,然后在目标工地采集几百张实际场景图片,人工标注后做fine-tune。这样模型对实际场景的适应性好很多。
训练在x86服务器上做,用YOLOv5的官方仓库,batch size设16,训练100个epoch左右。数据增强开了Mosaic和MixUp,但实际部署时发现Mosaic增强会让模型对小目标检测变差,后来关掉了。训练完的模型在验证集上mAP大概0.85左右,实际场景测试召回率0.9,误报率0.05,基本满足需求。
4.3 模型转换与部署
训练好的.pt模型导出ONNX,再用trtexec生成TensorRT引擎。导出的时候注意输入尺寸要和实际视频流的分辨率匹配,我们用的是640x640,视频流是1080p,预处理的时候做resize和letterbox。
推理脚本用Python写,视频解码用GStreamer管道:
gst-launch-1.0 rtspsrc location=rtsp://... ! rtph264depay ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw,format=BGRx ! appsink这样解码后的帧直接在GPU内存里,Python端通过appsink拿到numpy数组,省去了CPU和GPU之间的拷贝。实测下来,单路1080p解码加推理,CPU占用率不到30%,GPU占用率60%左右,帧率稳定在20FPS。
4.4 告警逻辑与系统集成
告警逻辑很简单:遍历检测结果,如果发现类别是“未佩戴安全帽”且置信度大于0.5,就保存当前帧到本地,同时发一个HTTP POST请求到告警服务。保存图片的时候要注意磁盘空间,工地环境可能几个月没人清理,写个定时任务每天清理超过7天的图片。
系统集成方面,用systemd把推理脚本做成服务,开机自启,崩溃自动重启。日志用Python的logging模块写到文件,配合logrotate做日志轮转。这些运维细节看起来不起眼,但实际部署的时候能省很多麻烦。
5. 常见问题与排查技巧实录
5.1 系统与环境类问题
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 板子无法启动,电源灯亮但无显示 | 供电不足或SD卡损坏 | 换电源适配器,重新烧录SD卡 | 用官方推荐电源,SD卡用高速卡 |
| pip安装包报错“no matching distribution” | aarch64架构无预编译wheel | 查看包是否支持aarch64 | 从源码编译或找社区预编译版本 |
| TensorRT报“找不到libcudnn” | 环境变量未设置 | ldconfig -p | grep cudnn | 添加/usr/lib/aarch64-linux-gnu到LD_LIBRARY_PATH |
| 系统运行一段时间后卡死 | 散热不足导致降频或死机 | tegrastats查看温度 | 加装散热风扇,清理灰尘 |
5.2 模型部署类问题
YOLOv5部署最常见的报错是“ONNX导出失败”或者“TensorRT解析ONNX失败”。前者通常是opset版本不匹配,后者可能是ONNX里包含了TensorRT不支持的算子。排查方法是用Netron打开ONNX文件,看看有没有奇怪的算子。如果有,就在导出的时候简化模型结构,或者用ONNX Simplifier工具做一遍优化。
推理速度不达预期,先检查是不是跑在低功耗模式,再检查TensorRT引擎是不是FP16或者INT8。如果都正常,就看预处理和后处理是不是在CPU上跑,这部分有时候比推理本身还耗时。把预处理用CUDA实现,后处理用NMS的CUDA版本,整体速度能提升30%以上。
5.3 大模型与SLAM类问题
大模型推理OOM,先看模型量化等级,INT4比FP16省一半以上显存。再看KV Cache的上下文长度,设成2048试试。如果还不够,就换更小的模型,Qwen 1.8B不行就换0.5B。
SLAM建图漂移,九成是相机标定问题。用Kalibr或者ROS的camera_calibration工具重新标定,确保重投影误差小于0.5像素。另外,SLAM对时间同步要求很高,如果用的是多传感器融合,要确保IMU和相机的时间戳对齐。
提示:Jetson上跑SLAM,建议用ROS2而不是ROS1,ROS2的实时性和资源管理更好,而且对aarch64的支持更完善。
6. 从课程到项目:下一步可以怎么走
前九讲的内容覆盖了Jetson开发的主要技术点,但真正要把这些技能转化成项目能力,还需要做几件事。第一是找一个完整的项目从头到尾做一遍,不要只跑demo。第二是学会看官方文档和源码,Jetson的很多问题在NVIDIA的开发者论坛上都有答案,关键是能不能找到。第三是建立自己的代码库和配置库,把常用的推理脚本、GStreamer管道、TensorRT转换命令整理成模板,下次用的时候直接改参数就行。
我个人的习惯是每学一个新东西,就写一篇自己的笔记,记录踩过的坑和解决方案。这些笔记积累下来,就是自己的知识体系。Jetson这个平台更新很快,JetPack版本一年一个大版本,模型和工具链也在不断进化,但底层的逻辑是不变的:理解硬件特性,选对软件栈,做好性能优化,剩下的就是工程问题了。
最后分享一个小技巧:Jetson的社区非常活跃,遇到问题先搜NVIDIA Developer Forum和GitHub Issues,大概率有人已经踩过同样的坑。如果找不到,就把错误日志完整贴出来提问,不要只写“跑不起来”,信息越详细,得到有效回复的概率越高。