ORIN NX 16G + ubuntu22.04 环境安装及模型部署
环境:从零搭建了整个Orin nx 上的环境,包括tensorrt,trex, tensorrt-edge-llm。
模型实战:测试模型最佳性能,首先需要开启MAXN模式,加锁定GPU频率,然后根据测试的模型是tensorrt-edge-llm支持的模型,还是普通网络模型来抉择测试方法。测试完后调回默认频率。
VLM大模型:tensorrt-edge-llm
普通网络模型:trtexec+polygraphy
瓶颈分析:
一、Orin NX 烧录
主机(ubuntu20.04)通过 sdk manager 烧录 orin nx 开发板,下面是辅助刷写的主机版本和支持刷写的Jetpack版本。可见ubuntu20.04支持jetpack6.2.x

官网下载主机(ubuntu)对应的sdk-manager:SDK Manager | NVIDIA Developer
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sdkmanager
登陆账号,选择jetpack版本进行安装和刷写,刷写过程中需要设置orin nx 板端账号和密码,Storage Device 选 NVME(没有就选default),Target Proxy Settings 选 Do not set proxy.
刷写完成后显示docker runtime 下载失败,但是不影响我们使用orin.
二、浏览器、中文设置、conda安装、torch下载、换源
2.1 firefox浏览器安装
Orin 上 snap2.70容易引发崩溃,特别是firefox浏览器会无法打开,一直转圈。为了阻止崩溃,所以一开始直接对snap降版本,并阻止其更新。
参考:
# 下载指定版本的Snapd
snap download snapd --revision=24724
# 安装并锁定版本
sudo snap ack snapd_24724.assert
sudo snap install snapd_24724.snap
sudo snap refresh --hold snapd
# 安装 firefox
sudo apt-get install firefox
2.2 orin 设置中文
jetpack 6.2.1 是 ubuntu_22.04+cuda_12.6的系统
参考:
为 Ubuntu22.04 系统添加中文输入法_ubuntu22.04中文输入法-CSDN博客文章浏览阅读5.1w次,点赞93次,收藏299次。本文详细介绍了如何在Ubuntu22.04操作系统中添加中文输入法。首先,通过安装Chinese语言包,然后在Settings的Region&Language选项中管理已安装的语言。接着,使用终端命令安装ibus-pinyin输入法引擎,并在Keyboard设置中添加Chinese(IntelligentPinyin)输入源。完成后,用户可以方便地切换中英文输入法。https://blog.csdn.net/weixin_44916154/article/details/124582379?fromshare=blogdetail&sharetype=blogdetail&sharerId=124582379&sharerefer=PC&sharesource=qq_56719965&sharefrom=from_link注意:在 sudo apt-get install ibus-pinyin 之后直接重启就可以使用拼音了。
2.3 arm conda 安装
在Jetson Orin NX上,由于系统是基于 aarch64 架构的,官方Anaconda并不直接支持。因此,最佳方案是使用专为ARM架构设计的 Miniforge。
进入官网进行下载:Releases · conda-forge/miniforge · GitHub

JetPack6.2自带的python是3.10,为了后续使用tensorrt工具链顺利,创建的conda环境也需要是3.10.
2.4 arm torch 安装
NVIDIA官方为不同JetPack版本提供的PyTorch预编译包(.whl文件)
可以下载官网jetpack6.2+cuda12.6推荐的torch版本:jp6/cu126 index
下载 torch-2.11.0 、torchvision-0.26.0 、torchaudio-2.10.0
更多版本:jp6/cu126: simple list (including inherited indices)
官方的torch下载速度非常非常慢!!!!!!!!!!!!!!!!!!!!!!!
2.5 Orin NX ubuntu22.04 换源
2.5.1 apt 换源
给 Jetson Orin 上的 Ubuntu 22.04 换源,核心是将默认源地址替换为国内镜像站。需要注意,Jetson 是 ARM 架构,必须使用 ports.ubuntu.com 这个专门为 ARM 设备准备的源,不能直接用 x86 。
参考:Jeston Orin NX Ubuntu22.04 安装ROS2 humble_jetson 22.04 换源-CSDN博客
# 备份原始源
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
# 添加中科大镜像
# 使用 sed 命令一键替换,针对 Ubuntu 22.04 (Jammy) 系统
sudo sed -i 's|http://ports.ubuntu.com/ubuntu-ports/|https://mirrors.ustc.edu.cn/ubuntu-ports/|g' /etc/apt/sources.list
# 更新源
sudo apt update
2.5.2 pip 换源
cd ~
mkdir ~/.pip
sudo gedit ~/.pip/pip.conf
# 写入以下内容
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host =
pypi.tuna.tsinghua.edu.cn
# 保存退出
三、TensorRT环境安装
3.1 启用 Orin NX 自身的 tensorrt
(若自行下载tensorrt工具链:TensorRT 10.x Download | NVIDIA Developer)
参考:
# 安装jetpack
sudo apt install nvidia-jetpack
# 查看 jetpack 版本
dpkg -l | grep tensorrt

查找trtexec路径,并添加到环境变量中
# 查看tenorrt路径
sudo find /usr -name trtexec

sudo gedit ~/.bashrc
export PATH=$PATH:/usr/src/tensorrt/bin
export PATH=$PATH:/usr/src/tensorrt/samples
source ~/.bashrc
查看 tensorrt 命令是否存在,输出参数行代表命令正常运行:
trtexec -h

3.2 安装 TensorRT OSS
TensorRT OSS仓库主要包含以下开源组件:
-
官方插件 (Plugins):TensorRT官方实现的一系列预定义操作(如:
CustomSlice,InstanceNormalization等)。某些复杂的网络结构必须依赖这些插件才能运行。 -
模型解析器 (Parsers):将其他格式的模型转换为TensorRT引擎的工具,主要包括:
-
ONNX Parser:解析ONNX格式的模型。
-
Caffe Parser:解析Caffe格式的模型。
-
-
示例应用 (Sample Applications):展示如何使用TensorRT C++/Python API进行推理的示例代码
下载本地 tensorrt 对应版本的 tensorrt oss:https://github.com/NVIDIA/TensorRT
安装基础的 cuda torch 环境
# 首先创建 conda 环境
conda create --name TensorRTOSS python=3.10.12
conda activate TensorRTOSS
# 将 Conda lib 路径添加到 LD_LIBRARY_PATH 是解决 C++ 库版本不匹配问题
#echo 'export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH' >> ~/.bashrc
#source ~/.bashrc
conda env config vars set LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATH
# 安装 torch 环境
pip install torch-2.11.0-cp310-cp310-linux_aarch64.whl
pip install torchaudio-2.10.0-cp310-cp310-linux_aarch64.whl
pip install torchvision-0.26.0-cp310-cp310-linux_aarch64.whl
为了利用 trt-engine-explorer 进行模型转换及模型性能可视化,需要安装下面两个模型:
安装 pytorch-quantization
cd TensorRT-10.6.0/tools/pytorch-quantization/
# Install PyTorch and prerequisites
pip install -r requirements.txt
# jupyter 画图阶段会出现报错: MoudleNotFoundError:NO module named 'pkg_rescources'
# 解决方法:提前对 setuptools 降级
pip install setuptools==59.6.0
# build
python setup.py install
在进行 python setup.py install 遇到报错:缺少cudss依赖
ImportError: libcudss.so.0: cannot open shared object file: No such file or directory

如果是torch2.5.0则会报错:缺少 cusparseLt库
ImportError: libcusparseLt.so.0: cannot open shared object file: No such file or directory

