news 2026/9/7 19:01:05

vLLM 中 Qwen2.5-Omni 多模态离线推理实战:Thinker-Only 模式、提示词格式与音频视频混合输入

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
vLLM 中 Qwen2.5-Omni 多模态离线推理实战:Thinker-Only 模式、提示词格式与音频视频混合输入

vLLM 中 Qwen2.5-Omni 多模态离线推理实战:Thinker-Only 模式、提示词格式与音频视频混合输入

【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm

本文以 vLLM 仓库中 Qwen2.5-Omni 离线推理示例文档 为核心,系统讲解如何在 vLLM 中只运行 Qwen2.5-Omni 的 Thinker(理解端)完成音频、图像、视频及混合模态的离线推理。读完本文,你将掌握该模型正确的提示词占位符格式、limit_mm_per_prompt等关键引擎参数配置,以及use_audio_in_video(视频音轨随视频一起输入)这一进阶用法在源码层面的实现原理。

1. 什么是 "Thinker Only" 推理

Qwen2.5-Omni 官方完整架构包含负责感知的 Thinker 与负责语音生成的 Talker 两部分。在 vLLM 中,注册到模型注册表的推理实现是Thinker 部分Qwen2_5OmniModelQwen2_5OmniForConditionalGeneration两个架构名都统一映射到qwen2_5_omni_thinker模块下的Qwen2_5OmniThinkerForConditionalGeneration,见 模型注册表。这意味着:

  • 输入可以是文本、音频、图像、视频(或其中任意组合);
  • 输出只有文本回复,不生成语音;
  • 核心实现位于 qwen2_5_omni_thinker.py,从源码结构看,其视觉编码复用了qwen2_5_vlQwen2_5_VisionTransformer,音频编码复用 transformers 的Qwen2_5OmniAudioEncoder,并参考qwen2_audio的特征长度计算逻辑(文件头部导入清单 L52-L65 可印证)。

示例目录 examples/generate/multimodal/qwen2_5_omni/ 提供了两类入口:

  1. 本目录下的 only_thinker.py:面向音频 + 图像 + 视频等多模态组合场景;
  2. 上层的 audio_language_offline.py 与 vision_language_offline.py:面向单一模态场景,通过--model-type qwen2_5_omni复用。

2. 混合模态推理:only_thinker.py 的运行方式

原文档给出的三种典型命令如下:

# 音频 + 图像 + 视频(混合模态) python examples/generate/multimodal/qwen2_5_omni/only_thinker.py \ -q mixed_modalities # 从单个视频文件中同时读取视觉与音频输入 python examples/generate/multimodal/qwen2_5_omni/only_thinker.py \ -q use_audio_in_video # 多段音频输入 python examples/generate/multimodal/qwen2_5_omni/only_thinker.py \ -q multi_audios

脚本的-q / --query-type参数在 query_map 中定义了四种取值:

查询类型输入组合说明
mixed_modalities(默认)音频 + 图像 + 视频一次提示词同时携带三种模态
use_audio_in_video视频(含音轨)视觉与音频都取自同一视频文件
multi_audios2 段音频比较两段音频是否相同
multi_images2 张图像比较两张图像的差别

另有--seed参数(默认0),用于在初始化vllm.LLM时固定随机种子。

2.1 引擎与采样参数

main() 函数 中的关键配置如下:

