# PR #34175 完整报告

- 仓库：`sgl-project/sglang`
- 标题：[VLM] Replace deprecated image processor use_fast
- 合并时间：2026-08-12 00:14
- 原文链接：http://prhub.com.cn/sgl-project/sglang/pull/34175

---

# 执行摘要

- 一句话：以 image-processor-backend 参数取代废弃的 use_fast 快图像处理器
- 推荐动作：值得精读，尤其是 `_apply_image_processor_backend` 对 ProcessorMixin kwargs 泄漏问题的处理手法（只替换 image 子处理器、保留 processor 的 tokenizer/chat_template），这是与 Transformers ProcessorMixin 交互时容易踩坑的设计决策。建议关注两个后续验证点：
 1) `auto` 默认值在常见 VLM（Qwen2.5-VL、LLaVA、InternVL 等）上的实际 backend 选择与精度影响；
 2) 是否需要在 vLLM 等依赖同一 `use_fast` 语义生态的地方同步推广。

# 功能与动机

PR body 明确说明："The previous fix passed `backend` through `AutoProcessor`. Transformers forwards generic processor kwargs to every sub-processor, so Qwen2.5-VL also received it in the video processor and failed with `AttributeError: can't set attribute 'backend'`."。即上一轮修复在 AutoProcessor 上透传 backend 会把参数泄漏到 video processor 等子处理器并崩溃。同时默认值保持 `auto` 可同时规避 `use_fast` 的 deprecation warning 和无谓的显式 backend 选择；需要确定性行为的用户可选 `torchvision` 或 `pil`。

# 实现拆解

整体分为四步：

1. **参数层改造（server_args.py）**：新增 `--image-processor-backend`（`Literal["auto","torchvision","pil"]`，默认 `auto`，NS("mm")），并把 `disable_fast_image_processor` 标记为 Deprecated；在 `_handle_deprecated_args` 中若旧标志为真且新参数不是 `auto`/`pil` 则抛 `ValueError`，否则发一次 `WARNING` 并映射 `image_processor_backend="pil"`。

2. **核心解析逻辑（utils/hf_transformers/processor.py）**：新增 `resolve_image_processor_backend(server_args)`（尊重旧标志）、`_normalize_image_processor_backend`（校验合法值、处理 `use_fast` 冲突）与 `_apply_image_processor_backend`（只对 `processor.image_processor` 调用 `AutoImageProcessor.from_pretrained(backend=...)` 重新加载，不从 `AutoProcessor` 传 backend）；`get_processor` 的 `use_fast` 默认值从 `True` 改为 `None`。

3. **调用点迁移**：`tokenizer_manager.get_processor_wrapper`、`encode_receiver._init_mm_processor`、`scheduler.init_tokenizer`、`encode_server._load_mm_processor` 均改为 `image_processor_backend=resolve_image_processor_backend(...)`，并去掉各处的 `ValueError("does not have a slow version")` 重试分支（逻辑下沉到 `get_processor`）；`encode_server` 的 `use_image_processor_gpu` 条件改为 `resolve_image_processor_backend(...) != "pil"`。

4. **配套测试 / 文档**：`test_server_args.py` 新增 `TestImageProcessorBackend`（新参数不置旧标志、旧标志只警告一次映射到 pil、冲突抛 ValueError）；`test_hf_transformers.py` 新增 `test_does_not_forward_backend_to_auto_processor` 与 `test_applies_pil_backend_only_to_image_processor`；`test_server_args_migration.py` 校验三个合法 choice；docs 同步更新 `vlm_query.mdx`、`server_arguments.mdx`、NPU `support_features.mdx`；multimodal_gen 的 loader 与测试工具同步调整。

关键文件：
- `python/sglang/srt/utils/hf_transformers/processor.py`（模块 处理器加载；类别 source；类型 core-logic；符号 resolve_image_processor_backend, _normalize_image_processor_backend, _apply_image_processor_backend）: 核心解析与 backend 应用逻辑所在：新增 `resolve_image_processor_backend`、`_normalize_image_processor_backend`、`_apply_image_processor_backend`，`get_processor` 签名收敛 `use_fast` 并接入新参数。
- `python/sglang/srt/server_args.py`（模块 参数管理；类别 source；类型 core-logic；符号 _handle_deprecated_args, image_processor_backend, disable_fast_image_processor）: 新增 `--image-processor-backend` 参数、把旧标志标记为 Deprecated，并在 `_handle_deprecated_args` 中完成一次警告迁移与冲突校验。
- `python/sglang/srt/managers/tokenizer_manager.py`（模块 请求管理；类别 source；类型 core-logic；符号 get_processor_wrapper）: 主服务侧 processor 加载入口，迁移到新参数并删除重复的 ValueError 慢速回退逻辑。
- `python/sglang/srt/disaggregation/encode_receiver.py`（模块 解耦编码；类别 source；类型 dependency-wiring；符号 _init_mm_processor）: disaggregation 编码器侧 processor 初始化同步迁移，消除 use_fast 透传。
- `test/registered/unit/server_args/test_server_args.py`（模块 参数测试；类别 test；类型 test-coverage；符号 TestImageProcessorBackend, test_new_backend_does_not_set_legacy_flag, test_legacy_flag_maps_to_pil_with_one_warning, test_legacy_flag_rejects_torchvision_backend）: 新增 TestImageProcessorBackend 覆盖新参数 / 旧标志 / 冲突三条迁移路径，守住 CLI 兼容契约。
- `test/registered/unit/utils/test_hf_transformers.py`（模块 处理器测试；类别 test；类型 test-coverage；符号 test_does_not_forward_backend_to_auto_processor, test_applies_pil_backend_only_to_image_processor）: 关键行为测试：验证 backend 不会透传给 AutoProcessor、只重建 image 子处理器。

