8GB 小钢炮跑大模型!MLC-LLM 让 Jetson Orin Nano Super 飙到 60 tok/s(真机实测)
一句话先说结论:8GB 的 Jetson Orin Nano Super,用 MLC-LLM 跑 Qwen2.5-1.5B 实测 60 tok/s,跑 3B 也有 33 tok/s,首 token 延迟不到 0.2 秒,峰值内存 4.44GB / 5.02GB,全程不 OOM。这篇把从踩坑到跑通的全过程写出来,你照着做也能复现。
一、先说背景:为啥折腾这么个东西
咱手里有块 Jetson Orin Nano Super 8GB,就那种巴掌大的边缘 AI 小板子。8GB 统一内存,CPU 和 GPU 共享,sm_87 架构,1024 个 CUDA 核。
之前一直在上面折腾部署大模型,走的是 TensorRT-Edge-LLM 路线。0.5B 模型倒是跑通了,实测 21.9-30.5 tok/s,TTFT 1.9 秒,峰值内存 4.23GB。但想上 1.5B 的时候,五次 OOM,五次——构建期峰值内存直接撑爆 8GB,1.5B 那张 445MB 的 embedding 表就是压死骆驼的最后一根稻草。
后来调研了一圈,发现 MLC-LLM 这条编译器路线恰好能绕开这个坑:编译在 PC 上做(或者容器里 JIT),构建期内存压力根本不出现在 Jetson 上。加上 q4f16_1 量化把权重从 3GB 压到 840MB,8GB 跑 1.5B 甚至 3B 都有戏。
那就干。这篇博客记录的是真机实测全过程,不是纸上谈兵。
二、实验环境一览
先交代下家底:
| 项目 | 配置 | 备注 |
|---|---|---|
| 设备 | Jetson Orin Nano Super 8GB | NVIDIA 边缘 AI 设备 |
| SoC | Orin(sm_87,Ampere) | 1024 CUDA 核,128-bit LPDDR5 |
| 内存 | 8GB 统一内存 | CPU+GPU 共享,系统占用后可用 7.6GB |
| 存储 | 937GB NVMe SSD | 存模型绰绰有余 |
| 功耗模式 | MAXN_SUPER(25W) | 拉满性能模式 |
| JetPack | 6.2(R36.5.0) | CUDA 12.6.x |
| 容器 | dustynv/mlc:0.20.0-r36.4.0 | 6.9GB,内置 MLC-LLM v0.20.0 全家桶 |
| 量化 | q4f16_1 | int4 权重 + fp16 激活 |
模型选了两个:
- Qwen2.5-1.5B-Instruct:1.54B 参数,权重 840MB(30 个 shard)
- Qwen2.5-3B-Instruct:3.09B 参数,权重 1.9GB(62 个 shard)
两个都是 32K 上下文窗口,q4f16_1 量化格式——HuggingFace 上 mlc-ai 官方组织有预转换好的,直接下就能用。
三、原理速通:为啥 MLC 行而 TRT 不行
不懂原理直接照抄容易翻车,花三分钟讲清楚。
TRT-Edge-LLM 的问题:引擎必须在 Jetson 上构建,构建期峰值内存 = 权重 × 2.5~3 + builder。1.5B 的 embedding 层(445MB)在 TRT 下还不能量化,直接 OOM。
MLC-LLM 的解法:它是编译器路线——不是在运行时解释执行 ONNX,而是用 TVM 把模型编译成 Jetson 专属的 CUDA 库(.so)。编译可以在 PC 上做(交叉编译),也可以在容器里 JIT 编译。关键是:构建内存压力不出现在你的 Jetson 上。
再加上 q4f16_1 量化:权重压成 int4(每 4 bit 存一个权重 + 每组一个 fp16 scale),激活保持 fp16。1.5B 权重从 3GB 压到 840MB,省了 70%。
| 路线 | 本质 | 8GB 的痛点 |
|---|---|---|
| TRT-Edge-LLM | 运行时解释执行 plugin ONNX | 必须在 Jetson 上构建,1.5B 直接 OOM |
| MLC-LLM | 编译器把模型变成专属 CUDA 程序 | 编译在 PC/容器完成,8GB 只承担运行期 |
一句话:MLC 把"构建"和"运行"解耦了,8GB 只管跑,不管编译。
四、实操开始:从零到跑通
4.1 环境检查
先把基础环境确认一遍:
# 一键检查
./jetson-run.sh check
输出长这样就 OK:
R36.5.0 JP6.2 ✅
716GB 磁盘 ✅
Docker + nvidia-runtime ✅
MAXN_SUPER ✅
然后挂个 swap 防止 JIT 编译时 OOM(这步很重要,别跳):
./jetson-run.sh swap-on
# 结果:8G swap 已挂载 ✅
4.2 拉容器
dustynv 是 NVIDIA Jetson 生态的知名维护者,他维护的 MLC 容器跟 JetPack 版本严格对应,拿来就能用:
sudo docker pull dustynv/mlc:0.20.0-r36.4.0
# 6.9GB,拉一次就行
这个镜像里东西很全:CUDA 12.6、cuDNN、CUTLASS、FlashAttention-2、PyTorch 2.8、flashinfer、完整的 MLC-LLM v0.20.0 环境。不用自己从源码编译,省好几个小时。
4.3 下载权重(第一个坑来了)
这里我踩了第一个坑。容器里直接 git clone huggingface.co,exit 128,连不上——国内网络限制嘛。
解决方案很简单,宿主机走镜像站下:
export HF_ENDPOINT=https://hf-mirror.com
hf download mlc-ai/Qwen2.5-1.5B-Instruct-q4f16_1-MLC \
--local-dir ~/work/mlc/models/Qwen2.5-1.5B-Instruct-q4f16_1-MLC
# 840MB,嗖嗖的就下完了 ✅
划重点:HuggingFace 上
mlc-ai官方组织已经有 Qwen2.5 系列的 q4f16_1 预转换格式了,不用自己跑convert_weight,直接下就能用。3B 的也一样,改个 repo 名就行。
4.4 启动服务(第二个坑)
这里踩了第二个坑——参数不兼容。网上很多教程用的是老版本参数 --max-batch-size 1 --max-total-sequence-length 4096,但 v0.20.0 改了参数体系,变成 --overrides 了。
# ❌ 老版本写法(v0.20.0 不认)
--max-batch-size 1 --max-total-sequence-length 4096
# ✅ v0.20.0 正确写法
--overrides "max_num_sequence=1;max_total_seq_length=4096"
完整的启动命令长这样:
sudo docker run -d --runtime nvidia --name mlc-serve --network=host \
-v ~/work/mlc:/workspace -w /workspace \
dustynv/mlc:0.20.0-r36.4.0 \
mlc_llm serve /workspace/models/Qwen2.5-1.5B-Instruct-q4f16_1-MLC \
--device cuda:0 --host 0.0.0.0 --port 8000 \
--mode local --overrides "max_num_sequence=1;max_total_seq_length=4096"
启动后看日志,几个关键信息:
- JIT 编译:约 1.5 分钟(首次跑会编译模型库,之后就缓存了)
- 内存估算:3670MB(Parameters 828MB + KVCache 174MB + Temporary 2668MB)
- 端口:8000 ✅
- 引擎模式:local(单并发优先,边缘设备就该这么配)
4.5 性能测试
./benchmark.sh
结果出来的那一刻,说实话有点激动:
| 指标 | 数值 | 评价 |
|---|---|---|
| TTFT(首 token) | 0.077s | 快到离谱 |
| 生成速度 | 60.05 tok/s | 远超预期 |
| 生成 token 数 | 135 | |
| 总时延 | 2.308s | |
| 峰值内存 | 4.44GB / 7.6GB | 余量 3.1GB |
| 整机功耗 | 20.2W 峰值 | 在 25W 上限内 |
| GPU 利用率 | 96% @ 1013MHz | 满负荷 |
| GPU 温度 | 56.8°C | 非常健康 |
60 tok/s! 之前文档给的预期是 20-40 tok/s,实测直接翻倍。对比之前 TRT 跑 0.5B 才 21.9-30.5 tok/s,这次是 1.5B 模型跑出 2-2.7 倍速度,还有之前用相同硬件使用llama.cpp部署qwen2.5-1.5B_Q4_K_M 的速度只有38.37 tok/s,几乎翻倍,当然这是因为它们量化程度不同。
五、上 3B:第三个坑
1.5B 跑通了,心就大了——能不能上 3B?
5.1 脚本参数化
先把脚本改成支持环境变量切换,MODEL_SIZE 默认 1.5B,设成 3B 就切大模型:
# 下 3B 权重
MODEL_SIZE=3B ./jetson-run.sh download
# 1.9GB,62 个 shard ✅
5.2 内存优化(第三个坑)
3B 模型默认的 context_window_size 是 32768(32K),直接跑会 OOM——这是第三个坑。
默认配置会按 32K 上下文预分配内存池,8GB 上根本扛不住。解决方案是一套参数组合拳压下去:
--overrides "max_num_sequence=1;max_total_seq_length=2048;context_window_size=2048;prefill_chunk_size=1280"
四个参数各自的作用:
| 参数 | 默认值 | 压成 | 省了啥 |
|---|---|---|---|
max_total_seq_length | 4096 | 2048 | KV pool 省 0.5-1GB |
context_window_size | 32768 | 2048 | 避免 32K 预分配(最大的坑) |
prefill_chunk_size | 2048 | 1280 | 削减 prefill 激活峰值 |
max_num_sequence | — | 1 | 防并发翻倍 |
5.3 启动 + 测试
MODEL_SIZE=3B MAX_SEQ_LEN=2048 ./jetson-run.sh serve
启动观察:JIT 编译约 3-5 分钟(比 1.5B 长一倍),内存稳定,swap 用了 348MB(JIT 阶段,推理时基本不用),无 OOM。
MODEL_SIZE=3B ./benchmark.sh
3B 测试结果:
| 指标 | 数值 | 评价 |
|---|---|---|
| TTFT | 0.175s | 依然很快 |
| 生成速度 | 33.11 tok/s | 实用速度 |
| 峰值内存 | 5.02GB / 7.6GB | 余量 2.5GB |
| 功耗 | 21.4W | 在 25W 内 |
| GPU 利用率 | 99% @ 1013MHz | 满负荷 |
| GPU 温度 | 60°C | 健康 |
3B 跑 33 tok/s,内存才 5.02GB,还剩 2.5GB 余量。8GB 跑 3B 大模型,真成了。
六、数据对比:一目了然
6.1 1.5B vs 3B 正面刚
| 指标 | 1.5B | 3B | 变化 | 评价 |
|---|---|---|---|---|
| 生成速度 | 60.05 tok/s | 33.11 tok/s | -45% | 3B 慢 1.8x,但实用 |
| TTFT | 0.077s | 0.175s | +127% | 都在 0.2s 内 |
| 峰值内存 | 4.44GB | 5.02GB | +13% | 只多 0.58GB |
| 内存余量 | 3.1GB | 2.5GB | -0.6GB | 3B 仍有余量 |
| 功耗 | 20.2W | 21.4W | +6% | 都在 25W 内 |
| GPU 利用率 | 96% | 99% | +3% | 都满负荷 |
| GPU 温度 | 56.8°C | 60°C | +3°C | 都健康 |
| 权重大小 | 840MB | 1.9GB | +126% | 3B 多 1.1GB |
6.2 跟之前的 TRT 0.5B 横比
这才是最直观的——同样 8GB 设备上:
| 指标 | MLC 1.5B | TRT 0.5B | 差距 |
|---|---|---|---|
| 生成速度 | 60 tok/s | 21.9-30.5 tok/s | MLC 快 2-2.7x |
| TTFT | 0.077s | 1.9s | MLC 快 25 倍 |
| 峰值内存 | 4.44GB | 4.23GB | 基本持平 |
| 模型规模 | 1.5B | 0.5B | MLC 支持大 3 倍的模型 |
| 流式输出 | 原生支持 | 要改源码重编译 | MLC 开箱即用 |
同样 4.4GB 内存,MLC 跑的模型大了 3 倍,速度快了 2 倍多,TTFT 快了 25 倍——q4f16 量化的威力全在这张表里了。
七、1.5B 还是 3B?看你的场景
跑通两个模型后,怎么选?我给个参考:
选 1.5B 的场景:
- 实时对话系统(60 tok/s 响应飞快,用户基本不用等)
- 多用户并发场景(3.1GB 内存余量大,扛得住)
- 简单问答任务(1.5B 的智能能力够用了)
- 功耗敏感场景(20.2W 更省电)
选 3B 的场景:
- 复杂推理任务(3B 智能能力显著更强)
- 专业领域应用(质量优先于速度)
- 单用户或低并发(2.5GB 余量足够)
- 能接受 33 tok/s 的响应速度(其实也不慢)
切换也很方便,一条命令搞定:
# 跑 1.5B
./jetson-run.sh serve
# 跑 3B(压参数)
MODEL_SIZE=3B MAX_SEQ_LEN=2048 ./jetson-run.sh serve
两个模型一分钟内就能切换,完全可以按需来。
八、三个坑总结(避坑指南)
这次实操踩了三个坑,汇总一下帮大家避雷:
| # | 坑 | 现象 | 解法 |
|---|---|---|---|
| 1 | HuggingFace 连不上 | 容器内 git clone exit 128 | 宿主机走HF_ENDPOINT=https://hf-mirror.com 镜像站下载 |
| 2 | 参数不兼容 | v0.20.0 不认--max-batch-size | 用--overrides "max_num_sequence=1;max_total_seq_length=4096" |
| 3 | 3B 默认 32K 上下文 OOM | 启动直接撑爆内存 | 压参数:context_window_size=2048;max_total_seq_length=2048;prefill_chunk_size=1280 |
还有几个容易忽略的点:
- 一定要挂 swap:JIT 编译阶段会吃额外内存,8GB 上不挂 swap 偶尔会 OOM,挂个 8G swap 就稳了
- 功耗模式拉满:务必确认是 MAXN_SUPER(25W),不然性能打折
- 版本要统一:容器版本(0.20.0-r36.4.0)、MLC 版本(v0.20.0)、JetPack 版本(6.2/R36.4)三者要匹配,别混用
九、验证流式输出(ROS2 集成预备)
MLC 的 serve 是 OpenAI 兼容 API,流式输出开箱即用。curl 验证一下:
curl -N http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"Qwen2.5-1.5B-Instruct-q4f16_1-MLC","messages":[{"role":"user","content":"你好"}],"stream":true,"max_tokens":64}'
能看到 data: {"choices":[{"delta":{"content":"..."}}]} 逐 token 往外吐——这就是真流式。对比之前 TRT-Edge-LLM v0.6.0 要改源码重编译才能流式,MLC 这一点太省心了。
后续接 ROS2 的话,直接让节点请求 /v1/chat/completions?stream=true 就行,不用自己造轮子。
十、这套方案凭啥能成
最后总结一下这次实验的核心发现,四个关键点:
1. 编译器路线绕开了 8GB 构建红线
之前 TRT 跑 1.5B 五次 OOM 的根因是"构建必须在 Jetson 上做"。MLC 把编译放到了容器里(JIT)或 PC 上(交叉编译),8GB 只管运行,构建内存压力根本不出现。这次 1.5B 和 3B 全程零 OOM。
2. q4f16 量化是内存账本的关键
1.5B 权重从 3GB 压到 840MB,3B 从 6GB 压到 1.9GB,省了 60-70%。而且量化在编译期就完成了,运行时零开销——GPU 利用率 96-99% 说明 kernel 效率极高,量化没拖性能后腿。
3. 参数压降是 3B 能跑的最后一道保险
3B 默认 32K 上下文是最大的坑,不压就是 OOM。context_window_size=2048 + prefill_chunk_size=1280 这套组合拳把内存从理论 5.5-6GB 压到实际 5.02GB,留了 2.5GB 余量。
4. dustynv 容器是最快的落地路径
不用从源码编译 TVM + MLC-LLM(那得好几个小时),拉个 6.9GB 镜像就齐活了。JIT 编译 1.5B 才 1.5 分钟,3B 也就 3-5 分钟,首次跑完之后缓存复用,秒级启动。
十一、下一步:还能更快
跑通基线之后,还有两条提速路线:
路线一:PC 交叉编译(消除 JIT 开销)
- 在 PC 上用
mlc_llm compile --host aarch64-unknown-linux-gnu编出 sm_87 的 .so - scp 拷回 Jetson,启动时直接加载,省掉 JIT 编译等待
- 我已经写好了完整的 Dockerfile + 交叉编译脚本三件套,可以复用
路线二:EAGLE 推测解码(预期再提速 1.5-1.8x)
- 给目标模型挂一个 68M 参数的轻量预测头,让它"预判"下一个 token,再由目标模型一次验证
- 数学上保证无损(输出分布和普通解码完全一致)
- 1.5B 从 60 tok/s 预期能冲到 90-100 tok/s
- MLC 的 serve 原生支持
--speculative-mode eagle,腾讯 AngelSlim 在 HF 上发布了 Qwen2.5 系列的 EAGLE3 head,不用自己训练
这两条路可以叠加:先用交叉编译消 JIT,再上 EAGLE 提速,最终在 8GB 上跑到接近 100 tok/s 不是梦。
写在最后
8GB 的小板子跑 1.5B 大模型飙到 60 tok/s、跑 3B 也有 33 tok/s——放一年前这事想都不敢想。关键是选对路线:TRT 的"设备上构建"思路在 8GB 上走不通,MLC 的"编译器 + 量化 + 构建运行解耦"三件套正好打中所有痛点。
如果你也在 Jetson 上折腾大模型部署,强烈建议直接上 MLC-LLM + dustynv 容器这条路,少走弯路。文中的脚本和命令都是真机跑通的,照着敲就能复现。
完整实验数据已整理提交github https://github.com/X32/tensorRT_ONNX。
如果这篇博客对你有帮助,点个赞 + 收藏 + 关注三连呗 👍
后续会更新 ROS2 集成和 EAGLE 推测解码实测,感兴趣的朋友关注别走丢。
转载请注明出处,感谢支持!
更多推荐


所有评论(0)