执行摘要
- 一句话:将Transformers核心依赖从v4升级至v5.5.3,同步更新相关库并调整代码适配。
- 推荐动作:建议所有工程师精读此PR,尤其关注
vllm/tokenizers/registry.py和vllm/model_executor/model_loader/gguf_loader.py的变更,它们揭示了Transformers v5在配置加载和状态字典格式上的关键变化。设计决策中关于测试与生产环境依赖分离的权衡值得学习。
功能与动机
根据PR body描述,升级是为了'支持Transformers v5后发布的SoTA架构',当前v4版本已成为阻塞。作者hmellor在Issue评论中进一步解释:'v5是巨大的升级,我们花了4个月通过140个PR进行前向兼容,现在正处理最后边缘案例。'
实现拆解
-
更新依赖版本:
- 修改
requirements/test.in、requirements/nightly_torch_test.txt等文件,将Transformers pin至5.5.3,tokenizers至0.22.2,并提升PEFT下限至0.18.1、Accelerate至1.13.0、Mamba至2.3.0、compressed-tensors至0.15.0。
- 在CI环境中添加
HF_HUB_DOWNLOAD_TIMEOUT=60以应对huggingface-hub>=1的超时变更。
-
修复核心代码适配Transformers v5变化:
vllm/model_executor/models/gemma4_mm.py:为Gemma4AudioInputs张量模式添加dynamic_dims={"s"},支持变长音频序列;重构_call_hf_processor中的视频占位符替换逻辑,避免迭代错误。
vllm/tokenizers/registry.py:在get_tokenizer函数中引入get_config预加载配置,并处理错误tokenizer_class,通过_MODEL_TYPES_WITH_INCORRECT_TOKENIZER_CLASS集合绕过AutoTokenizer直接使用TokenizersBackend。
vllm/model_executor/model_loader/gguf_loader.py:在find_hf_name_in_tensor_map函数中,为多模态模型剥离外层model.前缀,并重新添加以匹配gguf-py格式。
vllm/model_executor/models/transformers/base.py等文件进行小幅配置键调整。
-
调整测试覆盖以跳过不兼容模型:
tests/models/registry.py:为InternLM2VEForCausalLM、Plamo2ForCausalLM、SarvamMLAForCausalLM、XverseForCausalLM等模型添加max_transformers_version限制和详细原因说明,临时跳过Transformers v5不兼容的测试。
tests/models/multimodal/generation/test_common.py:为ultravox、intern_vl、isaac等VLM测试添加skip标记,因模型在Transformers v5中损坏。
- 添加向后兼容测试,使用Transformers
4.57.5运行相同测试集。
-
配套与CI调整:
- 更新Dockerfile移除
--pre标志,确保稳定安装。
- 修复LoRA双流环境变量问题(如
test_olmoe_lora)。
- 通过提交历史可见,历经多次merge和修复以解决CI失败。
关键文件:
vllm/model_executor/models/gemma4_mm.py(模块 多模态模型;类别 source;类型 data-contract;符号 Gemma4AudioInputs, _call_hf_processor): 修复多模态模型音频输入张量模式,添加动态维度支持变长序列,并优化视频占位符替换逻辑以避免迭代错误。
vllm/tokenizers/registry.py(模块 tokenizer注册;类别 source;类型 dependency-wiring;符号 get_tokenizer): 修复tokenizer加载逻辑以适应Transformers v5的变化,包括预加载配置和处理错误tokenizer_class。
vllm/model_executor/model_loader/gguf_loader.py(模块 模型加载器;类别 source;类型 data-contract;符号 find_hf_name_in_tensor_map): 修复GGUF加载器以处理Transformers v5中多模态模型状态字典键的新前缀格式。
tests/models/registry.py(模块 测试注册表;类别 test;类型 test-coverage): 更新模型注册表以跳过Transformers v5不兼容的模型,确保CI测试通过并明确记录原因。
关键符号:get_tokenizer, _call_hf_processor, find_hf_name_in_tensor_map
关键源码片段
vllm/tokenizers/registry.py
修复tokenizer加载逻辑以适应Transformers v5的变化,包括预加载配置和处理错误tokenizer_class。
def get_tokenizer(tokenizer_name: str | Path, *args, **kwargs):
# 解析 tokenizer 参数
tokenizer_mode, tokenizer_name, args, kwargs = cached_resolve_tokenizer_args(...)
# 确保来自 vllm.transformers_utils.config 的配置在 tokenizer 加载前已注册到 AutoConfig
# 这是因为 tokenizer_cls_.from_pretrained 内部会调用 AutoConfig.from_pretrained
config = None
with contextlib.suppress(ValueError, OSError): # 对于无 config 的路径(如 LoRA 适配器),静默失败
config = get_config(tokenizer_name, trust_remote_code=True, revision=...)
# 处理 Hub 上 tokenizer_class 错误的模型类型
model_type = getattr(config, "model_type", None) if config else None
if model_type in _MODEL_TYPES_WITH_INCORRECT_TOKENIZER_CLASS: # 例如 {"step3_vl"}
from transformers.tokenization_utils_tokenizers import TokenizersBackend
tokenizer_cls_ = TokenizersBackend # 直接使用通用 fast tokenizer 后端
elif tokenizer_cls == TokenizerLike:
tokenizer_cls_ = TokenizerRegistry.load_tokenizer_cls(tokenizer_mode)
else:
tokenizer_cls_ = tokenizer_cls
return tokenizer_cls_.from_pretrained(tokenizer_name, *args, **kwargs)
vllm/model_executor/model_loader/gguf_loader.py
修复GGUF加载器以处理Transformers v5中多模态模型状态字典键的新前缀格式。
def find_hf_name_in_tensor_map(hf_name: str) -> str | None:
"""
将HuggingFace参数名映射到GGUF张量名。
"""
# 在 Transformers v5 中,多模态模型(如 Gemma3)将所有子模型包装在外层 'model.' 属性下
# 产生类似 'model.language_model.layers.0...' 的键。剥离此前缀以匹配 gguf-py 期望格式。
if is_multimodal and hf_name.startswith("model."):
hf_name = hf_name[6:] # 移除外层 'model.'
# 为多模态模型移除 'language_model.' 前缀,然后重新添加 'model.' 前缀
# 因为 gguf-py 文本张量映射期望 'model.layers...' 格式
if hf_name.startswith("language_model."):
hf_name = hf_name[15:] # 移除 'language_model.'
if is_multimodal:
hf_name = "model." + hf_name # 重新添加 'model.' 前缀以适配 gguf-py
# 后续解析权重后缀和映射逻辑保持不变
...
tests/models/registry.py
更新模型注册表以跳过Transformers v5不兼容的模型,确保CI测试通过并明确记录原因。
# 示例:为 Plamo2ForCausalLM 添加版本限制,因其自定义代码使用旧的 _tied_weight_keys 格式
"Plamo2ForCausalLM": _HfExamplesInfo(
"pfnet/plamo-2-1b",
trust_remote_code=True,
max_transformers_version="4.57", # 限制在 Transformers v4.57 及以下
transformers_version_reason={
"hf": (
"Custom model code uses `_tied_weight_keys: list[str]` but "
"Transformers v5 now expects `_tied_weight_keys: dict[str, str]`"
) # 明确记录不兼容原因,便于后续修复
},
),
评论区精华
- 依赖版本冲突:gemini-code-assist[bot]和cursor[bot]指出
requirements/common.txt中transformers < 5约束与测试文件升级冲突。作者hmellor回应:"This is fine, we want to test with 5 but support 4 if we can",表明策略是允许测试v5但保持生产环境对v4的支持。
- 代码风格优化:DarkLight1337在
gemma4_mm.py中建议避免字符串拼接,优化视频替换逻辑,提议使用列表插值方式,作者采纳了修改。
-
设计权衡讨论:hmellor在review中评论vllm/transformers_utils/config.py的变更,指出"v5 is just exposing issues that were always there",并质疑预注册配置是否违背了懒加载原则,体现了对Transformers v5内部机制变化的深度思考。
-
依赖版本冲突与测试策略 (design): 作者hmellor决定保持common.txt约束不变,允许测试文件独立升级以验证v5兼容性,平衡测试与生产环境支持。
- 代码实现优化 (style): 建议被采纳,代码修改为使用split和列表插值,避免迭代错误并提升可读性。
- 配置注册与懒加载权衡 (design): 通过get_tokenizer中的静默失败和条件检查来平衡兼容性与性能,确保自定义配置在必要时注册。
风险与影响
- 风险:
- 回归风险:临时跳过的模型如
Plamo2ForCausalLM、OpenCUAForConditionalGeneration等,若用户在生产环境使用这些模型,可能导致运行时失败。需在后续PR中尽快恢复支持。
- 兼容性断裂:Transformers v5的API变更(如
PretrainedConfig.__init__不再设置未声明属性)可能影响vLLM内部其他模块的隐式依赖,需全面测试核心路径。
- 性能波动:依赖库升级可能引入新版本中的性能退化或bug,例如huggingface-hub切换至httpx导致的超时问题,已通过环境变量缓解。
- 测试覆盖不全:大量测试被跳过,降低了代码变更的信心,需依赖后续修复和回归测试。
- 影响:
- 用户影响:用户可受益于Transformers v5支持的新模型架构(如Gemma4等),但部分旧模型暂时不可用,需等待团队后续修复。
- 系统影响:核心依赖升级影响整个项目的构建和运行时行为,所有模块需确保与Transformers v5兼容,可能引发连锁调整。
- 团队影响:团队需跟进跳过的模型列表,在后续PR中逐个修复,并维护v4/v5的向后兼容性测试。
- 社区影响:此举标志vLLM正式支持Transformers v5,有助于吸引使用最新模型的研究者和开发者。
- 风险标记:依赖升级风险, 测试覆盖不全, 模型兼容性断裂
关联脉络
- PR #39242 [ROCm] Add MLA dual RMS norm fusion (Q, KV) pass for DeepSeek/Kimi-K2: 同样涉及Transformers版本优化和ROCm平台适配,体现了团队在v5升级前后对Transformers集成的持续投入。
- PR #39733 [Core] Pass donate_graph_module=True to standalone_compile: 同属核心模块调整,展示vLLM在依赖升级(如PyTorch≥2.13dev)时的前向兼容性处理模式。
参与讨论