关键符号：resolve_image_processor_backend, _normalize_image_processor_backend, _apply_image_processor_backend, get_processor, get_processor_wrapper, _init_mm_processor, _load_mm_processor, _handle_deprecated_args

## 关键源码片段

### `python/sglang/srt/utils/hf_transformers/processor.py`

核心解析与 backend 应用逻辑所在：新增 `resolve_image_processor_backend`、`_normalize_image_processor_backend`、`_apply_image_processor_backend`，`get_processor` 签名收敛 `use_fast` 并接入新参数。

```python
# python/sglang/srt/utils/hf_transformers/processor.py

_IMAGE_PROCESSOR_BACKENDS = {"auto", "torchvision", "pil"}


def resolve_image_processor_backend(server_args) -> str:
    # 统一从 ServerArgs 解析 backend：旧标志 disable_fast_image_processor
    # 仍然生效并直接映射为 pil，保证迁移期行为一致。
    if getattr(server_args, "disable_fast_image_processor", False):
        return "pil"
    return getattr(server_args, "image_processor_backend", "auto")


def _normalize_image_processor_backend(
    image_processor_backend: Optional[str], use_fast: Optional[bool]
) -> str:
    # 校验合法取值，并把 Python 兼容别名 use_fast 归一化到新参数语义：
    # use_fast=True 等价 torchvision，use_fast=False 等价 pil。
    backend = image_processor_backend or "auto"
    if backend not in _IMAGE_PROCESSOR_BACKENDS:
        raise ValueError(
            f"Unsupported image processor backend: {backend}. "
            f"Expected one of {sorted(_IMAGE_PROCESSOR_BACKENDS)}."
        )

    if use_fast is not None:
        legacy_backend = "torchvision" if use_fast else "pil"
        if backend not in {"auto", legacy_backend}:
            raise ValueError(
                f"use_fast={use_fast} conflicts with "
                f"image_processor_backend={backend!r}."
            )
        backend = legacy_backend
    return backend


def _apply_image_processor_backend(
    processor, tokenizer_name, args, trust_remote_code, revision, backend, kwargs
):
    """只把显式 backend 应用到 image 子处理器，避免 ProcessorMixin
    把泛化 kwargs 泄漏给 video processor / tokenizer。"""
    if backend == "auto" or not hasattr(processor, "image_processor"):
        return processor

    image_processor = processor.image_processor
    if getattr(image_processor, "backend", None) == backend:
        return processor

    # 剔除可能冲突的旧参数后，用 AutoImageProcessor 重建 image 子处理器；
    # 其余子处理器（tokenizer、video、audio）保持 AutoProcessor 的默认加载。
    image_processor_kwargs = dict(kwargs)
    image_processor_kwargs.pop("backend", None)
    image_processor_kwargs.pop("use_fast", None)
    processor.image_processor = AutoImageProcessor.from_pretrained(
        tokenizer_name,
        *args,
        trust_remote_code=trust_remote_code,
        revision=revision,
        backend=backend,
        **image_processor_kwargs,
    )
    return processor

```

# 评论区精华

该 PR 的 review 评论数为 0，唯一的 issue 评论是作者自己的 `/tag-and-rerun-ci` 触发 CI。因此没有可提炼的评审交锋。

- 暂无高价值评论线程

# 风险与影响

- 风险：
 1. **行为差异风险**：默认从 `use_fast=True`（等效 torchvision）变为 `auto`，Transformers 可能为某些模型选择 `pil`，导致 VLM 图像预处理结果变化（尺寸、像素值归一化等细节），进而影响 e2e 精度 / 输出 token。
 2. **兼容性风险**：`get_processor(use_fast=...)` 仍支持，但 `use_fast=False` 现在映射为 `pil` 而非 `torchvision` 慢速版，语义有细微变化；`disable_fast_image_processor` 与 `image_processor_backend=torchvision` 同时使用会抛 ValueError，属于刻意设计的 breaking 行为，但依赖旧组合的用户脚本会失败。
 3. **漏改调用点风险**：仓库内还可能有第三方 / 自定义 processor 路径直接向 `AutoProcessor` 传 `backend` 或 `use_fast`；当前只迁移了列出的 4 处主调用点，`multimodal_gen` 的 loader 也只做了小改动，仍需全量 CI 覆盖。
 4. **`_apply_image_processor_backend` 的二段加载开销**：显式指定 backend 时，除 `AutoProcessor` 加载外还会额外 `AutoImageProcessor.from_pretrained` 一次（同一模型目录，通常有本地缓存），启动时间略有增加；且 `kwargs` 中残留 `size` 等 qwen2_vl 专用参数会被带到 image processor 构建中，存在参数不兼容的隐患。
 - 影响：影响范围集中在多模态模型的 processor 加载路径：tokenizer manager、scheduler、encode/disaggregation 服务、multimodal_gen 组件都受影响；默认行为下普通用户无感，显式使用 `--image-processor-backend` 或旧 `--disable-fast-image-processor` 的用户会看到新参数 / 单次警告。由于默认从 `use_fast=True` 改为 `auto`，所有 VLM 请求的图片预处理后端可能发生变化，属于中等偏高影响面；但本地 CI 的 e2e 测试通过，回归面可控。团队收益是消除了 Transformers 新版 deprecation warning 噪音，并为后端选择提供确定性入口。
 - 风险标记：默认行为变更 , 调用点较多 , 依赖上游参数语义 , 二段加载开销

# 关联脉络

- 暂无明显关联 PR