[VLM] replace deprecated image processor use_fast (#34175)

This commit is contained in:
Mick
2026-08-12 00:14:07 +08:00
committed by GitHub
parent b20c375c10
commit 8267d76c2c
21 changed files with 281 additions and 98 deletions
@@ -480,7 +480,9 @@ class ImageProcessorLoader(ComponentLoader):
def load_customized(
self, component_model_path: str, server_args: ServerArgs, component_name: str
) -> Any:
return AutoImageProcessor.from_pretrained(component_model_path, use_fast=True)
return AutoImageProcessor.from_pretrained(
component_model_path, backend="torchvision"
)
class AutoProcessorLoader(ComponentLoader):
@@ -73,7 +73,8 @@ class ARCluster(DisaggCluster):
"--enable-multimodal",
"--cuda-graph-bs",
"1",
"--disable-fast-image-processor",
"--image-processor-backend",
"pil",
"--tp-size",
str(len(gpus)),
"--port",
@@ -914,12 +914,11 @@ def get_clip_model() -> tuple[Any, Any]:
if "RobertaProcessing" not in str(e):
raise
logger.warning(
"Fast CLIP processor failed (%s), retrying with use_fast=False", e
"CLIP processor failed (%s), retrying with compatibility shim", e
)
processor = _load_clip_processor_with_roberta_processing_compat(
CLIPProcessor,
CLIP_MODEL_NAME,
use_fast=False,
)
model = CLIPModel.from_pretrained(CLIP_MODEL_NAME)
@@ -36,7 +36,10 @@ from sglang.srt.managers.schedule_batch import Modality, Req
from sglang.srt.server_args import ServerArgs
from sglang.srt.utils import ImageData
from sglang.srt.utils.common import safe_pickle_loads
from sglang.srt.utils.hf_transformers_utils import get_processor
from sglang.srt.utils.hf_transformers_utils import (
get_processor,
resolve_image_processor_backend,
)
from sglang.srt.utils.network import (
NetworkAddress,
get_local_ip_auto,
@@ -1674,32 +1677,14 @@ class MMReceiverBase(ABC):
if getattr(server_args, "tokenizer_backend", None) is not None:
extra_kwargs["tokenizer_backend"] = server_args.tokenizer_backend
_processor = None
try:
_processor = get_processor(
server_args.tokenizer_path,
tokenizer_mode=server_args.tokenizer_mode,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=not server_args.disable_fast_image_processor,
**extra_kwargs,
)
except ValueError as e:
error_message = str(e)
if "does not have a slow version" in error_message:
logger.info(
f"Processor {server_args.tokenizer_path} does not have a slow version. Automatically use fast version"
)
_processor = get_processor(
server_args.tokenizer_path,
tokenizer_mode=server_args.tokenizer_mode,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=True,
**extra_kwargs,
)
else:
raise e
_processor = get_processor(
server_args.tokenizer_path,
tokenizer_mode=server_args.tokenizer_mode,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
image_processor_backend=resolve_image_processor_backend(server_args),
**extra_kwargs,
)
enable_adaptive_dispatch_to_encoder = (
server_args.enable_adaptive_dispatch_to_encoder
@@ -92,6 +92,7 @@ from sglang.srt.utils import (
set_prometheus_multiproc_dir,
)
from sglang.srt.utils.common import configure_logger, maybe_reindex_device_id
from sglang.srt.utils.hf_transformers_utils import resolve_image_processor_backend
from sglang.srt.utils.network import (
NetworkAddress,
config_socket,
@@ -341,7 +342,8 @@ class MMEncoder:
torch.get_device_module(self.device).set_device(self.gpu_id)
self.use_image_processor_gpu = (
use_image_processor_gpu and not server_args.disable_fast_image_processor
use_image_processor_gpu
and resolve_image_processor_backend(server_args) != "pil"
)
self._build_vision_config(server_args.mm_process_config)
self.model_audio_sr = self._resolve_audio_sr()
@@ -606,12 +608,18 @@ class MMEncoder:
"""
from transformers import AutoImageProcessor, AutoVideoProcessor
image_processor_backend = resolve_image_processor_backend(server_args)
image_processor_kwargs = (
{}
if image_processor_backend == "auto"
else {"backend": image_processor_backend}
)
try:
self.image_processor = AutoImageProcessor.from_pretrained(
server_args.tokenizer_path or server_args.model_path,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=not server_args.disable_fast_image_processor,
**image_processor_kwargs,
)
except Exception as e:
logger.warning(f"Failed to load image processor: {e}")
@@ -622,7 +630,6 @@ class MMEncoder:
server_args.tokenizer_path or server_args.model_path,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=not server_args.disable_fast_image_processor,
)
except Exception as e:
logger.warning(f"Failed to load video processor: {e}")
@@ -634,7 +641,6 @@ class MMEncoder:
server_args.tokenizer_path or server_args.model_path,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=not server_args.disable_fast_image_processor,
)
if not hasattr(_audio_proc, "feature_extractor"):
logger.warning(
+2 -1
View File
@@ -315,6 +315,7 @@ from sglang.srt.utils.hf_transformers_utils import (
get_processor,
get_tokenizer,
get_tokenizer_from_processor,
resolve_image_processor_backend,
)
from sglang.srt.utils.msgspec_utils import msgspec_to_builtins
from sglang.srt.utils.numa_utils import get_numa_node_if_available, numa_bind_to_node
@@ -812,7 +813,7 @@ class Scheduler(
tokenizer_mode=get_serving().tokenizer_mode,
trust_remote_code=get_model().trust_remote_code,
revision=get_model().revision,
use_fast=not get_mm().disable_fast_image_processor,
image_processor_backend=resolve_image_processor_backend(get_mm()),
tokenizer_backend=get_serving().tokenizer_backend,
model_name=get_model().model_path,
)
+10 -28
View File
@@ -145,6 +145,7 @@ from sglang.srt.utils.hf_transformers_utils import (
get_processor,
get_tokenizer,
get_tokenizer_from_processor,
resolve_image_processor_backend,
)
from sglang.srt.utils.network import get_zmq_socket
from sglang.srt.utils.request_logger import RequestLogger
@@ -3556,34 +3557,15 @@ async def print_exception_wrapper(func):
def get_processor_wrapper(server_args):
try:
processor = get_processor(
server_args.tokenizer_path,
tokenizer_mode=server_args.tokenizer_mode,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=not server_args.disable_fast_image_processor,
tokenizer_backend=server_args.tokenizer_backend,
model_name=server_args.model_path,
)
except ValueError as e:
error_message = str(e)
if "does not have a slow version" in error_message:
logger.info(
f"Processor {server_args.tokenizer_path} does not have a slow version. Automatically use fast version"
)
processor = get_processor(
server_args.tokenizer_path,
tokenizer_mode=server_args.tokenizer_mode,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
use_fast=True,
tokenizer_backend=server_args.tokenizer_backend,
model_name=server_args.model_path,
)
else:
raise e
return processor
return get_processor(
server_args.tokenizer_path,
tokenizer_mode=server_args.tokenizer_mode,
trust_remote_code=server_args.trust_remote_code,
revision=server_args.revision,
image_processor_backend=resolve_image_processor_backend(server_args),
tokenizer_backend=server_args.tokenizer_backend,
model_name=server_args.model_path,
)
def determine_tensor_transport_mode(server_args: ServerArgs) -> TensorTransportMode:
@@ -206,7 +206,12 @@ class BaseMultimodalProcessor(ABC):
self.use_ipc_pool_handle_cache = (
self.use_cuda_ipc and envs.SGLANG_USE_IPC_POOL_HANDLE_CACHE.get()
)
self.disable_fast_image_processor = server_args.disable_fast_image_processor
self.image_processor_backend = getattr(
server_args, "image_processor_backend", "auto"
)
if getattr(server_args, "disable_fast_image_processor", False):
self.image_processor_backend = "pil"
self.disable_fast_image_processor = self.image_processor_backend == "pil"
self.skip_tokenizer_init = server_args.skip_tokenizer_init
mm_process_config = self.server_args.mm_process_config
+21 -1
View File
@@ -2766,6 +2766,12 @@ class ServerArgs:
"Enable global multimodal embedding cache to skip redundant ViT inference.",
NS("mm"),
] = False
image_processor_backend: A[
Literal["auto", "torchvision", "pil"],
"Image processor backend. 'auto' lets Transformers select the best "
"available backend.",
NS("mm"),
] = "auto"
mm_global_cache_backend: A[
str,
Arg(
@@ -2776,7 +2782,9 @@ class ServerArgs:
NS("mm"),
] = "mooncake"
disable_fast_image_processor: A[
bool, "Adopt base image processor instead of fast image processor.", NS("mm")
bool,
"Deprecated. Use --image-processor-backend=pil instead.",
NS("mm"),
] = False
mm_feature_transport: A[
Optional[Literal["cpu", "cuda_ipc", "cuda_vmm"]],
@@ -3990,6 +3998,18 @@ class ServerArgs:
)
def _handle_deprecated_args(self):
if self.disable_fast_image_processor:
if self.image_processor_backend not in {"auto", "pil"}:
raise ValueError(
"--disable-fast-image-processor conflicts with "
f"--image-processor-backend={self.image_processor_backend}."
)
logger.warning(
"--disable-fast-image-processor is deprecated; use "
"--image-processor-backend=pil instead."
)
self.image_processor_backend = "pil"
# Handle deprecated tool call parsers
deprecated_tool_call_parsers = {"qwen25": "qwen", "glm45": "glm"}
if self.tool_call_parser in deprecated_tool_call_parsers:
@@ -37,7 +37,7 @@ from .common import (
get_tokenizer_from_processor,
)
from .config import get_config
from .processor import get_processor
from .processor import get_processor, resolve_image_processor_backend
from .tokenizer import (
_fix_added_tokens_encoding,
_fix_v5_add_bos_eos_token,
@@ -57,6 +57,7 @@ __all__ = [
"get_generation_config",
"get_hf_text_config",
"get_processor",
"resolve_image_processor_backend",
"get_rope_config",
"get_sparse_attention_config",
"get_tokenizer",
@@ -18,6 +18,7 @@ from pathlib import Path
from typing import Optional
from transformers import (
AutoImageProcessor,
AutoProcessor,
AutoTokenizer,
PreTrainedTokenizerBase,
@@ -49,6 +50,72 @@ from .tokenizer import (
_fix_special_tokens_pattern,
)
_IMAGE_PROCESSOR_BACKENDS = {"auto", "torchvision", "pil"}
def resolve_image_processor_backend(server_args) -> str:
"""Resolve the new backend option while honoring the legacy disable flag."""
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:
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,
):
"""Apply an explicit backend only to the image sub-processor.
ProcessorMixin forwards generic kwargs to every sub-processor. Passing
``backend`` through AutoProcessor therefore also reaches tokenizers and
video processors, where it has different semantics or may be read-only.
"""
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
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
def _build_processor_manually(
model_path, config, trust_remote_code, revision, **kwargs
@@ -141,7 +208,8 @@ def get_processor(
tokenizer_mode: str = "auto",
trust_remote_code: bool = False,
tokenizer_revision: Optional[str] = None,
use_fast: Optional[bool] = True,
use_fast: Optional[bool] = None,
image_processor_backend: Optional[str] = None,
tokenizer_backend: str = "huggingface",
model_name: Optional[str] = None,
**kwargs,
@@ -152,6 +220,9 @@ def get_processor(
_ensure_fastokens_patched()
revision = kwargs.pop("revision", tokenizer_revision)
image_processor_backend = _normalize_image_processor_backend(
image_processor_backend, use_fast
)
tokenizer_name = resolve_runai_obj_uri(tokenizer_name)
if model_name is not None:
model_name = resolve_runai_obj_uri(model_name)
@@ -186,7 +257,6 @@ def get_processor(
# Checkpoints with language_model_only=True are text-only despite their
# multimodal-family config; route to tokenizer instead of the mm processor.
if getattr(config, "language_model_only", False):
kwargs.pop("use_fast", None)
return AutoTokenizer.from_pretrained(
tokenizer_name,
*args,
@@ -199,8 +269,6 @@ def get_processor(
if "size" not in kwargs:
kwargs["size"] = {"shortest_edge": 3136, "longest_edge": 1003520}
if config.model_type not in {"llava", "clip"}:
kwargs["use_fast"] = use_fast
try:
if "InternVL3_5" in tokenizer_name:
processor = AutoTokenizer.from_pretrained(
@@ -230,20 +298,7 @@ def get_processor(
except ValueError as e:
error_message = str(e)
if "does not have a slow version" in error_message:
logger.info(
"Processor %s does not have a slow version. Automatically use fast version",
tokenizer_name,
)
kwargs["use_fast"] = True
processor = AutoProcessor.from_pretrained(
tokenizer_name,
*args,
trust_remote_code=trust_remote_code,
revision=revision,
**kwargs,
)
elif "Unrecognized feature extractor" in error_message:
if "Unrecognized feature extractor" in error_message:
logger.info(
"AutoProcessor failed on feature extractor for %s, "
"constructing processor manually",
@@ -261,10 +316,9 @@ def get_processor(
):
logger.info(
"AutoProcessor for %s rejected standard kwargs, "
"retrying without trust_remote_code/use_fast",
"retrying without trust_remote_code",
tokenizer_name,
)
kwargs.pop("use_fast", None)
kwargs.pop("_from_auto", None)
processor = AutoProcessor.from_pretrained(
tokenizer_name,
@@ -274,6 +328,16 @@ def get_processor(
)
else:
raise
processor = _apply_image_processor_backend(
processor,
tokenizer_name,
args,
trust_remote_code,
revision,
image_processor_backend,
kwargs,
)
if (
isinstance(processor, PreTrainedTokenizerBase)
and getattr(config, "model_type", None) == "pixtral"