Qwen3.5 Does not work with variable length inputs using position_ids

用户在 HuggingFace Transformers 框架下使用 Qwen3.5 模型( Qwen3_5TextModel )进行 padding-free 变长序列推理。典型场景包括:将多个样本打包成一个 batch(packing),每个样本长度不同,通过 position_ids 在每个样

Qwen3.5 Does not work with variable length inputs using position_ids

Qwen3.5 Does not work with variable length inputs using position_ids

快速结论:该报错发生在使用 HuggingFace Transformers 对 Qwen3.5 模型进行 padding-free(变长输入)推理时。当仅传入 position_ids 而不传入 cu_seq_lens 时,Qwen3.5 的线性注意力(linear attention / Qwen3_5GatedDeltaNet)不会从 position_ids 自动推导序列边界,而是直接忽略 packed 边界,导致跨子序列的注意力计算错误,且无任何报错。优先排查是否已正确传入 cu_seq_lens_qcu_seq_lens_k 参数。

问题场景

用户在 HuggingFace Transformers 框架下使用 Qwen3.5 模型(Qwen3_5TextModel)进行 padding-free 变长序列推理。典型场景包括:将多个样本打包成一个 batch(packing),每个样本长度不同,通过 position_ids 在每个样本内部从 0 开始重置。下游框架(例如 Verl)假定对 HuggingFace 所有模型使用相同的接口(仅传 position_ids),而此时 Qwen3.5 会静默输出错误结果。

报错原文

# 静默错误,无显式报错。但输出结果错误。
# 使用 packed + position_ids only 时,第二个子序列的误差可达 ~0.38,而非 ~1e-7。
# 即使显式传入 cu_seq_lens,如果使用 torch fallback,结果依然错误。
# 验证脚本输出示例:
Comparison of packed forward vs independent forward:
  packed (position_ids only)      max|Δ| seqA=4.768e-07  seqB=3.818e-01  WRONG
  packed (explicit cu_seq_lens)   max|Δ| seqA=4.768e-07  seqB=3.818e-01  WRONG

原因分析

可能原因如下,已由 Issue 提交者复现并分析确认:

  • 接口问题:Qwen3_5GatedDeltaNet 的核心注意力实现只从 kwargs["cu_seq_lens_q"] 读取序列边界,而不会像标准 Flash Attention 路径一样从 position_ids 自动推导。因此当仅传入 position_ids(不传 cu_seq_lens)时,注意力计算不会拆分子序列,导致跨越 packing 边界进行错误计算。
  • Torch fallback(纯 PyTorch 回退)问题:回退函数 torch_chunk_gated_delta_rule 完全忽略传入的 cu_seqlens 参数,即使用户显式传入了 cu_seq_lens_qcu_seq_lens_k,该回退函数仍然会跨边界计算。此问题同样影响 Qwen3-Next 模型。

环境排查

  • 确认 Transformers 版本:v5.12.0(Issue 中参考的代码版本)。
  • 确认 PyTorch 版本:无特定要求,但建议使用较新版本以获得更好的 Flash Attention 支持。
  • 确认模型配置:Qwen3.5 模型中包含 GatedDeltaNet 注意力层的版本(layer_types 中包含 "gated_delta")。
  • 确认使用的注意力后端:是否实际调用了 torch fallback 还是 flash attention。

解决步骤

  1. 临时方案:始终传入 cu_seq_lens 参数。在调用 model 的 forward 时,明确传入 cu_seq_lens_qcu_seq_lens_kmax_length_qmax_length_k 参数。例如:
    cu = torch.tensor([0, len_seq_a, len_seq_a + len_seq_b], dtype=torch.int32).unsqueeze(0)
    output = model(
        input_ids=packed_input_ids,
        position_ids=position_ids,
        cu_seq_lens_q=cu,
        cu_seq_lens_k=cu,
        max_length_q=len_seq_a,
        max_length_k=len_seq_a,
    )

    注意:此方案仅在使用 Flash Attention 后端(非 torch fallback)时有效。

  2. 正确方案(需等待官方修复):Transformers 项目的提议修复方案为:
    1. 修改 Qwen3_5GatedDeltaNet,使其在检测到 packing(基于 position_ids 的跳变)时,自动从 position_ids 推导 cu_seq_lensmax_length,行为与其他模型保持一致。
    2. 修改 torch_chunk_gated_delta_rule,使其正确利用 cu_seqlens 参数,逐个处理子序列,而不是忽略该参数。

    可优先尝试使用社区 PR(如果有)或自行修改本地的 modeling 文件。

  3. 监控/警告(待官方添加,可优先尝试的临时措施):在自定义 wrapper 中,检查 position_ids 是否存在跨样本的跳变,如果检测到 packing 但未提供 cu_seq_lens,主动打印警告或抛出错误,避免静默出错。

验证方法

运行 Issue 附件中的复现脚本 reproduction.py(见 Issue 正文)。如果修复成功,packed + position_ids only 模式和 packed + explicit cu_seq_lens 模式下的 max|Δ| 对于所有子序列都应小于 1e-4,并输出 OK。若不满足,则问题未解决。

参考来源

huggingface/transformers #46851

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 9913

发表回复

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