Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions python/sglang/srt/configs/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ def __init__(
"Llama4ForConditionalGeneration",
"Step3VLForConditionalGeneration",
]
if self.hf_config.architectures[0] in mm_disabled_models:
if (
self.hf_config.architectures[0] in mm_disabled_models
and self.model_impl != ModelImpl.TRANSFORMERS
):
enable_multimodal = False
logger.info(
f"Multimodal is disabled for {self.hf_config.model_type}. To enable it, set --enable-multimodal."
Expand All @@ -165,8 +168,14 @@ def __init__(
self.is_generation = is_generation_model(
self.hf_config.architectures, is_embedding
)
self.is_multimodal = enable_multimodal and is_multimodal_model(
self.hf_config.architectures
has_multimodal_subconfig = (
self.hf_config is not self.hf_text_config
or hasattr(self.hf_config, "vision_config")
or hasattr(self.hf_config, "audio_config")
)
self.is_multimodal = enable_multimodal and (
is_multimodal_model(self.hf_config.architectures)
or has_multimodal_subconfig
)
self.is_multimodal_gen = enable_multimodal and is_multimodal_gen_model(
self.hf_config.architectures
Expand Down
2 changes: 2 additions & 0 deletions python/sglang/srt/managers/io_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,8 @@ class TokenizedGenerateReqInput(BaseReq):
# Whether to return entropy
return_entropy: bool = False

token_type_ids: Optional[List[int]] = None

need_wait_for_mm_inputs: bool = False
num_items_assigned: Optional[Dict[Modality, List[int]]] = None

Expand Down
17 changes: 16 additions & 1 deletion python/sglang/srt/managers/multimodal_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,27 @@ def import_processors(package_name: str, overwrite: bool = False):
def get_mm_processor(
hf_config, server_args: ServerArgs, processor, transport_mode, **kwargs
) -> BaseMultimodalProcessor:
model_impl = str(getattr(server_args, "model_impl", "auto")).lower()

for model_cls, processor_cls in PROCESSOR_MAPPING.items():
if model_cls.__name__ in hf_config.architectures:
if model_cls.__name__ not in hf_config.architectures:
continue
if model_impl != "transformers" or getattr(
processor_cls, "supports_transformers_backend", False
):
return processor_cls(
hf_config, server_args, processor, transport_mode, **kwargs
)

if model_impl in {"auto", "transformers"}:
from sglang.srt.multimodal.processors.transformers_auto import (
TransformersAutoMultimodalProcessor,
)

return TransformersAutoMultimodalProcessor(
hf_config, server_args, processor, transport_mode, **kwargs
)

Comment thread
adarshxs marked this conversation as resolved.
raise ValueError(
f"No processor registered for architecture: {hf_config.architectures}.\n"
f"Registered architectures: {[model_cls.__name__ for model_cls in PROCESSOR_MAPPING.keys()]}"
Expand Down
54 changes: 40 additions & 14 deletions python/sglang/srt/managers/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from torch.distributed import barrier

from sglang.jit_kernel.ngram_embedding import update_token_table
from sglang.srt.configs.model_config import ModelConfig
from sglang.srt.configs.model_config import ModelConfig, ModelImpl
from sglang.srt.constrained.grammar_manager import GrammarManager
from sglang.srt.disaggregation.decode import (
DecodePreallocQueue,
Expand Down Expand Up @@ -679,9 +679,25 @@ def init_cache_with_memory_pool(self):
self.tp_worker.get_memory_pool()
)

# Create cache
self.disable_radix_cache = server_args.disable_radix_cache or (
self.model_config.is_multimodal
and self.model_config.model_impl == ModelImpl.TRANSFORMERS
)
if self.disable_radix_cache and not server_args.disable_radix_cache:
logger.warning(
"Radix cache is disabled for multimodal models with the "
"Transformers backend to avoid multimodal prefix-cache mismatches."
)

effective_chunked_prefill_size = server_args.chunked_prefill_size
if (
self.model_config.is_multimodal
and self.model_config.model_impl == ModelImpl.TRANSFORMERS
):
effective_chunked_prefill_size = None

params = CacheInitParams(
disable=server_args.disable_radix_cache,
disable=self.disable_radix_cache,
req_to_token_pool=self.req_to_token_pool,
token_to_kv_pool_allocator=self.token_to_kv_pool_allocator,
page_size=self.page_size,
Expand All @@ -697,14 +713,11 @@ def init_cache_with_memory_pool(self):
enable_mamba_extra_buffer=server_args.enable_mamba_extra_buffer(),
pp_rank=self.pp_rank,
pp_size=self.pp_size,
chunked_prefill_size=server_args.chunked_prefill_size,
chunked_prefill_size=effective_chunked_prefill_size,
sliding_window_size=self.sliding_window_size,
)

if (
server_args.chunked_prefill_size is not None
and server_args.disable_radix_cache
):
if effective_chunked_prefill_size is not None and self.disable_radix_cache:
if not self.is_hybrid_swa:
from sglang.srt.mem_cache.chunk_cache import ChunkCache

Expand Down Expand Up @@ -800,9 +813,19 @@ def init_running_status(self):
self._engine_paused = False

def init_chunked_prefill(self):
# Init chunked prefill
self.chunked_prefill_size = self.server_args.chunked_prefill_size
if self.chunked_prefill_size <= 0: # -1 means disable
if (
self.chunked_prefill_size is not None
and self.chunked_prefill_size > 0
and self.model_config.is_multimodal
and self.model_config.model_impl == ModelImpl.TRANSFORMERS
):
logger.warning(
"Chunked prefill is disabled for multimodal models with the "
"Transformers backend to avoid partial multimodal chunk mismatches."
)
self.chunked_prefill_size = None
elif self.chunked_prefill_size is not None and self.chunked_prefill_size <= 0:
self.chunked_prefill_size = None
self.chunked_req = None
self.is_mixed_chunk = (
Expand Down Expand Up @@ -1640,6 +1663,7 @@ def handle_generate_request(
stream=recv_req.stream,
lora_id=recv_req.lora_id,
input_embeds=recv_req.input_embeds,
token_type_ids=recv_req.token_type_ids,
custom_logit_processor=recv_req.custom_logit_processor,
require_reasoning=recv_req.require_reasoning,
return_hidden_states=recv_req.return_hidden_states,
Expand Down Expand Up @@ -1722,10 +1746,12 @@ def handle_generate_request(
SessionController.adjust_mm_offsets(recv_req, req, image_inputs)

# The following steps are already fast, execute locally on each rank.
# Expand a single image token into multiple dummy tokens for receiving image embeddings
req.origin_input_ids = self.pad_input_ids_func(
req.origin_input_ids, image_inputs
)
# Expand a single image token into multiple dummy tokens for receiving image embeddings.
# The pad function is model-specific and can be None for some backends.
if self.pad_input_ids_func:
req.origin_input_ids = self.pad_input_ids_func(
req.origin_input_ids, image_inputs
)
req.extend_image_inputs(image_inputs)

if len(req.origin_input_ids) >= self.max_req_input_len:
Expand Down
5 changes: 5 additions & 0 deletions python/sglang/srt/managers/tokenizer_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,10 @@ async def _tokenize_one_request(

if mm_inputs and "input_ids" in mm_inputs:
input_ids = mm_inputs["input_ids"]
if mm_inputs and "token_type_ids" in mm_inputs:
token_type_ids = mm_inputs.pop("token_type_ids")
if not isinstance(token_type_ids, list):
token_type_ids = token_type_ids.flatten().tolist()
if (
envs.SGLANG_MM_PRECOMPUTE_HASH.get()
and mm_inputs
Expand Down Expand Up @@ -982,6 +986,7 @@ def _create_tokenized_object(
priority=obj.priority,
extra_key=obj.extra_key,
routing_key=obj.routing_key,
token_type_ids=token_type_ids,
need_wait_for_mm_inputs=obj.need_wait_for_mm_inputs,
num_items_assigned=obj.num_items_assigned,
)
Expand Down
11 changes: 11 additions & 0 deletions python/sglang/srt/model_executor/model_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1903,6 +1903,17 @@ def _dummy_run(self, batch_size: int, run_ctx=None):

if self.server_args.enable_torch_compile:
set_torch_compile_config()
should_disable_torch_compile = (
self.server_args.model_impl.lower() == ModelImpl.TRANSFORMERS
and not getattr(self.model, "_can_torch_compile", True)
)
if should_disable_torch_compile:
log_info_on_rank0(
logger,
"Transformers backend model reports it is not torch.compile "
"compatible (e.g. dynamic rope scaling). Disabling torch.compile.",
)
self.server_args.enable_torch_compile = False

if self.eagle_use_aux_hidden_state:
self.model.set_eagle3_layers_to_capture()
Expand Down
124 changes: 110 additions & 14 deletions python/sglang/srt/model_loader/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,79 @@ def set_default_torch_dtype(dtype: torch.dtype):
torch.set_default_dtype(old_dtype)


def _is_moe_model(model_config: ModelConfig, architectures: list[str]) -> bool:
lowered_arches = [arch.lower() for arch in architectures]
if any("moe" in arch or "mixtral" in arch for arch in lowered_arches):
return True

text_config = model_config.hf_text_config
expert_attrs = (
"num_local_experts",
"num_experts",
"num_experts_per_tok",
"moe_intermediate_size",
"n_routed_experts",
)
for attr in expert_attrs:
value = getattr(text_config, attr, None)
if value is None:
continue
if isinstance(value, bool):
if value:
return True
continue
if isinstance(value, (int, float)):
threshold = 0 if attr == "moe_intermediate_size" else 1
if value > threshold:
return True
continue
if isinstance(value, (list, tuple, set, dict)):
if len(value) > 0:
return True
continue
if isinstance(value, str) and value == "":
continue
if value is not None:
return True
return False


def _is_sequence_classification_model(architectures: list[str]) -> bool:
return any(
"sequenceclassification" in lowered or "rewardmodel" in lowered
for lowered in (arch.lower() for arch in architectures)
)


def _get_transformers_backend_arch(
model_config: ModelConfig, architectures: list[str]
) -> str:
is_pooling = not model_config.is_generation
is_multimodal = model_config.is_multimodal or (
model_config.hf_config is not model_config.hf_text_config
)
Comment thread
adarshxs marked this conversation as resolved.
is_moe = _is_moe_model(model_config, architectures)
base_arch = "ForCausalLM"
if is_pooling:
base_arch = (
"ForSequenceClassification"
if _is_sequence_classification_model(architectures)
else "EmbeddingModel"
)

arch = "Transformers"
if is_multimodal:
arch += "MultiModal"
if is_moe:
arch += "MoE"
return arch + base_arch


def resolve_transformers_arch(model_config: ModelConfig, architectures: list[str]):
for i, arch in enumerate(architectures):
if arch == "TransformersForCausalLM":
backend_arch = _get_transformers_backend_arch(model_config, architectures)

for arch in architectures:
if arch.startswith("Transformers"):
continue
auto_map: dict[str, str] = (
getattr(model_config.hf_config, "auto_map", None) or dict()
Expand All @@ -42,32 +112,59 @@ def resolve_transformers_arch(model_config: ModelConfig, architectures: list[str
# "AutoModel": "<your-repo-name>--<config-name>",
# "AutoModelFor<Task>": "<your-repo-name>--<config-name>",
# },
auto_modules = {
name: get_class_from_dynamic_module(
module, model_config.model_path, revision=model_config.revision
auto_modules = {}
try:
auto_modules = {
name: get_class_from_dynamic_module(
module, model_config.model_path, revision=model_config.revision
)
for name, module in sorted(auto_map.items(), key=lambda x: x[0])
}
except Exception as e:
logger.warning(
"Failed to load dynamic modules from auto_map for '%s': %s. "
"Skipping remote model compatibility checks.",
arch,
e,
)
for name, module in sorted(auto_map.items(), key=lambda x: x[0])
}
model_module = getattr(transformers, arch, None)
if model_module is None:
if "AutoModel" not in auto_map:
has_auto_model = "AutoModel" in auto_modules
if not has_auto_model and model_config.model_impl == ModelImpl.TRANSFORMERS:
logger.warning(
"Cannot resolve model class for '%s' and no auto_map.AutoModel "
"is present. Skipping compatibility gate because "
"--model-impl=transformers is explicitly requested.",
arch,
)
continue
if not has_auto_model and "AutoModel" not in auto_map:
raise ValueError(
f"Cannot find model module. '{arch}' is not a registered "
"model in the Transformers library (only relevant if the "
"model is meant to be in Transformers) and 'AutoModel' is "
"not present in the model config's 'auto_map' (relevant "
"if the model is custom)."
)
if not has_auto_model:
raise ValueError(
f"Cannot find model module. '{arch}' is not a registered "
"model in the Transformers library and loading the custom "
f"model from auto_map failed. The remote model code may be "
f"incompatible with the installed transformers version."
)
model_module = auto_modules["AutoModel"]
if model_config.model_impl == ModelImpl.TRANSFORMERS:
if hasattr(model_module, "is_backend_compatible") and (
not model_module.is_backend_compatible()
):
raise ValueError(
f"The Transformers implementation of {arch} is not "
"compatible with SGLang."
logger.warning(
"The Transformers implementation of %s reports it is not "
"backend-compatible (_supports_attention_backend=False). "
"Proceeding anyway because --model-impl=transformers was "
"explicitly requested. The model may not work correctly.",
arch,
)
architectures[i] = "TransformersForCausalLM"
if model_config.model_impl == ModelImpl.AUTO:
if hasattr(model_module, "is_backend_compatible") and (
not model_module.is_backend_compatible()
Expand All @@ -82,8 +179,7 @@ def resolve_transformers_arch(model_config: ModelConfig, architectures: list[str
"performance may not be optimal.",
arch,
)
architectures[i] = "TransformersForCausalLM"
return architectures
return [backend_arch]


def get_model_architecture(model_config: ModelConfig) -> Tuple[Type[nn.Module], str]:
Expand Down
2 changes: 1 addition & 1 deletion python/sglang/srt/models/qwen2.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def __init__(
) -> None:
super().__init__()
self.config = config
self.padding_idx = config.pad_token_id
self.padding_idx = getattr(config, "pad_token_id", None)
self.vocab_size = config.vocab_size
self.pp_group = get_pp_group()

Expand Down
Loading
Loading