Prhub

#44239 [Bugfix][CI/Build] Fix Plamo2 HF runner crash on transformers v5 (_tied_weights_keys list→dict)

原始 PR 作者 nikhilkulkarni1755 合并时间 2026-07-23 20:25 文件变更 2 提交数 7 评论 1 代码增减 +30 / -7

执行摘要

修复 Plamo2 在 transformers v5 下的 HF runner 崩溃

关联 Issue #38379(Transformers v5 升级跟踪)中记录了 Plamo2 在 transformers v5 下的测试失败。PR body 指出,HfRunner.from_pretrained() 在 transformers v5 中因 _tied_weights_keys 类型不匹配而抛出 AttributeError: 'list' object has no attribute 'keys'。生产代码不受影响(vLLM 通过 config.tie_word_embeddings 标志处理权重绑定),但测试基础设施不可用。

可快速合入。该 PR 是 Transformers v5 升级跟踪的一部分,修复方式合理,逻辑清晰,可作为未来类似兼容问题的修复模板。

讨论亮点

该 PR 没有 review 评论,但有 7 个提交的演进历史体现了关键决策:

  • 最初实现使用 auto_map 所有条目迭代 + 手动 warn_on_fail,后改为使用 vLLM 已有的 try_get_class_from_dynamic_module 函数。
  • 曾尝试直接删除 _tied_weights_keys,验证后发现会导致权重重新初始化为随机值,模型输出错误。
  • 曾添加单元测试文件 test_fix_v4_tied_weights_keys.py,但因 vLLM 无测试 conftest 工具的先例而被移除。

实现拆解

  1. tests/conftest.py 新增 _fix_v4_tied_weights_keys 函数:该函数接收一个模型类,检查其 _tied_weights_keys 是否为非空 list,若是则转换为 dict[str, str] 格式(将包含 "lm_head" 且以 ".weight" 结尾的键映射到 "model.embed_tokens.weight"),并通过 setattr 就地修改类属性,该修改通过 sys.modules 缓存保留到 from_pretrained() 中。

  2. HfRunner.__init__() 中集成修复:在调用 auto_cls.from_pretrained() 之前,通过 try_get_class_from_dynamic_module 获取模型类,并应用 _fix_v4_tied_weights_keys。只处理当前 auto_cls 对应的 auto_map 条目,避免影响其他模型。

  3. tests/models/registry.py 中移除 Plamo2 的版本限制:删除 max_transformers_version="4.57" 及对应的原因说明,使 Plamo2 能在 transformers v5 下参与测试。

文件 模块 状态 重要度
tests/conftest.py 测试工具 modified 5.83
tests/models/registry.py 测试注册 modified 4.37

关键符号

_fix_v4_tied_weights_keys

关键源码片段

tests/conftest.py test-coverage

新增 `_fix_v4_tied_weights_keys` 函数并在 `HfRunner.__init__()` 中调用,是修复的核心逻辑。

def _fix_v4_tied_weights_keys(model_cls: type) -> None:
    """Convert a v4 list-format _tied_weights_keys to the transformers v5 dict form."""
    tied = getattr(model_cls, "_tied_weights_keys", None)
    # 仅在属性为 list 且非空时执行转换
    if not isinstance(tied, list) or not tied:
        return
    # 将包含 "lm_head" 且以 ".weight" 结尾的键映射为 v5 的 dict 格式
    result = {
        k: "model.embed_tokens.weight"
        for k in tied
        if "lm_head" in k and k.endswith(".weight")
    }
    if result:
        setattr(model_cls, "_tied_weights_keys", result)
​
​
class HfRunner:
    def __init__(
        self,
        model_name: str,
        dtype: str = "auto",
        *,
        revision: str | None = None,
        model_kwargs: dict[str, Any] | None = None,
        trust_remote_code: bool = True,
        is_sentence_transformer: bool = False,
        is_cross_encoder: bool = False,
        ...
    ):
        ...
        else:
            # 在 from_pretrained 之前,对使用了 remote code 的模型修补 _tied_weights_keys
            if trust_remote_code and hasattr(self.config, "auto_map"):
                cls_ref = self.config.auto_map.get(auto_cls.__name__)
                if cls_ref is not None:
                    from vllm.transformers_utils.dynamic_module import (
                        try_get_class_from_dynamic_module,
                    )
                    model_cls = try_get_class_from_dynamic_module(
                        cls_ref,
                        model_name,
                        trust_remote_code=trust_remote_code,
                        warn_on_fail=False,
                    )
                    if model_cls is not None:
                        _fix_v4_tied_weights_keys(model_cls)
​
            model = cast(nn.Module, auto_cls.from_pretrained(...))

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

变更仅限测试基础设施,不影响 vLLM 生产代码。风险极低:

  1. _fix_v4_tied_weights_keys 仅当 _tied_weights_keys 为 list 且包含 "lm_head" 时才生效,其他模型不受影响。
  2. 使用 try_get_class_from_dynamic_module 失败时返回 None,不会引发异常。
  3. 删除版本限制后,Plamo2 测试在 transformers v5 下可能因其他依赖(如 causal_conv1d / mamba_ssm)而失败,但属于已有问题,与本次变更无关。

影响范围小:仅改变测试基础架构,使 Plamo2 模型能在 transformers v5 环境中运行测试。对其他模型或生产部署无影响。

关联 Issue

#38379 Upgrade to Transformers v5

完整报告

参与讨论