Prhub

#26320 fix(gemma4): register image/video/audio token_regex for HF-expanded prompts

原始 PR 作者 BiggieW 合并时间 2026-06-10 07:30 文件变更 1 提交数 6 评论 9 代码增减 +13 / -0

执行摘要

修复 Gemma4 多模态处理器 token_regex 缺失导致的 prompt 解析错误

Gemma4SGLangProcessor 未设置 token_regex,导致 parse_regex 回退到 re.escape(token_str),只能匹配单个 bare placeholder。当客户端使用 transformers 的 Gemma4 processor 生成的扩展 prompt(如 <|image> + N×<|image|> + <image|>)时,每个 patch token 被独立匹配,造成 token 数量远多于实际提供的多模态数据数量,从而抛出 RuntimeError: Mismatch: More 'IMAGE' tokens found than corresponding data provided.。gemma3.py 和 qwen_vl.py 已正确设置 image_token_regex,Gemma4 在 #21952 添加时遗漏了这一配置。

该 PR 修复逻辑清晰、代码简洁,值得阅读以理解多模态 token 扩展的处理模式。其设计决策——通过正则表达式的备选分支同时支持新旧格式——是保持向后兼容的通用方法。不过如果时间有限,可直接参考 gemma3.py 中已生效的相同模式,本 PR 仅是对齐遗漏。

讨论亮点

作者在 PR 评论区指出 CI 中的失败(AMD stage-b 基础设施超时、NPU 性能回归、缺少 run-ci-extra 标签)均与其变更无关。reviewer @kpham-sgl 和 @pyc96 均已批准 PR,最终由 @ch-wan 合并,确认失败测试在主分支上已存在问题。

实现拆解

  1. __init__ 方法中为 MultimodalSpecialTokens 构造调用补充三个命名参数:image_tokenvideo_tokenaudio_token 及其对应的正则表达式。
  2. 每个正则表达式采用两个备选分支:第一个分支匹配完整的 HF 扩展块(BOI + 至少一个 patch token + EOI),作为一条 marker 整体识别;第二个分支匹配单个 bare placeholder,确保对旧格式客户端保持向后兼容。
  3. 视频模态复用图像的 BOI/EOI 标记(<|image> / <image|>),中间 patch token 为 <|video|>,正则表达式据此构造。
  4. 在文件头新增 import re。整个变更集中在 __init__ 内部,无其他文件或外部行为变动。
文件 模块 状态 重要度
python/sglang/srt/multimodal/processors/gemma4.py 多模态 modified 5.19

关键符号

Gemma4SGLangProcessor.__init__

关键源码片段

python/sglang/srt/multimodal/processors/gemma4.py dependency-wiring

唯一的变更文件,在 Gemma4SGLangProcessor.__init__ 中为 image、video、audio 三种模态添加了 token 字符串和匹配扩展块的正则表达式,修复了导致 RuntimeError 的解析错误。

# File: python/sglang/srt/multimodal/processors/gemma4.pyimport re
from typing import Dict, List, Optional, Union
import numpy as np
import torchfrom sglang.srt.managers.multimodal_processor import (
    BaseMultimodalProcessor as SGLangBaseProcessor,
)
from sglang.srt.managers.schedule_batch import Modality, MultimodalProcessorOutput
from sglang.srt.models.gemma4_audio import _SSCP_CONV_STRIDE_SIZES
from sglang.srt.models.gemma4_mm import Gemma4ForConditionalGeneration
from sglang.srt.multimodal.processors.base_processor import MultimodalSpecialTokens
from sglang.srt.utils.video_decoder import VideoDecoderWrapper
​
​
class Gemma4SGLangProcessor(SGLangBaseProcessor):
    """Multimodal processor for Gemma4 supporting image, video, and audio inputs."""
​
    models = [Gemma4ForConditionalGeneration]
​
    def __init__(self, hf_config, server_args, _processor, *args, **kwargs):
        super().__init__(hf_config, server_args, _processor, *args, **kwargs)
​
        self.IM_START_TOKEN_ID = hf_config.boi_token_id
        self.IM_END_TOKEN_ID = hf_config.eoi_token_id
​
        self.AUDIO_START_TOKEN_ID = hf_config.boa_token_id
        self.AUDIO_END_TOKEN_ID = hf_config.eoa_token_id
​
        # 修复:为三种模态添加 token 字符串和匹配扩展块的正则表达式
        # 每个正则第一个备选匹配完整块 (BOI + N×patch + EOI) 作为一个 marker
        # 第二个备选匹配单个 bare placeholder,保持向后兼容
        self.mm_tokens = MultimodalSpecialTokens(
            image_token="<|image|>",
            image_token_id=hf_config.image_token_id,
            image_token_regex=re.compile(
                r"<\|image>(?:<\|image\|>)+<image\|>|<\|image\|>"
            ),
            video_token="<|video|>",
            video_token_id=hf_config.video_token_id,
            video_token_regex=re.compile(
                r"<\|image>(?:<\|video\|>)+<image\|>|<\|video\|>"
            ),
            audio_token="<|audio|>",
            audio_token_id=hf_config.audio_token_id,
            audio_token_regex=re.compile(
                r"<\|audio>(?:<\|audio\|>)+<audio\|>|<\|audio\|>"
            ),
        ).build(_processor)
​
        # Register image-processor and video-processor outputs so they are stored on
        # MultimodalDataItem via collect_mm_items_from_processor_output.
        self.ATTR_NAME_TO_MODALITY["image_position_ids"] = Modality.IMAGE
        self.ATTR_NAME_TO_MODALITY["video_position_ids"] = Modality.VIDEO

评论区精华

CI 失败是否由本 PR 引起 other

作者在评论中指出 AMD stage-b 基础设施超时、NPU 性能回归及缺少 run-ci-extra 标签均与其变更无关。

结论:reviewer 和合并者确认 CI 失败是已有问题,不影响合入。 · 已解决

风险与影响

风险极低。变更仅扩展了 MultimodalSpecialTokens 的配置字段,不影响原有逻辑。正则表达式包含 fallback 分支,因此旧有单占位符请求仍能正确匹配。主要风险在于正则表达式本身可能存在边界遗漏(如缺少 EOI 的异常情况),但当前实现与 gemma3 等已稳定运行的处理器模式一致。缺少对应的单元测试覆盖解析过程,但变更影响面小,可通过集成测试验证。

影响范围:仅限使用 Gemma4 模型且发送符合 HuggingFace processor 输出格式的请求的用户。修复前这些用户会遇到 RuntimeError,修复后请求能正常处理。对其他模态组合(如纯文本请求)无任何影响,对系统整体无破坏性变更。

缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论