jetpack6.2.1默认不包含cudss和cusparseLt,需手动下载:
cudss:Index of /compute/cudss/redist/libcudss/linux-sbsa
cusparseLt:Index of /compute/cusparselt/redist/libcusparse_lt/linux-aarch64
官方文档:
cudss:NVIDIA cuDSS (Preview): A high-performance CUDA Library for Direct Sparse Solvers — NVIDIA cuDSS
# 将下载的文件解压,并把头文件和库文件复制到系统的 CUDA 目录中
tar xf ${CUSPARSE_SOLVER_NAME}.tar.xz
sudo cp -a ${CUSPARSE_SOLVER_NAME}/include/* /usr/local/cuda/include/
sudo cp -a ${CUSPARSE_SOLVER_NAME}/lib/* /usr/local/cuda/lib64/
# 更新系统库缓存
sudo ldconfig
# 验证安装
ls /usr/local/cuda/lib64 | grep cudss
# 测试pytorch
python3 -c "import torch; print(torch.__version__)"

安装 trt-engine-explorer

cd TensorRT/tools/experimental/trt-engine-explorer
# 以开发模型安装 trex
python3 -m pip install -e .[notebook]
# 安装 Graphviz
sudo apt --yes install graphviz
# 以下是针对后续使用jupyterlab 会出现的各种问题的解决方法
# dash 依赖版本不兼容,进行版本降级
pip install dash==1.21.0 werkzeug==2.0.3 dash-bootstrap-components==0.13.1 dash_daq==0.5.0 dash_colorscales==0.0.4
# 检查是否能进入jupyter notebook
jupyter lab
ERROR:No matching distribution found for pynvx

pynvx 官方并未提供适用于 ARM 架构(如 aarch64)的预编译 wheel 文件。pip install pynvx 会尝试从 PyPI 下载适合当前平台的版本,但对 aarch64 架构,它找不到对应的 wheel,因此会失败。
源码编译pynvx,编译过程会在 Jetson 设备上生成适配 aarch64 架构的版本。
# 下载 pynvx 和 pybind11
git clone https://github.com/helloall1900/pynvx.git
cd pynvx
git clone https://github.com/pybind/pybind11.git pybind11
# 编译
pip install .

再次执行python3 -m pip install -e .[notebook],成功。
TensorRT OSS 使用
!!!已打包为bash脚本,路径为 /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine目录下 build_engine_llm.sh 和 build_engine_visual.sh
前景提要:使用 TensorRT-Edge-LLM 导出的 onnx 模型 进行模型转换,目的是为了方便使用trex进行模型可视化分析。
如果报错找不到 tensorrt,则将系统包路径添加到 Python 路径中。
# 找到系统 TensorRT 安装路径
dpkg -L python3-libnvinfer | grep -E 'dist-packages|site-packages'
# 临时设置
export PYTHONPATH=/usr/lib/python3.10/dist-packages:$PYTHONPATH
# 用trtexec 转换 tensorrt-edge-llm 导出的模型会报错 trt 找不到 llm 自定义的插件
# 直接导出后的模型利用 trtexec 量化
python3 /home/pub/TensorRT-release-10.3/tools/experimental/trt-engine-explorer/utils/process_engine.py \
/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/origin_onnx/llm/model.onnx \
/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/llm \
int8 \
preview=+aliasedPluginIO1003
# 量化后导出,trtexex转换
# llm部分
python3 /home/pub/TensorRT-release-10.3/tools/experimental/trt-engine-explorer/utils/process_engine.py \
/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/onnx/llm/model.onnx \
/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/llm \
stronglyTyped \
preview=+aliasedPluginIO1003
# shapes=
# visual部分 设置tokens=1000
python3 /home/pub/TensorRT-release-10.3/tools/experimental/trt-engine-explorer/utils/process_engine.py \
/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/onnx/visual/model.onnx \
/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/tokens1000/visual \
stronglyTyped \
preview=+aliasedPluginIO1003 \
shapes=input:1000x1536,rotary_pos_emb:1000x32,cu_seqlens:2,max_seqlen_carrier:1000,fast_pos_embed_idx:4x1000,fast_pos_embed_weight:4x1000
# 动态模型参数设置,当input数量过多时,不设置Shapes,让tretexec自行选择
# 对于Qwen3模型,有llm 和 visual 部分
# LLM部分:主要动态维度通常只有序列长度(sequence_length) 一个。
# visual部分:除了批次大小(batch),还可能涉及图像高度(H)、宽度(W) 等多个动态维度,这增加了自动推导的难度。
# --minShapes=inputs_embeds:1x1000x2048 \
# --optShapes=inputs_embeds:1x1000x2048 \
# --maxShapes=inputs_embeds:1x1000x2048
# 依旧报插件问题
export LD_PRELOAD=/home/pub/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
# 遇到报错:[E] Error[4]: IBuilder::buildSerializedNetwork: Error Code 4: Internal Error (Aliased I/O used by plugin n0 but PreviewFeature::kALIASED_PLUGIN_IO_10_03 not enabled.)
# 设置 --preview=+aliasedPluginIO1003 ,启用 aliasedPluginIO1003 预览功能
# 示例
python3 /home/pub/TensorRT-release-10.3/tools/experimental/trt-engine-explorer/utils/process_engine.py /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/onnx/visual/model.onnx /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/tokens1000/visual stronglyTyped preview=+aliasedPluginIO1003 shapes=input:1000x1536,rotary_pos_emb:1000x32,cu_seqlens:2,max_seqlen_carrier:1000,fast_pos_embed_idx:4x1000,fast_pos_embed_weight:4x1000
python3 /home/pub/TensorRT-release-10.3/tools/experimental/trt-engine-explorer/utils/process_engine.py /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/onnx/llm/model.onnx /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/tokens1000/llm stronglyTyped preview=+aliasedPluginIO1003 shapes=inputs_embeds:1x1000x2048,rope_rotary_cos_sin:1x1000x128,context_lengths:1,kvcache_start_index:1,last_token_ids:1x1,deepstack_embeds_0:1x1000x2048,deepstack_embeds_1:1x1000x2048,deepstack_embeds_2:1x1000x2048,past_key_values_0:1x2x8x0x128,past_key_values_1:1x2x8x0x128,past_key_values_2:1x2x8x0x128,past_key_values_3:1x2x8x0x128,past_key_values_4:1x2x8x0x128,past_key_values_5:1x2x8x0x128,past_key_values_6:1x2x8x0x128,past_key_values_7:1x2x8x0x128,past_key_values_8:1x2x8x0x128,past_key_values_9:1x2x8x0x128,past_key_values_10:1x2x8x0x128,past_key_values_11:1x2x8x0x128,past_key_values_12:1x2x8x0x128,past_key_values_13:1x2x8x0x128,past_key_values_14:1x2x8x0x128,past_key_values_15:1x2x8x0x128,past_key_values_16:1x2x8x0x128,past_key_values_17:1x2x8x0x128,past_key_values_18:1x2x8x0x128,past_key_values_19:1x2x8x0x128,past_key_values_20:1x2x8x0x128,past_key_values_21:1x2x8x0x128,past_key_values_22:1x2x8x0x128,past_key_values_23:1x2x8x0x128,past_key_values_24:1x2x8x0x128,past_key_values_25:1x2x8x0x128,past_key_values_26:1x2x8x0x128,past_key_values_27:1x2x8x0x128
llm的输入很多,可以写个python脚本来生成
# 生成形状字典
shapes = {
"inputs_embeds": "1x1000x2048",
"rope_rotary_cos_sin": "1x1000x128",
"context_lengths": "1",
"kvcache_start_index": "1",
"last_token_ids": "1x1",
"deepstack_embeds_0": "1x1000x2048",
"deepstack_embeds_1": "1x1000x2048",
"deepstack_embeds_2": "1x1000x2048",
}
# 添加 28 个 past_key_values
for i in range(28):
shapes[f"past_key_values_{i}"] = "1x2x8x0x128"
# 生成 --shapes 参数
shape_str = ",".join(f"{k}:{v}" for k, v in shapes.items())
print(shape_str)
ERROR:Cannot find plugin : AttentionPlugin
![]()
解决方法:
export LD_PRELOAD=/home/pub/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
[E] Error[4]: IBuilder::buildSerializedNetwork: Error Code 4: Internal Error (Aliased I/O used by plugin n0 but PreviewFeature::kALIASED_PLUGIN_IO_10_03 not enabled.)
解决方法:
设置 --preview=+aliasedPluginIO1003 ,启用 aliasedPluginIO1003 预览功能
交互式可视化分析
通过 trt-engine-explorer/utils/process_engine.py 可以得到模型引擎及性能文件

利用 jupyter lab 生成交互式可视化分析报告
首先进入 jupyter lab 界面
conda activate TensorRTOSS
jupyter lab
最好在性能分析文件保存路径下进行分析,生成report_card_visual(llm).ipynb
import IPython
from ipywidgets import widgets
from trex import *
from trex.notebook import *
from trex.report_card import *
engine_name = "/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/tokens900/visual/model.onnx.engine"
plan = EnginePlan(f"{engine_name}.graph.json", f"{engine_name}.profile.json", f"{engine_name}.profile.metadata.json")
# 设置 Pandas 显示无限制
import pandas as pd
pd.set_option('display.max.columns',None)
# 打印所有列
print(plan.df.columns.tolist())
print('===================================================================')
# 打印所有层
df = plan.df
print(df['Name'])
print('===================================================================')
# 打印最慢的几层
top3 = plan.df.nlargest(3, 'latency.pct_time')
for i in range(len(top3)):
layer = top3.iloc[i]
print("%s: %s" % (layer["Name"], layer["subtype"]))
print('===================================================================')
# 模型结构图
#report_card_draw_plan_graph_extended(plan, engine_name)
# 模型的结构,性能总结
plan.summary()
# 由于当前模型属性type为subtype
# 需要修改 /tools/experimental/trt-engine-explorer/trex/report_card.py 中的'type' 替换为 'subtype'
# 不同类型 Layer 的延时占比图
layer_latency_sunburst(plan.df, "Layers Latencies (%)")
# plan 的各个属性打印成表格
# report_card_table_view(plan)
# 多次推理后的延迟分布图,前期推理时不稳定,后期逐步稳定延迟接近一条直线 ,我自己推测可以考虑是否没设置warmUp
plot_engine_timings(timing_json_file= f"{engine_name}.timing.json")
# Performance
# 延迟和精度的汇总卡
report_card_perf_overview_widget(plan)
# Memory Footprint
# 内存占比,分权重和激活
report_card_memory_footprint_widget(plan)
# Convolutions
# 但是没有卷积层
#convs = plan.get_layers_by_type('Convolution')
#report_card_convolutions_overview_widget(convs)
四、TensorRT-Edge-LLM环境安装
简介
TensorRT Edge-LLM 是 NVIDIA 在嵌入式平台上为 LLM 和 VLM 提供高性能的 C++ 推理运行时。定量(INT4、NVFP4、FP8)可减少重量占用,使大型型号在受内存约束的设备上保持实用性。
Edge-LLM 支持从 Orin Nano 到 Thor 等整个 Jetson 系列的多种 LLM 和 VLM 系统。
参考:TensorRT Edge-LLM on Jetson | Jetson AI Lab



官网下载:https://github.com/NVIDIA/TensorRT-Edge-LLM
官方文档:Installation — TensorRT Edge-LLM
安装TensorRT-Edge-LLM
Part 1: Quantization and tensorrt_edgellm (x86 Host with GPU / Edge Device)
从 PyTorch 2.11 版本开始,官方已经支持在 aarch64 架构的 Linux 系统上,直接从 PyPI 安装包含 CUDA 支持的 wheel 包了,所以直接安装 tensorrt-edge-llm-v_0.8.0

Verify Your Prerequisites:
# Check CUDA installation
nvcc --version
# Should show CUDA 12.x or 13.x
# Check GPU and available memory
nvidia-smi
# Look for GPU memory (e.g., "24576MiB" for 24GB)
# Check Python version
python3 --version
# Should show Python 3.10 or higher
下载资源库
git clone https://github.com/NVIDIA/TensorRT-Edge-LLM.git
cd TensorRT-Edge-LLM
# 初始化 --progress 显示实际下载速度和剩余大小
git submodule update --init --recursive --progress
安装依赖
注意修改 requirements.txt 中 numpy==2.2.6,
pyproject.toml 中 numpy==2.2.6,torch==2.11.0,torchvision==0.26.0
pip安装的torch2.12,torchvision=0.27.0是cuda13编译,编译可以成功,但是量化阶段会报错cuda内核不匹配
conda create --name TensorRTLLM python=3.10.12
conda actiavte TensorRTLLM
# 安装 适配jetpack6.2.1 cuda12.6的 torch 环境
pip install torch-2.11.0-cp310-cp310-linux_aarch64.whl
pip install torchaudio-2.10.0-cp310-cp310-linux_aarch64.whl
pip install torchvision-0.26.0-cp310-cp310-linux_aarch64.whl
# Required for checkpoint export
# requirements.txt 里 numpy==2.4.6 改numpy==2.2.6
pip3 install -r requirements.txt
# Required for quantization, LoRA merge, vocabulary reduction, audio preprocessing,
# and tokenizer helpers
# 需要修改 pyproject.toml 中的 numpy==2.2.6,torch==2.11.0,torchvision==0.26.0
pip3 install ".[tools]"
# Required only for the experimental high-level Python API and server
pip3 install -r requirements-server.txt
当 numpy==2.4.6 时,报错:

设置环境变量,并验证
# export EDGE_LLM_PATH=/path/to/TensorRT-Edge-LLM
# export PYTHONPATH=$EDGE_LLM_PATH:$PYTHONPATH
export EDGE_LLM_PATH=/home/pub/TensorRT-Edge-LLM
export PYTHONPATH=$EDGE_LLM_PATH:$PYTHONPATH
# Verify the recommended quantization, export, LoRA, and vocabulary tools
tensorrt-edgellm-quantize --help
tensorrt-edgellm-export --help
tensorrt-edgellm-merge-lora --help
tensorrt-edgellm-reduce-vocab --help
Part 2: C++ Runtime (Edge Device)
jestson 设备与 对应 jetpack版本 的支持精度

系统需求

当前设备为:Jetson Orin + JetPack 6.2.1 + cuda12.6
JetPack 6.2 + Orin:
mkdir -p build
cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DTRT_PACKAGE_DIR=/usr \
-DCMAKE_TOOLCHAIN_FILE=cmake/aarch64_linux_toolchain.cmake \
-DEMBEDDED_TARGET=jetson-orin \
-DCUDA_CTK_VERSION=12.6 \
-DENABLE_CUTE_DSL=OFF
# -DENABLE_CUTE_DSL=ALL 容易在build时报错CUTE_DSL链接不到cuda动态库
Building on x86 GPU Systems (Optional for Developers)
如果要在使用 NVIDIA GPU 的 x86 工作站上进行构建和测试(在部署到 Edge 设备之前需要开发),可以改用以下配置:
mkdir -p build
cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DTRT_PACKAGE_DIR=/path/TensorRT-10.x.x \
-DCUDA_CTK_VERSION=<YOUR_CUDA_VERSION> \
-DENABLE_CUTE_DSL=ALL

Build Project & Verify Build
# Build Project
make -j$(nproc)
# Verify Build
# Test C++ examples
./examples/llm/llm_build --help
./examples/llm/llm_inference --help
设置-DENABLE_CUTE_DSL=ALL后编译会报错,没有找到解决方法,所以设置为-DENABLE_CUTE_DSL=OFF
ERROR:CUTE_DSL库未正确链接CUDA动态库

插件依赖
但凡在使用其他工具加载tensorrt-edge-llm编译的时候,插件依赖出问题:
比如![]()
直接引用插件就可解决
export LD_PRELOAD=/home/pub/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
LLM导出模型、量化模型(x86 / Jetson)
TensorRT-Edge-LLM 的 tensorrt-edgellm-quantize llm 命令,默认只量化 LLM 文本解码器主干,完全不触碰视觉分支权重。
若需要量化视觉分支,添加参数--visual_quantization fp8,并且使用多模态校准数据集:--dataset lmms-lab/MMMU
(由于 Orin nx 不支持 fp8,所以这里只需做 llm 量化即可 )
这里以Qwen3-VL-2B-Instruct模型为例
cd ..
# 设置环境变量
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM
export MODEL_NAME=Qwen3-VL-2B-Instruct
export PYTHONPATH=/home/pub/TensorRT-Edge-LLM:$PYTHONPATH
# 设置 hugging face 镜像链接
export HF_ENDPOINT=https://hf-mirror.com
pip install huggingface-hub==1.5.0
# Export FP16 model to ONNX
tensorrt-edgellm-export \
Qwen/Qwen3-VL-2B-Instruct \
$MODEL_NAME/onnx
# Or quantize an FP16/BF16 model first, then export the quantized checkpoint
tensorrt-edgellm-quantize llm \
--model_dir Qwen/Qwen3-VL-2B-Instruct \
--output_dir $MODEL_NAME/quantized \
--quantization int8_sq \
# --lm_head_quantization nvfp4
# --quantization: Backbone orin 只支持int8_q 、int4_awq
# --lm_head_quantization: LM head orin 只支持 int4_awq,不指定时,跟随 quantization 精度
tensorrt-edgellm-export \
$MODEL_NAME/quantized \
$MODEL_NAME/onnx
# Or export a pre-quantized INT4-AWQ checkpoint
# See https://huggingface.co/Qwen/Qwen3-4B-AWQ
tensorrt-edgellm-export \
/path/to/Qwen/Qwen3-4B-AWQ \
Qwen3-4B-AWQ/onnx \
# --externalize-weights int4_ffn 如果内存够,不要设置这个参数,
#会导致性能测试时,TensorRT 引擎在推理时找不到输入张量 _model.model.layers.0.mlp.gate_proj.qweight 的内存地址
当模型为qwen2-vl时,直接使用 tensorrt-edgellm-export 只能导出 llm 部分,因为 tensorrt-edge-llm 对 qwen3_vl 内置支持一体化导出(自动导出 llm+visual); 对 qwen2_vl 同样不会自动导出 visual,并且 没有封装 ViT 独立导出接口。
执行导出命令时可以看到 visual :no,说明 qwen2_vl 不在 tensorrt-edge-llm 支持的视觉模型白名单上。

查看TensorRT-Edge-LLM/build/lib/tensorrt_edgellm/onnx/export_encoder.py 可以发现 TensorRT-Edge-LLM v0.8.0 支持 以下视觉模型自动导出visual部分。

tensorrt-edgellm-export 是控制台入口脚本,底层指向源码:tensorrt_edgellm/scripts/export.py。基本上export_encoder.py 支持的模型,都在白名单内。不支持的模型,无法借助当前工具进行导出,tensorrt-edgellm-export-visual 手动调用 export_visual_onnx 进行导出这条路走不通。
推荐安装旧版本 tensorrt-edge-llm,v0.7.0版本以下支持qwen2_vl

安装旧版本tensorrt-edge-llm之后,成功导出未量化的qwen2_vl视觉部分,下载Qwen2-VL-2B-Instruct-AWQ,查看config文件也可以看到,视觉部分是跳过量化的。

模型量化时的环境报错:
ERROR:pip 安装了一个为 CUDA 13 编译的 PyTorch 版本
(此时torch为默认的torch2.12,torchvision=0.27.0)

报错:
huggingface_hub.errors.HfUriError: Invalid HF URI 'hf://datasets/cnn_dailymail@96df5e686bee6baa90b8bee7c28b81fa3fa6223d/.huggingface.yaml'. Repository id must be 'namespace/name', got 'cnn_dailymail'.
解决方法:
pip install huggingface-hub==1.5.0

LLM转换模型(Jetson)
# 设置环境变量
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM
export MODEL_NAME=Qwen3-VL-2B-Instruct
export PYTHONPATH=/home/pub/TensorRT-Edge-LLM:$PYTHONPATH
# Build language model engine
./build/examples/llm/llm_build \
--onnxDir $WORKSPACE_DIR/$MODEL_NAME/onnx/llm \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm \
--maxBatchSize 1 \
--maxInputLen 1024 \
--maxKVCacheCapacity 4096
# Build visual encoder engine
./build/examples/multimodal/visual_build \
--onnxDir $WORKSPACE_DIR/$MODEL_NAME/onnx/visual \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines \
--minImageTokens 128 \
--maxImageTokens 1024 \
--maxImageTokensPerImage 1024
# 为了测试模型,将 maxImageTokensPerImage 和 maxImageTokens 改为 1024
# tensorrt oss 可视化 用的还是 512
转换模型 参数一览

--profilingDetailed:仅在需要获取更细粒度的性能分析(如每个 ONNX op 的耗时)时开启,不影响功能
LLM模型推理(Jetson)
创建一个输入文件 $WORKSPACE_DIR/input_vlm.json,替换图片路径
{
"batch_size": 1,
"temperature": 1.0,
"top_p": 1.0,
"top_k": 50,
"max_generate_length": 128,
"requests": [
{
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": [
{
"type": "image",
"image": "/path/to/image.jpg"
},
{
"type": "text",
"text": "Please describe the image."
}
]
}
]
}
]
}
开始推理
./build/examples/llm/llm_inference \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm \
--multimodalEngineDir $WORKSPACE_DIR/$MODEL_NAME/engines/visual \
--inputFile $WORKSPACE_DIR/vlm_test/input_vlm.json \
--outputFile $WORKSPACE_DIR/vlm_test/output_vlm.json
LLM基准测试
llm_inference 是端到端推理的示例。在运行真正的 JSON 请求、应用聊天模板、生成文本、编写响应式 JSON 以及验证应用程序级行为时,请使用它。它还可以报告整体绩效指标,例如代币/秒。
llm_bench 是基准示例。在需要为内置引擎使用合成预填充/解码时,无需准备输入的JSON文件时使用。默认情况下,它会报告整体E2E计时;通过--profile收集内核级别崩溃的每层分析。
./build/examples/llm/llm_bench \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines \
--mode prefill \
--inputLen 128 \
--batchSize 1
参数解释
了解各Transformer模型结构,如图像 patch_size,merge_size参考
| 类别 | 参数 | 说明 | 必需/默认 |
|---|---|---|---|
| 必需选项 | --engineDir <dir> | TensorRT 引擎目录路径 | 必需 |
--mode <mode> | 基准测试模式,可选值:prefill、decode、spec_verify、spec_draft_proposal、spec_draft_prefill、visual | 必需 | |
| 模式特定选项 | prefill 模式 | ||
--inputLen | 输入序列长度 | 必需 | |
--reuseKVLen | 复用的 KV 缓存长度 | 可选,默认 0 | |
| decode 模式 | |||
--pastKVLen | 历史 KV 缓存长度; 解码开始时的初始缓存长度。 | 必需 | |
| spec_verify 模式 | |||
--verifyTreeSize | 验证树大小 | 必需 | |
--pastKVLen | 历史 KV 缓存长度 | 必需 | |
| spec_draft_proposal 模式 | |||
--draftTreeSize | 草稿树大小 | 必需 | |
--pastKVLen | 历史 KV 缓存长度 | 必需 | |
| spec_draft_prefill 模式 | |||
--inputLen | 输入序列长度 | 必需 | |
--reuseKVLen | 复用的 KV 缓存长度 | 可选,默认 0 | |
| visual 模式 | |||
--engineDir | 视觉编码器引擎目录(注意:会覆盖主 --engineDir) | 必需 | |
--imageSize <HxW> | 图像尺寸,例如 896x448。 grid_h = 图像高度 / patch_size grid_w = 图像宽度 / patch_size qwen3: patch_size=16, merge_size=2 | 必需 | |
| 通用选项 | --help | 显示帮助信息 | 可选 |
--debug | 启用调试模式(详细日志) | 可选 | |
--batchSize | 批处理大小 | 可选,默认 1 | |
--iterations | 性能分析迭代次数(预热后) | 可选,默认 10 | |
--warmup | 预热迭代次数 | 可选,默认 3 | |
--osl | 输出序列长度,用于 decode 端到端计时。osl=1:E2E 运行 --iterations 次,单个 Token 的生成延迟(Latency)。osl>1:E2E 运行完整序列解码一次,运行 1 次连续解码,包含 osl-1 个步骤(Prefill 已产生第一个 token)。输出 Token 生成速率 Generation(22.7 tok/s)。 | 可选,默认 1 | |
--profile | 启用逐层性能分析(默认禁用) | 可选 | |
--outputDir | 输出 CSV 文件的目录(层分析和 E2E 计时) | 可选 | |
--seed | 随机种子,用于可复现数据 | 可选,默认 0 | |
--noCudaGraph | 禁用 decode/EAGLE E2E 计时的 CUDA Graph 捕获。 默认启用,失败时会回退到非 Graph 模式 | 可选 | |
--extractLayerInfo <opts> | 逗号分隔的层信息提取选项:all、shapes、onnx_ops、tactics、data_types使用此选项会隐含启用 --profile | 可选 | |
| 推测解码选项 | --acceptRate | 每次推测解码迭代平均接受的 token 数(默认 5)。verify_steps = ceil((osl-1) / acceptRate) | 可选,默认 5 |
--draftStep | 每次推测解码迭代的草稿步数(默认 6)。draft_calls = verify_steps * (draftStep-1) | 可选,默认 6 |
llm decode 的性能测试
使用tensorrt-edge-llm llm_bench工具进行性能测试
./build/examples/llm/llm_bench \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm/ \
--mode decode \
--pastKVLen 10 \
--osl 100 \
--batchSize 1 \
--outputDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm.csv
llm decode 性能
| 模型模式 | 批处理大小 | 输出序列长度 (osl) | 端到端时延 (ms) | 平均Token时延 (ms) | 吞吐量 (tokens/s) | KV缓存长度 |
|---|---|---|---|---|---|---|
| Decode | 1 | 100 | 4377.34 | 44.22 | 22.62 | 10 |
完整的终端输出为:



qwen3 在 orin nx 16G 上的性能基准
Qwen 模型命名结构
| 结构部分 | 含义与说明 | 典型示例 |
|---|---|---|
| 系列与版本 | 标识模型所属的产品线和迭代代际,是理解模型能力的基础。 | Qwen (初代), Qwen1.5, Qwen2, Qwen2.5, Qwen3 |
| 参数量 | 表示模型的参数规模,B 代表十亿(Billion),M 代表百万(Million),这是衡量模型大小的核心指标。 | 1.5B, 7B, 72B;MoE模型如 30B-A3B (总参数量300亿,激活参数30亿) |
| 能力/模态 | 指明模型专精的任务领域或能处理的数据模态,是选型的关键。 | -VL (视觉语言多模态), -Coder (代码生成), -Math (数学推理) |
| 微调类型 | 表示模型在预训练后进行的特定对齐训练,决定了使用方式。 | -Instruct (指令微调,可直接对话), -Base (基础模型,需二次微调), -Chat (对话优化), -Thinking (深度思考模式) |
| 量化方法/格式 | 位于文件名末尾的标签,说明模型为部署而采用的压缩技术和文件格式。 | -GPTQ-Int4 (GPTQ算法的4-bit量化), -AWQ (AWQ算法的4-bit量化), .gguf (GGUF格式,含Q4_K_M, IQ3_M等量化配置) |
VLM 大模型量化方法
| 特性 | INT4 AWQ | INT8 SmoothQuant | GPTQ-Int4 | GPTQ-Int8 |
|---|---|---|---|---|
| 核心思路 | 保护激活值大的“重要”权重通道,减少精度损失 | 将量化难度从激活值“平滑”迁移到权重上,实现权重和激活同时量化 | 通过逐层最小化输出误差,用优化方法寻找最佳权重 | 原理同GPTQ,但量化位宽为8-bit |
| 量化对象 | 仅权重量化 (W4A16) | 权重+激活量化 (W8A8) | 仅权重量化 (W4A16) | 仅权重量化 (W8A16) |
| 模型压缩比 | 极高 (~4x) | 中等 (~2x) | 极高 (~4x) | 中等 (~2x) |
| 精度保留 | 高,通常优于GPTQ-Int4 | 很高,是INT8方案中的优等生 | 良好,是经典的4-bit方案 | 高,精度损失很小 |
| 推理速度 (小Batch) | 快,内存带宽是瓶颈时优势明显 | 快,得益于INT8 Tensor Core | 快 | 快 |
| 推理速度 (大Batch) | 相对变慢 | 优势明显,计算密度成为关键 | 相对变慢 | 相对变慢 |
| 部署兼容性 | TensorRT-LLM, llama.cpp, HuggingFace | TensorRT-LLM, ONNX Runtime, vLLM | TensorRT-LLM, AutoGPTQ, vLLM, HuggingFace | TensorRT-LLM, AutoGPTQ, vLLM, HuggingFace |
| 校准数据需求 | 较少 | 较多 | 中等 | 中等 |
| 典型应用场景 | 边缘设备、本地部署、极致显存优化 | 数据中心、追求高吞吐和高精度平衡 | 通用、生态成熟、社区支持广泛 | 通用、精度敏感型任务 |
命令
conda activate TensorRTLLM
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM
export MODEL_NAME=Qwen3-VL-2B-Instruct
export PYTHONPATH=/home/pub/TensorRT-Edge-LLM:$PYTHONPATH
# visual encoder
./build/examples/llm/llm_bench --engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/visual --mode visual --batchSize 1 --imageSize=960x960
# llm profil
./build/examples/llm/llm_bench --engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm/ --mode prefill --inputLen 512 --batchSize 1
# llm decoder
./build/examples/llm/llm_bench --engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm/ --mode decode --pastKVLen 512 --osl 64 --batchSize 1
orin nx 16G 性能基准
测试模型
Qwen3-VL-2B-Instruct
- 1-512-64: visual: 441(672x672), llm: 71
- 1-1024-128: visual: 900(960x960), llm: 124
Qwen2-1.5B-Instruct
- Qwen2-1.5B-Instruct
- Qwen2-1.5B-Instruct-AWQ
Qwen2.5-0.5B-Instruct
- Qwen2.5-0.5B-Instruct
- Qwen2.5-0.5B-Instruct-AWQ
| Model | BS-InSeq-OutSeq | Precision | Overall Latency (ms) | Overall Token/s | Visual Encode Latency (ms) | LLM Prefill Latency (ms) | LLM Prefill Token/s | Decode Latency (ms) | Decode Token/s | 平均 DDR 带宽 (GB/s) | 峰值 DDR 带宽 (GB/s) | 理论计算带宽 (GB/s) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Qwen3-VL-2B-Instruct | 1-512-64 | INT8 (15W) | |||||||||||
| Qwen3-VL-2B-Instruct | 1-512-64 | INT8 (MAXN) | |||||||||||
| Qwen3-VL-2B-Instruct | 1-1024-128 | INT8 (15W) | |||||||||||
| Qwen3-VL-2B-Instruct | 1-1024-128 | INT8 (MAXN) | |||||||||||
| Qwen2-1.5B-Instruct | 1-512-64 | INT8 (MAXN) | |||||||||||
| Qwen2-1.5B-Instruct-AWQ | 1-512-64 | INT4 (MAXN) | |||||||||||
| Qwen2-1.5B-Instruct | 1-1024-128 | INT8 (MAXN) | |||||||||||
| Qwen2-1.5B-Instruct-AWQ | 1-1024-128 | INT4 (MAXN) | |||||||||||
| Qwen2.5-0.5B-Instruct | 1-512-64 | INT8 (MAXN) | |||||||||||
| Qwen2.5-0.5B-Instruct-AWQ | 1-512-64 | INT4 (MAXN) | |||||||||||
| Qwen2.5-0.5B-Instruct | 1-1024-128 | INT8 (MAXN) | |||||||||||
| Qwen2.5-0.5B-Instruct-AWQ | 1-1024-128 | INT4 (MAXN) |
测试模型
Qwen3-VL-2B-Instruct
- 1-512-55: visual: 196(448x448), llm: 316
| 模型 | 量化类型 | 序列长度 | KV Cache | BPU 核数 | ViT(ms) | TTFT(ms) | Prefill TPS | Decode TPS | 内存 (GB) |
|---|---|---|---|---|---|---|---|---|---|
| Qwen3-VL-2B-Instruct | W8A8 | 512 | 1024 |
指标含义
| 指标 | 计算方式 | 涵盖阶段 | 物理含义 |
|---|---|---|---|
| Overall Token/s | 输出Token数 / 总体延迟 | Prefill + Decode | 总输出 Token 数 除以 端到端总延迟 |
| Decode Token/s | 输出Token数 / Decode阶段耗时 | Decode 阶段 | 仅衡量“生成速度”,更接近用户感知的“说话速度” |
Token分配
常见图像尺寸对应的 qwen3-vl 视觉 token 数
| 尺寸 (H×W) | 是否能被 32 整除 | 视觉 Token 数 | 适用场景 |
|---|---|---|---|
| 224×224 | ✅ | 49 | 轻量快速,适合小图 |
| 448×448 | ✅ | 196 | 均衡推荐 |
| 576×576 | ✅ | 324 | 接近 560 的替代 |
| 672×672 | ✅ | 441 | 高清图,细节丰富 |
| 896×896 | ✅ | 784 | 高分辨率,细粒度识别 |
| 1024×1024 | ✅ | 1024 | 极限分辨率(需注意总 token 数) |
DDR Bandwidth 计算
计算公式
- 带宽 = 内存频率 (MHz) × 2 × 位宽 (Bits) ÷ 8 (把Bit变成Byte) ÷ 1000 (把MHz变成GB/s).
- 位宽:Orin NX 的内存控制器(EMC)是 128-bit 的接口。
- DDR 内存在一个周期内传输两次数据(上升沿和下降沿各一次),因此有效数据率是内存实际频率的两倍。
利用 tegrastats 监控 模型推理时的实时内存和显存带宽占用情况(例如 EMC_FREQ 或GR3D_FREQ 的变化),计算带宽峰值速率和均值速率。
-
GR3D_FREQ(GPU 频率与利用率): 这代表板载GPU(即iGPU)的运行状态。GR3D_FREQ X%@[Y, Y,...]可以拆解为两部分来看:-
X%:表示在当前频率下,GPU核心的实时利用率。这个数值越高,说明GPU计算越繁忙。 -
[Y, Y,...]:表示此时GPU各核心(在部分较新Jetson机型上会显示多个核心频率)的实际运行频率,单位是MHz。例如在AGX Orin等新平台上,你会看到类似GR3D_FREQ 40%@[600, 600]的输出,代表两个GPC核心都以600MHz运行,利用率为40%。
-
-
EMC_FREQ(外部内存控制器频率与带宽占用): 它反映的是内存控制器的繁忙程度,可以理解为内存带宽的“使用率”X%,后面通常跟着当前运行频率YMHz。这个数值高,意味着CPU或GPU正在大量进行数据读写,内存带宽是此时系统的性能瓶颈之一。
已打包好两个脚本在 /home/pub/TensorRT-Edge-LLM/vlm_test
conda activate TensorRTLLM
cd ~/TensorRT-Edge-LLM
sh vlm_test/ddr.sh

监控脚本 ddr.sh
#!/bin/bash
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM
export PYTHONPATH=/home/pub/TensorRT-Edge-LLM:$PYTHONPATH
# ================= 直接在这里赋值 =================
#MODEL_NAME="Qwen3-VL-2B-Instruct" # 模型名称
#MODEL_NAME="Qwen2.5-0.5B-Instruct"
#MODEL_NAME="Qwen2.5-0.5B-Instruct-AWQ"
#MODEL_NAME="Qwen2-1.5B-Instruct"
MODEL_NAME="Qwen2-1.5B-Instruct-AWQ"
INPUT_TOKENS=512 # Token 数量
#INPUT_TOKENS=1024
# ================================================
# ================= 配置区 =================
LOG_FILE="$MODEL_NAME/tegra_monitor_${INPUT_TOKENS}.log"
INTERVAL_MS=50
# ==========================================
# 创建模型目录
mkdir -p "$MODEL_NAME"
echo "=========================================="
echo "DDR Bandwidth Monitoring & Analysis"
echo "=========================================="
echo "Model Name: $MODEL_NAME"
echo "Input Tokens: $INPUT_TOKENS"
echo "Log File: $LOG_FILE"
echo "Interval: ${INTERVAL_MS}ms"
echo "=========================================="
# 1. 清理历史残存进程
sudo pkill -f "tegrastats --interval" 2>/dev/null
# 2. 记录开始时间
START_TIME=$(date +%s%3N)
echo "开始推理时间戳: $START_TIME"
# 3. 启动 tegrastats 后台记录
sudo tegrastats --interval $INTERVAL_MS > $LOG_FILE 2>/dev/null &
TEGRA_PID=$!
echo "tegrastats 已启动 (PID: $TEGRA_PID),日志写入: $LOG_FILE"
# 4. 执行 Qwen3-VL 推理程序
echo "正在执行模型推理..."
./build/examples/llm/llm_inference \
--engineDir "$WORKSPACE_DIR/$MODEL_NAME/engines/llm" \
--inputFile "$WORKSPACE_DIR/vlm_test/$MODEL_NAME/input_vlm_${INPUT_TOKENS}.json" \
--outputFile "$WORKSPACE_DIR/vlm_test/$MODEL_NAME/output_vlm_${INPUT_TOKENS}.json"
RESULT_CODE=$?
# 5. 记录结束时间
END_TIME=$(date +%s%3N)
echo "结束推理时间戳: $END_TIME"
# 6. 杀掉 tegrastats 进程
sudo kill -SIGINT $TEGRA_PID
sleep 1
if ps -p $TEGRA_PID > /dev/null; then
sudo kill -9 $TEGRA_PID 2>/dev/null
fi
echo "监控结束。总耗时: $((END_TIME - START_TIME)) 毫秒。"
echo ""
# 7. 计算带宽
echo "=========================================="
echo "开始分析 DDR 带宽..."
echo "=========================================="
# Python 脚本路径
PYTHON_SCRIPT="/home/pub/TensorRT-Edge-LLM/vlm_test/tegra_monitor.py"
# 检查日志文件是否存在
if [ ! -f "$LOG_FILE" ]; then
echo "❌ 错误: 日志文件不存在: $LOG_FILE"
exit 1
fi
# 检查 Python 脚本是否存在
if [ ! -f "$PYTHON_SCRIPT" ]; then
echo "❌ 错误: Python 脚本不存在: $PYTHON_SCRIPT"
exit 1
fi
# 调用 Python 脚本,传递 MODEL_NAME 和 INPUT_TOKENS
echo "执行命令: python3 $PYTHON_SCRIPT $MODEL_NAME $INPUT_TOKENS"
python3 "$PYTHON_SCRIPT" "$MODEL_NAME" "$INPUT_TOKENS"
# 检查执行结果
if [ $? -eq 0 ]; then
echo ""
echo "✅ 带宽分析完成!"
echo "📄 结果已保存到: $MODEL_NAME/bandwidth_result_${INPUT_TOKENS}.txt"
else
echo ""
echo "❌ 带宽分析失败,请检查错误信息"
exit 1
fi
echo "=========================================="
echo "全部完成!"
echo "=========================================="
# 8.确保完全释放终端
stty echo 2>/dev/null
exit $RESULT_CODE
带宽计算脚本 tegra_monitor.py
#!/usr/bin/env python3
import re
import os
import sys
# ================== 从命令行读取参数 ==================
def print_usage():
print("用法: python3 tegra_monitor.py <MODEL_NAME> <INPUT_TOKENS>")
print("示例:")
print(" python3 tegra_monitor.py Qwen3-VL-2B-Instruct 512")
print(" python3 tegra_monitor.py Llama-2-7B 1024")
sys.exit(1)
if len(sys.argv) < 3:
print("错误: 缺少参数")
print_usage()
# 读取参数
MODEL_NAME = sys.argv[1]
INPUT_TOKENS = int(sys.argv[2])
# ================== 构建文件路径 ==================
# 构建输入日志文件名
log_file = f"{MODEL_NAME}/tegra_monitor_{INPUT_TOKENS}.log"
# 构建输出文件名
output_filename = f"bandwidth_result_{INPUT_TOKENS}.txt"
OUTPUT_FILE = f"{MODEL_NAME}/{output_filename}"
# 确保目录存在
os.makedirs(MODEL_NAME, exist_ok=True)
def log_print(*args, **kwargs):
"""既打印到屏幕,又写入文件的函数"""
print(*args, **kwargs)
content = " ".join(str(arg) for arg in args)
with open(OUTPUT_FILE, 'a', encoding='utf-8') as f:
f.write(content + "\n")
# 清空输出文件
with open(OUTPUT_FILE, 'w') as f:
f.write(f"# DDR Bandwidth Analysis Result\n")
f.write(f"# Model: {MODEL_NAME}\n")
f.write(f"# Log file: {log_file}\n")
f.write(f"# Input Tokens: {INPUT_TOKENS}\n")
f.write(f"# Generated at: {os.popen('date').read().strip()}\n")
f.write(f"# {'='*50}\n\n")
# ================== 主要处理逻辑 ==================
emc_freqs = []
try:
with open(log_file, 'r') as f:
lines = f.readlines()
except FileNotFoundError:
log_print(f"错误:日志文件不存在 - {log_file}")
log_print("请先运行 tegrastats 监控生成日志文件")
sys.exit(1)
for line in lines:
match = re.search(r'EMC_FREQ\s+\d+%@(\d+)', line)
if match:
freq_mhz = int(match.group(1))
emc_freqs.append(freq_mhz)
# 带宽 = 内存频率 (MHz) × 2 × 位宽 (Bits) ÷ 8 (把Bit变成Byte) ÷ 1000 (把MHz变成GB/s).
# 128-bit ddr 128/8=16
if emc_freqs:
peak_freq = max(emc_freqs)
avg_freq = sum(emc_freqs) / len(emc_freqs)
peak_bw = peak_freq *2 * 16 / 1000
avg_bw = avg_freq *2 * 16 / 1000
log_print(f"模型名称: {MODEL_NAME}")
log_print(f"采样点数: {len(emc_freqs)} 个")
log_print(f"EMC最高频率: {peak_freq} MHz")
log_print(f"EMC平均频率: {avg_freq:.0f} MHz")
log_print("-" * 30)
log_print(f"【DDR 峰值带宽】: {peak_bw:.2f} GB/s")
log_print(f"【DDR 平均带宽】: {avg_bw:.2f} GB/s")
# 额外输出汇总信息到文件头部
with open(OUTPUT_FILE, 'r+') as f:
content = f.read()
f.seek(0)
summary = f"""# ========== Summary ==========
# Model: {MODEL_NAME}
# Total samples: {len(emc_freqs)}
# Peak frequency: {peak_freq} MHz
# Average frequency: {avg_freq:.0f} MHz
# Peak bandwidth: {peak_bw:.2f} GB/s
# Average bandwidth: {avg_bw:.2f} GB/s
# {'='*50}
"""
f.write(summary + content)
else:
log_print("未能从日志中解析出 EMC_FREQ,请检查 tegrastats 版本。")
模型的token计算
由于TensorRT-Edge-LLM的 有自己的输入模板,所以模板会占用一部分token。以下是针对纯文本和混合模型的输入token计算。
纯文本输入 llm 的 token 计算 check_llm_length.py
from transformers import AutoTokenizer
# 调用模型自身的分词器
MODEL_PATH = "/home/pub/TensorRT-Edge-LLM/Qwen/Qwen2.5-0.5B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
# 用户输入文本
user_text = "用户文本"
# 标准对话消息
messages = [
{"role": "user", "content":user_text}
]
# 原生模板渲染,和TensorRT-Edge-LLM内部逻辑完全一致
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True # 开启:追加 <|im_start|>assistant\n
)
# 完整送入LLM的序列ids
input_ids = tokenizer.encode(prompt, add_special_tokens=False)
total_seq_len = len(input_ids)
# 单独统计用户文本自身token(仅作参考)
user_only_ids = tokenizer.encode(user_text, add_special_tokens=False)
user_only_len = len(user_only_ids)
print(f"==== Qwen2 纯文本Token统计 ====")
print(f"用户文本单独token数量:{user_only_len}")
print(f"【送入LLM Prefill总序列长度(框架校验值)】:{total_seq_len}")
print(f"差值 = 对话模板所有角色标记token总和")
视觉和文本混合输入的 llm token 计算 check_llm_length.py
import os
from transformers import AutoTokenizer
MODEL_PATH = "/home/pub/TensorRT-Edge-LLM/Qwen/Qwen3-VL-2B-Instruct"
# 1. 直接用 AutoTokenizer 加载本地分词器
try:
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True)
except Exception as e:
print(f"❌ 加载失败: {e}")
exit(1)
# 2. 你的纯文本内容 (从 JSON 的 "text" 字段提取)
user_text = """用户文本"""
user_text_tokens = tokenizer.encode(user_text, add_special_tokens=False)
user_text_tokens_len = len(user_text_tokens)
print("=" * 50)
print(f"✅ user_tex 输入 Token 数 = {user_text_tokens_len} 个")
print("=" * 50)
# 3. 图片产生的视觉 Token
image_width = 960
image_height = 960
# Qwen3-VL 视觉参数:patch_size=16, merge_size=2
grid_h = (image_height) // 16
grid_w = (image_width) // 16
total_patches = grid_h * grid_w
# merge_size=2 表示 2x2 合并,Token 数除以 4
image_tokens = total_patches // (2 * 2)
print(f"【 图像】产生的视觉 Token: {image_tokens} 个")
# 4. 查看模型输入框架,计算llm真实输入token数
# ============================
# 查看模型输入框架
# ============================
messages=[
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": [
{
"type": "image",
"image": "/home/pub/TensorRT-Edge-LLM/vlm_test/vlm_test_img/Cloud_woman_960x960.png"
},
{
"type": "text",
"text": user_text
}
]
}
]
# 获取框架原生模板文本
raw_template_str = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
print("====原生模板字符串====")
print(repr(raw_template_str))
# 把原生模板里【单个image_pad】替换成N个image_pad,模拟框架行为
real_str = raw_template_str.replace("<|image_pad|>", "<|image_pad|>"*image_tokens)
real_ids = tokenizer.encode(real_str, add_special_tokens=False)
print(f"\n【框架对齐版本】token总长度:{len(real_ids)}")
五、TesorRT-Edge-LLM v0.6.0 部署
支持 Qwne2_vl 模型的视觉分支onnx导出及模型转化
安装
Part 1: Quantization and tensorrt_edgellm (x86 Host with GPU / Edge Device)
Verify Your Prerequisites
# Check CUDA installation
nvcc --version
# Should show CUDA 12.x or 13.x
# Check GPU and available memory
nvidia-smi
# Look for GPU memory (e.g., "24576MiB" for 24GB)
# Check Python version
python3 --version
# Should show Python 3.10 or higher
下载资源库及依赖
创建好虚拟环境后,导入系统的tensorrt10.3,安装 torch-2.10.0-cp310-cp310-linux_aarch64.whl
# 安装源码
git clone -b v0.6.0 --single-branch https://github.com/NVIDIA/TensorRT-Edge-LLM
cd TensorRT-Edge-LLM
git submodule update --init --recursive
# 创建环境
conda create --name tensorrtllmv060 python=3.10.12
conda activate tensorrtllmv060
# 导入系统环境,系统tensorrt
export PYTHONPATH=/usr/lib/python3.10/dist-packages:$PYTHONPATH
# 安装 orin 适配的torch
pip install /home/pub/torch_for_jetpack6.2/torch-2.10.0-cp310-cp310-linux_aarch64.whl
# 安装依赖
pip3 install .
验证环境
# Test export tools
tensorrt-edgellm-export-llm --help
tensorrt-edgellm-quantize-llm --help
Part 2: C++ Runtime (Edge Device)
mkdir build
cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DTRT_PACKAGE_DIR=/usr \
-DCMAKE_TOOLCHAIN_FILE=cmake/aarch64_linux_toolchain.cmake \
-DEMBEDDED_TARGET=jetson-orin
LLM导出模型、量化模型(x86 / Jetson)
# 设置环境变量
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM
export PYTHONPATH=$WORKSPACE_DIR:$PYTHONPATH
export MODEL_NAME=Qwen2-VL-2B
# 设置 hugging face 镜像链接
export HF_ENDPOINT=https://hf-mirror.com
pip install huggingface-hub==1.5.0
# Quantize language model
tensorrt-edgellm-quantize-llm \
--model_dir Qwen/$MODEL_NAME \
--quantization fp8 \
--output_dir $MODEL_NAME/quantized
# Export language model
tensorrt-edgellm-export-llm \
--model_dir $MODEL_NAME/quantized \
--output_dir $MODEL_NAME/onnx/llm
# Export visual encoder
tensorrt-edgellm-export-visual \
--model_dir Qwen/$MODEL_NAME \
--output_dir $MODEL_NAME/onnx/visual
LLM转换模型(Jetson)
# 设置环境变量
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM
export PYTHONPATH=$WORKSPACE_DIR:$PYTHONPATH
export MODEL_NAME=Qwen2-VL-2B
# Build language model engine
./build/examples/llm/llm_build \
--onnxDir $WORKSPACE_DIR/$MODEL_NAME/onnx/llm \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm \
--maxBatchSize 1 \
--maxInputLen 1024 \
--maxKVCacheCapacity 4096
# Build visual encoder engine
./build/examples/multimodal/visual_build \
--onnxDir $WORKSPACE_DIR/$MODEL_NAME/onnx/visual \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/visual \
--minImageTokens 128 \
--maxImageTokens 512 \
--maxImageTokensPerImage 512
量化精度
orin 在 v0.6.0版本 只支持 int4_awq
| Inputs | Outputs | Description | |
|---|---|---|---|
|
| HuggingFace Model | Quantized Model | Quantize LLM models using NVIDIA ModelOpt. Supports FP8, INT4 AWQ, and NVFP4 quantization methods for memory reduction and performance optimization |
|
| HuggingFace/Quantized Model | ONNX Model | Export LLM models to ONNX format. Handles standard LLMs and EAGLE base models with precision-specific optimizations and graph surgery |
|
| VLM Model | Visual ONNX | Export visual encoders for multimodal models. Supports vision components with FP8 quantization and dynamic resolution |
|
| Base + Draft Models | Draft ONNX | Export EAGLE draft models for speculative decoding. Specialized export for EAGLE3 draft model architectures with vocabulary mapping support |
|
| Base + Draft Models | Quantized Draft | Quantize EAGLE draft models. Specialized quantization for draft models using base model inputs for calibration |
|
| ONNX Model | LoRA-enabled ONNX | Insert LoRA patterns into existing ONNX models. Adds dynamic LoRA support to ONNX models by modifying the computational graph |
|
| LoRA Weights | SafeTensors | Process LoRA weights for runtime use. Processes LoRA adapter weights according to TensorRT Edge-LLM specifications for runtime loading |
LLM模型推理(Jetson)
创建一个输入文件 $WORKSPACE_DIR/input_vlm.json,替换图片路径
{
"batch_size": 1,
"temperature": 1.0,
"top_p": 1.0,
"top_k": 50,
"max_generate_length": 128,
"requests": [
{
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": [
{
"type": "image",
"image": "/path/to/image.jpg"
},
{
"type": "text",
"text": "Please describe the image."
}
]
}
]
}
]
}
开始推理
# 设置环境变量
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM
export PYTHONPATH=$WORKSPACE_DIR:$PYTHONPATH
export MODEL_NAME=Qwen2-VL-2B
./build/examples/llm/llm_inference \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm \
--multimodalEngineDir $WORKSPACE_DIR/$MODEL_NAME/engines/visual \
--inputFile $WORKSPACE_DIR/input_vlm.json \
--outputFile $WORKSPACE_DIR/output_vlm.json
性能基准
llm性能测试
依旧可以通过llm_bench测试模型性能,但只支持llm。看参数命令,相当于运行了一遍trtexec进行模型推理。

visual 性能测试
视觉分支模型直接使用trtexec进行推理。
# 首先需要导入tensorrt-edge-llm的插件依赖,否则trtexec会找不到依赖
export LD_PRELOAD=/home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
# 开始推理
trtexec \
--loadEngine=xxx.engine \
--iterations=1000 \
--duration=0 \
--warmUp=1000 \
--useCudaGraph \
--noDataTransfers \
--shapes=
qwen2_vl视觉分支测试实践
tensorrt-edge-llm v0.6.0的版本暂不支持huggingface上已量化好的模型,也不支持视觉模块量化,且官方统计的visual encoder性能是未量化的。
模型导出
export WORKSPACE_DIR=/home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM
export PYTHONPATH=$WORKSPACE_DIR:$PYTHONPATH
export MODEL_NAME=Qwen2-VL-2B
tensorrt-edgellm-export-visual \
--model_dir Qwen/$MODEL_NAME \
--output_dir $MODEL_NAME/onnx/visual
模型转换
./build/examples/multimodal/visual_build \
--onnxDir $WORKSPACE_DIR/$MODEL_NAME/onnx/visual \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/visual \
--minImageTokens 128 \
--maxImageTokens 1024 \
--maxImageTokensPerImage 1024
查看引擎基础信息
polygraphy inspect model /home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM/Qwen2-VL-2B/engines/visual/visual/visual.engine --mode=engine

发现模型的最大最小输入的shape是设置的token大小的4倍,这是因为:
- --maxImageTokens是下采样后的最终视觉 token 数(输入给 LLM 的)。
- 引擎输入input(hw,1176)是下采样前的 Patch token 数(ViT 主干的实际输入)。
- qwen2_vl的视觉部分做了2D 下采样(空间分辨率减半,H/2 × W/2) 最终视觉 tokens = Patch tokens / 4
模型性能
设置需要输入到llm的ImageToken=900
trtexec \
--loadEngine=/home/pub/TensorRT-Edge-LLM_v0.6.0/TensorRT-Edge-LLM/Qwen2-VL-2B/engines/visual/visual/visual.engine \
--iterations=1000 \
--duration=0 \
--warmUp=1000 \
--useCudaGraph \
--noDataTransfers \
-shapes=input:3600x1176,rotary_pos_emb:3600x40,cu_seqlens:2,max_seqlen_carrier:3600

六、NVIDIA Nsight Systems
nsys需要在sudo权限下才能收集更全面的信息
nsys 分析 llm_inference的完整执行过程
# 命令一共是两部分、nsys监测 + 运行你原本的脚本
sudo nsys profile --trace=cuda,nvtx,osrt \
--output=llm_inference_profile \
--force-overwrite=true \
./build/examples/llm/llm_inference \
--engineDir $WORKSPACE_DIR/$MODEL_NAME/engines/llm \
--multimodalEngineDir $WORKSPACE_DIR/$MODEL_NAME/engines/visual \
--inputFile $WORKSPACE_DIR/vlm_test/input_vlm.json \
--outputFile $WORKSPACE_DIR/vlm_test/output_vlm.json
# sys 监测部分
sudo nsys profile --trace=cuda,nvtx,osrt \
--output=llm_inference_profile \
--force-overwrite=true
命令解析
--trace=cuda,nvtx,osrt:追踪 CUDA API、NVTX 标记(如果有)和操作系统运行时活动。
--output=llm_inference_profile:指定输出文件的前缀名。
--force-overwrite=true:若输出文件已存在则直接覆盖。
其余部分是 llm_inference 程序及其参数
nsys 分析 trtexec 的完整执行过程
# 如果是 TensorRT-Edge-LLM 生成的 onnx 模型转的模型 会报 Cannot find plugin 的错误
export LD_PRELOAD=/home/pub/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
# nsys 生成分析数据
sudo nsys profile -o /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/profile \
--capture-range=cudaProfilerApi \
--cuda-graph-trace=node \
trtexec \
--loadEngine=/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/llm/model.onnx.engine \
--warmUp=0 \
--duration=0 \
--iterations=50
# 这样也可以
sudo nsys profile -o /home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/profile \
--capture-range=cudaProfilerApi \
--cuda-graph-trace=node \
trtexec \
--loadEngine=/home/pub/TensorRT-Edge-LLM/Qwen3-VL-2B-Instruct/oss_engine/tokens1000/visual/model.onnx.engine \
--warmUp=0 \
--duration=0 \
--iterations=50
生成 Nsight System GUI可以直接打开的.nsys-rep数据
只生成 .qdstrm 文件而没有自动转为 .nsys-rep,通常是因为 nsys 找不到或无法运行它的格式转换工具 QdstrmImporter。 .qdstrm 是一个中间格式的临时文件。
nsys profile 正常结束时会调用 QdstrmImporter 将 .qdstrm 转换为最终的 .nsys-rep 报告。如果转换失败,就会只剩下 .qdstrm 文件。
# QdstrmImporter
find / -name QdstrmImporter 2>/dev/null
# QdstrmImporter 在.qdstrm 文件同目录下生成一个同名的 .nsys-rep 文件
/path/to/QdstrmImporter -i /path/to/your/profile.qdstrm
七、ORIN NX 配置交换空间
建议配置高质量的 NVMe SSD 作为 Swap 分区,以防内存溢出导致进程被杀。
orin nx 设备上已经设置了近 8G 的 swap 分区,但无法支持大模型。
检查当前swap状态
swapon --show # 查看激活的swap设备
free -h # 查看内存和swap总大小

显示Jetson Orin 当前使用的是 ZRAM(压缩内存交换),而不是磁盘上的交换文件。
ZRAM 的原理:它从你的物理内存(15GB)中划出一部分空间,经过压缩后当作交换分区使用。由于压缩比通常可达 2~3 倍,所以它提供了 7.6GB 的交换空间,但实际只占用物理内存约 2~3GB。
优势与局限:ZRAM 速度极快(因为还是在内存里读写),但它无法无限扩大,因为它本质上是“借用”物理内存。你看到的 Swap 7.6G,实际上已经是当前配置的容量上限了。
创建磁盘交换文件
将文件放在 SSD 或 NVMe 。
# 创建8GB大小的交换文件
sudo fallocate -l 16G /swapfile
# 设置文件权限(仅root可读写,保障安全)
sudo chmod 600 /swapfile
# 格式化为Swap分区
sudo mkswap /swapfile
# 立即启用交换空间
sudo swapon /swapfile
八、临时退出图形界面
- 按
Ctrl + Alt + F3(或F4、F5等)。这会切换到另一个纯文本的控制台(tty)。你需要用你的用户名和密码重新登录一次。 - 登录后,执行命令关闭图形桌面服务,需要再输入一次密码。
sudo systemctl stop gdm3 -
查看gdm3状态
systemctl status gdm3 -
jtop 查看当前内存占用情况
jtop -
返回图形界面
sudo systemctl start gdm3 - 然后按
Ctrl + Alt + F1(或F2,取决于你的系统配置)通常就可以切换回图形登录界面。
九、功耗 & 性能模式锁满算力
测试模型最佳性能需要开启满功耗模式(MAXN)和 GPU 频率锁定(因为ORIN会动态调频)
1.开启MAXN(命令或者手动选择Power mode)
sudo nvpmodel -m 0
2.锁定CPU/GPU/DLA/PVA全部最高频率
sudo jetson_clocks
3.查看当前 GPU 频率
sudo jetson_clocks --show
![]()
开发板默认是DVFS(Dynamic voltage and frequency scaling (DVFS) is the adjustment of power and speed settings on a computing device’s various processors)模式,
长时间满载会触发热节流,温度达到上限则强制降频。如果需要在某个程序运行时使用高性能模式,程序运行结束后调回DVFS模式,请跟随:
1.保存当前的DVFS模式
sudo jetson_clocks --store


2.开启锁频,程序执行结束后,恢复DVFS模式
sudo jetson_clocks --restore
十、Qwen3-2B-VL-Instruct 导出模型维度一览
vision Input
| 张量名称 | 原动态维度 | 500 tokens 对应 shape | 修改逻辑 |
|---|---|---|---|
| input | [total_tokens, 1536] | [500, 1536] | 第一维是视觉 token 总数,为核心修改项;隐层维度 1536 固定不变 |
| rotary_pos_emb | [total_tokens, 32] | [500, 32] | 旋转位置编码张量,第一维必须和输入 token 数严格对齐;编码维度 32 固定 |
| cu_seqlens | [batch_p1] | [2] | 累积序列长度张量,形状仅和 batch 数相关(单 batch = batch+1 = 2),形状本身不随 token 数变化;张量内部的数值需要同步设为 [0, 500],和输入长度匹配 |
| max_seqlen_carrier | [max_seqlen] | [500] | 最大序列长度载体,维度值等于支持的最大视觉 token 数,需和输入长度对齐 |
| fast_pos_embed_idx | [4, total_tokens] | [4, 500] | 快速位置嵌入索引,第一维组数 4 固定,第二维对齐 token 总数 |
| fast_pos_embed_weight | [4, total_tokens] | [4, 500] | 快速位置嵌入权重,和索引张量形状一一对应,第二维同步修改 |
参考输入
静态
shapes=input:500x1536,rotary_pos_emb:500x32,cu_seqlens:2,max_seqlen_carrier:500,fast_pos_embed_idx:4x500,fast_pos_embed_weight:4x500
动态
minShapes=input:1x1536,rotary_pos_emb:1x32,cu_seqlens:2,max_seqlen_carrier:1,fast_pos_embed_idx:4x1,fast_pos_embed_weight:4x1 \
optShapes=input:500x1536,rotary_pos_emb:500x32,cu_seqlens:2,max_seqlen_carrier:500,fast_pos_embed_idx:4x500,fast_pos_embed_weight:4x500 \
maxShapes=input:1000x1536,rotary_pos_emb:1000x32,cu_seqlens:2,max_seqlen_carrier:1000,fast_pos_embed_idx:4x1000,fast_pos_embed_weight:4x1000
llm Input
更多推荐


所有评论(0)