[Bug]: A multimodal item can still be split across prefill chunks with disable_chunked_mm_input=True

该问题出现在 vLLM 调度器启用 disable_chunked_mm_input=True (即禁止多模态输入分块)时,单个多模态 item 仍可能被拆到多个 prefill chunk 中执行;优先排查 self.scheduler_config.disable_chunked_mm_inpu

快速结论:该问题出现在 vLLM 调度器启用 disable_chunked_mm_input=True(即禁止多模态输入分块)时,单个多模态 item 仍可能被拆到多个 prefill chunk 中执行;优先排查 self.scheduler_config.disable_chunked_mm_input 守卫中的边界判断(是否存在 off-by-one)。

适用环境:Issue 中确认在 vLLM 生产 Docker 镜像 vllm/vllm-openai:v0.26.0-cu129-ubuntu2404、CUDA 12.9.1、构建 commit ffd46bfab2128bb84146050e98b51a617c6575ab 下复现;复现讨论基于 commit 83d4c6196ad90f98515c6be113cb2e957b60a832 的调度器代码(该守卫在当时的 main 上仍相同)。测试模型为 llava-1.5-7b。原文未给出 Python 与 PyTorch 精确版本。

最快修复方案:暂无确认的一步修复方案。Issue 讨论中更倾向的候选修复是把守卫中 (A) 处的严格小于 < 改为 <=,并保留 (A) 检查;同时因为该改动会让编码器-解码器(encoder-decoder)模型进入该守卫并回滚为 0 token,讨论建议在守卫中显式加上 and not self.is_encoder_decoder。上述修复在 Issue 关闭时尚未合并验证。

注意事项:单改 <= 会导致 tests/v1/core/test_scheduler.py 中三个交叉注意力测试失败(test_cross_attn_blocks_not_over_allocated、test_cross_attn_blocks_not_under_allocated、test_variable_length_cross_attn_block_allocation,报 assert 0 == 3)。此外,compute_mm_encoder_budget() 会校验 max_num_batched_tokens,但没有任何逻辑校验 long_prefill_token_threshold:当该阈值低于单个 mm item 长度时,仅加 <= 会让该请求每步都拿 0 token、永久饥饿(engine 持续 idle);long_prefill_token_threshold 影响属于讨论中修正的“不会饥饿”说法,使用前需注意。

问题场景

在 vLLM 上运行多模态模型(讨论中为 llava-1.5-7b)推理,并通过 disable_chunked_mm_input=True 期望禁止多模态输入被拆分到多个 prefill chunk 时,实际调度仍会把一个 mm item 分片。典型可触发配置为 max_num_batched_tokens=800、long_prefill_token_threshold=770,同时存在一个 3000 token 的纯文本请求和一个 mm item 位于 [3, 769) 的请求。

报错原文

[Bug]: A multimodal item can still be split across prefill chunks with disable_chunked_mm_input=True

step 1: scheduled={'text': 770, 'mm': 3}    mm_req: computed 0 -> 3
step 2: scheduled={'text': 770, 'mm': 30}   mm_req: computed 3 -> 33    # item chunked
step 3: scheduled={'text': 770, 'mm': 30}   mm_req: computed 33 -> 63   # item chunked
step 4: scheduled={'text': 690, 'mm': 110}  mm_req: computed 63 -> 173  # item chunked

assert 0 == 3

原因分析

可能原因是调度器中 self.scheduler_config.disable_chunked_mm_input 相关守卫存在 off-by-one:守卫包含 (A) 与 (B) 两个判断,(A) 使用严格 <。当 num_computed_tokens=3、start_pos=3 时,(A) 计算 3 < 3 为 False,整个守卫在 (B) 被求值前短路,而这恰恰是 item 尚未开始计算的边界状态,(B) 本可捕获重叠。由于回滚会把 num_computed_tokens 停在 start_pos 上,下一步必然再次命中该 off-by-one,于是 item 被逐步分片。另一个相关点:compute_mm_encoder_budget() 会校验 max_num_batched_tokens,但未校验 long_prefill_token_threshold;当每步 token 配额低于单个 mm item 长度时,会出现结构性触发。编码器-解码器模型下 start_pos 恒为 0,mm_position.length 为编码器长度、不属于解码器 token 序列,因此该范围算术在它们身上无意义,靠 x < 0 静默排除。

环境排查

  • 确认 vLLM 版本与镜像:Issue 复现环境为 vllm/vllm-openai:v0.26.0-cu129-ubuntu2404,构建 commit ffd46bfab2128bb84146050e98b51a617c6575ab。
  • 确认 CUDA 版本:环境变量显示 CUDA_VERSION=12.9.1;NVIDIA_REQUIRE_CUDA=cuda>=12.9。
  • 确认算子架构:TORCH_CUDA_ARCH_LIST=7.5 8.0 8.6 8.9 9.0 10.0 12.0。
  • 确认调度参数:max_num_batched_tokens=800、long_prefill_token_threshold=770(检查阈值是否低于单个 mm item 长度)。
  • 确认模型类型:是否运行多模态模型(讨论中为 llava-1.5-7b),以及是否为 encoder-decoder 架构。
  • 确认复现 commit 上该守卫代码是否仍与 83d4c6196ad90f98515c6be113cb2e957b60a832 一致。

解决步骤

  1. 定位调度器中读取 self.scheduler_config.disable_chunked_mm_input 的守卫逻辑,确认 (A) 判断使用严格 <,并在 num_computed_tokens=3、start_pos=3 时验证 (A) 返回 False 导致 (B) 被短路。
  2. 按讨论中更倾向的方案,把 (A) 的严格小于 < 改为 <=(保留 (A),不整体删除),以只改变边界而不移除检查。
  3. 在该守卫中显式补充 and not self.is_encoder_decoder,避免编码器-解码器模型x <= 0 进入守卫后被每步回滚为 0 token。
  4. 对低于单个 mm item 长度的 long_prefill_token_threshold 场景另作评估,补充校验或限制,避免仅加 <= 后请求永久饥饿。
  5. 对使用相同场景的调度器级 stub/单测复跑,确认不再出现 item 被分片的 step 序列。

验证方法

使用相同的 llava-1.5-7b 调度场景(max_num_batched_tokens=800、long_prefill_token_threshold=770、文本 3000 token + mm item [3, 769))复跑,观察在 computed 3 -> 33/63/173 一类步骤中该请求是否获得 0 token 并在后续步骤一次性调度整个 item,而不是被拆成多个 chunk;同时运行 tests/v1/core/test_scheduler.py 中三个交叉注意力测试,确认通过。注意 long_prefill_token_threshold 低于 item 长度的场景需单独验证不会出现每步 0 token 的饥饿。

参考来源

vllm-project/vllm #52306

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29018

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注