llm = LLM( model="Qwen/Qwen2.5-Omni-7B", max_model_len=5632, # 单条请求最大上下文长度 max_num_seqs=5, # 引擎最大并发序列数 limit_mm_per_prompt=query_result.limit_mm_per_prompt, # 每种模态每请求的最大数量 seed=args.seed, ) sampling_params = SamplingParams(temperature=0.2, max_tokens=64)

几个要点(脚本注释 L23-L25 有明确说明):

  • max_num_seqsmax_model_len的默认值在低显存 GPU 上可能 OOM;示例中的取值是在单张 NVIDIA L4上验证可运行的;
  • temperature=0.2是为了在批量推理时即使提示词相同也能得到有差异的输出,实际生产可按需调低或改为贪心;
  • limit_mm_per_prompt由每个查询自行声明,例如混合模态查询声明为{"audio": 1, "image": 1, "video": 1},多音频查询声明为{"audio": 2}。它决定了处理器预分配的占位符数量上限,是 vLLM 多模态请求的必要参数之一。

2.2 提示词格式:占位符必须与多模态数据一一对应

以混合模态查询 get_mixed_modalities_query() 为例,提示词结构为:

<|im_start|>system {系统提示词}<|im_end|> <|im_start|>user <|audio_bos|><|AUDIO|><|audio_eos|> <|vision_bos|><|IMAGE|><|vision_eos|> <|vision_bos|><|VIDEO|><|vision_eos|> {问题文本}<|im_end|> <|im_start|>assistant

其中系统提示词固定为:

You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.

要点:

  • 每多一个模态项,就要在提示词中多写一组对应的占位符序列(<|audio_bos|><|AUDIO|><|audio_eos|>/<|vision_bos|><|IMAGE|><|vision_eos|>/<|vision_bos|><|VIDEO|><|vision_eos|>),占位符数量必须与multi_modal_data中实际提供的数据条数严格一致
  • multi_modal_data的键为"audio""image""video",值可为单个数据(图像用convert_image_mode(..., "RGB")转 RGB 模式;音频为(波形, 采样率)元组)或列表(多音频、多图像场景,见 multi_audios 与 multi_images 的构造)。

3. 进阶用法:use_audio_in_video(视频音轨随帧输入)

use_audio_in_video是该模型比较有特色的用法:不是分别传入视频和音频,而是从同一个视频文件中同时抽取画面帧和音轨,让模型在理解画面内容的同时把宝宝说话的内容转写出来。get_use_audio_in_video_query() 的构造逻辑是:

asset = VideoAsset(name="baby_reading", num_frames=16) audio = asset.get_audio(sampling_rate=16000) # 从视频抽取 16kHz 音轨 inputs = { "prompt": prompt, # 只包含一组 <|VIDEO|> 占位符 "multi_modal_data": { "video": asset.np_ndarrays, # 16 帧画面 "audio": audio, # 同一视频的音频 }, "mm_processor_kwargs": { "use_audio_in_video": True, # 关键开关 }, }

注意此时提示词里只有一组<|vision_bos|><|VIDEO|><|vision_eos|>,并没有单独的音频占位符——音频会被交错合并进视频 token 序列

从源码看,模型实现专门处理了这条路径:

  • Qwen2_5OmniThinkerMultiModalProcessor 会读取mm_kwargs中的use_audio_in_video(L588-L608),并在该开关开启且提示词中含音频占位符时调用专用的omni_get_updates_use_audio_in_video逻辑重算占位符替换(L632-L639);
  • 处理器会把use_audio_in_video编码为张量随多模态特征一起传递(L889-L890),并建立"视频偏移 -> 对应音频特征长度"的映射,说明音频是按视频分块与画面交错的(L1175-L1268);
  • 前向阶段有两个专门辅助函数:check_interleaved_audio_video用于判断某个视频片段内视频/音频 token 是否确实交错排列(L136-L180),merge_interleaved_embeddings负责把分别编码的视频、音频(以及可能共存的图像)embedding 按modality属性散射回正确的交错位置(L183-L209)。

从源码结构看,这套设计还考虑了多视频请求的边界情况:交错检查是按每个视频片段的局部 span 独立进行,避免多个视频之间的边界 token 导致整条序列被误判为非交错(check_interleaved_audio_video的 docstring L142-L152 明确解释了这一点)。此外源码中对use_audio_in_video=True有"音频与视频数量必须相等"的校验(L529 附近),这是使用该功能时需要注意的约束。

4. 单一模态推理:audio_language_offline.py 与 vision_language_offline.py

原文档指出也可以用通用多模态脚本单独测试某一类模态:

# 处理音频输入 python examples/generate/multimodal/audio_language_offline.py \ --model-type qwen2_5_omni # 处理图像输入 python examples/generate/multimodal/vision_language_offline.py \ --modality image \ --model-type qwen2_5_omni # 处理视频输入 python examples/generate/multimodal/vision_language_offline.py \ --modality video \ --model-type qwen2_5_omni

这两个脚本内置了多种模型的适配函数,按--model-type分发。

4.1 音频路径:run_qwen2_5_omni

audio_language_offline.py 中的 run_qwen2_5_omni 的实现要点:

  • EngineArgsmax_model_len=4096max_num_seqs=5limit_mm_per_prompt={"audio": audio_count}
  • 音频占位符按数量重复:<|audio_bos|><|AUDIO|><|audio_eos|>\n
  • 提示词使用与only_thinker.py相同的 Qwen 系统提示词模板;
  • --num-audios支持0/1/2(参数定义),问题文本随音频数量切换(question_per_audio_count),例如单音频默认为 "What is recited in the audio?";
  • 脚本主流程还会把未使用的模态上限强制置零(default_limits = {"image": 0, "video": 0, "audio": 0}再与模型自身的限制合并,L586-L590),注释说明这是为了省显存——这是一个值得借鉴的实践:按需关闭不使用的模态配额。

4.2 图像/视频路径:vision_language_offline.py

vision_language_offline.py 通过--modality image|video选择输入类型,Qwen2.5-Omni 走其中的qwen2_5_omni分支。图像输入经由ImageAsset/convert_image_mode处理,视频输入经由VideoAsset按指定帧数采样为np_ndarrays,与only_thinker.py的用法保持一致。

5. 关键参数小结与适用前提

参数示例取值作用与注意事项
max_model_len5632(only_thinker.py)/ 4096(audio 脚本)上下文上限;视频帧多、像素高时占位 token 会显著膨胀,需留足余量
max_num_seqs5并发序列数上限,直接影响显存占用
limit_mm_per_prompt{"audio": 1, "image": 1, "video": 1}每种模态每请求允许的最大条数,必须 ≥ 实际提供的数量
mm_processor_kwargs.use_audio_in_videoTrue让音频随视频分块交错输入,要求音频/视频数量匹配
seed/temperature0 / 0.2控制可复现性与输出多样性,与推理正确性无关

适用前提:示例默认加载Qwen/Qwen2.5-Omni-7B,需要能访问该模型权重;示例参数已在单张 L4 上验证,显存更小的环境应相应下调max_model_lenmax_num_seqs

6. 延伸阅读

  • 同目录体系下的 qwen3_omni/only_thinker.py 展示了 Qwen3-Omni 思考器的类似用法,对应模型实现为 qwen3_omni_moe_thinker.py,可对比演进差异;
  • 多模态输入的整体设计(multi_modal_datalimit_mm_per_prompt、占位符替换机制)可参考 多模态输入文档 与 mm_processing 设计文档。

【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 18:59:53

单片机毕设项目:基于 STM32 或 51 单片机的步进电机驱动智能摇床控制系统设计 基于 STM32 或 51 单片机的分贝采集婴儿哭闹识别监护装置设计

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/9/7 18:59:18

基于ThinkPHP+Vue的中药仓库管理系统设计与实践

做药店中药仓库管理系统这件事&#xff0c;是我帮一个做医药流通的朋友处理库存管理需求时真正动起来的。当时他们还在用Excel记录几百种中药饮片的进销存&#xff0c;效期、批次、养护记录全靠人工翻台账&#xff0c;一到盘点就头大。我调研了一圈之后&#xff0c;定了thinkph…

作者头像 李华
网站建设 2026/9/7 18:57:28

光伏电站监控大屏设计与实践:打破信息孤岛,实现一屏运维

1. 光伏电站碰上"信息孤岛"&#xff1a;为什么我们最终决定上大屏1.1 上百台逆变器分布在几公里山头上&#xff0c;靠什么掌握全局我做光伏电站运营这些年&#xff0c;感受最深的一件事是&#xff1a;电站越大&#xff0c;越容易"看不见"。组件铺在山坡上、…

作者头像 李华
网站建设 2026/9/7 18:56:41

Zynq xc7z020与复旦微FM25F32 QSPI Flash烧写配置实战指南

简介&#xff1a;针对Xilinx公司Zynq-7000系列现场可编程门阵列在国产化替代中&#xff0c;开发环境无法识别复旦微电子Nor型QSPI闪存FM25F32的问题&#xff0c;这套基于XC7Z020器件的验证工程给出了完整解决思路。作者利用自编烧写测试程序&#xff0c;绕过开发套件自带工具的…

作者头像 李华