Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ multimodal = [
"torchvision",
]

[tool.setuptools.package-data]
sgl_jax = ["**/*.yaml"]

[tool.setuptools.packages.find]
exclude = [
"assets*",
Expand Down
2 changes: 1 addition & 1 deletion python/sgl_jax/srt/configs/model_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ def __init__(
moe_backend: str | MoEBackend = MoEBackend.AUTO,
model_sub_dir: str | None = None,
) -> None:

self.model_path = model_path
self.model_sub_dir = model_sub_dir
self.revision = revision
Expand Down Expand Up @@ -696,6 +695,7 @@ def is_generation_model(model_architectures: list[str], is_embedding: bool = Fal
"Qwen2AudioForConditionalGeneration",
"Qwen2VLForConditionalGeneration",
"Qwen2_5_VLForConditionalGeneration",
"Qwen3VLForConditionalGeneration",
"KimiVLForConditionalGeneration",
"InternVLChatModel",
"Phi4MMForCausalLM",
Expand Down
12 changes: 6 additions & 6 deletions python/sgl_jax/srt/models/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ def import_model_classes():
entry = module.EntryClass
if isinstance(entry, list): # To support multiple model classes in one module
for tmp in entry:
assert (
tmp.__name__ not in model_arch_name_to_cls
), f"Duplicated model implementation for {tmp.__name__}"
assert tmp.__name__ not in model_arch_name_to_cls, (
f"Duplicated model implementation for {tmp.__name__}"
)
model_arch_name_to_cls[tmp.__name__] = tmp
else:
assert (
entry.__name__ not in model_arch_name_to_cls
), f"Duplicated model implementation for {entry.__name__}"
assert entry.__name__ not in model_arch_name_to_cls, (
f"Duplicated model implementation for {entry.__name__}"
)
model_arch_name_to_cls[entry.__name__] = entry

return model_arch_name_to_cls
Expand Down
176 changes: 176 additions & 0 deletions python/sgl_jax/srt/multimodal/configs/qwen_vl/qwen3_vl_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
from dataclasses import dataclass, field

from sgl_jax.srt.multimodal.configs.multimodal_base_config import MultiModalModelConfigs

@dataclass
class Qwen3VLVisionConfig:
"""Vision encoder configuration for Qwen3-VL."""

depth: int = 24
hidden_size: int = 1024
intermediate_size: int = 4096
num_heads: int = 16
in_channels: int = 3
patch_size: int = 16
temporal_patch_size: int = 2
spatial_merge_size: int = 2
out_hidden_size: int = 2048
num_position_embeddings: int = 2304
deepstack_visual_indexes: tuple = (5, 11, 17)
hidden_act: str = "gelu"
layer_norm_eps: float = 1e-6
rope_theta: float = 10000.0

@property
def head_dim(self) -> int:
return self.hidden_size // self.num_heads

@classmethod
def qwen3vl_2b(cls):
return cls(
depth=24,
hidden_size=1024,
intermediate_size=4096,
num_heads=16,
out_hidden_size=2048,
deepstack_visual_indexes=(5, 11, 17),
)

@classmethod
def qwen3vl_4b(cls):
return cls(
depth=24,
hidden_size=1024,
intermediate_size=4096,
num_heads=16,
out_hidden_size=2560,
deepstack_visual_indexes=(5, 11, 17),
)

@classmethod
def qwen3vl_8b(cls):
return cls(
depth=27,
hidden_size=1152,
intermediate_size=4304,
num_heads=16,
out_hidden_size=4096,
deepstack_visual_indexes=(8, 16, 24),
)

@classmethod
def qwen3vl_32b(cls):
return cls(
depth=27,
hidden_size=1152,
intermediate_size=4304,
num_heads=16,
out_hidden_size=5120,
deepstack_visual_indexes=(8, 16, 24),
)


@dataclass
class Qwen3VLTextConfig:
"""Text decoder configuration for Qwen3-VL."""

vocab_size: int = 151936
hidden_size: int = 2048
intermediate_size: int = 6144
num_hidden_layers: int = 28
num_attention_heads: int = 16
num_key_value_heads: int = 8
head_dim: int = 128
hidden_act: str = "silu"
rms_norm_eps: float = 1e-6
rope_theta: float = 5_000_000
mrope_section: tuple = (24, 20, 20) # T, H, W partitions of head_dim
attention_bias: bool = False
tie_word_embeddings: bool = True

@classmethod
def qwen3vl_2b(cls):
return cls(
hidden_size=2048,
intermediate_size=6144,
num_hidden_layers=28,
num_attention_heads=16,
num_key_value_heads=8,
tie_word_embeddings=True,
)

@classmethod
def qwen3vl_4b(cls):
return cls(
hidden_size=2560,
intermediate_size=9728,
num_hidden_layers=36,
num_attention_heads=32,
num_key_value_heads=8,
tie_word_embeddings=True,
)

@classmethod
def qwen3vl_8b(cls):
return cls(
hidden_size=4096,
intermediate_size=12288,
num_hidden_layers=36,
num_attention_heads=32,
num_key_value_heads=8,
tie_word_embeddings=False,
)

@classmethod
def qwen3vl_32b(cls):
return cls(
hidden_size=5120,
intermediate_size=25600,
num_hidden_layers=64,
num_attention_heads=64,
num_key_value_heads=8,
tie_word_embeddings=False,
)


@dataclass
class Qwen3VLConfig(MultiModalModelConfigs):
"""Combined configuration for Qwen3-VL model."""

vision_config: Qwen3VLVisionConfig = field(default_factory=Qwen3VLVisionConfig)
text_config: Qwen3VLTextConfig = field(default_factory=Qwen3VLTextConfig)
image_token_id: int = 151655
video_token_id: int = 151656
vision_start_token_id: int = 151652
vision_end_token_id: int = 151653

@classmethod
def qwen3vl_2b(cls):
"""Qwen3-VL 2B configuration."""
return cls(
vision_config=Qwen3VLVisionConfig.qwen3vl_2b(),
text_config=Qwen3VLTextConfig.qwen3vl_2b(),
)

@classmethod
def qwen3vl_4b(cls):
"""Qwen3-VL 4B configuration."""
return cls(
vision_config=Qwen3VLVisionConfig.qwen3vl_4b(),
text_config=Qwen3VLTextConfig.qwen3vl_4b(),
)

@classmethod
def qwen3vl_8b(cls):
"""Qwen3-VL 8B configuration."""
return cls(
vision_config=Qwen3VLVisionConfig.qwen3vl_8b(),
text_config=Qwen3VLTextConfig.qwen3vl_8b(),
)

@classmethod
def qwen3vl_32b(cls):
return cls(
vision_config=Qwen3VLVisionConfig.qwen3vl_32b(),
text_config=Qwen3VLTextConfig.qwen3vl_32b(),
)
5 changes: 3 additions & 2 deletions python/sgl_jax/srt/multimodal/entrypoint/http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,11 @@ def _execute_multimodal_server_warmup(

# Send a warmup request
# For Wan models, send an image generation request
if "Qwen2.5-VL" in server_args.model_path:
if "Qwen3-VL" in server_args.model_path or "Qwen2.5-VL" in server_args.model_path:
model_name = "Qwen/Qwen3-VL" if "Qwen3-VL" in server_args.model_path else "Qwen/Qwen2.5-VL"
request_endpoint = "/v1/chat/completions"
json_data = {
"model": "Qwen/Qwen2.5-VL",
"model": model_name,
"messages": [
{
"role": "user",
Expand Down
8 changes: 8 additions & 0 deletions python/sgl_jax/srt/multimodal/manager/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
from sgl_jax.srt.multimodal.models.qwen2_5VL.qwen2_5_vl_generation import (
Qwen2_5_VL_Generation,
)
from sgl_jax.srt.multimodal.models.qwen3_VL.qwen3_vl_vit import Qwen3_VL_VisionModel
from sgl_jax.srt.multimodal.models.qwen3_VL.qwen3_vl_generation import (
Qwen3_VL_Generation,
)
from sgl_jax.srt.multimodal.models.wan.diffusion.wan_dit import (
WanDualTransformer3DModel,
WanTransformer3DModel,
Expand Down Expand Up @@ -189,6 +193,10 @@ def get_model_class(name: str):
return Qwen2_5_VL_Generation
elif name == "Qwen2_5_VL_VisionModel":
return Qwen2_5_VL_VisionModel
elif name == "Qwen3_VL_Generation":
return Qwen3_VL_Generation
elif name == "Qwen3_VL_VisionModel":
return Qwen3_VL_VisionModel
elif name == "Qwen2ForCausalLM":
return Qwen2ForCausalLM
else:
Expand Down
43 changes: 43 additions & 0 deletions python/sgl_jax/srt/multimodal/models/qwen3_VL/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Qwen3-VL model implementation for SGLang-JAX.

This module provides the Qwen3-VL multimodal model for high-performance
distributed inference on TPUs.

Components:
- Qwen3_VL_VisionModel: Vision encoder with DeepStack feature extraction
- Qwen3_VL_Generation: Text decoder with M-RoPE for conditional generation
"""

from sgl_jax.srt.multimodal.models.qwen3_VL.qwen3_vl_generation import (
MRotaryEmbedding,
Qwen3_VL_Generation,
Qwen3_VL_Model,
)
from sgl_jax.srt.multimodal.models.qwen3_VL.qwen3_vl_vit import (
Qwen3_VL_VisionModel,
Qwen3_VL_VisionTransformer,
Qwen3_VLImageInputs,
Qwen3_VLVisionAttention,
Qwen3_VLVisionBlock,
Qwen3_VLVisionMLP,
Qwen3_VLVisionPatchEmbed,
Qwen3_VLVisionPatchMerger,
Qwen3_VLVisionRotaryEmbedding,
)

__all__ = [
# Vision components
"Qwen3_VL_VisionModel",
"Qwen3_VL_VisionTransformer",
"Qwen3_VLVisionPatchEmbed",
"Qwen3_VLVisionRotaryEmbedding",
"Qwen3_VLVisionMLP",
"Qwen3_VLVisionAttention",
"Qwen3_VLVisionBlock",
"Qwen3_VLVisionPatchMerger",
"Qwen3_VLImageInputs",
# Generation components
"MRotaryEmbedding",
"Qwen3_VL_Model",
"Qwen3_VL_Generation",
]
Loading
Loading