Prhub

#7620 [model] fix: use the transformers 5 rotary API in the GLM-4V attention patch

原始 PR 作者 alanhuangyoo 合并时间 2026-09-02 10:06 文件变更 1 提交数 2 评论 3 代码增减 +4 / -11

执行摘要

修复 GLM-4V 注意力层使用已废弃 transformers 4.x 旋转位置编码 API 导致的训练崩溃。

GLM-4V 训练在第一个注意力层就会失败,因为 glm4v_attn_forward 导入的 apply_multimodal_rotary_pos_emb 在所有被支持的 transformers 5.x 版本中均不存在(ImportError)。此问题由 #5724 (transformers upgrade to 5.3.0) 引入,升级了配置侧的键名但未同步更新注意力侧的 API 调用。

此 PR 值得精读,尤其是遇到类似依赖库重构后导致 API 不兼容的场景时。它展示了如何精准定位一个因上游破坏性变更而产生的导入错误,并通过少量、正确的代码修改进行修复。核心设计决策是遵循上游变更,删除冗余的兼容层代码,而不是试图恢复旧函数。

讨论亮点

评审者 wuxibin89 针对作者提交的回归测试文件 tests/models/test_glm4v_rotary_on_cpu.py 提出“CI not needed”。作者 alanhuangyoo 表示同意并删除了该测试文件,同时强调修复本身(更改导入和函数调用)是自立的,因为目标函数在现有依赖下根本不存在,因此该补丁修复是明确且必要的。讨论未涉及核心修改逻辑,仅决定了测试的去留。

实现拆解

  1. 入口与问题定位: 问题位于 verl/models/transformers/glm4v.py 中的 glm4v_attn_forward 函数。当使用 remove_padding 或 ulysses_sp_size > 1 时,该函数会替换 GLM-4V 模型的注意力前向逻辑,是训练的核心路径。
  2. 核心逻辑修改: 将导入语句从 apply_multimodal_rotary_pos_emb 更改为 apply_rotary_pos_emb。随后,删除了为获取旧函数所需的 mrope_section 参数而编写的一整段兼容性逻辑(包括对 self.rope_scaling 和 self.rope_parameter 的 getattr 检查)。这是因为 transformers 5.x 的 Glm4vTextRotaryEmbedding 已在生成 cos/sin 时处理了 mrope_section,新的 apply_rotary_pos_emb 函数无需再接收该参数。最终调用简化为 apply_rotary_pos_emb(query_states, key_states, cos, sin)。
  3. 测试与配套: 作者最初提交了一个 CPU 级别的回归测试文件 tests/models/test_glm4v_rotary_on_cpu.py,用于验证修复后函数行为正确。然而,在评审过程中,评审者认为此测试“CI not needed”,因此该测试文件被移除。本次变更未引入其他配置、部署或 schema 更改。
文件 模块 状态 重要度
verl/models/transformers/glm4v.py 模型层 modified 6.71

关键符号

glm4v_attn_forward

关键源码片段

verl/models/transformers/glm4v.py data-contract

包含了导致 GLM-4V 训练崩溃的注意力补丁函数 `glm4v_attn_forward`,是本次修复的核心源码文件。

# verl/models/transformers/glm4v.py - glm4v_attn_forward 函数片段(修复后)
def glm4v_attn_forward(
    self: "Glm4vTextAttention",
    hidden_states: torch.Tensor,
    attention_mask: Optional[torch.Tensor] = None,
    position_ids: Optional[torch.LongTensor] = None,
    position_embeddings: Optional[tuple[torch.Tensor, torch.Tensor]] = None,
    **kwargs,
) -> tuple[torch.Tensor, None, None]:
    # 关键修复:更新导入为 transformers 5.x 的旋转位置编码函数
    from transformers.models.glm4v.modeling_glm4v import apply_rotary_pos_emb, repeat_kv
​
    bsz, q_len, _ = hidden_states.size()
    query_states = self.q_proj(hidden_states)
    key_states = self.k_proj(hidden_states)
    value_states = self.v_proj(hidden_states)
​
    query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
    key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
    value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
​
    # Because the input can be padded, the absolute sequence length depends on the max position id.
    # Glm4vTextRotaryEmbedding already folds mrope_section into cos/sin, so this is the plain
    # application, exactly as Glm4vTextAttention.forward does it.
    cos, sin = position_embeddings
    # 关键修复:调用新的旋转函数,无需 mrope_section 参数
    query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
    key_states = repeat_kv(key_states, self.num_key_value_groups)
    value_states = repeat_kv(value_states, self.num_key_value_groups)
    # ... 后续 Flash Attention 逻辑保持不变 ...

评论区精华

回归测试文件的必要性 测试

作者提交了专门针对旋转编码 API 的 CPU 单元测试 `test_glm4v_rotary_on_cpu.py`。评审者 wuxibin89 指出 'CI not needed',认为该修复无需特定的 CI 测试覆盖。

结论:作者同意移除该测试文件,认为修复本身(更改导入和函数调用)已足够明确。 · 已解决

风险与影响

  1. 回归风险: 极低。本次变更将调用从不存在的 API(apply_multimodal_rotary_pos_emb)切换为与 transformers 5.x 上游实现一致的、存在的 API(apply_rotary_pos_emb),修复了一个阻塞性错误。
  2. 正确性风险: 低。新调用 apply_rotary_pos_emb(q, k, cos, sin) 的参数签名与 transformers 5.x 中 Glm4vTextAttention.forward 的调用完全一致,确保了旋转位置编码的数学操作正确。
  3. 测试覆盖风险: 中低。原作者提交的 CPU 测试被移除,目前缺乏针对 glm4v_attn_forward 函数的直接单元测试。虽然主要逻辑(注意力计算)由现有 GPU 测试覆盖,但旋转编码部分现在缺少特定的回归测试。
  1. 用户影响: 直接修复了 GLM-4V 模型训练在所有 transformers 5.x 版本上的崩溃问题,影响所有使用 GLM-4V 并启用 remove_padding 或 ulysses_sp_size > 1 功能的用户。
  2. 系统影响: 恢复了 verl 训练框架对 GLM-4V 模型的支持,确保了核心训练流程的稳定性。
  3. 团队影响: 清晰地展示了依赖库 API 升级后需同步更新下游代码的维护模式,为后续维护提供了参考。
依赖 API 破坏性变更 测试覆盖不足

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论