`modeling_qwen3_vl.py` performed D2H makes cpu wait gpu

这个报错通常发生在使用 Transformers 运行 Qwen3-VL 多模态模型、尤其是视觉前向(vision prefill)阶段时,表现为 `modeling_qwen3_vl.py` 中 `lengths.tolist()` 等操作触发 D2H(device-to-host)拷贝,使 CP

快速结论:这个报错通常发生在使用 Transformers 运行 Qwen3-VL 多模态模型、尤其是视觉前向(vision prefill)阶段时,表现为 `modeling_qwen3_vl.py` 中 `lengths.tolist()` 等操作触发 D2H(device-to-host)拷贝,使 CPU 超前于 GPU、GPU 被迫等待,单次同步耗时超过 250ms。优先排查视觉注意力层内的重复张量到 Python 列表转换,以及 RoPE 位置索引构造中的标量搬移。

适用环境:Issue 已确认涉及 Transformers 的 Qwen3-VL 模型实现(`modeling_qwen3_vl.py`)、非 Flash Attention 后端下的视觉注意力路径;正文与评论未明确给出具体 Python、CUDA、PyTorch 版本、操作系统或显卡型号,这些项目需以你自己实际环境为准。

最快修复方案:暂无确认的一步修复方案。Issue 中讨论的是优化方向(将段长度元数据在视觉前向只计算一次,并张量化 RoPE 构造),并未给出已合入或可直接套用的补丁。

注意事项:Issue 评论中提到的“每层只提取一次 segment 元数据”“用 tensor 操作替代 `.tolist()` + `itertools.groupby()`”属于待验证的优化设计,不是已验证结论;其中还特别提醒 `.to(position_ids.device)` 若两侧本就在同一设备应为 no-op,不应仅凭代码外观就认定它是真实 H2D 传输,需以 profiler 实测为准。改为稠密 block-diagonal 注意力掩码虽然能去掉 Python split,但会带来显存与算力平方级增长,不应作为默认方案。

问题场景

用户在 Transformers 中运行 Qwen3-VL 多模态模型(图片/视频输入,走视觉前向)时,遇到性能问题而非崩溃:视觉注意力层里对 packed 序列做 split,需要 Python 整数长度,于是调用 lengths.tolist() 把 CUDA 张量同步回主机,产生 D2H pageable→host 拷贝。用户用 profiler 观察到该操作耗时超过 250ms,导致 CPU 跑到 GPU 前面、GPU 反过来等 CPU。此外,RoPE 位置索引构造路径中 current_pos += max(grid_thw[1], grid_thw[2]) // spatial_merge_size、position_ids[:, batch_idx] = llm_positions.to(position_ids.device)、mrope_position_deltas = torch.tensor(mrope_position_deltas, device=input_ids.device).unsqueeze(1) 也被报告存在同类同步问题。

报错原文

`modeling_qwen3_vl.py` performed D2H makes cpu wait gpu

creates `D2H pageable->host`, it costs more than `250ms` and makes gpu is waited by cpu that already ahead.

No D2H or H2D during forward, to make model run faster

原因分析

可能原因是视觉注意力层在每个 vision-attention block 内都执行一次 lengths = cu_seqlens[1:] - cu_seqlens[:-1] 后再 lengths.tolist(),而 packed 序列的分段在整个视觉前向中是常量,却被重复提取,形成 O(层数) 级别的同步。其次,get_rope_index() 里用 input_token_type.tolist() 配合 Python itertools.groupby() 处理模态元数据、用 Python max() 累加 current_pos、再用 torch.tensor(...) 重建 GPU 张量,也可能引入标量提取与新的 host-to-device 拷贝。Issue 评论将这三类同步问题视为相互独立、需分别度量和修复的对象,并未确认其中某一个是唯一根因。

环境排查

  • 确认使用的 Transformers 版本,以及是否包含 Issue 引用的 modeling_qwen3_vl.py 对应提交(516a6b40b7d5ae7147306661378ea0ebe4ee238e)附近或之后的改动。
  • 确认视觉注意力实际走的是哪种后端:eager、SDPA 还是 Flash Attention;Issue 指出非 Flash Attention 后端下每层都会触发 lengths.tolist()。
  • 确认输入形态:单图、多图、单视频、图文/视频混合,以及 packed 视觉序列的数量与大小,这些会影响 split 次数与同步频率。
  • 确认运行设备为 CUDA 还是 CPU;Issue 要求优化同时兼容 CPU 执行、tracing 与 torch.compile,排查时也应分别验证。
  • 确认 PyTorch、CUDA、Python 版本以及显卡型号;Issue 未提供这些具体信息,需自行记录以复现环境。
  • 确认是否开启 torch.compile,以及是否存在 graph break。

解决步骤

  1. 先用 profiler 建立可靠基线:采集 CPU self time、CUDA kernel time、D2H/H2D memcpy 事件、host 同步事件、graph breaks、峰值显存与端到端视觉 prefill 延迟。计时建议使用 CUDA events 或在测量区间外显式同步,避免隐式同步干扰结果。
  2. 定位同步热点:确认 lengths.tolist() 是否在每个 vision-attention block 内被反复执行,以及它是否是耗时最大的同步点。
  3. 可优先尝试的改进方向(来自 Issue 讨论,非已验证补丁):在 Qwen3VisionModel.forward() 中一次性推导不可变的 segment 元数据,再传给每个 vision block 与 attention layer,避免在层内重复计算或传输。
  4. 保留现有 cu_seqlens 张量供 Flash Attention 使用;仅对公开 PyTorch API 要求 Python 整数 split sizes 的后端,使用预算好的 host split sizes。
  5. 尽可能从张量搬上加速器之前的原始 CPU 侧 grid 元数据推导 host split sizes;若调用方只提供 CUDA cu_seqlens,兼容回退可能仍需要一次显式转换,但这可将 O(层数) 同步降为一次。
  6. 针对 get_rope_index(),可优先尝试张量化:用 tensor 操作检测模态 run 边界,替代 input_token_type.tolist() 与 itertools.groupby();将 current_pos 保持为 device scalar tensor,用 torch.maximum(...) 替代 Python max(grid_thw[1], grid_thw[2]);用 torch.stack(...) 替代 torch.tensor(mrope_position_deltas, device=...);并避免冗余的设备转换。
  7. 在改动前先用 profiler 验证 .to(position_ids.device) 是否真的产生 H2D;若 llm_positions 与 position_ids 已在同一设备,该调用应为 no-op。
  8. 若考虑用稠密 block-diagonal mask 消除 Python split,需先做显存与算力基准测试,避免二次方级回归;Issue 明确不建议在无基准证据时作为默认方案。

验证方法

用第 1 步建立的基准矩阵(eager / SDPA / Flash Attention、单图 / 多图 / 单视频 / 混合输入、不同 packed 序列数量与大小、warm-up 后测量、CPU 与 CUDA、eager 与 torch.compile)回归验证:确认视觉前向期间不再出现重复的 D2H/H2D memcpy 与 host 同步事件,端到端视觉 prefill 延迟下降,同时输出在 eager、SDPA、Flash Attention 下保持一致。补充断言:检测到的 image/video run 数量、可用 grid 条目数量、生成的位置数量与未 mask token 数一致,输出 dtype、device、shape 不变。

参考来源

huggingface/transformers #47649

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 27202

发表回复

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