使用 TensorRT-Edge-LLM 0.9.0 在端侧测试 Qwen3-Omni

使用 TensorRT-Edge-LLM 0.9.0 在端侧测试 Qwen3-Omni

本文介绍如何用 NVIDIA TensorRT-Edge-LLM(https://github.com/NVIDIA/TensorRT-Edge-LLM.git)

**v0.9.0** 部署 **Qwen3-Omni-30B-A3B-Instruct**,并在一组按时间排序的 RGB 帧与原始 PCM 音频上发起一次多模态 `handleRequest`------与我们在 Jetson Thor 上验证的小型 C++ 样例一致。


1. 什么是 TensorRT-Edge-LLM?

**TensorRT Edge-LLM** 是 NVIDIA 面向嵌入式平台(Jetson、DRIVE、DGX Spark)的

高性能 **C++** 大模型推理运行时,覆盖 LLM、VLM 与 Omni 等模型。

```bash

git clone https://github.com/NVIDIA/TensorRT-Edge-LLM.git

cd TensorRT-Edge-LLM

git checkout v0.9.0 # 或仓库中对应的 0.9.0 release tag

```

为什么适合端侧

  • **TensorRT + CUDA kernel**,追求低延迟

  • **量化**(如 NVFP4),便于把大模型装进设备显存

  • **面向量产的 C++ 运行时**(部署阶段可不依赖 Python)

  • 端到端链路:Hugging Face 权重 → ONNX → TensorRT engine → C++ API

三阶段流水线

```

Hugging Face 模型

→ 量化 / 导出(Python 工具链)

→ ONNX 图 + tokenizer / chat template

→ engine 构建(llm_build / visual_build / audio_build)

→ TensorRT engines

→ C++ 运行时(LLMInferenceRuntime::handleRequest)

```

支持的模型族包括 Qwen、Llama、InternVL、Phi、Gemma、Nemotron,以及 Qwen3-Omni

等 Omni 变体。完整矩阵与 JetPack / DriveOS 要求见项目文档。


2. Qwen3-Omni-30B-A3B-Instruct:从 HF 到 ONNX 再到 engine

2.1 模型概览

Qwen3-Omni-30B-A3B-Instruct(https://huggingface.co/Qwen/Qwen3-Omni-30B-A3B-Instruct)

是统一的多模态 MoE 模型,可接收 **文本 + 音频 + 图像/视频**,并输出 **文本**(可选地通过 Talker 路径输出语音)。

在 TensorRT-Edge-LLM 中,Omni 拆成 **六个 engine**:

| Engine | 作用 |

|--------|------|

| **Thinker** | 文本解码器------生成助手 token |

| **Talker** | Codec token 解码器(语音路径) |

| **CodePredictor** | Codec 上的小型预测头 |

| **Audio encoder** | Whisper 风格 mel → 音频嵌入 |

| **Visual encoder** | Qwen3-VL 风格 ViT → 视觉嵌入 |

| **Code2Wav** | Codec token → 24 kHz PCM(TTS) |

若只做 **文本输出** 的多模态测试(描述视频 + 总结音频),通常只需要

**Thinker + audio encoder + visual encoder**。仅在需要语音输出时,才需要

Talker / CodePredictor / Code2Wav。

2.2 环境变量

```bash

export WORKSPACE_DIR=$HOME/tensorrt-edgellm-workspace

mkdir -p $WORKSPACE_DIR

export OMNI_MODEL=Qwen3-Omni-30B-A3B-Instruct

export HF_ROOT=Qwen/$OMNI_MODEL # 或本地 HF 快照目录

export ONNX=WORKSPACE_DIR/OMNI_MODEL/onnx

export ENG=WORKSPACE_DIR/OMNI_MODEL/engines

export QUANT_ROOT=WORKSPACE_DIR/OMNI_MODEL/nvfp4

```

请先安装并编译 **TensorRT-Edge-LLM 0.9.0**(见该 tag 对应的

Installation Guide(https://github.com/NVIDIA/TensorRT-Edge-LLM))。

2.3 量化(NVFP4 Thinker + Talker)

```bash

tensorrt-edgellm-quantize qwen3-omni \

--model_dir $HF_ROOT \

--output_dir $QUANT_ROOT \

--talker_num_audio 150 \

--talker_num_image 150 \

--talker_num_text 200

```

输出:

```

$QUANT_ROOT/

├── thinker/ # NVFP4 文本 MoE(Thinker)

└── talker/ # NVFP4 Talker 主干

```

视觉 / 音频 / code2wav 编码器通常保持 FP16,并从原始 HF root 导出。

2.4 导出 ONNX

```bash

mkdir -p $ONNX

Thinker

tensorrt-edgellm-export QUANT_ROOT/thinker ONNX/thinker

Talker(并从完整 HF root 提取 projection sidecar)

tensorrt-edgellm-export \

--talker-sidecar-from $HF_ROOT \

QUANT_ROOT/talker ONNX/talker

Visual + audio(以及可选的 TTS 组件)

tensorrt-edgellm-export \

--components visual,audio,code2wav,code_predictor \

HF_ROOT ONNX/multimodal

```

期望目录结构(简化):

```

$ONNX/

├── thinker/llm/ # model.onnx、config.json、tokenizer、chat template

├── talker/llm/ # 另含 hidden_projection / text_projection

└── multimodal/

├── audio/

├── visual/

├── code2wav/

└── code_predictor/

```

2.5 构建 TensorRT engine

```bash

以下 profile 与 thirdpart/engine/*/config.json 中的 builder_config 一致。

Thinker

./build/examples/llm/llm_build \

--onnxDir $ONNX/thinker/llm \

--engineDir $ENG/thinker \

--maxBatchSize 2 \

--maxInputLen 131072 \

--maxKVCacheCapacity 135168

Talker(仅文本多模态时可省略)

./build/examples/llm/llm_build \

--onnxDir $ONNX/talker/llm \

--engineDir $ENG/talker \

--maxBatchSize 2 \

--maxInputLen 131072 \

--maxKVCacheCapacity 135168

Audio encoder(maxTimeSteps=46875 约对应 16 kHz 下 ~5 分钟音频)

./build/examples/multimodal/audio_build \

--onnxDir $ONNX/multimodal/audio \

--engineDir $ENG/multimodal/audio \

--minTimeSteps 100 \

--maxTimeSteps 46875 \

--minCodeLen 1 \

--optCodeLen 300 \

--maxCodeLen 2000

Visual encoder

./build/examples/multimodal/visual_build \

--onnxDir $ONNX/multimodal/visual \

--engineDir $ENG/multimodal/visual \

--minImageTokens 4 \

--maxImageTokens 1024 \

--maxImageTokensPerImage 512

```

这些构建参数与 `thirdpart/engine` 中已发布的 engine 一致。若需更小显存占用,可自行下调。

运行时较常用的目录布局:

```

$ENG/

├── thinker/ # llm.engine、tokenizer、processed_chat_template.json

└── multimodal/

├── audio/ # audio_encoder.engine

└── visual/ # visual.engine

```


3. 用图片序列 + PCM 做推理(Edge-LLM 0.9.0)

本节对应基于 **TensorRT-Edge-LLM 0.9.0** 的小型 C++ 样例(`avi_inference`):

在一次 `LLMInferenceRuntime::handleRequest` 中同时送入:

  • 按时间排序的 RGB 帧(作为短视频),

  • 16 kHz 单声道 float32 PCM,

  • 文本 prompt。

3.1 输入

| 模态 | 示例 | 说明 |

|------|------|------|

| 视频帧 | `order_food/0.png ... 5.png` | 分辨率一致,按时间顺序 |

| 音频 | `sess-....f32le` | 原始单声道 **f32le**,16 kHz(不是 WAV 容器) |

| Prompt | `what did you see and hear?` | 也可要求输出带 `Video:` / `Audio:` 分段 |

PCM 体量自检示例:`30 s × 16000 × 4 bytes = 1 920 000` bytes。

3.2 构造请求(C++ 示意)

```cpp

#include "runtime/llmInferenceRuntime.h"

#include "runtime/imageUtils.h"

#include "runtime/audioUtils.h"

#include "runtime/audioLoader.h"

#include "common/trtUtils.h"

using namespace trt_edgellm::rt;

// 1) 视频:帧堆叠 → ImageData T,H,W,3 uint8 RGB

auto video = imageUtils::loadVideoFromFrames(framePaths, /*fps=*/0.2);

// 2) 音频:host 侧单声道 FP32 @ 16 kHz

audioUtils::AudioData audio;

audio.pcm = std::make_shared<audio::AudioPCM>();

audio.pcm->samples = /* load f32le */;

audio.pcm->sampleRate = 16000;

audio.pcm->numChannels = 1;

audio.sampleRate = 16000;

// 3) 一条 user 消息:视觉 + 音频 + 文本

LLMGenerationRequest request;

request.applyChatTemplate = true;

request.addGenerationPrompt = true;

request.generateAudio = false; // 只要文本回答

request.maxGenerateLength = 512;

request.requests.resize(1);

Message user;

user.role = "user";

// 重要:为 Qwen3-Omni MRoPE 包上 start/end 标记

user.contents.push_back({"text", "<|vision_start|>"});

user.contents.push_back({"video", "frames"});

user.contents.push_back({"text", "<|vision_end|>"});

user.contents.push_back({"text", "<|audio_start|>"});

user.contents.push_back({"audio", ""});

user.contents.push_back({"text", "<|audio_end|>"});

user.contents.push_back({"text", "what did you see and hear?"});

request.requests0.messages.push_back(std::move(user));

request.requests0.imageBuffers.push_back(std::move(video));

request.requests0.audioBuffers.push_back(std::move(audio));

// 4) Runtime

cudaStream_t stream;

cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking);

auto plugin = trt_edgellm::loadEdgellmPluginLib();

LLMInferenceRuntime runtime(

"/path/to/engine/thinker",

"/path/to/engine/multimodal",

/*loraMap=*/{},

stream);

LLMGenerationResponse response;

runtime.handleRequest(request, response, stream, /*returnHiddenStates=*/false);

std::cout << response.outputTexts0 << std::endl;

```

**输入约定**

  • 帧必须是 **uint8 RGB**;均值/方差归一化在 ViT runner 内部完成。

  • Qwen3-Omni 音频输入为 **16 kHz 单声道原始 FP32 PCM**;mel 由 audio runner 内部提取。

  • 消息里 `video` / `audio` 类型条目须与 `imageBuffers` / `audioBuffers` **一一对应**。

  • 若 `processed_chat_template.json` 只插入裸的 `<|video_pad|>` / `<|audio_pad|>`,

请自行注入 `<|vision_start|>...<|vision_end|>` 与 `<|audio_start|>...<|audio_end|>`

(Omni 的 MRoPE 需要这些包裹符)。

3.3 实用限制:视觉 token 预算

视觉 engine 有 max HW / image-token 上限。高分辨率长帧序列可能超限

(例如 6×720p → ViT token 过多)。**不重建 engine** 时的缓解办法:

  • 对帧做子采样(如 `--max-frames 4`),或

  • 在上游先缩小分辨率,

使总视觉 token 落在 engine 限制内。

3.4 命令行示例

```bash

export EDGELLM_PLUGIN_PATH=/path/to/tensorrt-edge-llm-build/libNvInfer_edgellm_plugin.so.1.0

export LD_LIBRARY_PATH=/path/to/tensorrt-edge-llm-build:$LD_LIBRARY_PATH

./avi_inference \

--frames-dir /path/to/frames \

--pcm /path/to/audio.f32le \

--thinker /path/to/engine/thinker \

--multimodal /path/to/engine/multimodal \

--prompt "请严格分两段回答,标题为 Video 与 Audio。Video:描述画面。Audio:转写你听到的内容。" \

--fps 0.2 \

--max-frames 4 \

--max-new-tokens 512 \

--output-dir ./outputs

```

3.5 返回结果是什么

API 在 `response.outputTexts0` 中返回 **一个** 字符串,并没有单独的

`video_result` / `audio_result` 字段。两种模态在一次 Thinker 解码中融合。

若希望结果更易读,可在 prompt 中要求模型按段落标注。

较好的回答形态示例:

```text

Video

... 来自帧的场景描述 ...

Audio

... 来自 PCM 的转写 / 摘要 ...

```


小结

  1. **TensorRT-Edge-LLM 0.9.0** 是面向 Jetson 类 GPU 的端侧 LLM / VLM / Omni C++ 栈。

  2. **Qwen3-Omni** 以多 engine 图部署:量化 → 导出 ONNX → `*_build` 生成 engine。

  3. **一次 `handleRequest`** 即可同时消费帧序列 + PCM + 文本并返回联合回答------

很适合端侧"你看到了什么、听到了什么?"类应用。

参考

相关推荐
stormzhangV2 小时前
2026 年 8 月,我的最新 AI 装机单
人工智能·openai·ai编程
暴躁的小鸟2 小时前
附近口碑好的斜视配镜训练的眼视光中心
人工智能·python·深度学习
deepseek232 小时前
OpenAI 首次为自家模型踩刹车:Astra「无法排除关键网络能力」,Preparedness Framework 第一次真的咬人
人工智能·网络安全·ai agent
zhangfeng11332 小时前
免费 GPU 资源清单(按用途选)包括国产显卡 和 amd显卡 英伟达v100等
人工智能·ai编程·显卡
今天的砖头有点烫手啊2 小时前
AI Agent 开发实战(十):Agent 设计模式(ReAct / Plan-Execute / Reflection)
人工智能·react.js·设计模式
用户8181870627462 小时前
第1章 大模型的本质:为什么"预测下一个词"能做出这么多事
人工智能
敲代码的玉米C2 小时前
让两个模型一写一审
前端·人工智能·架构
程序员cxuan2 小时前
Claude Opus 5 的系统提示词被扒出来了
人工智能·后端·程序员
董员外2 小时前
RAG 系统进化论(十):可运营 RAG,从原型到长期运行的知识系统
人工智能·后端·设计模式