
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_q 和 cu_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_q和cu_seq_lens_k,该回退函数仍然会跨边界计算。此问题同样影响Qwen3-Next模型。
环境排查
- 确认 Transformers 版本:v5.12.0(Issue 中参考的代码版本)。
- 确认 PyTorch 版本:无特定要求,但建议使用较新版本以获得更好的 Flash Attention 支持。
- 确认模型配置:Qwen3.5 模型中包含
GatedDeltaNet注意力层的版本(layer_types中包含"gated_delta")。 - 确认使用的注意力后端:是否实际调用了 torch fallback 还是 flash attention。
解决步骤
- 临时方案:始终传入
cu_seq_lens参数。在调用model的 forward 时,明确传入cu_seq_lens_q、cu_seq_lens_k、max_length_q、max_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)时有效。
- 正确方案(需等待官方修复):Transformers 项目的提议修复方案为:
- 修改
Qwen3_5GatedDeltaNet,使其在检测到 packing(基于position_ids的跳变)时,自动从position_ids推导cu_seq_lens和max_length,行为与其他模型保持一致。 - 修改
torch_chunk_gated_delta_rule,使其正确利用cu_seqlens参数,逐个处理子序列,而不是忽略该参数。
可优先尝试使用社区 PR(如果有)或自行修改本地的 modeling 文件。
- 修改
- 监控/警告(待官方添加,可优先尝试的临时措施):在自定义 wrapper 中,检查
position_ids是否存在跨样本的跳变,如果检测到 packing 但未提供cu_seq_lens,主动打印警告或抛出错误,避免静默出错。
验证方法
运行 Issue 附件中的复现脚本 reproduction.py(见 Issue 正文)。如果修复成功,packed + position_ids only 模式和 packed + explicit cu_seq_lens 模式下的 max|Δ| 对于所有子序列都应小于 1e-4,并输出 OK。若不满足,则问题未解决。



