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_5OmniModel与Qwen2_5OmniForConditionalGeneration两个架构名都统一映射到qwen2_5_omni_thinker模块下的Qwen2_5OmniThinkerForConditionalGeneration,见 模型注册表。这意味着:
- 输入可以是文本、音频、图像、视频(或其中任意组合);
- 输出只有文本回复,不生成语音;
- 核心实现位于 qwen2_5_omni_thinker.py,从源码结构看,其视觉编码复用了
qwen2_5_vl的Qwen2_5_VisionTransformer,音频编码复用 transformers 的Qwen2_5OmniAudioEncoder,并参考qwen2_audio的特征长度计算逻辑(文件头部导入清单 L52-L65 可印证)。
示例目录 examples/generate/multimodal/qwen2_5_omni/ 提供了两类入口:
- 本目录下的 only_thinker.py:面向音频 + 图像 + 视频等多模态组合场景;
- 上层的 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_audios | 2 段音频 | 比较两段音频是否相同 |
multi_images | 2 张图像 | 比较两张图像的差别 |
另有--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_seqs与max_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 的实现要点:
EngineArgs:max_model_len=4096、max_num_seqs=5、limit_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_len | 5632(only_thinker.py)/ 4096(audio 脚本) | 上下文上限;视频帧多、像素高时占位 token 会显著膨胀,需留足余量 |
max_num_seqs | 5 | 并发序列数上限,直接影响显存占用 |
limit_mm_per_prompt | 如{"audio": 1, "image": 1, "video": 1} | 每种模态每请求允许的最大条数,必须 ≥ 实际提供的数量 |
mm_processor_kwargs.use_audio_in_video | True | 让音频随视频分块交错输入,要求音频/视频数量匹配 |
seed/temperature | 0 / 0.2 | 控制可复现性与输出多样性,与推理正确性无关 |
适用前提:示例默认加载Qwen/Qwen2.5-Omni-7B,需要能访问该模型权重;示例参数已在单张 L4 上验证,显存更小的环境应相应下调max_model_len或max_num_seqs。
6. 延伸阅读
- 同目录体系下的 qwen3_omni/only_thinker.py 展示了 Qwen3-Omni 思考器的类似用法,对应模型实现为 qwen3_omni_moe_thinker.py,可对比演进差异;
- 多模态输入的整体设计(
multi_modal_data、limit_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),仅供参考