CUDA out of memory

在 vLLM 上为 Gemma 4 多模态模型启用 encoder CUDA graph( cudagraph_mm_encoder: true )并开启视频输入时,捕获阶段会按 max_frames_per_batch 为每个预算分配整幅图像尺寸的 dense pixel buffer,导致出现

快速结论:在 vLLM 上为 Gemma 4 多模态模型启用 encoder CUDA graph(cudagraph_mm_encoder: true)并开启视频输入时,捕获阶段会按 max_frames_per_batch 为每个预算分配整幅图像尺寸的 dense pixel buffer,导致出现 CUDA out of memory。优先排查捕获 dummy 的内存占用与预算行数是否被合理限制。

适用环境:Issue 已确认环境:vLLM 0.31.1rc1.dev159+g4274ae956(main @ 4274ae956c,预编译 wheel),torch 2.13.0+cu132,torchvision 0.28.0,transformers 5.19.0,CUDA 13.2,驱动 595.91.07,单卡 RTX 5090 32 GB(sm_120),模型 nvidia/Gemma-4-26B-A4B-NVFP4。

最快修复方案:暂无已合入的一步修复版本。Issue 作者已验证的临时规避方式是关闭 encoder CUDA graph(不启用 cudagraph_mm_encoder),工作负载可正常启动;真正的行数上限修复由 #61092 实现。

注意事项:关闭 encoder CUDA graph 只是配置层规避,不解决分配逻辑本身的问题;#61092 中的行数上限在 L40S + gemma-4-E2B-it 视频场景验证可启动,但视频输出与 eager 的一致性还需 #60687。Issue 场景为单卡 RTX 5090 上的视频路径验证,非生产负载。

问题场景

用户通过 vllm serve 启动 Gemma 4 多模态模型,开启 fp8 KV cache、--limit-mm-per-prompt '{"image": 1, "video": 1}'、--media-io-kwargs '{"video": {"num_frames": 32}}',并在 --compilation-config 中设置 {"cudagraph_mm_encoder": true}。引擎在 encoder CUDA graph 捕获阶段崩溃,此时尚未进入正常推理。

报错原文

INFO [encoder_cudagraph.py:208] EncoderCudaGraphManager initialized with paths={'default': [70, 140, 280, 560, 1120, 2240, 4096]}, max_batch_size=58, max_frames_per_batch=1856, use_dp=False, capture_axes=()
...
  File ".../vllm/v1/worker/encoder_cudagraph.py", line 324, in _capture_budget_graph
    output = self.model.encoder_cudagraph_forward({**values}, path=path)
  File ".../vllm/model_executor/models/gemma4_mm.py", line 1994, in encoder_cudagraph_forward
    inputs_embeds = vt.patch_embedder(
  File ".../transformers/models/gemma4/modeling_gemma4.py", line 624, in forward
    pixel_values = 2 * (pixel_values - 0.5)
torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 6.69 GiB. GPU 0 has a total capacity of 31.36 GiB of which 4.42 GiB is free.

原因分析

Issue 给出的根因链路如下:

  • 用户未显式设置时,EncoderCudaGraphManager.__init__ 推导出 max_batch_size = min(4096 // 70, 70) = 58,max_frames_per_batch = 58 * 32 = 1856。
  • 在 Qwen2.5-VL / Qwen3-VL / GLM-4.1V 中,max_frames_per_batch 只决定预算如何跨帧铺开(cu_seqlens、捕获网格),像素 buffer 接近 token 预算。但 Gemma 4 的 prepare_encoder_cudagraph_capture_inputs 把它当作 dense pixel buffer 的行数,每行按整幅图像尺寸分配。
  • 结果是每个预算都分配 1856 行,token 预算并不会缩小行数;280 token 预算和 4096 token 预算拿到同样大的 (1856, 2520, 768) bf16 buffer。
  • 每个预算的 dummy 作为 graph 的 input_buffers 保留,7 个预算合计约 38.5 GiB bf16 dummy 输入,32 GB 卡在捕获完成前即失败。
  • 此外捕获从最大预算开始,先对整块 dummy 做一次 eager forward(1856 × 2520 ≈ 4.7M patch token 一次送入 vision tower),而该路径不像 eager encoder 那样使用 _encoder_chunk 分块。

环境排查

  • 确认 vLLM 版本,是否包含 encoder CUDA graph 中按 token_budget // 70 限制捕获行数的修复(#61092)。
  • 确认 torch、transformers、CUDA 版本与驱动是否与上述已知环境一致。
  • 确认显卡显存:32 GB 卡在该分配规模下必然不足。
  • 确认启动参数中是否启用了 cudagraph_mm_encoder,以及视频帧数 num_frames、--max-num-batched-tokens 的取值。
  • 启动日志中检查 max_batch_size 与 max_frames_per_batch 的推导值,判断捕获行数是否异常偏大。

解决步骤

  1. 可优先尝试:从 --compilation-config 中移除或关闭 cudagraph_mm_encoder,让 workload 先能启动。Issue 中报告该配置规避可让视频路径启动,但这不是对分配问题的修复。
  2. 关注 #61092:该 PR 将捕获行数限制为 token_budget // 70,4096 预算下从 1856 行降为 58 行;其中还提到在 L40S 上 gemma-4-E2B-it 视频 + encoder CG 可以启动。
  3. 升级到包含该行数上限修复的 vLLM 版本后,再恢复 cudagraph_mm_encoder: true 验证。
  4. 若需要视频输出与 eager 路径一致,还需等待/包含 #60687 的相关修复。

验证方法

用相同启动参数重新启动引擎:若不再在 encoder CUDA graph 捕获阶段出现 CUDA out of memory,且日志中 max_frames_per_batch 对应的捕获行数与 token 预算的比例合理,说明行数上限生效;随后再跑一次视频输入请求,确认能正常返回并与 eager 模式输出做对比。

参考来源

vllm-project/vllm #61045

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29341

发表回复

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