ZhengyangZhang commited on
Commit
d57c7b3
·
verified ·
1 Parent(s): 650ca8b

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. lib/python3.12/site-packages/sglang/srt/configs/__init__.py +13 -0
  2. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/__init__.cpython-312.pyc +0 -0
  3. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/chatglm.cpython-312.pyc +0 -0
  4. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/dbrx.cpython-312.pyc +0 -0
  5. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/deepseekvl2.cpython-312.pyc +0 -0
  6. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/device_config.cpython-312.pyc +0 -0
  7. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/exaone.cpython-312.pyc +0 -0
  8. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/janus_pro.cpython-312.pyc +0 -0
  9. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/load_config.cpython-312.pyc +0 -0
  10. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/model_config.cpython-312.pyc +0 -0
  11. lib/python3.12/site-packages/sglang/srt/configs/__pycache__/utils.cpython-312.pyc +0 -0
  12. lib/python3.12/site-packages/sglang/srt/configs/chatglm.py +78 -0
  13. lib/python3.12/site-packages/sglang/srt/configs/dbrx.py +279 -0
  14. lib/python3.12/site-packages/sglang/srt/configs/deepseekvl2.py +676 -0
  15. lib/python3.12/site-packages/sglang/srt/configs/device_config.py +17 -0
  16. lib/python3.12/site-packages/sglang/srt/configs/exaone.py +195 -0
  17. lib/python3.12/site-packages/sglang/srt/configs/janus_pro.py +628 -0
  18. lib/python3.12/site-packages/sglang/srt/configs/load_config.py +89 -0
  19. lib/python3.12/site-packages/sglang/srt/configs/model_config.py +558 -0
  20. lib/python3.12/site-packages/sglang/srt/configs/utils.py +25 -0
  21. lib/python3.12/site-packages/sglang/srt/connector/__init__.py +51 -0
  22. lib/python3.12/site-packages/sglang/srt/connector/__pycache__/__init__.cpython-312.pyc +0 -0
  23. lib/python3.12/site-packages/sglang/srt/connector/__pycache__/base_connector.cpython-312.pyc +0 -0
  24. lib/python3.12/site-packages/sglang/srt/connector/__pycache__/redis.cpython-312.pyc +0 -0
  25. lib/python3.12/site-packages/sglang/srt/connector/__pycache__/s3.cpython-312.pyc +0 -0
  26. lib/python3.12/site-packages/sglang/srt/connector/__pycache__/utils.cpython-312.pyc +0 -0
  27. lib/python3.12/site-packages/sglang/srt/connector/base_connector.py +112 -0
  28. lib/python3.12/site-packages/sglang/srt/connector/redis.py +85 -0
  29. lib/python3.12/site-packages/sglang/srt/connector/s3.py +122 -0
  30. lib/python3.12/site-packages/sglang/srt/connector/serde/__init__.py +31 -0
  31. lib/python3.12/site-packages/sglang/srt/connector/serde/__pycache__/__init__.cpython-312.pyc +0 -0
  32. lib/python3.12/site-packages/sglang/srt/connector/serde/__pycache__/safe_serde.cpython-312.pyc +0 -0
  33. lib/python3.12/site-packages/sglang/srt/connector/serde/__pycache__/serde.cpython-312.pyc +0 -0
  34. lib/python3.12/site-packages/sglang/srt/connector/serde/safe_serde.py +29 -0
  35. lib/python3.12/site-packages/sglang/srt/connector/serde/serde.py +43 -0
  36. lib/python3.12/site-packages/sglang/srt/connector/utils.py +35 -0
  37. lib/python3.12/site-packages/sglang/srt/layers/activation.py +172 -0
  38. lib/python3.12/site-packages/sglang/srt/layers/dp_attention.py +260 -0
  39. lib/python3.12/site-packages/sglang/srt/layers/elementwise.py +424 -0
  40. lib/python3.12/site-packages/sglang/srt/layers/layernorm.py +183 -0
  41. lib/python3.12/site-packages/sglang/srt/layers/linear.py +1307 -0
  42. lib/python3.12/site-packages/sglang/srt/layers/logits_processor.py +586 -0
  43. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_native.py +139 -0
  44. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/__init__.py +40 -0
  45. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=14336,device_name=NVIDIA_A100-SXM4-80GB,dtype=int8_w8a16.json +146 -0
  46. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=14336,device_name=NVIDIA_A100-SXM4-80GB.json +146 -0
  47. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=7168,device_name=NVIDIA_A100-SXM4-80GB,dtype=int8_w8a16.json +218 -0
  48. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=7168,device_name=NVIDIA_A100-SXM4-80GB.json +218 -0
  49. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=128,N=192,device_name=NVIDIA_H20.json +146 -0
  50. lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=128,N=384,device_name=NVIDIA_H20.json +146 -0
lib/python3.12/site-packages/sglang/srt/configs/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sglang.srt.configs.chatglm import ChatGLMConfig
2
+ from sglang.srt.configs.dbrx import DbrxConfig
3
+ from sglang.srt.configs.deepseekvl2 import DeepseekVL2Config
4
+ from sglang.srt.configs.exaone import ExaoneConfig
5
+ from sglang.srt.configs.janus_pro import MultiModalityConfig
6
+
7
+ __all__ = [
8
+ "ExaoneConfig",
9
+ "ChatGLMConfig",
10
+ "DbrxConfig",
11
+ "DeepseekVL2Config",
12
+ "MultiModalityConfig",
13
+ ]
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (583 Bytes). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/chatglm.cpython-312.pyc ADDED
Binary file (2.26 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/dbrx.cpython-312.pyc ADDED
Binary file (11.5 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/deepseekvl2.cpython-312.pyc ADDED
Binary file (24.8 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/device_config.cpython-312.pyc ADDED
Binary file (1.07 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/exaone.cpython-312.pyc ADDED
Binary file (10 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/janus_pro.cpython-312.pyc ADDED
Binary file (25.1 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/load_config.cpython-312.pyc ADDED
Binary file (4.3 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/model_config.cpython-312.pyc ADDED
Binary file (19.8 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/__pycache__/utils.cpython-312.pyc ADDED
Binary file (1.1 kB). View file
 
lib/python3.12/site-packages/sglang/srt/configs/chatglm.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from
2
+ # https://github.com/THUDM/ChatGLM2-6B
3
+ # https://github.com/vllm-project/vllm/blob/main/vllm/transformers_utils/configs/chatglm.py
4
+
5
+ # ChatGLM2 and ChatGLM3 share the same config.
6
+ # ChatGLM4 is officially supported by Huggingface
7
+ # transformers >= 4.46.0 is required
8
+ # https://huggingface.co/docs/transformers/en/model_doc/glm
9
+ from transformers import PretrainedConfig
10
+
11
+
12
+ class ChatGLMConfig(PretrainedConfig):
13
+ model_type = "chatglm"
14
+ attribute_map = {
15
+ "num_hidden_layers": "num_layers",
16
+ "n_head_kv": "multi_query_group_num",
17
+ }
18
+
19
+ def __init__(
20
+ self,
21
+ num_layers=28,
22
+ padded_vocab_size=65024,
23
+ hidden_size=4096,
24
+ ffn_hidden_size=13696,
25
+ kv_channels=128,
26
+ num_attention_heads=32,
27
+ seq_length=2048,
28
+ hidden_dropout=0.0,
29
+ attention_dropout=0.0,
30
+ layernorm_epsilon=1e-5,
31
+ rmsnorm=True,
32
+ apply_residual_connection_post_layernorm=False,
33
+ post_layer_norm=True,
34
+ add_bias_linear=False,
35
+ add_qkv_bias=False,
36
+ interleaved_qkv=False,
37
+ bias_dropout_fusion=True,
38
+ multi_query_attention=False,
39
+ multi_query_group_num=1,
40
+ apply_query_key_layer_scaling=True,
41
+ attention_softmax_in_fp32=True,
42
+ fp32_residual_connection=False,
43
+ quantization_bit=0,
44
+ pre_seq_len=None,
45
+ prefix_projection=False,
46
+ **kwargs
47
+ ):
48
+ self.num_layers = num_layers
49
+ self.vocab_size = padded_vocab_size
50
+ self.padded_vocab_size = padded_vocab_size
51
+ self.hidden_size = hidden_size
52
+ self.ffn_hidden_size = ffn_hidden_size
53
+ self.kv_channels = kv_channels
54
+ self.num_attention_heads = num_attention_heads
55
+ self.seq_length = seq_length
56
+ # It is to be compatible with long lora.
57
+ self.max_position_embeddings = seq_length
58
+ self.hidden_dropout = hidden_dropout
59
+ self.attention_dropout = attention_dropout
60
+ self.layernorm_epsilon = layernorm_epsilon
61
+ self.rmsnorm = rmsnorm
62
+ self.apply_residual_connection_post_layernorm = (
63
+ apply_residual_connection_post_layernorm
64
+ )
65
+ self.post_layer_norm = post_layer_norm
66
+ self.add_bias_linear = add_bias_linear
67
+ self.add_qkv_bias = add_qkv_bias
68
+ self.bias_dropout_fusion = bias_dropout_fusion
69
+ self.multi_query_attention = multi_query_attention
70
+ self.multi_query_group_num = multi_query_group_num
71
+ self.apply_query_key_layer_scaling = apply_query_key_layer_scaling
72
+ self.attention_softmax_in_fp32 = attention_softmax_in_fp32
73
+ self.fp32_residual_connection = fp32_residual_connection
74
+ self.quantization_bit = quantization_bit
75
+ self.pre_seq_len = pre_seq_len
76
+ self.prefix_projection = prefix_projection
77
+ self.interleaved_qkv = interleaved_qkv
78
+ super().__init__(**kwargs)
lib/python3.12/site-packages/sglang/srt/configs/dbrx.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from
2
+ # https://huggingface.co/databricks/dbrx-base/blob/main/configuration_dbrx.py
3
+ # https://github.com/vllm-project/vllm/blob/main/vllm/transformers_utils/configs/dbrx.py
4
+ """Dbrx configuration."""
5
+
6
+ from typing import Any, Optional
7
+
8
+ from transformers.configuration_utils import PretrainedConfig
9
+ from transformers.utils import logging
10
+
11
+ logger = logging.get_logger(__name__)
12
+
13
+ DBRX_PRETRAINED_CONFIG_ARCHIVE_MAP = {} # type: ignore
14
+
15
+
16
+ class DbrxAttentionConfig(PretrainedConfig):
17
+ """Configuration class for Dbrx Attention.
18
+
19
+ [`DbrxAttention`] class. It is used to instantiate attention layers
20
+ according to the specified arguments, defining the layers architecture.
21
+
22
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
23
+ documentation from [`PretrainedConfig`] for more information.
24
+
25
+ Args:
26
+ attn_pdrop (`float`, *optional*, defaults to 0.0):
27
+ The dropout probability for the attention layers.
28
+ clip_qkv (`float`, *optional*, defaults to None):
29
+ If not `None`, clip the queries, keys, and values in the attention layer to this value.
30
+ kv_n_heads (Optional[int]): For grouped_query_attention only, allow user to specify number of kv heads.
31
+ rope_theta (float): The base frequency for rope.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ attn_pdrop: float = 0,
37
+ clip_qkv: Optional[float] = None,
38
+ kv_n_heads: int = 1,
39
+ rope_theta: float = 10000.0,
40
+ **kwargs: Any,
41
+ ):
42
+ super().__init__(**kwargs)
43
+ self.attn_pdrop = attn_pdrop
44
+ self.clip_qkv = clip_qkv
45
+ self.kv_n_heads = kv_n_heads
46
+ self.rope_theta = rope_theta
47
+
48
+ for k in ["model_type"]:
49
+ if k in kwargs:
50
+ kwargs.pop(k)
51
+ if len(kwargs) != 0:
52
+ raise ValueError(f"Found unknown {kwargs=}")
53
+
54
+ @classmethod
55
+ def from_pretrained(
56
+ cls, pretrained_model_name_or_path: str, **kwargs: Any
57
+ ) -> "PretrainedConfig":
58
+ cls._set_token_in_kwargs(kwargs)
59
+
60
+ config_dict, kwargs = cls.get_config_dict(
61
+ pretrained_model_name_or_path, **kwargs
62
+ )
63
+
64
+ if config_dict.get("model_type") == "dbrx":
65
+ config_dict = config_dict["attn_config"]
66
+
67
+ if (
68
+ "model_type" in config_dict
69
+ and hasattr(cls, "model_type")
70
+ and config_dict["model_type"] != cls.model_type
71
+ ):
72
+ logger.warning(
73
+ "You are using a model of type %s to instantiate a model of "
74
+ "type %s. This is not supported for all configurations of "
75
+ "models and can yield errors.",
76
+ config_dict["model_type"],
77
+ cls.model_type,
78
+ )
79
+
80
+ return cls.from_dict(config_dict, **kwargs)
81
+
82
+
83
+ class DbrxFFNConfig(PretrainedConfig):
84
+ """Configuration class for Dbrx FFN.
85
+
86
+ [`DbrxFFN`] class. It is used to instantiate feedforward layers according to
87
+ the specified arguments, defining the layers architecture.
88
+
89
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
90
+ documentation from [`PretrainedConfig`] for more information.
91
+
92
+ Args:
93
+ ffn_act_fn (dict, optional): A dict specifying activation function for the FFN.
94
+ The dict should have a key 'name' with the value being the name of
95
+ the activation function along with any additional keyword arguments.
96
+ ffn_hidden_size (int, optional): The hidden size of the feedforward network.
97
+ moe_num_experts (int, optional): The number of experts in the mixture of experts layer.
98
+ moe_top_k (int, optional): The number of experts to use in the mixture of experts layer.
99
+ moe_jitter_eps (float, optional): The jitter epsilon for the mixture of experts layer.
100
+ moe_loss_weight (float, optional): The loss weight for the mixture of experts layer.
101
+ moe_normalize_expert_weights (float, optional): The normalization factor for the expert weights.
102
+ uniform_expert_assignment (bool, optional): Whether to use uniform expert assignment.
103
+ This should only be used for benchmarking purposes.
104
+ """
105
+
106
+ def __init__(
107
+ self,
108
+ ffn_act_fn: Optional[dict] = None,
109
+ ffn_hidden_size: int = 3584,
110
+ moe_num_experts: int = 4,
111
+ moe_top_k: int = 1,
112
+ moe_jitter_eps: Optional[float] = None,
113
+ moe_loss_weight: float = 0.01,
114
+ moe_normalize_expert_weights: Optional[float] = 1,
115
+ uniform_expert_assignment: bool = False,
116
+ **kwargs: Any,
117
+ ):
118
+ super().__init__()
119
+ if ffn_act_fn is None:
120
+ ffn_act_fn = {"name": "silu"}
121
+ self.ffn_act_fn = ffn_act_fn
122
+ self.ffn_hidden_size = ffn_hidden_size
123
+ self.moe_num_experts = moe_num_experts
124
+ self.moe_top_k = moe_top_k
125
+ self.moe_jitter_eps = moe_jitter_eps
126
+ self.moe_loss_weight = moe_loss_weight
127
+ self.moe_normalize_expert_weights = moe_normalize_expert_weights
128
+ self.uniform_expert_assignment = uniform_expert_assignment
129
+
130
+ for k in ["model_type"]:
131
+ if k in kwargs:
132
+ kwargs.pop(k)
133
+ if len(kwargs) != 0:
134
+ raise ValueError(f"Found unknown {kwargs=}")
135
+
136
+ @classmethod
137
+ def from_pretrained(
138
+ cls, pretrained_model_name_or_path: str, **kwargs: Any
139
+ ) -> "PretrainedConfig":
140
+ cls._set_token_in_kwargs(kwargs)
141
+
142
+ config_dict, kwargs = cls.get_config_dict(
143
+ pretrained_model_name_or_path, **kwargs
144
+ )
145
+
146
+ if config_dict.get("model_type") == "dbrx":
147
+ config_dict = config_dict["ffn_config"]
148
+
149
+ if (
150
+ "model_type" in config_dict
151
+ and hasattr(cls, "model_type")
152
+ and config_dict["model_type"] != cls.model_type
153
+ ):
154
+ logger.warning(
155
+ "You are using a model of type %s to instantiate a model of "
156
+ "type %s. This is not supported for all "
157
+ "configurations of models and can yield errors.",
158
+ config_dict["model_type"],
159
+ cls.model_type,
160
+ )
161
+
162
+ return cls.from_dict(config_dict, **kwargs)
163
+
164
+
165
+ class DbrxConfig(PretrainedConfig):
166
+ """Configuration class for Dbrx.
167
+
168
+ [`DbrxModel`]. It is used to instantiate a Dbrx model according to the
169
+ specified arguments, defining the model architecture.
170
+
171
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
172
+ documentation from [`PretrainedConfig`] for more information.
173
+
174
+
175
+ Args:
176
+ d_model (`int`, *optional*, defaults to 6144):
177
+ Dimensionality of the embeddings and hidden states.
178
+ n_heads (`int`, *optional*, defaults to 48):
179
+ Number of attention heads for each attention layer in the Transformer encoder.
180
+ n_layers (`int`, *optional*, defaults to 40):
181
+ Number of hidden layers in the Transformer encoder.
182
+ max_seq_len (`int`, *optional*, defaults to 32768):
183
+ The maximum sequence length of the model.
184
+ vocab_size (`int`, *optional*, defaults to 100352):
185
+ Vocabulary size of the Dbrx model. Defines the maximum number of different tokens that can be represented by
186
+ the `inputs_ids` passed when calling [`DbrxModel`].
187
+ resid_pdrop (`float`, *optional*, defaults to 0.0):
188
+ The dropout probability applied to the attention output before combining with residual.
189
+ emb_pdrop (`float`, *optional*, defaults to 0.0):
190
+ The dropout probability for the embedding layer.
191
+ attn_config (`dict`, *optional*):
192
+ A dictionary used to configure the model's attention module.
193
+ ffn_config (`dict`, *optional*):
194
+ A dictionary used to configure the model's FFN module.
195
+ use_cache (`bool`, *optional*, defaults to `False`):
196
+ Whether or not the model should return the last key/values attentions (not used by all models).
197
+ initializer_range (`float`, *optional*, defaults to 0.02):
198
+ The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
199
+ output_router_logits (`bool`, *optional*, defaults to `False`):
200
+ Whether or not the router logits should be returned by the model. Enabling this will also
201
+ allow the model to output the auxiliary loss. See [here]() for more details
202
+ router_aux_loss_coef (`float`, *optional*, defaults to 0.001):
203
+ The aux loss factor for the total loss.
204
+
205
+
206
+ Example:
207
+ ```python
208
+ >>> from transformers import DbrxConfig, DbrxModel
209
+
210
+ >>> # Initializing a Dbrx configuration
211
+ >>> configuration = DbrxConfig()
212
+
213
+ >>> # Initializing a model (with random weights) from the configuration
214
+ >>> model = DbrxModel(configuration)
215
+
216
+ >>> # Accessing the model configuration
217
+ >>> configuration = model.config
218
+ ```
219
+ """
220
+
221
+ model_type = "dbrx"
222
+ attribute_map = {
223
+ "num_attention_heads": "n_heads",
224
+ "hidden_size": "d_model",
225
+ "num_hidden_layers": "n_layers",
226
+ "max_position_embeddings": "max_seq_len",
227
+ }
228
+
229
+ def __init__(
230
+ self,
231
+ d_model: int = 2048,
232
+ n_heads: int = 16,
233
+ n_layers: int = 24,
234
+ max_seq_len: int = 2048,
235
+ vocab_size: int = 32000,
236
+ resid_pdrop: float = 0.0,
237
+ emb_pdrop: float = 0.0,
238
+ attn_config: Optional[DbrxAttentionConfig] = None,
239
+ ffn_config: Optional[DbrxFFNConfig] = None,
240
+ use_cache: bool = True,
241
+ initializer_range: float = 0.02,
242
+ output_router_logits: bool = False,
243
+ router_aux_loss_coef: float = 0.05,
244
+ **kwargs: Any,
245
+ ):
246
+ if attn_config is None:
247
+ self.attn_config = DbrxAttentionConfig()
248
+ elif isinstance(attn_config, dict):
249
+ self.attn_config = DbrxAttentionConfig(**attn_config)
250
+ else:
251
+ self.attn_config = attn_config
252
+
253
+ if ffn_config is None:
254
+ self.ffn_config = DbrxFFNConfig()
255
+ elif isinstance(ffn_config, dict):
256
+ self.ffn_config = DbrxFFNConfig(**ffn_config)
257
+ else:
258
+ self.ffn_config = ffn_config
259
+
260
+ self.d_model = d_model
261
+ self.n_heads = n_heads
262
+ self.n_layers = n_layers
263
+ self.max_seq_len = max_seq_len
264
+ self.vocab_size = vocab_size
265
+ self.resid_pdrop = resid_pdrop
266
+ self.emb_pdrop = emb_pdrop
267
+ self.use_cache = use_cache
268
+ self.initializer_range = initializer_range
269
+ self.output_router_logits = output_router_logits
270
+ self.router_aux_loss_coef = router_aux_loss_coef
271
+
272
+ tie_word_embeddings = kwargs.pop("tie_word_embeddings", False)
273
+ if tie_word_embeddings:
274
+ raise ValueError("tie_word_embeddings is not supported for Dbrx models.")
275
+
276
+ super().__init__(
277
+ tie_word_embeddings=tie_word_embeddings,
278
+ **kwargs,
279
+ )
lib/python3.12/site-packages/sglang/srt/configs/deepseekvl2.py ADDED
@@ -0,0 +1,676 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import os
3
+ from dataclasses import dataclass
4
+ from typing import Dict, List, Optional, Tuple
5
+
6
+ import torch
7
+ from PIL import Image, ImageOps
8
+ from transformers import (
9
+ AutoProcessor,
10
+ LlamaTokenizerFast,
11
+ PretrainedConfig,
12
+ ProcessorMixin,
13
+ )
14
+
15
+
16
+ def select_best_resolution(image_size, candidate_resolutions):
17
+ # used for cropping
18
+ original_width, original_height = image_size
19
+ best_fit = None
20
+ max_effective_resolution = 0
21
+ min_wasted_resolution = float("inf")
22
+
23
+ for width, height in candidate_resolutions:
24
+ scale = min(width / original_width, height / original_height)
25
+ downscaled_width, downscaled_height = int(original_width * scale), int(
26
+ original_height * scale
27
+ )
28
+ effective_resolution = min(
29
+ downscaled_width * downscaled_height, original_width * original_height
30
+ )
31
+ wasted_resolution = (width * height) - effective_resolution
32
+
33
+ if effective_resolution > max_effective_resolution or (
34
+ effective_resolution == max_effective_resolution
35
+ and wasted_resolution < min_wasted_resolution
36
+ ):
37
+ max_effective_resolution = effective_resolution
38
+ min_wasted_resolution = wasted_resolution
39
+ best_fit = (width, height)
40
+
41
+ return best_fit
42
+
43
+
44
+ class DictOutput(object):
45
+ def keys(self):
46
+ return self.__dict__.keys()
47
+
48
+ def __getitem__(self, item):
49
+ return self.__dict__[item]
50
+
51
+ def __setitem__(self, key, value):
52
+ self.__dict__[key] = value
53
+
54
+
55
+ @dataclass
56
+ class VLChatProcessorOutput(DictOutput):
57
+ input_ids: torch.LongTensor
58
+ target_ids: torch.LongTensor
59
+ images: torch.Tensor
60
+ images_seq_mask: torch.BoolTensor
61
+ images_spatial_crop: torch.LongTensor
62
+
63
+ def __len__(self):
64
+ return len(self.input_ids)
65
+
66
+
67
+ class ImageTransform(object):
68
+ def __init__(
69
+ self,
70
+ mean: Optional[Tuple[float, float, float]] = (0.5, 0.5, 0.5),
71
+ std: Optional[Tuple[float, float, float]] = (0.5, 0.5, 0.5),
72
+ normalize: bool = True,
73
+ ):
74
+ self.mean = mean
75
+ self.std = std
76
+ self.normalize = normalize
77
+
78
+ # only load torchvision.transforms when needed
79
+ try:
80
+ import torchvision.transforms as T
81
+
82
+ # FIXME: add version check for gguf
83
+ except ImportError as err:
84
+ raise ImportError(
85
+ "Please install torchvision via `pip install torchvision` to use Deepseek-VL2."
86
+ ) from err
87
+
88
+ transform_pipelines = [T.ToTensor()]
89
+
90
+ if normalize:
91
+ transform_pipelines.append(T.Normalize(mean, std))
92
+
93
+ self.transform = T.Compose(transform_pipelines)
94
+
95
+ def __call__(self, pil_img: Image.Image):
96
+ x = self.transform(pil_img)
97
+ return x
98
+
99
+
100
+ class DeepseekVLV2Processor(ProcessorMixin):
101
+ tokenizer_class = ("LlamaTokenizer", "LlamaTokenizerFast")
102
+ attributes = ["tokenizer"]
103
+
104
+ def __init__(
105
+ self,
106
+ tokenizer: LlamaTokenizerFast,
107
+ candidate_resolutions: Tuple[Tuple[int, int]],
108
+ patch_size: int,
109
+ downsample_ratio: int,
110
+ image_mean: Tuple[float, float, float] = (0.5, 0.5, 0.5),
111
+ image_std: Tuple[float, float, float] = (0.5, 0.5, 0.5),
112
+ normalize: bool = True,
113
+ image_token: str = "<image>",
114
+ pad_token: str = "<|▁pad▁|>",
115
+ add_special_token: bool = False,
116
+ sft_format: str = "deepseek",
117
+ mask_prompt: bool = True,
118
+ ignore_id: int = -100,
119
+ **kwargs,
120
+ ):
121
+
122
+ self.candidate_resolutions = candidate_resolutions
123
+ self.image_size = candidate_resolutions[0][0]
124
+ self.patch_size = patch_size
125
+ self.image_mean = image_mean
126
+ self.image_std = image_std
127
+ self.normalize = normalize
128
+ self.downsample_ratio = downsample_ratio
129
+
130
+ self.image_transform = ImageTransform(
131
+ mean=image_mean, std=image_std, normalize=normalize
132
+ )
133
+ self.tokenizer = tokenizer
134
+ # must set this,padding side with make a difference in batch inference
135
+ self.tokenizer.padding_side = "left"
136
+
137
+ # add the pad_token as special token to use 'tokenizer.pad_token' and 'tokenizer.pad_token_id'
138
+ if tokenizer.pad_token is None:
139
+ self.tokenizer.add_special_tokens({"pad_token": pad_token})
140
+
141
+ # add image token
142
+ image_token_id = self.tokenizer.vocab.get(image_token)
143
+ if image_token_id is None:
144
+ special_tokens = [image_token]
145
+ special_tokens_dict = {"additional_special_tokens": special_tokens}
146
+ self.tokenizer.add_special_tokens(special_tokens_dict)
147
+ self.image_token_id = self.tokenizer.vocab.get(image_token)
148
+
149
+ # add five special tokens for grounding-related tasks
150
+ # <|ref|>, <|/ref|>, <|det|>, <|/det|>, <|grounding|>
151
+ special_tokens = ["<|ref|>", "<|/ref|>", "<|det|>", "<|/det|>", "<|grounding|>"]
152
+ special_tokens_dict = {"additional_special_tokens": special_tokens}
153
+ self.tokenizer.add_special_tokens(special_tokens_dict)
154
+
155
+ # add special tokens for SFT data
156
+ special_tokens = ["<|User|>", "<|Assistant|>"]
157
+ special_tokens_dict = {"additional_special_tokens": special_tokens}
158
+ self.tokenizer.add_special_tokens(special_tokens_dict)
159
+
160
+ self.image_token = image_token
161
+ self.pad_token = pad_token
162
+ self.add_special_token = add_special_token
163
+ self.sft_format = sft_format
164
+ self.mask_prompt = mask_prompt
165
+ self.ignore_id = ignore_id
166
+
167
+ super().__init__(
168
+ tokenizer,
169
+ **kwargs,
170
+ )
171
+
172
+ def format_messages_v2(self, messages, pil_images, max_req_input_len=-1):
173
+ """play the role of format_messages_v2 and get_images_info in the last version"""
174
+ tokenized_data = []
175
+ masked_tokenized_data = [] # labels
176
+ images_list = []
177
+ images_seq_mask = []
178
+ images_spatial_crop = []
179
+
180
+ image_index = 0
181
+ image_token_cnt = messages.count(self.image_token)
182
+ tokenized_str, images, seq_mask, spatial_crop = self.tokenize_with_images(
183
+ messages,
184
+ pil_images[image_index : image_index + image_token_cnt],
185
+ bos=True,
186
+ eos=True,
187
+ cropping=len(pil_images) <= 2,
188
+ max_req_input_len=max_req_input_len,
189
+ )
190
+
191
+ image_index = image_token_cnt
192
+ tokenized_data += tokenized_str
193
+ if self.mask_prompt:
194
+ masked_tokenized_data += [self.ignore_id] * len(tokenized_str)
195
+ else:
196
+ masked_tokenized_data += tokenized_str
197
+ images_list += images
198
+ images_seq_mask += seq_mask
199
+ images_spatial_crop += spatial_crop
200
+
201
+ assert len(tokenized_data) == len(
202
+ images_seq_mask
203
+ ), f"format_messages_v2: tokenized_str's length {len(tokenized_str)} is not equal to imags_seq_mask's length {len(images_seq_mask)}"
204
+
205
+ return (
206
+ tokenized_data,
207
+ masked_tokenized_data,
208
+ images_list,
209
+ images_seq_mask,
210
+ images_spatial_crop,
211
+ )
212
+
213
+ @property
214
+ def bos_id(self):
215
+ return self.tokenizer.bos_token_id
216
+
217
+ @property
218
+ def eos_id(self):
219
+ return self.tokenizer.eos_token_id
220
+
221
+ @property
222
+ def pad_id(self):
223
+ return self.tokenizer.pad_token_id
224
+
225
+ def encode(self, text: str, bos: bool = True, eos: bool = False):
226
+ t = self.tokenizer.encode(text, add_special_tokens=False)
227
+
228
+ if bos:
229
+ t = [self.bos_id] + t
230
+ if eos:
231
+ t = t + [self.eos_id]
232
+
233
+ return t
234
+
235
+ def decode(self, t: List[int], **kwargs) -> str:
236
+ return self.tokenizer.decode(t, **kwargs)
237
+
238
+ def process_one(
239
+ self,
240
+ prompt: str = None,
241
+ conversations: List[Dict[str, str]] = None,
242
+ images: List[Image.Image] = None,
243
+ apply_sft_format: bool = False,
244
+ inference_mode: bool = True,
245
+ system_prompt: str = "",
246
+ max_req_input_len: int = -1,
247
+ **kwargs,
248
+ ):
249
+ """
250
+
251
+ Args:
252
+ prompt (str): the formatted prompt;
253
+ conversations (List[Dict]): conversations with a list of messages;
254
+ images (List[ImageType]): the list of images;
255
+ apply_sft_format (bool): if prompt is not None, then apply the SFT format to prompt;
256
+ if conversations is not None, then it will always apply the SFT format to conversations;
257
+ inference_mode (bool): if True, then remove the last eos token;
258
+ system_prompt (str): the system prompt;
259
+ **kwargs:
260
+
261
+ Returns:
262
+ outputs (BaseProcessorOutput): the output of the processor,
263
+ - input_ids (torch.LongTensor): [N + image tokens]
264
+ - target_ids (torch.LongTensor): [N + image tokens]
265
+ - images (torch.FloatTensor): [n_images, 3, H, W]
266
+ - image_id (int): the id of the image token
267
+ - num_image_tokens (List[int]): the number of image tokens
268
+ """
269
+
270
+ assert (
271
+ prompt is None or conversations is None
272
+ ), "prompt and conversations cannot be used at the same time."
273
+
274
+ (
275
+ tokenized_str,
276
+ masked_tokenized_str,
277
+ images_list,
278
+ images_seq_mask,
279
+ images_spatial_crop,
280
+ ) = self.format_messages_v2(conversations, images, max_req_input_len)
281
+
282
+ assert (
283
+ len(tokenized_str) == len(images_seq_mask) == len(masked_tokenized_str)
284
+ ), (
285
+ f"tokenized_str's length {len(tokenized_str)}, input_ids' length {len(masked_tokenized_str)}, "
286
+ f"imags_seq_mask's length {len(images_seq_mask)}, are not equal"
287
+ )
288
+
289
+ input_ids = torch.LongTensor(tokenized_str)
290
+ target_ids = torch.LongTensor(masked_tokenized_str)
291
+ images_seq_mask = torch.tensor(images_seq_mask, dtype=torch.bool)
292
+
293
+ # set input_ids < 0 | input_ids == self.image_token_id as ignore_id
294
+ target_ids[(input_ids < 0) | (input_ids == self.image_token_id)] = (
295
+ self.ignore_id
296
+ )
297
+ input_ids[input_ids < 0] = self.pad_id
298
+
299
+ if inference_mode:
300
+ assert input_ids[-1] == self.eos_id
301
+ input_ids = input_ids[:-1]
302
+ target_ids = target_ids[:-1]
303
+ images_seq_mask = images_seq_mask[:-1]
304
+
305
+ if len(images_list) == 0:
306
+ images = torch.zeros((1, 3, self.image_size, self.image_size))
307
+ images_spatial_crop = torch.zeros((1, 2), dtype=torch.long)
308
+ else:
309
+ images = torch.stack(images_list, dim=0)
310
+ images_spatial_crop = torch.tensor(images_spatial_crop, dtype=torch.long)
311
+
312
+ prepare = VLChatProcessorOutput(
313
+ input_ids=input_ids,
314
+ target_ids=target_ids,
315
+ images=images,
316
+ images_seq_mask=images_seq_mask,
317
+ images_spatial_crop=images_spatial_crop,
318
+ )
319
+
320
+ return prepare
321
+
322
+ def __call__(
323
+ self,
324
+ *,
325
+ prompt: str = None,
326
+ conversations: List[Dict[str, str]] = None,
327
+ images: List[Image.Image] = None,
328
+ apply_sft_format: bool = False,
329
+ inference_mode: bool = True,
330
+ system_prompt: str = "",
331
+ max_req_input_len: int = -1,
332
+ **kwargs,
333
+ ):
334
+ prepare = self.process_one(
335
+ prompt=prompt,
336
+ conversations=conversations,
337
+ images=images,
338
+ apply_sft_format=apply_sft_format,
339
+ inference_mode=inference_mode,
340
+ system_prompt=system_prompt,
341
+ max_req_input_len=max_req_input_len,
342
+ )
343
+
344
+ return prepare
345
+
346
+ def find_all_indices(self, messages, target_value):
347
+ indices = []
348
+ for index, item in enumerate(messages):
349
+ if item == target_value:
350
+ indices.append(index)
351
+ return indices
352
+
353
+ def tokenize_with_images(
354
+ self,
355
+ conversation: str,
356
+ images: List[Image.Image],
357
+ bos: bool = True,
358
+ eos: bool = True,
359
+ cropping: bool = True,
360
+ max_req_input_len: int = -1,
361
+ ):
362
+ """Tokenize text with <image> tags."""
363
+ images_list, images_seq_mask, images_spatial_crop = [], [], []
364
+ text_splits = conversation.split(self.image_token)
365
+ tokenized_str = []
366
+ for text_sep, image in zip(text_splits, images):
367
+ """encode text_sep"""
368
+ tokenized_sep = self.encode(text_sep, bos=False, eos=False)
369
+ tokenized_str += tokenized_sep
370
+ images_seq_mask += [False] * len(tokenized_sep)
371
+
372
+ """select best resolution for anyres"""
373
+ if cropping:
374
+ best_width, best_height = select_best_resolution(
375
+ image.size, self.candidate_resolutions
376
+ )
377
+ else:
378
+ best_width, best_height = self.image_size, self.image_size
379
+ # print(image.size, (best_width, best_height)) # check the select_best_resolutions func
380
+
381
+ """process the global view"""
382
+ global_view = ImageOps.pad(
383
+ image,
384
+ (self.image_size, self.image_size),
385
+ color=tuple(int(x * 255) for x in self.image_transform.mean),
386
+ )
387
+ images_list.append(self.image_transform(global_view))
388
+
389
+ """process the local views"""
390
+ local_view = ImageOps.pad(
391
+ image,
392
+ (best_width, best_height),
393
+ color=tuple(int(x * 255) for x in self.image_transform.mean),
394
+ )
395
+ for i in range(0, best_height, self.image_size):
396
+ for j in range(0, best_width, self.image_size):
397
+ images_list.append(
398
+ self.image_transform(
399
+ local_view.crop(
400
+ (j, i, j + self.image_size, i + self.image_size)
401
+ )
402
+ )
403
+ )
404
+
405
+ """record height / width crop num"""
406
+ num_width_tiles, num_height_tiles = (
407
+ best_width // self.image_size,
408
+ best_height // self.image_size,
409
+ )
410
+ images_spatial_crop.append([num_width_tiles, num_height_tiles])
411
+
412
+ """add image tokens"""
413
+ h = w = math.ceil(
414
+ (self.image_size // self.patch_size) / self.downsample_ratio
415
+ )
416
+ # global views tokens h * (w + 1), 1 is for line seperator
417
+ tokenized_image = [self.image_token_id] * h * (w + 1)
418
+ # add a seperator between global and local views
419
+ tokenized_image += [self.image_token_id]
420
+ # local views tokens, (num_height_tiles * h) * (num_width_tiles * w + 1)
421
+ tokenized_image += (
422
+ [self.image_token_id]
423
+ * (num_height_tiles * h)
424
+ * (num_width_tiles * w + 1)
425
+ )
426
+
427
+ tokenized_str += tokenized_image
428
+ images_seq_mask += [True] * len(tokenized_image)
429
+ # print(width_crop_num, height_crop_num, len(tokenized_image)) # test the correctness of the number of image-related tokens
430
+
431
+ """process the last text split"""
432
+ tokenized_sep = self.encode(text_splits[-1], bos=False, eos=False)
433
+ # deal with video, limit with request len
434
+ if max_req_input_len > -1:
435
+ if max_req_input_len < len(tokenized_sep) + len(tokenized_str) - 1:
436
+ rest = max_req_input_len - len(tokenized_sep) - 1 - 1024
437
+ tokenized_str = tokenized_str[:rest]
438
+ images_seq_mask = images_seq_mask[:rest]
439
+ tokenized_str += tokenized_sep
440
+ images_seq_mask += [False] * len(tokenized_sep)
441
+
442
+ """add the bos and eos tokens"""
443
+ if bos:
444
+ tokenized_str = [self.bos_id] + tokenized_str
445
+ images_seq_mask = [False] + images_seq_mask
446
+ if eos:
447
+ tokenized_str = tokenized_str + [self.eos_id]
448
+ images_seq_mask = images_seq_mask + [False]
449
+
450
+ assert len(tokenized_str) == len(
451
+ images_seq_mask
452
+ ), f"tokenize_with_images func: tokenized_str's length {len(tokenized_str)} is not equal to imags_seq_mask's length {len(images_seq_mask)}"
453
+
454
+ return tokenized_str, images_list, images_seq_mask, images_spatial_crop
455
+
456
+
457
+ class DeepseekVL2VisionEncoderConfig(PretrainedConfig):
458
+ model_type: str = "vision"
459
+
460
+ model_name: str = "siglip_large_patch16_384"
461
+ image_size: int = 384
462
+ patch_size: int = 16
463
+ width: int = 1024
464
+ layers: int = 24
465
+ heads: int = 16
466
+ mlp_ratio: int = 4
467
+ global_pool: str = "map"
468
+ ignore_head: bool = True
469
+ class_token: bool = False
470
+ num_classes: int = 0
471
+ use_checkpoint: bool = False
472
+ weight_init: str = "skip"
473
+ deterministic: bool = False
474
+ num_recomputing_layers: int = 0
475
+
476
+ def __init__(
477
+ self,
478
+ model_name: str = "siglip_large_patch16_384",
479
+ image_size: int = 384,
480
+ patch_size: int = 16,
481
+ width: int = 1024,
482
+ layers: int = 24,
483
+ heads: int = 16,
484
+ mlp_ratio: int = 4,
485
+ global_pool: str = "map",
486
+ ignore_head: bool = True,
487
+ class_token: bool = False,
488
+ num_classes: int = 0,
489
+ use_checkpoint: bool = False,
490
+ **kwargs,
491
+ ):
492
+ self.model_name = model_name
493
+ self.image_size = image_size
494
+ self.patch_size = patch_size
495
+ self.width = width
496
+ self.layers = layers
497
+ self.heads = heads
498
+ self.mlp_ratio = mlp_ratio
499
+ self.global_pool = global_pool
500
+ self.ignore_head = ignore_head
501
+ self.class_token = class_token
502
+ self.num_classes = num_classes
503
+ self.use_checkpoint = use_checkpoint
504
+
505
+ super().__init__(**kwargs)
506
+
507
+
508
+ class DeepseekVL2MlpProjectorConfig(PretrainedConfig):
509
+ model_type = "mlp_projector"
510
+ projector_type: str = "downsample_mlp_gelu"
511
+ input_dim: int = 1152
512
+ n_embed: int = 2048
513
+ depth: int = 2
514
+ mlp_ratio: int = 1
515
+ downsample_ratio: int = 2
516
+ token_pooling: bool = False
517
+
518
+ def __init__(
519
+ self,
520
+ projector_type: str = "downsample_mlp_gelu",
521
+ input_dim: int = 1152,
522
+ n_embed: int = 2048,
523
+ depth: int = 2,
524
+ mlp_ratio: int = 1,
525
+ downsample_ratio: int = 2,
526
+ **kwargs,
527
+ ):
528
+ self.projector_type = projector_type
529
+ self.input_dim = input_dim
530
+ self.n_embed = n_embed
531
+ self.depth = depth
532
+ self.mlp_ratio = mlp_ratio
533
+ self.downsample_ratio = downsample_ratio
534
+
535
+ super().__init__(**kwargs)
536
+
537
+
538
+ class DeepseekV2Config(PretrainedConfig):
539
+
540
+ model_type = "deepseek_v2"
541
+ keys_to_ignore_at_inference = ["past_key_values"]
542
+
543
+ def __init__(
544
+ self,
545
+ vocab_size=102400,
546
+ hidden_size=4096,
547
+ intermediate_size=11008,
548
+ moe_intermediate_size=1407,
549
+ num_hidden_layers=30,
550
+ num_attention_heads=32,
551
+ num_key_value_heads=32,
552
+ n_shared_experts=None,
553
+ n_routed_experts=None,
554
+ ep_size=1,
555
+ routed_scaling_factor=1.0,
556
+ kv_lora_rank=512,
557
+ q_lora_rank=1536,
558
+ qk_rope_head_dim=64,
559
+ v_head_dim=128,
560
+ qk_nope_head_dim=128,
561
+ topk_method="gready",
562
+ n_group=None,
563
+ topk_group=None,
564
+ num_experts_per_tok=None,
565
+ moe_layer_freq=1,
566
+ first_k_dense_replace=0,
567
+ norm_topk_prob=False,
568
+ scoring_func="softmax",
569
+ aux_loss_alpha=0.001,
570
+ seq_aux=True,
571
+ hidden_act="silu",
572
+ max_position_embeddings=2048,
573
+ initializer_range=0.02,
574
+ rms_norm_eps=1e-6,
575
+ use_cache=True,
576
+ pad_token_id=None,
577
+ bos_token_id=100000,
578
+ eos_token_id=100001,
579
+ pretraining_tp=1,
580
+ tie_word_embeddings=False,
581
+ rope_theta=10000.0,
582
+ rope_scaling=None,
583
+ attention_bias=False,
584
+ attention_dropout=0.0,
585
+ use_mla=True,
586
+ **kwargs,
587
+ ):
588
+ self.vocab_size = vocab_size
589
+ self.max_position_embeddings = max_position_embeddings
590
+ self.hidden_size = hidden_size
591
+ self.intermediate_size = intermediate_size
592
+ self.moe_intermediate_size = moe_intermediate_size
593
+ self.num_hidden_layers = num_hidden_layers
594
+ self.num_attention_heads = num_attention_heads
595
+ self.n_shared_experts = n_shared_experts
596
+ self.n_routed_experts = n_routed_experts
597
+ self.ep_size = ep_size
598
+ self.routed_scaling_factor = routed_scaling_factor
599
+ self.kv_lora_rank = kv_lora_rank
600
+ self.q_lora_rank = q_lora_rank
601
+ self.qk_rope_head_dim = qk_rope_head_dim
602
+ self.v_head_dim = v_head_dim
603
+ self.qk_nope_head_dim = qk_nope_head_dim
604
+ self.topk_method = topk_method
605
+ self.n_group = n_group
606
+ self.topk_group = topk_group
607
+ self.num_experts_per_tok = num_experts_per_tok
608
+ self.moe_layer_freq = moe_layer_freq
609
+ self.first_k_dense_replace = first_k_dense_replace
610
+ self.norm_topk_prob = norm_topk_prob
611
+ self.scoring_func = scoring_func
612
+ self.aux_loss_alpha = aux_loss_alpha
613
+ self.seq_aux = seq_aux
614
+ # for backward compatibility
615
+ if num_key_value_heads is None:
616
+ num_key_value_heads = num_attention_heads
617
+
618
+ self.num_key_value_heads = num_key_value_heads
619
+ self.hidden_act = hidden_act
620
+ self.initializer_range = initializer_range
621
+ self.rms_norm_eps = float(rms_norm_eps)
622
+ self.pretraining_tp = pretraining_tp
623
+ self.use_cache = use_cache
624
+ self.rope_theta = rope_theta
625
+ self.rope_scaling = rope_scaling
626
+ self.attention_bias = attention_bias
627
+ self.attention_dropout = attention_dropout
628
+ self.use_mla = use_mla
629
+
630
+ super().__init__(
631
+ pad_token_id=pad_token_id,
632
+ bos_token_id=bos_token_id,
633
+ eos_token_id=eos_token_id,
634
+ tie_word_embeddings=tie_word_embeddings,
635
+ **kwargs,
636
+ )
637
+
638
+
639
+ class DeepseekVL2Config(PretrainedConfig):
640
+ model_type = "deepseek_vl_v2"
641
+ vision_config: DeepseekVL2VisionEncoderConfig
642
+ projector_config: DeepseekVL2MlpProjectorConfig
643
+ language_config: DeepseekV2Config
644
+
645
+ tile_tag: str = "2D"
646
+ global_view_pos: str = "head"
647
+ candidate_resolutions: Tuple[Tuple[int, int]] = ((384, 384),)
648
+
649
+ def __init__(
650
+ self,
651
+ tile_tag: str = "tile_tag",
652
+ global_view_pos: str = "head",
653
+ candidate_resolutions: Tuple[Tuple[int, int]] = ((384, 384),),
654
+ **kwargs,
655
+ ):
656
+ super().__init__(**kwargs)
657
+
658
+ vision_config = kwargs.get("vision_config", {})
659
+ self.vision_config = DeepseekVL2VisionEncoderConfig(**vision_config)
660
+
661
+ projector_config = kwargs.get("projector_config", {})
662
+ self.projector_config = DeepseekVL2MlpProjectorConfig(**projector_config)
663
+
664
+ language_config = kwargs.get("language_config", {})
665
+ if isinstance(language_config, DeepseekV2Config):
666
+ self.language_config = language_config
667
+ else:
668
+ self.language_config = DeepseekV2Config(**language_config)
669
+
670
+ self.tile_tag = tile_tag
671
+ self.global_view_pos = global_view_pos
672
+ self.candidate_resolutions = candidate_resolutions
673
+ self.architectures = ["DeepseekVL2ForCausalLM"]
674
+
675
+
676
+ AutoProcessor.register(DeepseekVL2Config, DeepseekVLV2Processor)
lib/python3.12/site-packages/sglang/srt/configs/device_config.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import Optional
3
+
4
+ import torch
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class DeviceConfig:
10
+ device: Optional[torch.device]
11
+
12
+ def __init__(self, device: str = "cuda") -> None:
13
+ if device in ["cuda", "xpu", "hpu", "cpu"]:
14
+ self.device_type = device
15
+ else:
16
+ raise RuntimeError(f"Not supported device type: {device}")
17
+ self.device = torch.device(self.device_type)
lib/python3.12/site-packages/sglang/srt/configs/exaone.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024 The LG AI Research EXAONE Lab. All rights reserved.
3
+ # Copyright 2024 The LG CNS AI Engineering Team.
4
+ # Copyright 2023-2024 SGLang Team.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ """ EXAONE model configuration """
18
+ from typing import Any, Dict
19
+
20
+ from transformers.configuration_utils import PretrainedConfig
21
+ from transformers.utils import logging
22
+
23
+ logger = logging.get_logger(__name__)
24
+
25
+ EXAONE_PRETRAINED_CONFIG_ARCHIVE_MAP: Dict[str, Any] = {}
26
+
27
+
28
+ # ruff: noqa: E501
29
+ class ExaoneConfig(PretrainedConfig):
30
+ r"""
31
+ This is the configuration class to store the configuration of a :class:`~transformers.ExaoneModel`. It is used to
32
+ instantiate a EXAONE model according to the specified arguments, defining the model architecture. Instantiating a
33
+ configuration with the defaults will yield a similar configuration to that of the Exaone
34
+
35
+ Configuration objects inherit from :class:`~transformers.PretrainedConfig` and can be used to control the model
36
+ outputs. Read the documentation from :class:`~transformers.PretrainedConfig` for more information.
37
+
38
+
39
+ Args:
40
+ vocab_size (:obj:`int`, `optional`, defaults to 102400):
41
+ Vocabulary size of the EXAONE model. Defines the number of different tokens that can be represented by the
42
+ :obj:`inputs_ids` passed when calling :class:`~transformers.ExaoneModel`. Vocabulary size of the model.
43
+ Defines the different tokens that can be represented by the `inputs_ids` passed to the forward method of
44
+ :class:`~transformers.EXAONEModel`.
45
+ max_position_embeddings (:obj:`int`, `optional`, defaults to 2048):
46
+ The maximum sequence length that this model might ever be used with. Typically set this to something large
47
+ just in case (e.g., 512 or 1024 or 2048).
48
+ hidden_size (:obj:`int`, `optional`, defaults to 2048):
49
+ Dimensionality of the encoder layers and the pooler layer.
50
+ num_layers (:obj:`int`, `optional`, defaults to 32):
51
+ Number of hidden layers in the Transformer encoder.
52
+ num_attention_heads (:obj:`int`, `optional`, defaults to 32):
53
+ Number of attention heads for each attention layer in the Transformer decoder.
54
+ num_key_value_heads (:obj:`int`, `optional`):
55
+ This is the number of key_value heads that should be used to implement Grouped Query Attention. If
56
+ `num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
57
+ `num_key_value_heads=1 the model will use Multi Query Attention (MQA) otherwise GQA is used. When
58
+ converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
59
+ by meanpooling all the original heads within that group. For more details checkout [this
60
+ paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to
61
+ `num_attention_heads`.
62
+ intermediate_size (:obj:`int`, `optional`, defaults to `hidden_size * 4`):
63
+ Dimensionality of the "intermediate" (i.e., feed-forward) layer in the Transformer encoder.
64
+ activation_function (:obj:`str` or :obj:`function`, `optional`, defaults to :obj:`"silu"`):
65
+ The non-linear activation function (function or string) in the decoder.
66
+ rope_theta (:obj:`float`, `optional`, defaults to 10000.0):
67
+ The base period of the RoPE embeddings.
68
+ rope_scaling (:obj:`Dict`, `optional`):
69
+ Dictionary containing the scaling configuration for the RoPE embeddings. NOTE: if you apply new rope type
70
+ and you expect the model to work on longer `max_position_embeddings`, we recommend you to update this value
71
+ accordingly.
72
+ Expected contents:
73
+ `rope_type` (:obj:`str`):
74
+ The sub-variant of RoPE to use. Can be one of ['default', 'linear', 'dynamic', 'yarn', 'longrope',
75
+ 'llama3'], with 'default' being the original RoPE implementation.
76
+ `factor` (:obj:`float`, `optional`):
77
+ Used with all rope types except 'default'. The scaling factor to apply to the RoPE embeddings. In
78
+ most scaling types, a `factor` of x will enable the model to handle sequences of length x *
79
+ original maximum pre-trained length.
80
+ `original_max_position_embeddings` (:obj:`int`, `optional`):
81
+ Used with 'dynamic', 'longrope' and 'llama3'. The original max position embeddings used during
82
+ pretraining.
83
+ `attention_factor` (:obj:`float`, `optional`):
84
+ Used with 'yarn' and 'longrope'. The scaling factor to be applied on the attention
85
+ computation. If unspecified, it defaults to value recommended by the implementation, using the
86
+ `factor` field to infer the suggested value.
87
+ `beta_fast` (:obj:`float`, `optional`):
88
+ Only used with 'yarn'. Parameter to set the boundary for extrapolation (only) in the linear
89
+ ramp function. If unspecified, it defaults to 32.
90
+ `beta_slow` (:obj:`float`, `optional`):
91
+ Only used with 'yarn'. Parameter to set the boundary for interpolation (only) in the linear
92
+ ramp function. If unspecified, it defaults to 1.
93
+ `short_factor` (:obj:`List[float]`, `optional`):
94
+ Only used with 'longrope'. The scaling factor to be applied to short contexts (<
95
+ `original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
96
+ size divided by the number of attention heads divided by 2
97
+ `long_factor` (:obj:`List[float]`, `optional`):
98
+ Only used with 'longrope'. The scaling factor to be applied to long contexts (<
99
+ `original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
100
+ size divided by the number of attention heads divided by 2
101
+ `low_freq_factor` (:obj:`float`, `optional`):
102
+ Only used with 'llama3'. Scaling factor applied to low frequency components of the RoPE
103
+ `high_freq_factor` (:obj:`float`, `optional`):
104
+ Only used with 'llama3'. Scaling factor applied to high frequency components of the RoPE
105
+ embed_dropout (:obj:`float`, `optional`, defaults to 0.0):
106
+ The dropout probabilitiy for all fully connected layers in the embeddings, encoder, and pooler.
107
+ attention_dropout (:obj:`float`, `optional`, defaults to 0.0):
108
+ The dropout ratio for the attention probabilities.
109
+ layer_norm_epsilon (:obj:`float`, `optional`, defaults to 1e-5):
110
+ The epsilon used by the layer normalization layers.
111
+ initializer_range (:obj:`float`, `optional`, defaults to 0.02):
112
+ The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
113
+ use_cache (:obj:`bool`, `optional`, defaults to :obj:`True`):
114
+ Whether or not the model should return the last key/values attentions (not used by all models). Only
115
+ relevant if ``configs.is_decoder=True``.
116
+ bos_token_id (:obj:`int`, `optional`, defaults to 0):
117
+ Beginning of stream token id.
118
+ eos_token_id (:obj:`int`, `optional`, defaults to 2):
119
+ End of stream token id.
120
+ tie_word_embeddings (:obj:`bool`, `optional`, defaults to :obj:`True`):
121
+ Whether to tie weight embeddings
122
+ gradient_checkpointing (:obj:`bool`, `optional`, defaults to :obj:`False`):
123
+ If True, use gradient checkpointing to save memory at the expense of slower backward pass.
124
+
125
+ Example::
126
+
127
+ >>> from transformers import EXAONEModel, ExaoneConfig
128
+
129
+ >>> # Initializing a EXAONE configuration
130
+ >>> configuration = ExaoneConfig()
131
+
132
+ >>> # Initializing a model from configuration
133
+ >>> model = EXAONEModel(configuration)
134
+
135
+ >>> # Accessing the model configuration
136
+ >>> configuration = model.configs
137
+ """
138
+
139
+ model_type = "exaone"
140
+ keys_to_ignore_at_inference = ["past_key_values"]
141
+ attribute_map = {"num_hidden_layers": "num_layers"}
142
+
143
+ def __init__(
144
+ self,
145
+ vocab_size=102400,
146
+ max_position_embeddings=2048,
147
+ hidden_size=2048,
148
+ num_layers=32,
149
+ num_attention_heads=32,
150
+ num_key_value_heads=None,
151
+ intermediate_size=None,
152
+ activation_function="silu",
153
+ rope_theta=10000.0,
154
+ rope_scaling=None,
155
+ embed_dropout=0.0,
156
+ attention_dropout=0.0,
157
+ layer_norm_epsilon=1e-5,
158
+ initializer_range=0.02,
159
+ use_cache=True,
160
+ bos_token_id=0,
161
+ eos_token_id=2,
162
+ tie_word_embeddings=True,
163
+ **kwargs
164
+ ):
165
+ self.vocab_size = vocab_size
166
+ self.max_position_embeddings = max_position_embeddings
167
+ self.hidden_size = hidden_size
168
+ self.num_layers = num_layers
169
+ self.num_attention_heads = num_attention_heads
170
+ self.num_hidden_layers = num_layers
171
+ if num_key_value_heads is None:
172
+ num_key_value_heads = num_attention_heads
173
+ self.num_key_value_heads = num_key_value_heads
174
+ if intermediate_size:
175
+ self.intermediate_size = intermediate_size
176
+ else:
177
+ self.intermediate_size = hidden_size * 4
178
+ self.activation_function = activation_function
179
+ self.embed_dropout = embed_dropout
180
+ self.attention_dropout = attention_dropout
181
+ self.layer_norm_epsilon = layer_norm_epsilon
182
+ self.initializer_range = initializer_range
183
+ self.use_cache = use_cache
184
+ self.rope_theta = rope_theta
185
+ self.rope_scaling = rope_scaling
186
+
187
+ self.bos_token_id = bos_token_id
188
+ self.eos_token_id = eos_token_id
189
+
190
+ super().__init__(
191
+ bos_token_id=bos_token_id,
192
+ eos_token_id=eos_token_id,
193
+ tie_word_embeddings=tie_word_embeddings,
194
+ **kwargs
195
+ )
lib/python3.12/site-packages/sglang/srt/configs/janus_pro.py ADDED
@@ -0,0 +1,628 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from:
2
+ # https://github.com/deepseek-ai/Janus/tree/main/janus/models
3
+
4
+ from dataclasses import dataclass
5
+ from typing import Dict, List, Tuple, Union
6
+
7
+ import numpy as np
8
+ import PIL
9
+ import torch
10
+ from PIL.Image import Image
11
+ from transformers import (
12
+ BaseImageProcessor,
13
+ BatchFeature,
14
+ LlamaConfig,
15
+ LlamaTokenizerFast,
16
+ PretrainedConfig,
17
+ ProcessorMixin,
18
+ )
19
+ from transformers.image_utils import to_numpy_array
20
+
21
+ from sglang.srt.configs.utils import register_image_processor, register_processor
22
+ from sglang.srt.mm_utils import expand2square
23
+
24
+
25
+ class DictToObject(dict):
26
+ def __init__(self, dictionary):
27
+ super(self).__init__(dictionary)
28
+
29
+ for key, value in dictionary.items():
30
+ if isinstance(value, dict):
31
+ value = DictToObject(value)
32
+ setattr(self, key, value)
33
+
34
+
35
+ class VisionConfig(PretrainedConfig):
36
+ model_type = "vision"
37
+ cls: str = ""
38
+ params = {}
39
+
40
+ def __init__(self, **kwargs):
41
+ super().__init__(**kwargs)
42
+
43
+ self.cls = kwargs.get("cls", "")
44
+ if not isinstance(self.cls, str):
45
+ self.cls = self.cls.__name__
46
+
47
+ self.params = kwargs.get("params", {})
48
+
49
+
50
+ class GenAlignerConfig(PretrainedConfig):
51
+ model_type = "gen_aligner"
52
+ cls: str = ""
53
+ params = {}
54
+
55
+ def __init__(self, **kwargs):
56
+ super().__init__(**kwargs)
57
+
58
+ self.cls = kwargs.get("cls", "")
59
+ if not isinstance(self.cls, str):
60
+ self.cls = self.cls.__name__
61
+
62
+ self.params = kwargs.get("params", {})
63
+
64
+
65
+ class GenHeadConfig(PretrainedConfig):
66
+ model_type = "gen_head"
67
+ cls: str = ""
68
+ params = {}
69
+
70
+ def __init__(self, **kwargs):
71
+ super().__init__(**kwargs)
72
+
73
+ self.cls = kwargs.get("cls", "")
74
+ if not isinstance(self.cls, str):
75
+ self.cls = self.cls.__name__
76
+
77
+ self.params = kwargs.get("params", {})
78
+
79
+
80
+ class AlignerConfig(PretrainedConfig):
81
+ model_type = "aligner"
82
+ cls: str = ""
83
+ params = {}
84
+
85
+ def __init__(self, **kwargs):
86
+ super().__init__(**kwargs)
87
+
88
+ self.cls = kwargs.get("cls", "")
89
+ if not isinstance(self.cls, str):
90
+ self.cls = self.cls.__name__
91
+
92
+ self.params = kwargs.get("params", {})
93
+
94
+
95
+ class GenVisionConfig(PretrainedConfig):
96
+ model_type = "gen_vision"
97
+ cls: str = ""
98
+ params = {}
99
+
100
+ def __init__(self, **kwargs):
101
+ super().__init__(**kwargs)
102
+
103
+ self.cls = kwargs.get("cls", "")
104
+ if not isinstance(self.cls, str):
105
+ self.cls = self.cls.__name__
106
+
107
+ self.params = kwargs.get("params", {})
108
+
109
+
110
+ @dataclass
111
+ class SigLIPVisionCfg:
112
+ width: int = 1152
113
+ layers: Union[Tuple[int, int, int, int], int] = 27
114
+ heads: int = 16
115
+ patch_size: int = 14
116
+ image_size: Union[Tuple[int, int], int] = 336
117
+ global_pool: str = "map"
118
+ mlp_ratio: float = 3.7362
119
+ class_token: bool = False
120
+ num_classes: int = 0
121
+ use_checkpoint: bool = False
122
+
123
+
124
+ class MultiModalityConfig(PretrainedConfig):
125
+ model_type = "multi_modality"
126
+ vision_config: VisionConfig
127
+ aligner_config: AlignerConfig
128
+
129
+ gen_vision_config: GenVisionConfig
130
+ gen_aligner_config: GenAlignerConfig
131
+ gen_head_config: GenHeadConfig
132
+
133
+ language_config: LlamaConfig
134
+
135
+ def __init__(self, **kwargs):
136
+ super().__init__(**kwargs)
137
+ vision_config = kwargs.get("vision_config", {})
138
+ self.vision_config = VisionConfig(**vision_config)
139
+
140
+ aligner_config = kwargs.get("aligner_config", {})
141
+ self.aligner_config = AlignerConfig(**aligner_config)
142
+
143
+ gen_vision_config = kwargs.get("gen_vision_config", {})
144
+ self.gen_vision_config = GenVisionConfig(**gen_vision_config)
145
+
146
+ gen_aligner_config = kwargs.get("gen_aligner_config", {})
147
+ self.gen_aligner_config = GenAlignerConfig(**gen_aligner_config)
148
+
149
+ gen_head_config = kwargs.get("gen_head_config", {})
150
+ self.gen_head_config = GenHeadConfig(**gen_head_config)
151
+
152
+ language_config = kwargs.get("language_config", {})
153
+ if isinstance(language_config, LlamaConfig):
154
+ self.language_config = language_config
155
+ else:
156
+ self.language_config = LlamaConfig(**language_config)
157
+
158
+
159
+ class VLMImageProcessor(BaseImageProcessor):
160
+ model_input_names = ["pixel_values"]
161
+
162
+ def __init__(
163
+ self,
164
+ image_size: int,
165
+ min_size: int = 14,
166
+ image_mean: Union[Tuple[float, float, float], List[float]] = (
167
+ 0.48145466,
168
+ 0.4578275,
169
+ 0.40821073,
170
+ ),
171
+ image_std: Union[Tuple[float, float, float], List[float]] = (
172
+ 0.26862954,
173
+ 0.26130258,
174
+ 0.27577711,
175
+ ),
176
+ rescale_factor: float = 1.0 / 255.0,
177
+ do_normalize: bool = True,
178
+ **kwargs,
179
+ ):
180
+ super().__init__(**kwargs)
181
+
182
+ self.image_size = image_size
183
+ self.rescale_factor = rescale_factor
184
+ self.image_mean = image_mean
185
+ self.image_std = image_std
186
+ self.min_size = min_size
187
+ self.do_normalize = do_normalize
188
+
189
+ if image_mean is None:
190
+ self.background_color = (127, 127, 127)
191
+ else:
192
+ self.background_color = tuple([int(x * 255) for x in image_mean])
193
+
194
+ def resize(self, pil_img: Image) -> np.ndarray:
195
+ """
196
+
197
+ Args:
198
+ pil_img (PIL.Image): [H, W, 3] in PIL.Image in RGB
199
+
200
+ Returns:
201
+ x (np.ndarray): [3, self.image_size, self.image_size]
202
+ """
203
+
204
+ width, height = pil_img.size
205
+ max_size = max(width, height)
206
+
207
+ size = [
208
+ max(int(height / max_size * self.image_size), self.min_size),
209
+ max(int(width / max_size * self.image_size), self.min_size),
210
+ ]
211
+
212
+ if width <= 0 or height <= 0 or size[0] <= 0 or size[1] <= 0:
213
+ # print(f"orig size = {pil_img.size}, new size = {size}")
214
+ raise ValueError("Invalid size!")
215
+
216
+ def resize(
217
+ pil_img, size, interpolation=PIL.Image.Resampling.BICUBIC, antialias=True
218
+ ):
219
+ if isinstance(size, int):
220
+ w, h = pil_img.size
221
+ if (w <= h and w == size) or (h <= w and h == size):
222
+ return pil_img
223
+ if w < h:
224
+ ow = size
225
+ oh = int(size * h / w)
226
+ else:
227
+ oh = size
228
+ ow = int(size * w / h)
229
+ size = (ow, oh)
230
+ else:
231
+ size = (size[1], size[0])
232
+
233
+ return pil_img.resize(
234
+ size, resample=interpolation, reducing_gap=None if antialias else 3.0
235
+ )
236
+
237
+ pil_img = resize(
238
+ pil_img, size, interpolation=PIL.Image.Resampling.BICUBIC, antialias=True
239
+ )
240
+
241
+ pil_img = expand2square(pil_img, self.background_color)
242
+ x = to_numpy_array(pil_img)
243
+
244
+ # [H, W, 3] -> [3, H, W]
245
+ x = np.transpose(x, (2, 0, 1))
246
+
247
+ return x
248
+
249
+ def preprocess(self, images, return_tensors: str = "pt", **kwargs) -> BatchFeature:
250
+ # resize and pad to [self.image_size, self.image_size]
251
+ # then convert from [H, W, 3] to [3, H, W]
252
+ if not isinstance(images, list):
253
+ images = [images]
254
+ images: List[np.ndarray] = [self.resize(image) for image in images]
255
+ images = [image[:3, ...] for image in images]
256
+
257
+ # rescale from [0, 255] -> [0, 1]
258
+ images = [
259
+ self.rescale(
260
+ image=image,
261
+ scale=self.rescale_factor,
262
+ input_data_format="channels_first",
263
+ )
264
+ for image in images
265
+ ]
266
+
267
+ # normalize
268
+ if self.do_normalize:
269
+ images = [
270
+ self.normalize(
271
+ image=image,
272
+ mean=self.image_mean,
273
+ std=self.image_std,
274
+ input_data_format="channels_first",
275
+ )
276
+ for image in images
277
+ ]
278
+ data = {"pixel_values": images}
279
+ return BatchFeature(data=data, tensor_type=return_tensors)
280
+
281
+ @property
282
+ def default_shape(self):
283
+ return [3, self.image_size, self.image_size]
284
+
285
+
286
+ class DictOutput(object):
287
+ def keys(self):
288
+ return self.__dict__.keys()
289
+
290
+ def __getitem__(self, item):
291
+ return self.__dict__[item]
292
+
293
+ def __setitem__(self, key, value):
294
+ self.__dict__[key] = value
295
+
296
+
297
+ @dataclass
298
+ class VLChatProcessorOutput(DictOutput):
299
+ sft_format: str
300
+ input_ids: torch.Tensor
301
+ pixel_values: torch.Tensor
302
+ num_image_tokens: torch.IntTensor
303
+
304
+ def __len__(self):
305
+ return len(self.input_ids)
306
+
307
+
308
+ @dataclass
309
+ class BatchedVLChatProcessorOutput(DictOutput):
310
+ sft_format: List[str]
311
+ input_ids: torch.Tensor
312
+ pixel_values: torch.Tensor
313
+ attention_mask: torch.Tensor
314
+ images_seq_mask: torch.BoolTensor
315
+ images_emb_mask: torch.BoolTensor
316
+
317
+
318
+ # FIXME: had to place Official Processor here, since image_processor module would not be imported in all threads,
319
+ # hence AutoProcessor registration would not be affective in some cases
320
+ class VLChatProcessor(ProcessorMixin):
321
+ image_processor_class = "AutoImageProcessor"
322
+ tokenizer_class = ("LlamaTokenizer", "LlamaTokenizerFast")
323
+
324
+ attributes = ["image_processor", "tokenizer"]
325
+
326
+ def __init__(
327
+ self,
328
+ image_processor: VLMImageProcessor,
329
+ tokenizer: LlamaTokenizerFast,
330
+ image_tag: str = "<image_placeholder>",
331
+ image_start_tag: str = "<begin_of_image>",
332
+ image_end_tag: str = "<end_of_image>",
333
+ pad_tag: str = "<|▁pad▁|>",
334
+ num_image_tokens: int = 576,
335
+ add_special_token: bool = False,
336
+ sft_format: str = "deepseek",
337
+ mask_prompt: bool = True,
338
+ ignore_id: int = -100,
339
+ **kwargs,
340
+ ):
341
+ self.image_processor = image_processor
342
+ self.tokenizer = tokenizer
343
+
344
+ image_id = self.tokenizer.vocab.get(image_tag)
345
+ if image_id is None:
346
+ special_tokens = [image_tag]
347
+ special_tokens_dict = {"additional_special_tokens": special_tokens}
348
+ self.tokenizer.add_special_tokens(special_tokens_dict)
349
+ # print(f"Add image tag = {image_tag} to the tokenizer")
350
+
351
+ self.image_tag = image_tag
352
+ self.image_start_tag = image_start_tag
353
+ self.image_end_tag = image_end_tag
354
+ self.pad_tag = pad_tag
355
+
356
+ self.num_image_tokens = num_image_tokens
357
+ self.add_special_token = add_special_token
358
+ self.sft_format = sft_format
359
+ self.ignore_id = ignore_id
360
+
361
+ super().__init__(
362
+ image_processor,
363
+ tokenizer,
364
+ **kwargs,
365
+ )
366
+
367
+ @property
368
+ def image_token(self):
369
+ return self.image_tag
370
+
371
+ @property
372
+ def image_id(self) -> int:
373
+ image_id = self.tokenizer.vocab.get(self.image_tag)
374
+ return image_id
375
+
376
+ @property
377
+ def image_start_id(self):
378
+ image_start_id = self.tokenizer.vocab.get(self.image_start_tag)
379
+ return image_start_id
380
+
381
+ @property
382
+ def image_end_id(self):
383
+ image_end_id = self.tokenizer.vocab.get(self.image_end_tag)
384
+ return image_end_id
385
+
386
+ @property
387
+ def image_start_token(self):
388
+ return self.image_start_tag
389
+
390
+ @property
391
+ def image_end_token(self):
392
+ return self.image_end_tag
393
+
394
+ @property
395
+ def pad_id(self):
396
+ pad_id = self.tokenizer.vocab.get(self.pad_tag)
397
+ return pad_id
398
+
399
+ def add_image_token(
400
+ self,
401
+ image_indices: List[int],
402
+ input_ids: torch.LongTensor,
403
+ ):
404
+ """
405
+
406
+ Args:
407
+ image_indices (List[int]): [index_0, index_1, ..., index_j]
408
+ input_ids (torch.LongTensor): [N]
409
+
410
+ Returns:
411
+ input_ids (torch.LongTensor): [N + image tokens]
412
+ num_image_tokens (torch.IntTensor): [n_images]
413
+ """
414
+
415
+ input_slices = []
416
+
417
+ start = 0
418
+ for index in image_indices:
419
+ if self.add_special_token:
420
+ end = index + 1
421
+ else:
422
+ end = index
423
+
424
+ # original text tokens
425
+ input_slices.append(input_ids[start:end])
426
+
427
+ # add boi, image tokens, eoi and set the mask as False
428
+ input_slices.append(self.image_start_id * torch.ones((1), dtype=torch.long))
429
+ input_slices.append(
430
+ self.image_id * torch.ones((self.num_image_tokens,), dtype=torch.long)
431
+ )
432
+ input_slices.append(self.image_end_id * torch.ones((1), dtype=torch.long))
433
+ start = index + 1
434
+
435
+ # the left part
436
+ input_slices.append(input_ids[start:])
437
+
438
+ # concat all slices
439
+ input_ids = torch.cat(input_slices, dim=0)
440
+ num_image_tokens = torch.IntTensor([self.num_image_tokens] * len(image_indices))
441
+
442
+ return input_ids, num_image_tokens
443
+
444
+ def process_one(
445
+ self,
446
+ prompt: str = None,
447
+ images: List[Image] = None,
448
+ **kwargs,
449
+ ):
450
+ """
451
+
452
+ Args:
453
+ prompt (str): the formatted prompt;
454
+ images (List[ImageType]): the list of images;
455
+ **kwargs:
456
+
457
+ Returns:
458
+ outputs (BaseProcessorOutput): the output of the processor,
459
+ - input_ids (torch.LongTensor): [N + image tokens]
460
+ - target_ids (torch.LongTensor): [N + image tokens]
461
+ - images (torch.FloatTensor): [n_images, 3, H, W]
462
+ - image_id (int): the id of the image token
463
+ - num_image_tokens (List[int]): the number of image tokens
464
+ """
465
+
466
+ sft_format = prompt
467
+ # tokenize
468
+ input_ids = self.tokenizer.encode(sft_format)
469
+ input_ids = torch.LongTensor(input_ids)
470
+
471
+ # add image tokens to the input_ids
472
+ image_token_mask: torch.Tensor = (input_ids == self.image_id).to(torch.bool)
473
+ image_indices = image_token_mask.nonzero()
474
+ input_ids, num_image_tokens = self.add_image_token(
475
+ image_indices=image_indices,
476
+ input_ids=input_ids,
477
+ )
478
+
479
+ # load images
480
+ images_outputs = self.image_processor(images, return_tensors="pt")
481
+
482
+ prepare = VLChatProcessorOutput(
483
+ sft_format=sft_format,
484
+ input_ids=input_ids,
485
+ pixel_values=images_outputs.pixel_values,
486
+ num_image_tokens=num_image_tokens,
487
+ )
488
+
489
+ return prepare
490
+
491
+ def __call__(
492
+ self,
493
+ *,
494
+ prompt: str = None,
495
+ conversations: List[Dict[str, str]] = None,
496
+ images: List[Image] = None,
497
+ force_batchify: bool = True,
498
+ **kwargs,
499
+ ):
500
+ """
501
+
502
+ Args:
503
+ prompt (str): the formatted prompt;
504
+ conversations (List[Dict]): conversations with a list of messages;
505
+ images (List[ImageType]): the list of images;
506
+ force_batchify (bool): force batchify the inputs;
507
+ **kwargs:
508
+
509
+ Returns:
510
+ outputs (BaseProcessorOutput): the output of the processor,
511
+ - input_ids (torch.LongTensor): [N + image tokens]
512
+ - images (torch.FloatTensor): [n_images, 3, H, W]
513
+ - image_id (int): the id of the image token
514
+ - num_image_tokens (List[int]): the number of image tokens
515
+ """
516
+
517
+ prepare = self.process_one(
518
+ prompt=prompt, conversations=conversations, images=images
519
+ )
520
+
521
+ if force_batchify:
522
+ prepare = self.batchify([prepare])
523
+
524
+ return prepare
525
+
526
+ def batchify(
527
+ self, prepare_list: List[VLChatProcessorOutput]
528
+ ) -> BatchedVLChatProcessorOutput:
529
+ """
530
+ Preprocesses the inputs for multimodal inference.
531
+
532
+ Args:
533
+ prepare_list (List[VLChatProcessorOutput]): A list of VLChatProcessorOutput.
534
+
535
+ Returns:
536
+ BatchedVLChatProcessorOutput: A dictionary of the inputs to use for multimodal inference.
537
+ """
538
+
539
+ batch_size = len(prepare_list)
540
+ sft_format = []
541
+ n_images = []
542
+ seq_lens = []
543
+ for prepare in prepare_list:
544
+ n_images.append(len(prepare.num_image_tokens))
545
+ seq_lens.append(len(prepare))
546
+
547
+ input_token_max_len = max(seq_lens)
548
+ max_n_images = max(1, max(n_images))
549
+
550
+ batched_input_ids = torch.full(
551
+ (batch_size, input_token_max_len), self.pad_id
552
+ ).long() # FIXME
553
+ batched_attention_mask = torch.zeros((batch_size, input_token_max_len)).long()
554
+ batched_pixel_values = torch.zeros(
555
+ (batch_size, max_n_images, *self.image_processor.default_shape)
556
+ ).float()
557
+ batched_images_seq_mask = torch.zeros((batch_size, input_token_max_len)).bool()
558
+ batched_images_emb_mask = torch.zeros(
559
+ (batch_size, max_n_images, self.num_image_tokens)
560
+ ).bool()
561
+
562
+ for i, prepare in enumerate(prepare_list):
563
+ input_ids = prepare.input_ids
564
+ seq_len = len(prepare)
565
+ n_image = len(prepare.num_image_tokens)
566
+ # left-padding
567
+ batched_attention_mask[i, -seq_len:] = 1
568
+ batched_input_ids[i, -seq_len:] = torch.LongTensor(input_ids)
569
+ batched_images_seq_mask[i, -seq_len:] = input_ids == self.image_id
570
+
571
+ if n_image > 0:
572
+ batched_pixel_values[i, :n_image] = prepare.pixel_values
573
+ for j, n_image_tokens in enumerate(prepare.num_image_tokens):
574
+ batched_images_emb_mask[i, j, :n_image_tokens] = True
575
+
576
+ sft_format.append(prepare.sft_format)
577
+
578
+ batched_prepares = BatchedVLChatProcessorOutput(
579
+ input_ids=batched_input_ids,
580
+ attention_mask=batched_attention_mask,
581
+ pixel_values=batched_pixel_values,
582
+ images_seq_mask=batched_images_seq_mask,
583
+ images_emb_mask=batched_images_emb_mask,
584
+ sft_format=sft_format,
585
+ )
586
+
587
+ return batched_prepares
588
+
589
+
590
+ class VLMImageProcessorConfig(PretrainedConfig):
591
+ model_type = "deepseek_vlm"
592
+ image_size: int
593
+ min_size: int
594
+ image_mean: Union[Tuple[float, float, float], List[float]]
595
+ image_std: Union[Tuple[float, float, float], List[float]]
596
+ rescale_factor: float
597
+ do_normalize: bool
598
+
599
+ def __init__(
600
+ self,
601
+ image_size: int,
602
+ min_size: int = 14,
603
+ image_mean: Union[Tuple[float, float, float], List[float]] = (
604
+ 0.48145466,
605
+ 0.4578275,
606
+ 0.40821073,
607
+ ),
608
+ image_std: Union[Tuple[float, float, float], List[float]] = (
609
+ 0.26862954,
610
+ 0.26130258,
611
+ 0.27577711,
612
+ ),
613
+ rescale_factor: float = 1.0 / 255.0,
614
+ do_normalize: bool = True,
615
+ **kwargs,
616
+ ):
617
+ self.image_size = image_size
618
+ self.min_size = min_size
619
+ self.image_mean = image_mean
620
+ self.image_std = image_std
621
+ self.rescale_factor = rescale_factor
622
+ self.do_normalize = do_normalize
623
+
624
+ super().__init__(**kwargs)
625
+
626
+
627
+ register_processor(MultiModalityConfig, VLChatProcessor)
628
+ register_image_processor(MultiModalityConfig, VLMImageProcessor)
lib/python3.12/site-packages/sglang/srt/configs/load_config.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/config.py
2
+ import enum
3
+ import json
4
+ import logging
5
+ from dataclasses import dataclass, field
6
+ from typing import List, Optional, Union
7
+
8
+ from sglang.srt.utils import is_hip
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class LoadFormat(str, enum.Enum):
14
+ AUTO = "auto"
15
+ PT = "pt"
16
+ SAFETENSORS = "safetensors"
17
+ NPCACHE = "npcache"
18
+ DUMMY = "dummy"
19
+ SHARDED_STATE = "sharded_state"
20
+ GGUF = "gguf"
21
+ BITSANDBYTES = "bitsandbytes"
22
+ MISTRAL = "mistral"
23
+ LAYERED = "layered"
24
+ JAX = "jax"
25
+ REMOTE = "remote"
26
+
27
+
28
+ @dataclass
29
+ class LoadConfig:
30
+ """
31
+ download_dir: Directory to download and load the weights, default to the
32
+ default cache directory of huggingface.
33
+ load_format: The format of the model weights to load:
34
+ "auto" will try to load the weights in the safetensors format and
35
+ fall back to the pytorch bin format if safetensors format is
36
+ not available.
37
+ "pt" will load the weights in the pytorch bin format.
38
+ "safetensors" will load the weights in the safetensors format.
39
+ "npcache" will load the weights in pytorch format and store
40
+ a numpy cache to speed up the loading.
41
+ "dummy" will initialize the weights with random values, which is
42
+ mainly for profiling.
43
+ "bitsandbytes" will load nf4 type weights.
44
+ ignore_patterns: The list of patterns to ignore when loading the model.
45
+ Default to "original/**/*" to avoid repeated loading of llama's
46
+ checkpoints.
47
+ decryption_key_file: If set, decrypts the output files with a password read
48
+ from this file (after PBKDF2).
49
+ """
50
+
51
+ load_format: Union[str, LoadFormat] = LoadFormat.AUTO
52
+ download_dir: Optional[str] = None
53
+ model_loader_extra_config: Optional[Union[str, dict]] = field(default_factory=dict)
54
+ ignore_patterns: Optional[Union[List[str], str]] = None
55
+ decryption_key_file: Optional[str] = None
56
+
57
+ def __post_init__(self):
58
+ model_loader_extra_config = self.model_loader_extra_config or {}
59
+ if isinstance(model_loader_extra_config, str):
60
+ self.model_loader_extra_config = json.loads(model_loader_extra_config)
61
+ self._verify_load_format()
62
+
63
+ if self.ignore_patterns is not None and len(self.ignore_patterns) > 0:
64
+ logger.info(
65
+ "Ignoring the following patterns when downloading weights: %s",
66
+ self.ignore_patterns,
67
+ )
68
+ else:
69
+ self.ignore_patterns = ["original/**/*"]
70
+
71
+ def _verify_load_format(self) -> None:
72
+ if not isinstance(self.load_format, str):
73
+ return
74
+
75
+ load_format = self.load_format.lower()
76
+ self.load_format = LoadFormat(load_format)
77
+
78
+ rocm_not_supported_load_format: List[str] = []
79
+ if is_hip() and load_format in rocm_not_supported_load_format:
80
+ rocm_supported_load_format = [
81
+ f
82
+ for f in LoadFormat.__members__
83
+ if (f not in rocm_not_supported_load_format)
84
+ ]
85
+ raise ValueError(
86
+ f"load format '{load_format}' is not supported in ROCm. "
87
+ f"Supported load formats are "
88
+ f"{rocm_supported_load_format}"
89
+ )
lib/python3.12/site-packages/sglang/srt/configs/model_config.py ADDED
@@ -0,0 +1,558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ==============================================================================
14
+
15
+ import json
16
+ import logging
17
+ import math
18
+ import os
19
+ from enum import IntEnum, auto
20
+ from typing import List, Optional, Set, Union
21
+
22
+ import torch
23
+ from transformers import PretrainedConfig
24
+
25
+ from sglang.srt.hf_transformers_utils import get_config, get_context_length
26
+ from sglang.srt.layers.quantization import QUANTIZATION_METHODS
27
+ from sglang.srt.utils import get_bool_env_var, is_hip
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class AttentionArch(IntEnum):
33
+ MLA = auto()
34
+ MHA = auto()
35
+
36
+
37
+ class ModelConfig:
38
+ def __init__(
39
+ self,
40
+ model_path: str,
41
+ trust_remote_code: bool = True,
42
+ revision: Optional[str] = None,
43
+ context_length: Optional[int] = None,
44
+ model_override_args: Optional[str] = None,
45
+ is_embedding: Optional[bool] = None,
46
+ enable_multimodal: Optional[bool] = None,
47
+ dtype: str = "auto",
48
+ quantization: Optional[str] = None,
49
+ override_config_file: Optional[str] = None,
50
+ ) -> None:
51
+
52
+ self.model_path = model_path
53
+ self.revision = revision
54
+ self.quantization = quantization
55
+
56
+ # Parse args
57
+ self.maybe_pull_model_tokenizer_from_remote()
58
+ self.model_override_args = json.loads(model_override_args)
59
+ kwargs = {}
60
+ if override_config_file and override_config_file.strip():
61
+ kwargs["_configuration_file"] = override_config_file.strip()
62
+
63
+ self.hf_config = get_config(
64
+ self.model_path,
65
+ trust_remote_code=trust_remote_code,
66
+ revision=revision,
67
+ model_override_args=self.model_override_args,
68
+ **kwargs,
69
+ )
70
+ self.hf_text_config = get_hf_text_config(self.hf_config)
71
+ self.attention_chunk_size = getattr(
72
+ self.hf_text_config, "attention_chunk_size", None
73
+ )
74
+
75
+ if enable_multimodal is None:
76
+ mm_disabled_models = [
77
+ "Gemma3ForConditionalGeneration",
78
+ "Llama4ForConditionalGeneration",
79
+ ]
80
+ if self.hf_config.architectures[0] in mm_disabled_models:
81
+ enable_multimodal = False
82
+ logger.info(
83
+ f"Multimodal is disabled for {self.hf_config.model_type}. To enable it, set --enable-multimodal."
84
+ )
85
+ else:
86
+ enable_multimodal = True
87
+
88
+ # Check model type
89
+ self.is_generation = is_generation_model(
90
+ self.hf_config.architectures, is_embedding
91
+ )
92
+ self.is_multimodal = enable_multimodal and is_multimodal_model(
93
+ self.hf_config.architectures
94
+ )
95
+ self.is_multimodal_gen = enable_multimodal and is_multimodal_gen_model(
96
+ self.hf_config.architectures
97
+ )
98
+ self.is_image_gen = enable_multimodal and is_image_gen_model(
99
+ self.hf_config.architectures
100
+ )
101
+ self.is_audio_model = enable_multimodal and is_audio_model(
102
+ self.hf_config.architectures
103
+ )
104
+ self.is_encoder_decoder = is_encoder_decoder_model(self.hf_config.architectures)
105
+ self.dtype = _get_and_verify_dtype(self.hf_text_config, dtype)
106
+
107
+ # Derive context length
108
+ derived_context_len = get_context_length(self.hf_text_config)
109
+ if context_length is not None:
110
+ if context_length > derived_context_len:
111
+ if get_bool_env_var(
112
+ "SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN", default="True"
113
+ ):
114
+ logger.warning(
115
+ f"Warning: User-specified context_length ({context_length}) is greater than the derived context_length ({derived_context_len}). "
116
+ f"This may lead to incorrect model outputs or CUDA errors."
117
+ )
118
+ self.context_len = context_length
119
+ else:
120
+ raise ValueError(
121
+ f"User-specified context_length ({context_length}) is greater than the derived context_length ({derived_context_len}). "
122
+ f"This may lead to incorrect model outputs or CUDA errors. Note that the derived context_length may differ from max_position_embeddings in the model's config. "
123
+ f"To allow overriding this maximum, set the env var SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1"
124
+ )
125
+ else:
126
+ self.context_len = context_length
127
+ else:
128
+ self.context_len = derived_context_len
129
+
130
+ # Unify the config keys for hf_text_config
131
+ self.head_dim = getattr(
132
+ self.hf_text_config,
133
+ "head_dim",
134
+ self.hf_text_config.hidden_size // self.hf_text_config.num_attention_heads,
135
+ )
136
+
137
+ # FIXME: temporary special judge for MLA architecture
138
+ if (
139
+ "DeepseekV2ForCausalLM" in self.hf_config.architectures
140
+ or "DeepseekV3ForCausalLM" in self.hf_config.architectures
141
+ or "DeepseekV3ForCausalLMNextN" in self.hf_config.architectures
142
+ ):
143
+ self.head_dim = 256
144
+ self.attention_arch = AttentionArch.MLA
145
+ self.kv_lora_rank = self.hf_config.kv_lora_rank
146
+ self.qk_nope_head_dim = self.hf_config.qk_nope_head_dim
147
+ self.qk_rope_head_dim = self.hf_config.qk_rope_head_dim
148
+ self.v_head_dim = self.hf_config.v_head_dim
149
+
150
+ # Handle rope scaling with yarn
151
+ self.scaling = 1 / math.sqrt(self.qk_nope_head_dim + self.qk_rope_head_dim)
152
+ if self.hf_config.rope_scaling:
153
+ mscale_all_dim = self.hf_config.rope_scaling.get(
154
+ "mscale_all_dim", False
155
+ )
156
+ scaling_factor = self.hf_config.rope_scaling["factor"]
157
+ mscale = yarn_get_mscale(scaling_factor, float(mscale_all_dim))
158
+ self.scaling = self.scaling * mscale * mscale
159
+
160
+ elif "MiniCPM3ForCausalLM" in self.hf_config.architectures:
161
+ self.head_dim = 128
162
+ self.attention_arch = AttentionArch.MLA
163
+ self.kv_lora_rank = self.hf_config.kv_lora_rank
164
+ self.qk_rope_head_dim = self.hf_config.qk_rope_head_dim
165
+ elif "DeepseekVL2ForCausalLM" in self.hf_config.architectures and getattr(
166
+ self.hf_text_config, "use_mla", True
167
+ ):
168
+ self.head_dim = 256
169
+ self.attention_arch = AttentionArch.MLA
170
+ self.kv_lora_rank = self.hf_text_config.kv_lora_rank
171
+ self.qk_rope_head_dim = self.hf_text_config.qk_rope_head_dim
172
+ else:
173
+ self.attention_arch = AttentionArch.MHA
174
+
175
+ self.num_attention_heads = self.hf_text_config.num_attention_heads
176
+ self.num_key_value_heads = getattr(
177
+ self.hf_text_config, "num_key_value_heads", None
178
+ )
179
+
180
+ # for Dbrx and MPT models
181
+ if self.hf_config.model_type in ["dbrx", "mpt"]:
182
+ self.num_key_value_heads = getattr(
183
+ self.hf_config.attn_config, "kv_n_heads", None
184
+ )
185
+
186
+ if self.num_key_value_heads is None:
187
+ self.num_key_value_heads = self.num_attention_heads
188
+ self.hidden_size = self.hf_text_config.hidden_size
189
+ self.num_hidden_layers = self.hf_text_config.num_hidden_layers
190
+ self.vocab_size = self.hf_text_config.vocab_size
191
+
192
+ # Verify quantization
193
+ self._verify_quantization()
194
+
195
+ # Cache attributes
196
+ self.hf_eos_token_id = self.get_hf_eos_token_id()
197
+ self.image_token_id = getattr(self.hf_config, "image_token_id", None)
198
+
199
+ # adapted from https://github.com/vllm-project/vllm/blob/main/vllm/config.py#L289
200
+ def get_total_num_kv_heads(self) -> int:
201
+ """Returns the total number of KV heads."""
202
+ # For GPTBigCode & Falcon:
203
+ # NOTE: for falcon, when new_decoder_architecture is True, the
204
+ # multi_query flag is ignored and we use n_head_kv for the number of
205
+ # KV heads.
206
+ falcon_model_types = ["falcon", "RefinedWeb", "RefinedWebModel"]
207
+ new_decoder_arch_falcon = (
208
+ self.hf_config.model_type in falcon_model_types
209
+ and getattr(self.hf_config, "new_decoder_architecture", False)
210
+ )
211
+ if not new_decoder_arch_falcon and getattr(
212
+ self.hf_text_config, "multi_query", False
213
+ ):
214
+ # Multi-query attention, only one KV head.
215
+ # Currently, tensor parallelism is not supported in this case.
216
+ return 1
217
+
218
+ # For DBRX and MPT
219
+ if self.hf_config.model_type in ["mpt"]:
220
+ if "kv_n_heads" in self.hf_config.attn_config:
221
+ return self.hf_config.attn_config["kv_n_heads"]
222
+ return self.hf_config.num_attention_heads
223
+ if self.hf_config.model_type in ["dbrx"]:
224
+ return getattr(
225
+ self.hf_config.attn_config,
226
+ "kv_n_heads",
227
+ self.hf_config.num_attention_heads,
228
+ )
229
+
230
+ attributes = [
231
+ # For Falcon:
232
+ "n_head_kv",
233
+ "num_kv_heads",
234
+ # For LLaMA-2:
235
+ "num_key_value_heads",
236
+ # For ChatGLM:
237
+ "multi_query_group_num",
238
+ ]
239
+ for attr in attributes:
240
+ num_kv_heads = getattr(self.hf_text_config, attr, None)
241
+ if num_kv_heads is not None:
242
+ return num_kv_heads
243
+
244
+ # For non-grouped-query attention models, the number of KV heads is
245
+ # equal to the number of attention heads.
246
+ return self.hf_text_config.num_attention_heads
247
+
248
+ def get_num_kv_heads(self, tensor_parallel_size) -> int:
249
+ """Returns the number of KV heads per GPU."""
250
+ total_num_kv_heads = self.get_total_num_kv_heads()
251
+ # If tensor parallelism is used, we divide the number of KV heads by
252
+ # the tensor parallel size. We will replicate the KV heads in the
253
+ # case where the number of KV heads is smaller than the tensor
254
+ # parallel size so each GPU has at least one KV head.
255
+ return max(1, total_num_kv_heads // tensor_parallel_size)
256
+
257
+ # adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/config.py
258
+ def _parse_quant_hf_config(self):
259
+ quant_cfg = getattr(self.hf_config, "quantization_config", None)
260
+ if quant_cfg is None:
261
+ # compressed-tensors uses a "compression_config" key
262
+ quant_cfg = getattr(self.hf_config, "compression_config", None)
263
+ if quant_cfg is None:
264
+ # check if is modelopt model -- modelopt doesn't have corresponding field
265
+ # in hf `config.json` but has a standalone `hf_quant_config.json` in the root directory
266
+ # example: https://huggingface.co/nvidia/Llama-3.1-8B-Instruct-FP8/tree/main
267
+ is_local = os.path.exists(self.model_path)
268
+ modelopt_quant_config = {"quant_method": "modelopt"}
269
+ if not is_local:
270
+ from huggingface_hub import HfApi
271
+
272
+ hf_api = HfApi()
273
+ if hf_api.file_exists(self.model_path, "hf_quant_config.json"):
274
+ quant_cfg = modelopt_quant_config
275
+ elif os.path.exists(os.path.join(self.model_path, "hf_quant_config.json")):
276
+ quant_cfg = modelopt_quant_config
277
+ return quant_cfg
278
+
279
+ # adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/config.py
280
+ def _verify_quantization(self) -> None:
281
+ supported_quantization = [*QUANTIZATION_METHODS]
282
+ rocm_supported_quantization = [
283
+ "awq",
284
+ "gptq",
285
+ "fp8",
286
+ "compressed_tensors",
287
+ "compressed-tensors",
288
+ "fbgemm_fp8",
289
+ "w8a8_fp8",
290
+ ]
291
+ optimized_quantization_methods = [
292
+ "fp8",
293
+ "marlin",
294
+ "modelopt",
295
+ "gptq_marlin_24",
296
+ "gptq_marlin",
297
+ "awq_marlin",
298
+ "fbgemm_fp8",
299
+ "compressed_tensors",
300
+ "compressed-tensors",
301
+ "experts_int8",
302
+ "w8a8_int8",
303
+ "w8a8_fp8",
304
+ "moe_wna16",
305
+ ]
306
+ compatible_quantization_methods = {
307
+ "modelopt_fp4": ["modelopt"],
308
+ "w8a8_int8": ["compressed-tensors", "compressed_tensors"],
309
+ "w8a8_fp8": ["compressed-tensors", "compressed_tensors"],
310
+ }
311
+ if self.quantization is not None:
312
+ self.quantization = self.quantization.lower()
313
+
314
+ # Parse quantization method from the HF model config, if available.
315
+ quant_cfg = self._parse_quant_hf_config()
316
+
317
+ if quant_cfg is not None:
318
+ quant_method = quant_cfg.get("quant_method", "").lower()
319
+
320
+ # Detect which checkpoint is it
321
+ for _, method in QUANTIZATION_METHODS.items():
322
+ quantization_override = method.override_quantization_method(
323
+ quant_cfg, self.quantization
324
+ )
325
+ if quantization_override:
326
+ quant_method = quantization_override
327
+ self.quantization = quantization_override
328
+ break
329
+
330
+ # Verify quantization configurations.
331
+ if self.quantization is None:
332
+ self.quantization = quant_method
333
+ elif self.quantization != quant_method:
334
+ if (
335
+ self.quantization not in compatible_quantization_methods
336
+ or quant_method
337
+ not in compatible_quantization_methods[self.quantization]
338
+ ):
339
+ raise ValueError(
340
+ "Quantization method specified in the model config "
341
+ f"({quant_method}) does not match the quantization "
342
+ f"method specified in the `quantization` argument "
343
+ f"({self.quantization})."
344
+ )
345
+
346
+ if self.quantization is not None:
347
+ if self.quantization not in supported_quantization:
348
+ raise ValueError(
349
+ f"Unknown quantization method: {self.quantization}. Must "
350
+ f"be one of {supported_quantization}."
351
+ )
352
+ if is_hip() and self.quantization not in rocm_supported_quantization:
353
+ raise ValueError(
354
+ f"{self.quantization} quantization is currently not "
355
+ f"supported in ROCm."
356
+ )
357
+ if self.quantization not in optimized_quantization_methods:
358
+ logger.warning(
359
+ "%s quantization is not fully "
360
+ "optimized yet. The speed can be slower than "
361
+ "non-quantized models.",
362
+ self.quantization,
363
+ )
364
+
365
+ def get_hf_eos_token_id(self) -> Optional[Set[int]]:
366
+ eos_ids = getattr(self.hf_config, "eos_token_id", None)
367
+ if eos_ids:
368
+ # it can be either int or list of int
369
+ eos_ids = {eos_ids} if isinstance(eos_ids, int) else set(eos_ids)
370
+ return eos_ids
371
+
372
+ def maybe_pull_model_tokenizer_from_remote(self) -> None:
373
+ """
374
+ Pull the model config files to a temporary
375
+ directory in case of remote.
376
+
377
+ Args:
378
+ model: The model name or path.
379
+
380
+ """
381
+ from sglang.srt.connector import create_remote_connector
382
+ from sglang.srt.utils import is_remote_url
383
+
384
+ if is_remote_url(self.model_path):
385
+ logger.info("Pulling model configs from remote...")
386
+ # BaseConnector implements __del__() to clean up the local dir.
387
+ # Since config files need to exist all the time, so we DO NOT use
388
+ # with statement to avoid closing the client.
389
+ client = create_remote_connector(self.model_path)
390
+ if is_remote_url(self.model_path):
391
+ client.pull_files(allow_pattern=["*config.json"])
392
+ self.model_weights = self.model_path
393
+ self.model_path = client.get_local_dir()
394
+
395
+
396
+ def get_hf_text_config(config: PretrainedConfig):
397
+ """Get the "sub" config relevant to llm for multi modal models.
398
+ No op for pure text models.
399
+ """
400
+ class_name = config.architectures[0]
401
+ if class_name.startswith("Llava") and class_name.endswith("ForCausalLM"):
402
+ # We support non-hf version of llava models, so we do not want to
403
+ # read the wrong values from the unused default text_config.
404
+ # NOTE(HandH1998): We set `torch_dtype` of config to `torch.float16` for the weights, as
405
+ # `torch.float16` is default used for image features in `python/sglang/srt/models/llava.py`.
406
+ setattr(config, "torch_dtype", torch.float16)
407
+ return config
408
+
409
+ if hasattr(config, "text_config"):
410
+ # The code operates under the assumption that text_config should have
411
+ # `num_attention_heads` (among others). Assert here to fail early
412
+ # if transformers config doesn't align with this assumption.
413
+ assert hasattr(config.text_config, "num_attention_heads")
414
+ return config.text_config
415
+ if hasattr(config, "language_config"):
416
+ return config.language_config
417
+ else:
418
+ return config
419
+
420
+
421
+ # adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/config.py
422
+ _STR_DTYPE_TO_TORCH_DTYPE = {
423
+ "half": torch.float16,
424
+ "float16": torch.float16,
425
+ "float": torch.float32,
426
+ "float32": torch.float32,
427
+ "bfloat16": torch.bfloat16,
428
+ }
429
+
430
+
431
+ # adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/config.py
432
+ def _get_and_verify_dtype(
433
+ config: PretrainedConfig,
434
+ dtype: Union[str, torch.dtype],
435
+ ) -> torch.dtype:
436
+ # NOTE: getattr(config, "torch_dtype", torch.float32) is not correct
437
+ # because config.torch_dtype can be None.
438
+ config_dtype = getattr(config, "torch_dtype", None)
439
+ if config_dtype is None:
440
+ config_dtype = torch.float32
441
+
442
+ if isinstance(dtype, str):
443
+ dtype = dtype.lower()
444
+ if dtype == "auto":
445
+ if config_dtype == torch.float32:
446
+ if config.model_type.startswith("gemma"):
447
+ if config.model_type == "gemma":
448
+ gemma_version = ""
449
+ else:
450
+ gemma_version = config.model_type[5]
451
+ logger.info(
452
+ f"For Gemma {gemma_version}, we downcast float32 to bfloat16 instead "
453
+ "of float16 by default. Please specify `dtype` if you "
454
+ "want to use float16."
455
+ )
456
+ torch_dtype = torch.bfloat16
457
+ else:
458
+ # Following the common practice, we use float16 for float32
459
+ # models.
460
+ torch_dtype = torch.float16
461
+ else:
462
+ torch_dtype = config_dtype
463
+ else:
464
+ if dtype not in _STR_DTYPE_TO_TORCH_DTYPE:
465
+ raise ValueError(f"Unknown dtype: {dtype}")
466
+ torch_dtype = _STR_DTYPE_TO_TORCH_DTYPE[dtype]
467
+ elif isinstance(dtype, torch.dtype):
468
+ torch_dtype = dtype
469
+ else:
470
+ raise ValueError(f"Unknown dtype: {dtype}")
471
+
472
+ # Verify the dtype.
473
+ if torch_dtype != config_dtype:
474
+ if torch_dtype == torch.float32:
475
+ # Upcasting to float32 is allowed.
476
+ logger.info("Upcasting %s to %s.", config_dtype, torch_dtype)
477
+ pass
478
+ elif config_dtype == torch.float32:
479
+ # Downcasting from float32 to float16 or bfloat16 is allowed.
480
+ logger.info("Downcasting %s to %s.", config_dtype, torch_dtype)
481
+ pass
482
+ else:
483
+ # Casting between float16 and bfloat16 is allowed with a warning.
484
+ logger.warning("Casting %s to %s.", config_dtype, torch_dtype)
485
+
486
+ return torch_dtype
487
+
488
+
489
+ def is_generation_model(model_architectures: List[str], is_embedding: bool = False):
490
+ # We have two ways to determine whether a model is a generative model.
491
+ # 1. Check the model architecture
492
+ # 2. check the `is_embedding` server args
493
+
494
+ if (
495
+ "LlamaEmbeddingModel" in model_architectures
496
+ or "MistralModel" in model_architectures
497
+ or "LlamaForSequenceClassification" in model_architectures
498
+ or "LlamaForSequenceClassificationWithNormal_Weights" in model_architectures
499
+ or "InternLM2ForRewardModel" in model_architectures
500
+ or "Qwen2ForRewardModel" in model_architectures
501
+ or "Qwen2ForSequenceClassification" in model_architectures
502
+ or "CLIPModel" in model_architectures
503
+ ):
504
+ return False
505
+ else:
506
+ return not is_embedding
507
+
508
+
509
+ multimodal_model_archs = [
510
+ "DeepseekVL2ForCausalLM",
511
+ "Gemma3ForConditionalGeneration",
512
+ "Grok1VForCausalLM",
513
+ "Grok1AForCausalLM",
514
+ "LlavaLlamaForCausalLM",
515
+ "Llama4ForConditionalGeneration",
516
+ "LlavaMistralForCausalLM",
517
+ "LlavaQwenForCausalLM",
518
+ "LlavaVidForCausalLM",
519
+ "MiniCPMO",
520
+ "MiniCPMV",
521
+ "MultiModalityCausalLM",
522
+ "MllamaForConditionalGeneration",
523
+ "Qwen2VLForConditionalGeneration",
524
+ "Qwen2_5_VLForConditionalGeneration",
525
+ "CLIPModel",
526
+ ]
527
+
528
+
529
+ def is_multimodal_model(model_architectures: List[str]):
530
+ if any(
531
+ multi_model_arch in model_architectures
532
+ for multi_model_arch in multimodal_model_archs
533
+ ):
534
+ return True
535
+ else:
536
+ return False
537
+
538
+
539
+ def is_multimodal_gen_model(model_architectures: List[str]):
540
+ return False
541
+
542
+
543
+ def is_image_gen_model(model_architectures: List[str]):
544
+ return False
545
+
546
+
547
+ def is_audio_model(model_architectures: List[str]):
548
+ return False
549
+
550
+
551
+ def is_encoder_decoder_model(model_architectures: List[str]):
552
+ return "MllamaForConditionalGeneration" in model_architectures
553
+
554
+
555
+ def yarn_get_mscale(scale: float = 1, mscale: float = 1) -> float:
556
+ if scale <= 1:
557
+ return 1.0
558
+ return 0.1 * mscale * math.log(scale) + 1.0
lib/python3.12/site-packages/sglang/srt/configs/utils.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Type
2
+
3
+ from transformers import (
4
+ AutoImageProcessor,
5
+ AutoProcessor,
6
+ BaseImageProcessor,
7
+ PretrainedConfig,
8
+ ProcessorMixin,
9
+ )
10
+
11
+
12
+ def register_image_processor(
13
+ config: Type[PretrainedConfig], image_processor: Type[BaseImageProcessor]
14
+ ):
15
+ """
16
+ register customized hf image processor while removing hf impl
17
+ """
18
+ AutoImageProcessor.register(config, None, image_processor, None, exist_ok=True)
19
+
20
+
21
+ def register_processor(config: Type[PretrainedConfig], processor: Type[ProcessorMixin]):
22
+ """
23
+ register customized hf processor while removing hf impl
24
+ """
25
+ AutoProcessor.register(config, processor, exist_ok=True)
lib/python3.12/site-packages/sglang/srt/connector/__init__.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ import enum
4
+ import logging
5
+
6
+ from sglang.srt.connector.base_connector import (
7
+ BaseConnector,
8
+ BaseFileConnector,
9
+ BaseKVConnector,
10
+ )
11
+ from sglang.srt.connector.redis import RedisConnector
12
+ from sglang.srt.connector.s3 import S3Connector
13
+ from sglang.srt.utils import parse_connector_type
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class ConnectorType(str, enum.Enum):
19
+ FS = "filesystem"
20
+ KV = "KV"
21
+
22
+
23
+ def create_remote_connector(url, device="cpu") -> BaseConnector:
24
+ connector_type = parse_connector_type(url)
25
+ if connector_type == "redis":
26
+ return RedisConnector(url)
27
+ elif connector_type == "s3":
28
+ return S3Connector(url)
29
+ else:
30
+ raise ValueError(f"Invalid connector type: {url}")
31
+
32
+
33
+ def get_connector_type(client: BaseConnector) -> ConnectorType:
34
+ if isinstance(client, BaseKVConnector):
35
+ return ConnectorType.KV
36
+ if isinstance(client, BaseFileConnector):
37
+ return ConnectorType.FS
38
+
39
+ raise ValueError(f"Invalid connector type: {client}")
40
+
41
+
42
+ __all__ = [
43
+ "BaseConnector",
44
+ "BaseFileConnector",
45
+ "BaseKVConnector",
46
+ "RedisConnector",
47
+ "S3Connector",
48
+ "ConnectorType",
49
+ "create_remote_connector",
50
+ "get_connector_type",
51
+ ]
lib/python3.12/site-packages/sglang/srt/connector/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (1.79 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/__pycache__/base_connector.cpython-312.pyc ADDED
Binary file (5.7 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/__pycache__/redis.cpython-312.pyc ADDED
Binary file (4.92 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/__pycache__/s3.cpython-312.pyc ADDED
Binary file (6.16 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/__pycache__/utils.cpython-312.pyc ADDED
Binary file (1.9 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/base_connector.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ import os
4
+ import shutil
5
+ import signal
6
+ import tempfile
7
+ from abc import ABC, abstractmethod
8
+ from typing import Generator, List, Optional, Tuple
9
+
10
+ import torch
11
+
12
+
13
+ class BaseConnector(ABC):
14
+ """
15
+ For fs connector such as s3:
16
+ <connector_type>://<path>/<filename>
17
+
18
+ For kv connector such as redis:
19
+ <connector_type>://<host>:<port>/<model_name>/keys/<key>
20
+ <connector_type://<host>:<port>/<model_name>/files/<filename>
21
+ """
22
+
23
+ def __init__(self, url: str, device: torch.device = "cpu"):
24
+ self.url = url
25
+ self.device = device
26
+ self.closed = False
27
+ self.local_dir = tempfile.mkdtemp()
28
+ for sig in (signal.SIGINT, signal.SIGTERM):
29
+ existing_handler = signal.getsignal(sig)
30
+ signal.signal(sig, self._close_by_signal(existing_handler))
31
+
32
+ def get_local_dir(self):
33
+ return self.local_dir
34
+
35
+ @abstractmethod
36
+ def weight_iterator(
37
+ self, rank: int = 0
38
+ ) -> Generator[Tuple[str, torch.Tensor], None, None]:
39
+ raise NotImplementedError()
40
+
41
+ @abstractmethod
42
+ def pull_files(
43
+ self,
44
+ allow_pattern: Optional[List[str]] = None,
45
+ ignore_pattern: Optional[List[str]] = None,
46
+ ) -> None:
47
+ raise NotImplementedError()
48
+
49
+ def close(self):
50
+ if self.closed:
51
+ return
52
+
53
+ self.closed = True
54
+ if os.path.exists(self.local_dir):
55
+ shutil.rmtree(self.local_dir)
56
+
57
+ def __enter__(self):
58
+ return self
59
+
60
+ def __exit__(self, exc_type, exc_value, traceback):
61
+ self.close()
62
+
63
+ def __del__(self):
64
+ self.close()
65
+
66
+ def _close_by_signal(self, existing_handler=None):
67
+
68
+ def new_handler(signum, frame):
69
+ self.close()
70
+ if existing_handler:
71
+ existing_handler(signum, frame)
72
+
73
+ return new_handler
74
+
75
+
76
+ class BaseKVConnector(BaseConnector):
77
+
78
+ @abstractmethod
79
+ def get(self, key: str) -> Optional[torch.Tensor]:
80
+ raise NotImplementedError()
81
+
82
+ @abstractmethod
83
+ def getstr(self, key: str) -> Optional[str]:
84
+ raise NotImplementedError()
85
+
86
+ @abstractmethod
87
+ def set(self, key: str, obj: torch.Tensor) -> None:
88
+ raise NotImplementedError()
89
+
90
+ @abstractmethod
91
+ def setstr(self, key: str, obj: str) -> None:
92
+ raise NotImplementedError()
93
+
94
+ @abstractmethod
95
+ def list(self, prefix: str) -> List[str]:
96
+ raise NotImplementedError()
97
+
98
+
99
+ class BaseFileConnector(BaseConnector):
100
+ """
101
+ List full file names from remote fs path and filter by allow pattern.
102
+
103
+ Args:
104
+ allow_pattern: A list of patterns of which files to pull.
105
+
106
+ Returns:
107
+ list[str]: List of full paths allowed by the pattern
108
+ """
109
+
110
+ @abstractmethod
111
+ def glob(self, allow_pattern: str) -> List[str]:
112
+ raise NotImplementedError()
lib/python3.12/site-packages/sglang/srt/connector/redis.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ import logging
4
+ from typing import Generator, List, Optional, Tuple
5
+ from urllib.parse import urlparse
6
+
7
+ import torch
8
+
9
+ from sglang.srt.connector import BaseKVConnector
10
+ from sglang.srt.connector.serde import create_serde
11
+ from sglang.srt.connector.utils import pull_files_from_db
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class RedisConnector(BaseKVConnector):
17
+
18
+ def __init__(self, url: str, device: torch.device = "cpu"):
19
+ import redis
20
+
21
+ super().__init__(url, device)
22
+ parsed_url = urlparse(url)
23
+ self.connection = redis.Redis(host=parsed_url.hostname, port=parsed_url.port)
24
+ self.model_name = parsed_url.path.lstrip("/")
25
+ # TODO: more serde options
26
+ self.s, self.d = create_serde("safe")
27
+
28
+ def get(self, key: str) -> Optional[torch.Tensor]:
29
+ val = self.connection.get(key)
30
+
31
+ if val is None:
32
+ logger.error("Key %s not found", key)
33
+ return None
34
+
35
+ return self.d.from_bytes(val)
36
+
37
+ def getstr(self, key: str) -> Optional[str]:
38
+ val = self.connection.get(key)
39
+ if val is None:
40
+ logger.error("Key %s not found", key)
41
+ return None
42
+
43
+ return val.decode("utf-8")
44
+
45
+ def set(self, key: str, tensor: torch.Tensor) -> None:
46
+ assert tensor is not None
47
+ self.connection.set(key, self.s.to_bytes(tensor))
48
+
49
+ def setstr(self, key: str, obj: str) -> None:
50
+ self.connection.set(key, obj)
51
+
52
+ def list(self, prefix: str) -> List[str]:
53
+ cursor = 0
54
+ all_keys: List[bytes] = []
55
+
56
+ while True:
57
+ ret: Tuple[int, List[bytes]] = self.connection.scan(
58
+ cursor=cursor, match=f"{prefix}*"
59
+ ) # type: ignore
60
+ cursor, keys = ret
61
+ all_keys.extend(keys)
62
+ if cursor == 0:
63
+ break
64
+
65
+ return [key.decode("utf-8") for key in all_keys]
66
+
67
+ def weight_iterator(
68
+ self, rank: int = 0
69
+ ) -> Generator[Tuple[str, bytes], None, None]:
70
+ keys = self.list(f"{self.model_name}/keys/rank_{rank}/")
71
+ for key in keys:
72
+ val = self.get(key)
73
+ key = key.removeprefix(f"{self.model_name}/keys/rank_{rank}/")
74
+ yield key, val
75
+
76
+ def pull_files(
77
+ self,
78
+ allow_pattern: Optional[List[str]] = None,
79
+ ignore_pattern: Optional[List[str]] = None,
80
+ ) -> None:
81
+ pull_files_from_db(self, self.model_name, allow_pattern, ignore_pattern)
82
+
83
+ def close(self):
84
+ self.connection.close()
85
+ super().close()
lib/python3.12/site-packages/sglang/srt/connector/s3.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ import fnmatch
4
+ import os
5
+ from pathlib import Path
6
+ from typing import Generator, Optional, Tuple
7
+
8
+ import torch
9
+
10
+ from sglang.srt.connector import BaseFileConnector
11
+
12
+
13
+ def _filter_allow(paths: list[str], patterns: list[str]) -> list[str]:
14
+ return [
15
+ path
16
+ for path in paths
17
+ if any(fnmatch.fnmatch(path, pattern) for pattern in patterns)
18
+ ]
19
+
20
+
21
+ def _filter_ignore(paths: list[str], patterns: list[str]) -> list[str]:
22
+ return [
23
+ path
24
+ for path in paths
25
+ if not any(fnmatch.fnmatch(path, pattern) for pattern in patterns)
26
+ ]
27
+
28
+
29
+ def list_files(
30
+ s3,
31
+ path: str,
32
+ allow_pattern: Optional[list[str]] = None,
33
+ ignore_pattern: Optional[list[str]] = None,
34
+ ) -> tuple[str, str, list[str]]:
35
+ """
36
+ List files from S3 path and filter by pattern.
37
+
38
+ Args:
39
+ s3: S3 client to use.
40
+ path: The S3 path to list from.
41
+ allow_pattern: A list of patterns of which files to pull.
42
+ ignore_pattern: A list of patterns of which files not to pull.
43
+
44
+ Returns:
45
+ tuple[str, str, list[str]]: A tuple where:
46
+ - The first element is the bucket name
47
+ - The second element is string represent the bucket
48
+ and the prefix as a dir like string
49
+ - The third element is a list of files allowed or
50
+ disallowed by pattern
51
+ """
52
+ parts = path.removeprefix("s3://").split("/")
53
+ prefix = "/".join(parts[1:])
54
+ bucket_name = parts[0]
55
+
56
+ objects = s3.list_objects_v2(Bucket=bucket_name, Prefix=prefix)
57
+ paths = [obj["Key"] for obj in objects.get("Contents", [])]
58
+
59
+ paths = _filter_ignore(paths, ["*/"])
60
+ if allow_pattern is not None:
61
+ paths = _filter_allow(paths, allow_pattern)
62
+
63
+ if ignore_pattern is not None:
64
+ paths = _filter_ignore(paths, ignore_pattern)
65
+
66
+ return bucket_name, prefix, paths
67
+
68
+
69
+ class S3Connector(BaseFileConnector):
70
+
71
+ def __init__(self, url: str) -> None:
72
+ import boto3
73
+
74
+ super().__init__(url)
75
+ self.client = boto3.client("s3")
76
+
77
+ def glob(self, allow_pattern: Optional[list[str]] = None) -> list[str]:
78
+ bucket_name, _, paths = list_files(
79
+ self.client, path=self.url, allow_pattern=allow_pattern
80
+ )
81
+ return [f"s3://{bucket_name}/{path}" for path in paths]
82
+
83
+ def pull_files(
84
+ self,
85
+ allow_pattern: Optional[list[str]] = None,
86
+ ignore_pattern: Optional[list[str]] = None,
87
+ ) -> None:
88
+ """
89
+ Pull files from S3 storage into the temporary directory.
90
+
91
+ Args:
92
+ s3_model_path: The S3 path of the model.
93
+ allow_pattern: A list of patterns of which files to pull.
94
+ ignore_pattern: A list of patterns of which files not to pull.
95
+
96
+ """
97
+ bucket_name, base_dir, files = list_files(
98
+ self.client, self.url, allow_pattern, ignore_pattern
99
+ )
100
+ if len(files) == 0:
101
+ return
102
+
103
+ for file in files:
104
+ destination_file = os.path.join(self.local_dir, file.removeprefix(base_dir))
105
+ local_dir = Path(destination_file).parent
106
+ os.makedirs(local_dir, exist_ok=True)
107
+ self.client.download_file(bucket_name, file, destination_file)
108
+
109
+ def weight_iterator(
110
+ self, rank: int = 0
111
+ ) -> Generator[Tuple[str, torch.Tensor], None, None]:
112
+ from sglang.srt.model_loader.weight_utils import (
113
+ runai_safetensors_weights_iterator,
114
+ )
115
+
116
+ # only support safetensor files now
117
+ hf_weights_files = self.glob(allow_pattern=["*.safetensors"])
118
+ return runai_safetensors_weights_iterator(hf_weights_files)
119
+
120
+ def close(self):
121
+ self.client.close()
122
+ super().close()
lib/python3.12/site-packages/sglang/srt/connector/serde/__init__.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ # inspired by LMCache
4
+ from typing import Optional, Tuple
5
+
6
+ import torch
7
+
8
+ from sglang.srt.connector.serde.safe_serde import SafeDeserializer, SafeSerializer
9
+ from sglang.srt.connector.serde.serde import Deserializer, Serializer
10
+
11
+
12
+ def create_serde(serde_type: str) -> Tuple[Serializer, Deserializer]:
13
+ s: Optional[Serializer] = None
14
+ d: Optional[Deserializer] = None
15
+
16
+ if serde_type == "safe":
17
+ s = SafeSerializer()
18
+ d = SafeDeserializer(torch.uint8)
19
+ else:
20
+ raise ValueError(f"Unknown serde type: {serde_type}")
21
+
22
+ return s, d
23
+
24
+
25
+ __all__ = [
26
+ "Serializer",
27
+ "Deserializer",
28
+ "SafeSerializer",
29
+ "SafeDeserializer",
30
+ "create_serde",
31
+ ]
lib/python3.12/site-packages/sglang/srt/connector/serde/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (966 Bytes). View file
 
lib/python3.12/site-packages/sglang/srt/connector/serde/__pycache__/safe_serde.cpython-312.pyc ADDED
Binary file (2.2 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/serde/__pycache__/serde.cpython-312.pyc ADDED
Binary file (1.88 kB). View file
 
lib/python3.12/site-packages/sglang/srt/connector/serde/safe_serde.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ from typing import Union
4
+
5
+ import torch
6
+ from safetensors.torch import load, save
7
+
8
+ from sglang.srt.connector.serde.serde import Deserializer, Serializer
9
+
10
+
11
+ class SafeSerializer(Serializer):
12
+
13
+ def __init__(self):
14
+ super().__init__()
15
+
16
+ def to_bytes(self, t: torch.Tensor) -> bytes:
17
+ return save({"tensor_bytes": t.cpu().contiguous()})
18
+
19
+
20
+ class SafeDeserializer(Deserializer):
21
+
22
+ def __init__(self, dtype):
23
+ super().__init__(dtype)
24
+
25
+ def from_bytes_normal(self, b: Union[bytearray, bytes]) -> torch.Tensor:
26
+ return load(bytes(b))["tensor_bytes"].to(dtype=self.dtype)
27
+
28
+ def from_bytes(self, b: Union[bytearray, bytes]) -> torch.Tensor:
29
+ return self.from_bytes_normal(b)
lib/python3.12/site-packages/sglang/srt/connector/serde/serde.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ import abc
4
+ from abc import ABC, abstractmethod
5
+
6
+ import torch
7
+
8
+
9
+ class Serializer(ABC):
10
+
11
+ @abstractmethod
12
+ def to_bytes(self, t: torch.Tensor) -> bytes:
13
+ """
14
+ Serialize a pytorch tensor to bytes. The serialized bytes should contain
15
+ both the data and the metadata (shape, dtype, etc.) of the tensor.
16
+
17
+ Input:
18
+ t: the input pytorch tensor, can be on any device, in any shape,
19
+ with any dtype
20
+
21
+ Returns:
22
+ bytes: the serialized bytes
23
+ """
24
+ raise NotImplementedError
25
+
26
+
27
+ class Deserializer(metaclass=abc.ABCMeta):
28
+
29
+ def __init__(self, dtype):
30
+ self.dtype = dtype
31
+
32
+ @abstractmethod
33
+ def from_bytes(self, bs: bytes) -> torch.Tensor:
34
+ """
35
+ Deserialize a pytorch tensor from bytes.
36
+
37
+ Input:
38
+ bytes: a stream of bytes
39
+
40
+ Output:
41
+ torch.Tensor: the deserialized pytorch tensor
42
+ """
43
+ raise NotImplementedError
lib/python3.12/site-packages/sglang/srt/connector/utils.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Optional
6
+ from urllib.parse import urlparse
7
+
8
+ from sglang.srt.connector import BaseConnector
9
+
10
+
11
+ def parse_model_name(url: str) -> str:
12
+ """
13
+ Parse the model name from the url.
14
+ Only used for db connector
15
+ """
16
+ parsed_url = urlparse(url)
17
+ return parsed_url.path.lstrip("/")
18
+
19
+
20
+ def pull_files_from_db(
21
+ connector: BaseConnector,
22
+ model_name: str,
23
+ allow_pattern: Optional[list[str]] = None,
24
+ ignore_pattern: Optional[list[str]] = None,
25
+ ) -> None:
26
+ prefix = f"{model_name}/files/"
27
+ local_dir = connector.get_local_dir()
28
+ files = connector.list(prefix)
29
+
30
+ for file in files:
31
+ destination_file = os.path.join(local_dir, file.removeprefix(prefix))
32
+ local_dir = Path(destination_file).parent
33
+ os.makedirs(local_dir, exist_ok=True)
34
+ with open(destination_file, "wb") as f:
35
+ f.write(connector.getstr(file).encode("utf-8"))
lib/python3.12/site-packages/sglang/srt/layers/activation.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ==============================================================================
14
+ """Fused operators for activation layers."""
15
+
16
+ import logging
17
+ import math
18
+ from typing import Optional
19
+
20
+ import torch
21
+ import torch.nn as nn
22
+ import torch.nn.functional as F
23
+
24
+ from sglang.srt.custom_op import CustomOp
25
+ from sglang.srt.distributed import (
26
+ divide,
27
+ get_tensor_model_parallel_rank,
28
+ get_tensor_model_parallel_world_size,
29
+ )
30
+ from sglang.srt.layers.quantization.base_config import QuantizationConfig
31
+ from sglang.srt.utils import is_cuda, set_weight_attrs
32
+
33
+ _is_cuda = is_cuda()
34
+
35
+ if _is_cuda:
36
+ from sgl_kernel import gelu_and_mul, gelu_tanh_and_mul, silu_and_mul
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ class SiluAndMul(CustomOp):
42
+ def forward_native(self, x: torch.Tensor) -> torch.Tensor:
43
+ d = x.shape[-1] // 2
44
+ return F.silu(x[..., :d]) * x[..., d:]
45
+
46
+ def forward_cuda(self, x: torch.Tensor) -> torch.Tensor:
47
+ d = x.shape[-1] // 2
48
+ output_shape = x.shape[:-1] + (d,)
49
+ out = torch.empty(output_shape, dtype=x.dtype, device=x.device)
50
+ silu_and_mul(x, out)
51
+ return out
52
+
53
+
54
+ class GeluAndMul(CustomOp):
55
+ def __init__(self, approximate="tanh"):
56
+ super().__init__()
57
+ self.approximate = approximate
58
+
59
+ def forward_native(self, x: torch.Tensor) -> torch.Tensor:
60
+ d = x.shape[-1] // 2
61
+ return F.gelu(x[..., :d], approximate=self.approximate) * x[..., d:]
62
+
63
+ def forward_cuda(self, x: torch.Tensor) -> torch.Tensor:
64
+ d = x.shape[-1] // 2
65
+ output_shape = x.shape[:-1] + (d,)
66
+ out = torch.empty(output_shape, dtype=x.dtype, device=x.device)
67
+ if self.approximate == "tanh":
68
+ gelu_tanh_and_mul(x, out)
69
+ elif self.approximate == "none":
70
+ gelu_and_mul(x, out)
71
+ else:
72
+ raise RuntimeError("GeluAndMul only support tanh or none")
73
+ return out
74
+
75
+
76
+ class NewGELU(CustomOp):
77
+ def forward_native(self, x: torch.Tensor) -> torch.Tensor:
78
+ c = math.sqrt(2.0 / math.pi)
79
+ return 0.5 * x * (1.0 + torch.tanh(c * (x + 0.044715 * torch.pow(x, 3.0))))
80
+
81
+ def forward_cuda(self, x: torch.Tensor) -> torch.Tensor:
82
+ # TODO: Implement the CUDA kernel for NewGELU in sgl-kernel
83
+ return self.forward_native(x)
84
+
85
+
86
+ class QuickGELU(CustomOp):
87
+ def forward_native(self, x: torch.Tensor) -> torch.Tensor:
88
+ return x * torch.sigmoid(1.702 * x)
89
+
90
+ def forward_cuda(self, x: torch.Tensor) -> torch.Tensor:
91
+ # TODO(zhyncs): Implement the CUDA kernel for QuickGELU in sgl-kernel
92
+ return self.forward_native(x)
93
+
94
+
95
+ class ScaledActivation(nn.Module):
96
+ """An activation function with post-scale parameters.
97
+
98
+ This is used for some quantization methods like AWQ.
99
+ """
100
+
101
+ def __init__(
102
+ self,
103
+ act_module: nn.Module,
104
+ intermediate_size: int,
105
+ input_is_parallel: bool = True,
106
+ params_dtype: Optional[torch.dtype] = None,
107
+ ):
108
+ super().__init__()
109
+ self.act = act_module
110
+ self.input_is_parallel = input_is_parallel
111
+ if input_is_parallel:
112
+ tp_size = get_tensor_model_parallel_world_size()
113
+ intermediate_size_per_partition = divide(intermediate_size, tp_size)
114
+ else:
115
+ intermediate_size_per_partition = intermediate_size
116
+ if params_dtype is None:
117
+ params_dtype = torch.get_default_dtype()
118
+ self.scales = nn.Parameter(
119
+ torch.empty(intermediate_size_per_partition, dtype=params_dtype)
120
+ )
121
+ set_weight_attrs(self.scales, {"weight_loader": self.weight_loader})
122
+
123
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
124
+ return self.act(x) / self.scales
125
+
126
+ def weight_loader(self, param: nn.Parameter, loaded_weight: torch.Tensor):
127
+ param_data = param.data
128
+ if self.input_is_parallel:
129
+ tp_rank = get_tensor_model_parallel_rank()
130
+ shard_size = param_data.shape[0]
131
+ start_idx = tp_rank * shard_size
132
+ loaded_weight = loaded_weight.narrow(0, start_idx, shard_size)
133
+ assert param_data.shape == loaded_weight.shape
134
+ param_data.copy_(loaded_weight)
135
+
136
+
137
+ _ACTIVATION_REGISTRY = {
138
+ "gelu": nn.GELU(),
139
+ "gelu_pytorch_tanh": nn.GELU(approximate="tanh"),
140
+ }
141
+
142
+
143
+ def get_act_fn(
144
+ act_fn_name: str,
145
+ quant_config: Optional[QuantizationConfig] = None,
146
+ intermediate_size: Optional[int] = None,
147
+ input_is_parallel: bool = True,
148
+ params_dtype: Optional[torch.dtype] = None,
149
+ ) -> nn.Module:
150
+ """Get an activation function by name."""
151
+ act_fn_name = act_fn_name.lower()
152
+ if act_fn_name not in _ACTIVATION_REGISTRY:
153
+ raise ValueError(f"Activation function {act_fn_name!r} is not supported.")
154
+
155
+ act_fn = _ACTIVATION_REGISTRY[act_fn_name]
156
+ if quant_config is not None and act_fn_name in quant_config.get_scaled_act_names():
157
+ if intermediate_size is None:
158
+ raise ValueError(
159
+ "intermediate_size must be specified for scaled "
160
+ "activation functions."
161
+ )
162
+ return ScaledActivation(
163
+ act_fn, intermediate_size, input_is_parallel, params_dtype
164
+ )
165
+ return act_fn
166
+
167
+
168
+ if not _is_cuda:
169
+ logger.info(
170
+ "sgl-kernel is not available on Non-NV platforms. Fallback to other kernel libraries."
171
+ )
172
+ from vllm.model_executor.layers.activation import GeluAndMul, SiluAndMul
lib/python3.12/site-packages/sglang/srt/layers/dp_attention.py ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import functools
4
+ import logging
5
+ from contextlib import contextmanager
6
+ from typing import TYPE_CHECKING, List
7
+
8
+ import torch
9
+ import triton
10
+ import triton.language as tl
11
+
12
+ from sglang.srt.distributed import (
13
+ GroupCoordinator,
14
+ get_tensor_model_parallel_world_size,
15
+ get_tp_group,
16
+ tensor_model_parallel_all_reduce,
17
+ )
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ if TYPE_CHECKING:
22
+ from sglang.srt.model_executor.forward_batch_info import ForwardBatch
23
+
24
+ _ATTN_TP_GROUP = None
25
+ _ATTN_TP_RANK = None
26
+ _ATTN_TP_SIZE = None
27
+ _DP_RANK = None
28
+ _DP_SIZE = None
29
+
30
+
31
+ def compute_dp_attention_world_info(enable_dp_attention, tp_rank, tp_size, dp_size):
32
+ if not enable_dp_attention:
33
+ return tp_rank, tp_size, 0
34
+
35
+ attn_tp_size = tp_size // dp_size
36
+ dp_rank = tp_rank // attn_tp_size
37
+ attn_tp_rank = tp_rank % attn_tp_size
38
+ return attn_tp_rank, attn_tp_size, dp_rank
39
+
40
+
41
+ def initialize_dp_attention(
42
+ enable_dp_attention: bool,
43
+ tp_rank: int,
44
+ tp_size: int,
45
+ dp_size: int,
46
+ ):
47
+ global _ATTN_TP_GROUP, _ATTN_TP_RANK, _ATTN_TP_SIZE, _DP_RANK, _DP_SIZE
48
+
49
+ from sglang.srt.layers.sampler import SYNC_TOKEN_IDS_ACROSS_TP
50
+
51
+ _ATTN_TP_RANK, _ATTN_TP_SIZE, _DP_RANK = compute_dp_attention_world_info(
52
+ enable_dp_attention, tp_rank, tp_size, dp_size
53
+ )
54
+
55
+ if enable_dp_attention:
56
+ _DP_SIZE = dp_size
57
+ else:
58
+ _DP_SIZE = 1
59
+
60
+ tp_group = get_tp_group()
61
+ _ATTN_TP_GROUP = GroupCoordinator(
62
+ [
63
+ list(range(head, head + _ATTN_TP_SIZE))
64
+ for head in range(0, tp_size, _ATTN_TP_SIZE)
65
+ ],
66
+ tp_group.local_rank,
67
+ torch.distributed.get_backend(tp_group.device_group),
68
+ SYNC_TOKEN_IDS_ACROSS_TP,
69
+ False,
70
+ False,
71
+ False,
72
+ False,
73
+ group_name="attention_tp",
74
+ )
75
+
76
+
77
+ def get_attention_tp_group():
78
+ assert _ATTN_TP_GROUP is not None, "dp attention not initialized!"
79
+ return _ATTN_TP_GROUP
80
+
81
+
82
+ def get_attention_tp_rank():
83
+ assert _ATTN_TP_RANK is not None, "dp attention not initialized!"
84
+ return _ATTN_TP_RANK
85
+
86
+
87
+ def get_attention_tp_size():
88
+ assert _ATTN_TP_SIZE is not None, "dp attention not initialized!"
89
+ return _ATTN_TP_SIZE
90
+
91
+
92
+ def get_attention_dp_rank():
93
+ assert _DP_RANK is not None, "dp attention not initialized!"
94
+ return _DP_RANK
95
+
96
+
97
+ def get_attention_dp_size():
98
+ assert _DP_SIZE is not None, "dp attention not initialized!"
99
+ return _DP_SIZE
100
+
101
+
102
+ @contextmanager
103
+ def disable_dp_size():
104
+ """Patch the tp group temporarily until this function ends.
105
+
106
+ This method is for draft workers of speculative decoding to run draft model
107
+ with different tp degree from that of target model workers.
108
+
109
+ Args:
110
+ tp_group (GroupCoordinator): the tp group coordinator
111
+ """
112
+ global _DP_SIZE
113
+ assert _DP_SIZE is not None, "dp attention not initialized!"
114
+
115
+ old_dp_size = _DP_SIZE
116
+ _DP_SIZE = 1
117
+ try:
118
+ yield
119
+ finally:
120
+ _DP_SIZE = old_dp_size
121
+
122
+
123
+ def get_dp_local_info(forward_batch: ForwardBatch):
124
+ dp_rank = get_attention_dp_rank()
125
+
126
+ if forward_batch.dp_local_start_pos is None:
127
+ cumtokens = torch.cumsum(forward_batch.global_num_tokens_gpu, dim=0)
128
+ if dp_rank == 0:
129
+ local_start_pos = torch.zeros_like(cumtokens[0])
130
+ else:
131
+ local_start_pos = cumtokens[dp_rank - 1]
132
+ local_num_tokens = forward_batch.global_num_tokens_gpu[dp_rank]
133
+
134
+ forward_batch.dp_local_start_pos = local_start_pos
135
+ forward_batch.dp_local_num_tokens = local_num_tokens
136
+
137
+ return forward_batch.dp_local_start_pos, forward_batch.dp_local_num_tokens
138
+
139
+
140
+ @triton.jit
141
+ def memcpy_triton_kernel(
142
+ dst_ptr,
143
+ src_ptr,
144
+ offset_ptr,
145
+ sz_ptr,
146
+ offset_src: tl.constexpr,
147
+ chunk_size, # multiplied for offset and sz
148
+ BLOCK_SIZE: tl.constexpr,
149
+ ):
150
+ pid = tl.program_id(axis=0).to(tl.int64)
151
+ offset = tl.load(offset_ptr).to(tl.int64) * chunk_size
152
+ sz = tl.load(sz_ptr).to(tl.int64) * chunk_size
153
+
154
+ start_index = pid * BLOCK_SIZE
155
+ offs = tl.arange(0, BLOCK_SIZE)
156
+ mask = start_index + offs < sz
157
+
158
+ if offset_src:
159
+ data = tl.load(src_ptr + offset + start_index + offs, mask=mask)
160
+ tl.store(dst_ptr + start_index + offs, data, mask=mask)
161
+ else:
162
+ data = tl.load(src_ptr + start_index + offs, mask=mask)
163
+ tl.store(dst_ptr + offset + start_index + offs, data, mask=mask)
164
+
165
+
166
+ def prod(x):
167
+ return functools.reduce(lambda a, b: a * b, x, 1)
168
+
169
+
170
+ def memcpy_triton(dst, src, dim, offset, sz, offset_src):
171
+ max_size = min(src.numel(), dst.numel())
172
+ assert dim == 0, "dim != 0 unsupported"
173
+ assert src.shape[1:] == dst.shape[1:], "src and dst must have same shape"
174
+ chunk_size = prod(src.shape[1:])
175
+ BLOCK_SIZE = 8192
176
+ grid = (triton.cdiv(max_size, BLOCK_SIZE),)
177
+
178
+ memcpy_triton_kernel[grid](dst, src, offset, sz, offset_src, chunk_size, BLOCK_SIZE)
179
+
180
+
181
+ def _dp_gather(
182
+ global_tokens: torch.Tensor,
183
+ local_tokens: torch.Tensor,
184
+ forward_batch: ForwardBatch,
185
+ is_partial: bool,
186
+ ):
187
+ local_start_pos, local_num_tokens = get_dp_local_info(forward_batch)
188
+
189
+ global_tokens.fill_(0)
190
+ assert local_tokens.is_contiguous()
191
+ assert global_tokens.is_contiguous()
192
+
193
+ if local_tokens.shape[0] > 0 and (is_partial or get_attention_tp_rank() == 0):
194
+ assert (
195
+ local_tokens.untyped_storage() is not global_tokens.untyped_storage()
196
+ ), "aliasing between global_tokens and local_tokens not allowed"
197
+ memcpy_triton(
198
+ global_tokens, local_tokens, 0, local_start_pos, local_num_tokens, False
199
+ )
200
+
201
+ # Input IDs are in int 32. We should use inplace_all_reduce for local case becaues of custom all reduce.
202
+ NUM_GPUS_PER_NODE = 8
203
+ if (
204
+ not local_tokens.dtype.is_floating_point
205
+ and get_tensor_model_parallel_world_size() <= NUM_GPUS_PER_NODE
206
+ ):
207
+ torch.ops.sglang.inplace_all_reduce(
208
+ global_tokens, group_name=get_tp_group().unique_name
209
+ )
210
+
211
+ else:
212
+ global_tokens[:] = tensor_model_parallel_all_reduce(global_tokens)
213
+
214
+
215
+ def dp_gather_partial(
216
+ global_tokens: torch.Tensor,
217
+ local_tokens: torch.Tensor,
218
+ forward_batch: ForwardBatch,
219
+ ):
220
+ _dp_gather(global_tokens, local_tokens, forward_batch, is_partial=True)
221
+
222
+
223
+ def dp_gather_replicate(
224
+ global_tokens: torch.Tensor,
225
+ local_tokens: torch.Tensor,
226
+ forward_batch: ForwardBatch,
227
+ ):
228
+ _dp_gather(global_tokens, local_tokens, forward_batch, is_partial=False)
229
+
230
+
231
+ def dp_scatter(
232
+ local_tokens: torch.Tensor, # output
233
+ global_tokens: torch.Tensor, # input
234
+ forward_batch: ForwardBatch,
235
+ ):
236
+ # local_num_tokens is not necessarily the same as local_tokens.shape[0],
237
+ # since local_tokens may be padded for cuda graph
238
+ local_start_pos, local_num_tokens = get_dp_local_info(forward_batch)
239
+
240
+ local_tokens.fill_(0)
241
+ assert local_tokens.is_contiguous()
242
+ assert global_tokens.is_contiguous()
243
+ if local_tokens.shape[0] > 0:
244
+ assert (
245
+ local_tokens.untyped_storage() is not global_tokens.untyped_storage()
246
+ ), "aliasing between local_tokens and global_tokens not allowed"
247
+ memcpy_triton(
248
+ local_tokens, global_tokens, 0, local_start_pos, local_num_tokens, True
249
+ )
250
+
251
+
252
+ def tp_reduce_scatter(
253
+ output: torch.Tensor,
254
+ input_list: List[torch.Tensor],
255
+ ):
256
+ return get_attention_tp_group().reduce_scatter(output, input_list)
257
+
258
+
259
+ def tp_all_gather(output_list: List[torch.Tensor], input_: torch.Tensor):
260
+ return get_attention_tp_group().all_gather(input_, tensor_list=output_list)
lib/python3.12/site-packages/sglang/srt/layers/elementwise.py ADDED
@@ -0,0 +1,424 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Tuple
2
+
3
+ import torch
4
+ import triton
5
+ import triton.language as tl
6
+
7
+ from sglang.srt.utils import is_hip
8
+
9
+ _is_hip = is_hip()
10
+
11
+ fused_softcap_autotune = triton.autotune(
12
+ configs=[
13
+ triton.Config(kwargs={"BLOCK_SIZE": 128}, num_warps=4),
14
+ triton.Config(kwargs={"BLOCK_SIZE": 128}, num_warps=8),
15
+ triton.Config(kwargs={"BLOCK_SIZE": 128}, num_warps=16),
16
+ triton.Config(kwargs={"BLOCK_SIZE": 256}, num_warps=4),
17
+ triton.Config(kwargs={"BLOCK_SIZE": 256}, num_warps=8),
18
+ triton.Config(kwargs={"BLOCK_SIZE": 512}, num_warps=4),
19
+ triton.Config(kwargs={"BLOCK_SIZE": 512}, num_warps=8),
20
+ triton.Config(kwargs={"BLOCK_SIZE": 512}, num_warps=16),
21
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=4),
22
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=8),
23
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=16),
24
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=32),
25
+ triton.Config(kwargs={"BLOCK_SIZE": 2048}, num_warps=32),
26
+ triton.Config(kwargs={"BLOCK_SIZE": 4096}, num_warps=32),
27
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=32),
28
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=32),
29
+ triton.Config(kwargs={"BLOCK_SIZE": 32768}, num_warps=32),
30
+ ],
31
+ key=["n_ele"],
32
+ )
33
+
34
+
35
+ @triton.jit
36
+ def fused_softcap_kernel(
37
+ output_ptr,
38
+ input_ptr,
39
+ n_ele,
40
+ softcap_const: tl.constexpr,
41
+ BLOCK_SIZE: tl.constexpr,
42
+ ):
43
+ pid = tl.program_id(axis=0)
44
+ block_start = pid * BLOCK_SIZE
45
+ offsets = block_start + tl.arange(0, BLOCK_SIZE)
46
+ mask = offsets < n_ele
47
+ x = tl.load(input_ptr + offsets, mask=mask)
48
+ fx = x.to(tl.float32)
49
+ fxs = fx / softcap_const
50
+ exped = tl.exp(2 * fxs)
51
+ top = exped - 1
52
+ bottom = exped + 1
53
+ output = top / bottom * softcap_const
54
+ tl.store(output_ptr + offsets, output, mask=mask)
55
+
56
+
57
+ fused_softcap_kernel_autotuned = fused_softcap_autotune(fused_softcap_kernel)
58
+
59
+
60
+ def fused_softcap(x, softcap_const, autotune=False):
61
+ output = torch.empty_like(x, dtype=torch.float32)
62
+ n_elements = output.numel()
63
+ if autotune:
64
+ grid = lambda meta: (triton.cdiv(n_elements, meta["BLOCK_SIZE"]),)
65
+ fused_softcap_kernel_autotuned[grid](output, x, n_elements, softcap_const)
66
+ else:
67
+ fused_softcap_kernel[(triton.cdiv(n_elements, 128),)](
68
+ output, x, n_elements, softcap_const, BLOCK_SIZE=128, num_warps=8
69
+ )
70
+ return output
71
+
72
+
73
+ # cast to float + softcap
74
+ class Softcap:
75
+ def __init__(self, softcap_const: float):
76
+ self.softcap_const = softcap_const
77
+
78
+ def __call__(self, *args, **kwargs):
79
+ return self.forward(*args, **kwargs)
80
+
81
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
82
+ if x.is_cuda:
83
+ return self.forward_cuda(x)
84
+ else:
85
+ return self.forward_native(x)
86
+
87
+ def forward_native(self, x: torch.Tensor) -> torch.Tensor:
88
+ return torch.tanh(x.float() / self.softcap_const) * self.softcap_const
89
+
90
+ def forward_cuda(self, x: torch.Tensor, autotune=False) -> torch.Tensor:
91
+ return fused_softcap(x, self.softcap_const, autotune=autotune)
92
+
93
+
94
+ rmsnorm_autotune = triton.autotune(
95
+ configs=[
96
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=4, num_stages=1),
97
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=8, num_stages=1),
98
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=16, num_stages=1),
99
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=4),
100
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=8),
101
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=16),
102
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=4, num_stages=4),
103
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=8, num_stages=4),
104
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=16, num_stages=4),
105
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=8, num_stages=8),
106
+ triton.Config(kwargs={"BLOCK_SIZE": 1024}, num_warps=16, num_stages=8),
107
+ triton.Config(kwargs={"BLOCK_SIZE": 2048}, num_warps=8),
108
+ triton.Config(kwargs={"BLOCK_SIZE": 2048}, num_warps=16),
109
+ triton.Config(kwargs={"BLOCK_SIZE": 2048}, num_warps=8, num_stages=4),
110
+ triton.Config(kwargs={"BLOCK_SIZE": 2048}, num_warps=16, num_stages=4),
111
+ triton.Config(kwargs={"BLOCK_SIZE": 4096}, num_warps=8),
112
+ triton.Config(kwargs={"BLOCK_SIZE": 4096}, num_warps=16),
113
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=8),
114
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=16),
115
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=32),
116
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=8, num_stages=1),
117
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=16, num_stages=1),
118
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=32, num_stages=1),
119
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=8, num_stages=4),
120
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=16, num_stages=4),
121
+ triton.Config(kwargs={"BLOCK_SIZE": 8192}, num_warps=32, num_stages=4),
122
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=8),
123
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=16),
124
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=32),
125
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=8, num_stages=1),
126
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=16, num_stages=1),
127
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=32, num_stages=1),
128
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=8, num_stages=4),
129
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=16, num_stages=4),
130
+ triton.Config(kwargs={"BLOCK_SIZE": 16384}, num_warps=32, num_stages=4),
131
+ ],
132
+ key=["hidden_dim"],
133
+ )
134
+
135
+
136
+ @triton.jit
137
+ def fused_dual_residual_rmsnorm_kernel(
138
+ output_ptr,
139
+ mid_ptr,
140
+ activ_ptr,
141
+ residual_ptr,
142
+ weight1_ptr,
143
+ weight2_ptr,
144
+ eps: tl.constexpr,
145
+ hidden_dim: tl.constexpr,
146
+ BLOCK_SIZE: tl.constexpr,
147
+ ):
148
+ pid = tl.program_id(axis=0)
149
+ input_start = pid * hidden_dim
150
+
151
+ offsets = tl.arange(0, BLOCK_SIZE)
152
+ mask = offsets < hidden_dim
153
+
154
+ a_ = tl.load(activ_ptr + input_start + offsets, mask=mask, other=0.0)
155
+ a = a_.to(tl.float32)
156
+ rms = tl.sqrt(tl.sum(a * a, axis=0) / hidden_dim + eps)
157
+
158
+ r = tl.load(residual_ptr + input_start + offsets, mask=mask, other=0.0)
159
+ w1_ = tl.load(weight1_ptr + offsets, mask=mask, other=0.0)
160
+ w1 = w1_.to(tl.float32)
161
+
162
+ a2r = r + (a / rms * w1).to(r.dtype)
163
+ tl.store(
164
+ mid_ptr + input_start + offsets,
165
+ a2r,
166
+ mask=mask,
167
+ )
168
+
169
+ a2r = a2r.to(tl.float32)
170
+ rms2 = tl.sqrt(tl.sum(a2r * a2r, axis=0) / hidden_dim + eps)
171
+
172
+ w2_ = tl.load(weight2_ptr + offsets, mask=mask, other=0.0)
173
+ w2 = w2_.to(tl.float32)
174
+
175
+ tl.store(
176
+ output_ptr + input_start + offsets,
177
+ a2r / rms2 * w2, # implicitly casts to output dtype here
178
+ mask=mask,
179
+ )
180
+
181
+
182
+ fused_dual_residual_rmsnorm_kernel_autotune = rmsnorm_autotune(
183
+ fused_dual_residual_rmsnorm_kernel
184
+ )
185
+
186
+
187
+ def fused_dual_residual_rmsnorm(x, residual, weight1, weight2, eps, autotune=False):
188
+ assert len(x.shape) == 2
189
+ assert x.shape == residual.shape and x.dtype == residual.dtype
190
+ output, mid = torch.empty_like(x), torch.empty_like(x)
191
+ bs, hidden_dim = x.shape
192
+
193
+ min_num_warps = 16 if _is_hip else 32
194
+
195
+ if autotune:
196
+ fused_dual_residual_rmsnorm_kernel_autotune[(bs,)](
197
+ output, mid, x, residual, weight1, weight2, eps=eps, hidden_dim=hidden_dim
198
+ )
199
+ else:
200
+ config = {
201
+ "BLOCK_SIZE": triton.next_power_of_2(hidden_dim),
202
+ "num_warps": max(
203
+ min(
204
+ triton.next_power_of_2(triton.cdiv(hidden_dim, 256)), min_num_warps
205
+ ),
206
+ 4,
207
+ ),
208
+ }
209
+
210
+ fused_dual_residual_rmsnorm_kernel[(bs,)](
211
+ output,
212
+ mid,
213
+ x,
214
+ residual,
215
+ weight1,
216
+ weight2,
217
+ eps=eps,
218
+ hidden_dim=hidden_dim,
219
+ **config,
220
+ )
221
+
222
+ return output, mid
223
+
224
+
225
+ @triton.jit
226
+ def fused_rmsnorm_kernel(
227
+ output_ptr,
228
+ activ_ptr,
229
+ weight_ptr,
230
+ eps: tl.constexpr,
231
+ hidden_dim: tl.constexpr,
232
+ BLOCK_SIZE: tl.constexpr,
233
+ ):
234
+ pid = tl.program_id(axis=0)
235
+ input_start = pid * hidden_dim
236
+
237
+ offsets = tl.arange(0, BLOCK_SIZE)
238
+ mask = offsets < hidden_dim
239
+
240
+ a_ = tl.load(activ_ptr + input_start + offsets, mask=mask, other=0.0)
241
+ a = a_.to(tl.float32)
242
+ rms = tl.sqrt(tl.sum(a * a, axis=0) / hidden_dim + eps)
243
+
244
+ w1_ = tl.load(weight_ptr + offsets, mask=mask, other=0.0)
245
+ w1 = w1_.to(tl.float32)
246
+
247
+ a_rms = a / rms * w1
248
+
249
+ tl.store(
250
+ output_ptr + input_start + offsets,
251
+ a_rms, # implicitly casts to output dtype here
252
+ mask=mask,
253
+ )
254
+
255
+
256
+ def fused_rmsnorm(x, weight, eps, autotune=False, inplace=False):
257
+ assert len(x.shape) == 2
258
+ if inplace:
259
+ output = x
260
+ else:
261
+ output = torch.empty_like(x)
262
+ bs, hidden_dim = x.shape
263
+
264
+ min_num_warps = 16 if _is_hip else 32
265
+
266
+ config = {
267
+ "BLOCK_SIZE": triton.next_power_of_2(hidden_dim),
268
+ "num_warps": max(
269
+ min(triton.next_power_of_2(triton.cdiv(hidden_dim, 256)), min_num_warps), 4
270
+ ),
271
+ }
272
+
273
+ fused_rmsnorm_kernel[(bs,)](
274
+ output, x, weight, eps=eps, hidden_dim=hidden_dim, **config
275
+ )
276
+ return output
277
+
278
+
279
+ class FusedDualResidualRMSNorm:
280
+ """
281
+ Fused implementation of
282
+ y = RMSNorm2(RMSNorm1(x) + residual))
283
+ """
284
+
285
+ def __init__(self, rmsnorm1, rmsnorm2) -> None: # the one after rmsnorm1
286
+ self.rmsnorm1 = rmsnorm1
287
+ self.rmsnorm2 = rmsnorm2
288
+ self.variance_epsilon = self.rmsnorm1.variance_epsilon
289
+ assert self.rmsnorm1.variance_epsilon == self.rmsnorm2.variance_epsilon
290
+ assert self.rmsnorm1.weight.shape == self.rmsnorm2.weight.shape
291
+
292
+ def __call__(self, *args, **kwargs):
293
+ return self.forward(*args, **kwargs)
294
+
295
+ def forward(
296
+ self, x: torch.Tensor, residual: torch.Tensor
297
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
298
+ if x.is_cuda:
299
+ return self.forward_cuda(x, residual)
300
+ else:
301
+ return self.forward_flashinfer(x, residual)
302
+
303
+ def forward_cuda(
304
+ self, x: torch.Tensor, residual: torch.Tensor, autotune=False
305
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
306
+ return fused_dual_residual_rmsnorm(
307
+ x,
308
+ residual,
309
+ self.rmsnorm1.weight,
310
+ self.rmsnorm2.weight,
311
+ self.variance_epsilon,
312
+ autotune=autotune,
313
+ )
314
+
315
+ def forward_flashinfer(
316
+ self,
317
+ x: torch.Tensor,
318
+ residual: torch.Tensor,
319
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
320
+ normed1 = self.rmsnorm1(x)
321
+ residual = normed1 + residual
322
+ return self.rmsnorm2(residual), residual
323
+
324
+ def forward_native(
325
+ self,
326
+ x: torch.Tensor,
327
+ residual: torch.Tensor,
328
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
329
+ normed1 = self.rmsnorm1.forward_native(x)
330
+ residual = normed1 + residual
331
+ return self.rmsnorm2.forward_native(residual), residual
332
+
333
+
334
+ # gelu on first half of vector
335
+ @triton.jit
336
+ def gelu_and_mul_kernel(
337
+ out_hidden_states_ptr, # (bs, hidden_dim)
338
+ out_scales_ptr, # (bs,)
339
+ hidden_states_ptr, # (bs, hidden_dim * 2)
340
+ quant_max: tl.constexpr,
341
+ static_scale: tl.constexpr,
342
+ hidden_dim: tl.constexpr, # the output hidden_dim
343
+ BLOCK_SIZE: tl.constexpr,
344
+ ):
345
+ pid = tl.program_id(axis=0)
346
+
347
+ input_start = pid * hidden_dim * 2
348
+ output_start = pid * hidden_dim
349
+
350
+ input1_offs = tl.arange(0, BLOCK_SIZE)
351
+ mask = tl.arange(0, BLOCK_SIZE) < hidden_dim # shared for input1, input3, output
352
+ input3_offs = hidden_dim + tl.arange(0, BLOCK_SIZE)
353
+ output_offs = tl.arange(0, BLOCK_SIZE)
354
+
355
+ x1 = tl.load(
356
+ hidden_states_ptr + input_start + input1_offs, mask=mask, other=0.0
357
+ ).to(tl.float32)
358
+ x3 = tl.load(
359
+ hidden_states_ptr + input_start + input3_offs, mask=mask, other=0.0
360
+ ).to(tl.float32)
361
+
362
+ # gelu
363
+ # cast down before mul to better match training?
364
+ gelu_x1 = 0.5 * (1.0 + tl.erf(x1 * 0.7071067811865475)) * x1
365
+ out = x3 * gelu_x1.to(hidden_states_ptr.dtype.element_ty)
366
+
367
+ if quant_max is not None:
368
+ raise NotImplementedError()
369
+
370
+ tl.store(out_hidden_states_ptr + output_start + output_offs, out, mask=mask)
371
+
372
+
373
+ def gelu_and_mul_triton(
374
+ hidden_states,
375
+ scales=None,
376
+ quantize=None, # dtype to quantize to
377
+ out=None,
378
+ ):
379
+ bs, in_hidden_dim = hidden_states.shape
380
+ hidden_dim = in_hidden_dim // 2
381
+
382
+ if out is None:
383
+ out_hidden_states = torch.empty(
384
+ (bs, hidden_dim),
385
+ dtype=quantize or hidden_states.dtype,
386
+ device=hidden_states.device,
387
+ )
388
+ else:
389
+ assert out.shape == (bs, hidden_dim)
390
+ assert out.dtype == (quantize or hidden_states.dtype)
391
+ out_hidden_states = out
392
+ out_scales = None
393
+ static_scale = False
394
+ if quantize is not None:
395
+ if scales is None:
396
+ out_scales = torch.empty(
397
+ (bs,), dtype=torch.float32, device=hidden_states.device
398
+ )
399
+ else:
400
+ out_scales = scales
401
+ static_scale = True
402
+
403
+ config = {
404
+ # 8 ele per thread (not tuned)
405
+ "num_warps": max(
406
+ min(triton.next_power_of_2(triton.cdiv(hidden_dim, 8 * 32)), 32), 4
407
+ ),
408
+ }
409
+
410
+ gelu_and_mul_kernel[(bs,)](
411
+ out_hidden_states,
412
+ out_scales,
413
+ hidden_states,
414
+ quant_max=torch.finfo(quantize).max if quantize is not None else None,
415
+ static_scale=static_scale,
416
+ hidden_dim=hidden_dim,
417
+ BLOCK_SIZE=triton.next_power_of_2(hidden_dim),
418
+ **config,
419
+ )
420
+
421
+ if quantize is not None:
422
+ return out_hidden_states, out_scales
423
+ else:
424
+ return out_hidden_states, None
lib/python3.12/site-packages/sglang/srt/layers/layernorm.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ==============================================================================
14
+ """Fused operators for normalization layers."""
15
+
16
+ import logging
17
+ from typing import Optional, Tuple, Union
18
+
19
+ import torch
20
+ import torch.nn as nn
21
+
22
+ from sglang.srt.custom_op import CustomOp
23
+ from sglang.srt.utils import is_cuda, is_hip
24
+
25
+ _is_cuda = is_cuda()
26
+ _is_hip = is_hip()
27
+
28
+ if _is_cuda:
29
+ from sgl_kernel import (
30
+ fused_add_rmsnorm,
31
+ gemma_fused_add_rmsnorm,
32
+ gemma_rmsnorm,
33
+ rmsnorm,
34
+ )
35
+
36
+ if _is_hip:
37
+ from vllm._custom_ops import fused_add_rms_norm, rms_norm
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+
42
+ class RMSNorm(CustomOp):
43
+ def __init__(
44
+ self,
45
+ hidden_size: int,
46
+ eps: float = 1e-6,
47
+ ) -> None:
48
+ super().__init__()
49
+ self.weight = nn.Parameter(torch.ones(hidden_size))
50
+ self.variance_epsilon = eps
51
+
52
+ def forward(self, *args, **kwargs):
53
+ if torch.compiler.is_compiling():
54
+ return self.forward_native(*args, **kwargs)
55
+ if _is_cuda:
56
+ return self.forward_cuda(*args, **kwargs)
57
+ elif _is_hip:
58
+ return self.forward_hip(*args, **kwargs)
59
+ else:
60
+ return self.forward_native(*args, **kwargs)
61
+
62
+ def forward_cuda(
63
+ self,
64
+ x: torch.Tensor,
65
+ residual: Optional[torch.Tensor] = None,
66
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
67
+ if residual is not None:
68
+ fused_add_rmsnorm(x, residual, self.weight.data, self.variance_epsilon)
69
+ return x, residual
70
+ out = rmsnorm(x, self.weight.data, self.variance_epsilon)
71
+ return out
72
+
73
+ def forward_hip(
74
+ self,
75
+ x: torch.Tensor,
76
+ residual: Optional[torch.Tensor] = None,
77
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
78
+ if not x.is_contiguous():
79
+ # NOTE: Romove this if aiter kernel supports discontinuous input
80
+ x = x.contiguous()
81
+ if residual is not None:
82
+ fused_add_rms_norm(x, residual, self.weight.data, self.variance_epsilon)
83
+ return x, residual
84
+ out = torch.empty_like(x)
85
+ rms_norm(out, x, self.weight.data, self.variance_epsilon)
86
+ return out
87
+
88
+ def forward_native(
89
+ self,
90
+ x: torch.Tensor,
91
+ residual: Optional[torch.Tensor] = None,
92
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
93
+ if not x.is_contiguous():
94
+ x = x.contiguous()
95
+ orig_dtype = x.dtype
96
+ x = x.to(torch.float32)
97
+ if residual is not None:
98
+ x = x + residual.to(torch.float32)
99
+ residual = x.to(orig_dtype)
100
+
101
+ variance = x.pow(2).mean(dim=-1, keepdim=True)
102
+ x = x * torch.rsqrt(variance + self.variance_epsilon)
103
+ x = (x * self.weight).to(orig_dtype)
104
+ if residual is None:
105
+ return x
106
+ else:
107
+ return x, residual
108
+
109
+
110
+ class GemmaRMSNorm(CustomOp):
111
+ def __init__(
112
+ self,
113
+ hidden_size: int,
114
+ eps: float = 1e-6,
115
+ ) -> None:
116
+ super().__init__()
117
+ self.weight = nn.Parameter(torch.zeros(hidden_size))
118
+ self.variance_epsilon = eps
119
+
120
+ def forward(self, *args, **kwargs):
121
+ if torch.compiler.is_compiling():
122
+ return self.forward_native(*args, **kwargs)
123
+ if _is_cuda:
124
+ return self.forward_cuda(*args, **kwargs)
125
+ else:
126
+ return self.forward_native(*args, **kwargs)
127
+
128
+ def forward_native(
129
+ self,
130
+ x: torch.Tensor,
131
+ residual: Optional[torch.Tensor] = None,
132
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
133
+ orig_dtype = x.dtype
134
+ if residual is not None:
135
+ x = x + residual
136
+ residual = x
137
+
138
+ x = x.float()
139
+ variance = x.pow(2).mean(dim=-1, keepdim=True)
140
+ x = x * torch.rsqrt(variance + self.variance_epsilon)
141
+ x = x * (1.0 + self.weight.float())
142
+ x = x.to(orig_dtype)
143
+ return x if residual is None else (x, residual)
144
+
145
+ def forward_cuda(
146
+ self,
147
+ x: torch.Tensor,
148
+ residual: Optional[torch.Tensor] = None,
149
+ ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]:
150
+ if residual is not None:
151
+ gemma_fused_add_rmsnorm(
152
+ x, residual, self.weight.data, self.variance_epsilon
153
+ )
154
+ return x, residual
155
+ out = gemma_rmsnorm(x, self.weight.data, self.variance_epsilon)
156
+ return out
157
+
158
+
159
+ class Gemma3RMSNorm(nn.Module):
160
+ def __init__(self, dim: int, eps: float = 1e-6):
161
+ super().__init__()
162
+ self.eps = eps
163
+ self.weight = nn.Parameter(torch.zeros(dim))
164
+
165
+ def _norm(self, x):
166
+ return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
167
+
168
+ def forward(self, x):
169
+ output = self._norm(x.float())
170
+ # Llama does x.to(float16) * w whilst Gemma3 is (x * w).to(float16)
171
+ # See https://github.com/huggingface/transformers/pull/29402
172
+ output = output * (1.0 + self.weight.float())
173
+ return output.type_as(x)
174
+
175
+ def extra_repr(self):
176
+ return f"{tuple(self.weight.shape)}, eps={self.eps}"
177
+
178
+
179
+ if not (_is_cuda or _is_hip):
180
+ logger.info(
181
+ "sgl-kernel layernorm implementation is not available on current platform. Fallback to other kernel libraries."
182
+ )
183
+ from vllm.model_executor.layers.layernorm import GemmaRMSNorm, RMSNorm
lib/python3.12/site-packages/sglang/srt/layers/linear.py ADDED
@@ -0,0 +1,1307 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Adapted from https://github.com/vllm-project/vllm/blob/v0.6.4.post1/vllm/model_executor/layers/linear.py"""
2
+
3
+ import itertools
4
+ import logging
5
+ from abc import abstractmethod
6
+ from typing import Dict, List, Optional, Tuple
7
+
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from torch.nn.parameter import Parameter, UninitializedParameter
11
+
12
+ from sglang.srt.distributed import (
13
+ divide,
14
+ get_tensor_model_parallel_rank,
15
+ get_tensor_model_parallel_world_size,
16
+ split_tensor_along_last_dim,
17
+ tensor_model_parallel_all_gather,
18
+ tensor_model_parallel_all_reduce,
19
+ )
20
+ from sglang.srt.layers.parameter import (
21
+ BasevLLMParameter,
22
+ BlockQuantScaleParameter,
23
+ PackedColumnParameter,
24
+ PackedvLLMParameter,
25
+ PerTensorScaleParameter,
26
+ RowvLLMParameter,
27
+ _ColumnvLLMParameter,
28
+ )
29
+ from sglang.srt.layers.quantization.base_config import (
30
+ QuantizationConfig,
31
+ QuantizeMethodBase,
32
+ )
33
+ from sglang.srt.utils import set_weight_attrs
34
+
35
+ logger = logging.getLogger(__name__)
36
+
37
+ WEIGHT_LOADER_V2_SUPPORTED = [
38
+ "CompressedTensorsLinearMethod",
39
+ "AWQMarlinLinearMethod",
40
+ "AWQLinearMethod",
41
+ "GPTQMarlinLinearMethod",
42
+ "Fp8LinearMethod",
43
+ "BlockInt8LinearMethod",
44
+ "MarlinLinearMethod",
45
+ "QQQLinearMethod",
46
+ "GPTQMarlin24LinearMethod",
47
+ "TPUInt8LinearMethod",
48
+ "GPTQLinearMethod",
49
+ "FBGEMMFp8LinearMethod",
50
+ "ModelOptFp8LinearMethod",
51
+ "ModelOptFp4LinearMethod",
52
+ "IPEXAWQLinearMethod",
53
+ ]
54
+
55
+
56
+ def adjust_marlin_shard(param, shard_size, shard_offset):
57
+ marlin_tile_size = getattr(param, "marlin_tile_size", None)
58
+ if marlin_tile_size is None:
59
+ return shard_size, shard_offset
60
+
61
+ return shard_size * marlin_tile_size, shard_offset * marlin_tile_size
62
+
63
+
64
+ def adjust_bitsandbytes_4bit_shard(
65
+ param: Parameter, shard_offsets: Dict[str, Tuple[int, int]], loaded_shard_id: str
66
+ ) -> Tuple[int, int]:
67
+ """Adjust the quantization offsets and sizes for BitsAndBytes sharding."""
68
+
69
+ total, _ = shard_offsets["total"]
70
+ orig_offset, orig_size = shard_offsets[loaded_shard_id]
71
+
72
+ quantized_total = param.data.shape[0]
73
+ quantized_offset = orig_offset * quantized_total // total
74
+ quantized_size = orig_size * quantized_total // total
75
+
76
+ return quantized_size, quantized_offset
77
+
78
+
79
+ def adjust_scalar_to_fused_array(param, loaded_weight, shard_id):
80
+ """For fused modules (QKV and MLP) we have an array of length
81
+ N that holds 1 scale for each "logical" matrix. So the param
82
+ is an array of length N. The loaded_weight corresponds to
83
+ one of the shards on disk. Here, we slice the param based on
84
+ the shard_id for loading.
85
+ """
86
+ qkv_idxs = {"q": 0, "k": 1, "v": 2}
87
+
88
+ if isinstance(shard_id, str):
89
+ shard_id = qkv_idxs[shard_id]
90
+ elif not isinstance(shard_id, int):
91
+ raise ValueError(f"Unknown Shard Id {shard_id}")
92
+
93
+ # AutoFP8 scales do not have a shape
94
+ # compressed-tensors scales do have a shape
95
+ if len(loaded_weight.shape) != 0:
96
+ assert loaded_weight.shape[0] == 1
97
+ loaded_weight = loaded_weight[0]
98
+
99
+ return param[shard_id], loaded_weight
100
+
101
+
102
+ class LinearMethodBase(QuantizeMethodBase):
103
+ """Base class for different (maybe quantized) linear methods."""
104
+
105
+ @abstractmethod
106
+ def create_weights(
107
+ self,
108
+ layer: torch.nn.Module,
109
+ input_size_per_partition: int,
110
+ output_partition_sizes: List[int],
111
+ input_size: int,
112
+ output_size: int,
113
+ params_dtype: torch.dtype,
114
+ **extra_weight_attrs,
115
+ ):
116
+ """Create weights for a linear layer.
117
+ The weights will be set as attributes of the layer.
118
+
119
+ Args:
120
+ layer: The layer that is using the LinearMethodBase factory.
121
+ input_size_per_partition: Size of the weight input dim on rank X.
122
+ output_partition_sizes: Sizes of the output dim of each logical
123
+ weight on rank X. E.g., output_partition_sizes for QKVLinear
124
+ is a list contains the width of Wq, Wk, Wv on rank X.
125
+ input_size: Size of the input dim of the weight across all ranks.
126
+ output_size: Size of the output dim of the weight across all ranks.
127
+ params_dtype: Datatype of the parameters.
128
+ """
129
+ raise NotImplementedError
130
+
131
+ @abstractmethod
132
+ def apply(
133
+ self,
134
+ layer: torch.nn.Module,
135
+ x: torch.Tensor,
136
+ bias: Optional[torch.Tensor] = None,
137
+ ) -> torch.Tensor:
138
+ """Apply the weights in layer to the input tensor.
139
+ Expects create_weights to have been called before on the layer."""
140
+ raise NotImplementedError
141
+
142
+
143
+ class UnquantizedLinearMethod(LinearMethodBase):
144
+ """Linear method without quantization."""
145
+
146
+ def create_weights(
147
+ self,
148
+ layer: torch.nn.Module,
149
+ input_size_per_partition: int,
150
+ output_partition_sizes: List[int],
151
+ input_size: int,
152
+ output_size: int,
153
+ params_dtype: torch.dtype,
154
+ **extra_weight_attrs,
155
+ ):
156
+ weight = Parameter(
157
+ torch.empty(
158
+ sum(output_partition_sizes),
159
+ input_size_per_partition,
160
+ dtype=params_dtype,
161
+ ),
162
+ requires_grad=False,
163
+ )
164
+ set_weight_attrs(weight, {"input_dim": 1, "output_dim": 0})
165
+ layer.register_parameter("weight", weight)
166
+ set_weight_attrs(weight, extra_weight_attrs)
167
+
168
+ def apply(
169
+ self,
170
+ layer: torch.nn.Module,
171
+ x: torch.Tensor,
172
+ bias: Optional[torch.Tensor] = None,
173
+ ) -> torch.Tensor:
174
+
175
+ return F.linear(x, layer.weight, bias)
176
+
177
+
178
+ class LinearBase(torch.nn.Module):
179
+ """Base linear layer.
180
+
181
+ Args:
182
+ input_size: input dimension of the linear layer.
183
+ output_size: output dimension of the linear layer.
184
+ bias: If true, add bias.
185
+ skip_bias_add: If true, skip adding bias but instead return it.
186
+ params_dtype: Data type for the parameters.
187
+ quant_config: Quantization configure.
188
+ """
189
+
190
+ def __init__(
191
+ self,
192
+ input_size: int,
193
+ output_size: int,
194
+ skip_bias_add: bool = False,
195
+ params_dtype: Optional[torch.dtype] = None,
196
+ quant_config: Optional[QuantizationConfig] = None,
197
+ prefix: str = "",
198
+ ):
199
+ super().__init__()
200
+
201
+ # Keep input parameters
202
+ self.input_size = input_size
203
+ self.output_size = output_size
204
+ self.skip_bias_add = skip_bias_add
205
+ if params_dtype is None:
206
+ params_dtype = torch.get_default_dtype()
207
+ self.params_dtype = params_dtype
208
+ if quant_config is None:
209
+ self.quant_method: Optional[QuantizeMethodBase] = UnquantizedLinearMethod()
210
+ else:
211
+ self.quant_method = quant_config.get_quant_method(self, prefix=prefix)
212
+
213
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
214
+ raise NotImplementedError
215
+
216
+
217
+ class ReplicatedLinear(LinearBase):
218
+ """Replicated linear layer.
219
+
220
+ Args:
221
+ input_size: input dimension of the linear layer.
222
+ output_size: output dimension of the linear layer.
223
+ bias: If true, add bias.
224
+ skip_bias_add: If true, skip adding bias but instead return it.
225
+ params_dtype: Data type for the parameters.
226
+ quant_config: Quantization configure.
227
+ prefix: The name of the layer in the state dict, including all parents
228
+ (e.g. model.layers.0.qkv_proj)
229
+ """
230
+
231
+ def __init__(
232
+ self,
233
+ input_size: int,
234
+ output_size: int,
235
+ bias: bool = True,
236
+ skip_bias_add: bool = False,
237
+ params_dtype: Optional[torch.dtype] = None,
238
+ quant_config: Optional[QuantizationConfig] = None,
239
+ prefix: str = "",
240
+ ):
241
+ super().__init__(
242
+ input_size,
243
+ output_size,
244
+ skip_bias_add,
245
+ params_dtype,
246
+ quant_config,
247
+ prefix=prefix,
248
+ )
249
+
250
+ # All the linear layer supports quant method.
251
+ assert self.quant_method is not None
252
+ self.quant_method.create_weights(
253
+ self,
254
+ self.input_size,
255
+ [self.output_size],
256
+ self.input_size,
257
+ self.output_size,
258
+ self.params_dtype,
259
+ weight_loader=self.weight_loader,
260
+ )
261
+
262
+ if bias:
263
+ self.bias = Parameter(
264
+ torch.empty(self.output_size, dtype=self.params_dtype)
265
+ )
266
+ set_weight_attrs(
267
+ self.bias,
268
+ {
269
+ "output_dim": 0,
270
+ "weight_loader": self.weight_loader,
271
+ },
272
+ )
273
+ else:
274
+ self.register_parameter("bias", None)
275
+
276
+ def weight_loader(self, param: Parameter, loaded_weight: torch.Tensor):
277
+ # If the weight on disk does not have a shape, give it one
278
+ # (such scales for AutoFp8).
279
+ if len(loaded_weight.shape) == 0:
280
+ loaded_weight = loaded_weight.reshape(1)
281
+
282
+ assert param.size() == loaded_weight.size()
283
+ param.data.copy_(loaded_weight)
284
+
285
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
286
+ bias = self.bias if not self.skip_bias_add else None
287
+ assert self.quant_method is not None
288
+ output = self.quant_method.apply(self, x, bias)
289
+ output_bias = self.bias if self.skip_bias_add else None
290
+ return output, output_bias
291
+
292
+ def extra_repr(self) -> str:
293
+ s = f"in_features={self.input_size}"
294
+ s += f", output_features={self.output_size}"
295
+ s += f", bias={self.bias is not None}"
296
+ return s
297
+
298
+
299
+ class ColumnParallelLinear(LinearBase):
300
+ """Linear layer with column parallelism.
301
+
302
+ The linear layer is defined as Y = XA + b. A is parallelized along
303
+ its second dimension as A = [A_1, ..., A_p].
304
+
305
+ Args:
306
+ input_size: first dimension of matrix A.
307
+ output_size: second dimension of matrix A.
308
+ bias: If true, add bias.
309
+ gather_output: If true, call all-gather on output and make Y available
310
+ to all GPUs, otherwise, every GPU will have its output
311
+ which is Y_i = XA_i
312
+ skip_bias_add: This was added to enable performance optimizations where
313
+ bias can be fused with other element-wise operations. we
314
+ skip adding bias but instead return it.
315
+ params_dtype: Data type for the parameters.
316
+ quant_config: Quantization configure.
317
+ output_sizes: list of output sizes packed into one output, like for QKV
318
+ the list would be size 3.
319
+ prefix: The name of the layer in the state dict, including all parents
320
+ (e.g. model.layers.0.qkv_proj)
321
+ """
322
+
323
+ def __init__(
324
+ self,
325
+ input_size: int,
326
+ output_size: int,
327
+ bias: bool = True,
328
+ gather_output: bool = False,
329
+ skip_bias_add: bool = False,
330
+ params_dtype: Optional[torch.dtype] = None,
331
+ quant_config: Optional[QuantizationConfig] = None,
332
+ output_sizes: Optional[List[int]] = None,
333
+ prefix: str = "",
334
+ tp_rank: Optional[int] = None,
335
+ tp_size: Optional[int] = None,
336
+ use_presharded_weights: bool = False,
337
+ ):
338
+ super().__init__(
339
+ input_size, output_size, skip_bias_add, params_dtype, quant_config, prefix
340
+ )
341
+
342
+ self.gather_output = gather_output
343
+ self.use_presharded_weights = use_presharded_weights
344
+
345
+ # Divide the weight matrix along the last dimension.
346
+ if tp_rank is None:
347
+ tp_rank = get_tensor_model_parallel_rank()
348
+ if tp_size is None:
349
+ tp_size = get_tensor_model_parallel_world_size()
350
+ self.tp_rank, self.tp_size = tp_rank, tp_size
351
+ assert self.quant_method is not None
352
+ self.output_size_per_partition = divide(self.output_size, tp_size)
353
+ self.output_partition_sizes = [self.output_size_per_partition]
354
+ # If QKV or MergedColumn, use output size of each partition.
355
+ if hasattr(self, "output_sizes"):
356
+ self.output_partition_sizes = [
357
+ divide(output_size, tp_size) for output_size in self.output_sizes
358
+ ]
359
+
360
+ if output_sizes is None:
361
+ output_sizes = [output_size]
362
+
363
+ self.quant_method.create_weights(
364
+ layer=self,
365
+ input_size_per_partition=self.input_size,
366
+ output_partition_sizes=self.output_partition_sizes,
367
+ input_size=self.input_size,
368
+ output_size=self.output_size,
369
+ params_dtype=self.params_dtype,
370
+ weight_loader=(
371
+ self.weight_loader_v2
372
+ if self.quant_method.__class__.__name__ in WEIGHT_LOADER_V2_SUPPORTED
373
+ else self.weight_loader
374
+ ),
375
+ )
376
+ if bias:
377
+ self.bias = Parameter(
378
+ torch.empty(self.output_size_per_partition, dtype=params_dtype)
379
+ )
380
+ set_weight_attrs(
381
+ self.bias,
382
+ {
383
+ "output_dim": 0,
384
+ "weight_loader": self.weight_loader,
385
+ },
386
+ )
387
+ else:
388
+ self.register_parameter("bias", None)
389
+
390
+ def weight_loader(self, param: Parameter, loaded_weight: torch.Tensor):
391
+ output_dim = getattr(param, "output_dim", None)
392
+
393
+ # Special case for GGUF
394
+ is_gguf_weight = getattr(param, "is_gguf_weight", False)
395
+ is_gguf_weight_type = getattr(param, "is_gguf_weight_type", False)
396
+ if is_gguf_weight_type:
397
+ param.weight_type = loaded_weight.item()
398
+
399
+ # Materialize GGUF UninitializedParameter
400
+ if is_gguf_weight and isinstance(param, UninitializedParameter):
401
+ param.materialize(loaded_weight.shape, dtype=loaded_weight.dtype)
402
+
403
+ use_bitsandbytes_4bit = getattr(param, "use_bitsandbytes_4bit", False)
404
+
405
+ param_data = param.data
406
+ # bitsandbytes loads the weights of the specific portion
407
+ # no need to narrow here
408
+ if output_dim is not None and not use_bitsandbytes_4bit:
409
+ shard_size = param_data.shape[output_dim]
410
+ start_idx = self.tp_rank * shard_size
411
+ if not self.use_presharded_weights:
412
+ loaded_weight = loaded_weight.narrow(output_dim, start_idx, shard_size)
413
+
414
+ # Special case for loading scales off disk, which often do not
415
+ # have a shape (such as in the case of AutoFP8).
416
+ if len(loaded_weight.shape) == 0:
417
+ loaded_weight = loaded_weight.reshape(1)
418
+
419
+ assert param_data.shape == loaded_weight.shape
420
+ param_data.copy_(loaded_weight)
421
+
422
+ def weight_loader_v2(self, param: Parameter, loaded_weight: torch.Tensor):
423
+ # Special case for loading scales off disk, which often do not
424
+ # have a shape (such as in the case of AutoFP8).
425
+ if len(loaded_weight.shape) == 0:
426
+ assert loaded_weight.numel() == 1
427
+ loaded_weight = loaded_weight.reshape(1)
428
+
429
+ if isinstance(param, _ColumnvLLMParameter):
430
+ param.load_column_parallel_weight(
431
+ loaded_weight,
432
+ tp_rank=self.tp_rank,
433
+ use_presharded_weights=self.use_presharded_weights,
434
+ )
435
+ else:
436
+ # FIXME: This branch is needed to load deepseek v3 awq.
437
+ # However, we should fix this and avoid the branching here.
438
+ param.load_column_parallel_weight(loaded_weight)
439
+
440
+ def forward(self, input_):
441
+ bias = self.bias if not self.skip_bias_add else None
442
+
443
+ # Matrix multiply.
444
+ assert self.quant_method is not None
445
+ output_parallel = self.quant_method.apply(self, input_, bias)
446
+ if self.gather_output:
447
+ # All-gather across the partitions.
448
+ output = tensor_model_parallel_all_gather(output_parallel)
449
+ else:
450
+ output = output_parallel
451
+ output_bias = self.bias if self.skip_bias_add else None
452
+ return output, output_bias
453
+
454
+ def extra_repr(self) -> str:
455
+ s = f"in_features={self.input_size}"
456
+ s += f", output_features={self.output_size_per_partition}"
457
+ s += f", bias={self.bias is not None}"
458
+ s += f", tp_size={self.tp_size}"
459
+ s += f", gather_output={self.gather_output}"
460
+ return s
461
+
462
+
463
+ class MergedColumnParallelLinear(ColumnParallelLinear):
464
+ """Packed linear layers with column parallelism.
465
+
466
+ Similar to ColumnParallelLinear, but the weight matrix is concatenated
467
+ along the output dimension. When the weight matrix is loaded, the
468
+ different partitions are sharded separately.
469
+
470
+ Args:
471
+ input_size: input dimension of the linear layer.
472
+ output_sizes: list of output dimensions of the linear layer.
473
+ bias: If true, add bias.
474
+ gather_output: If true, call all-gather on output and make the output
475
+ available to all GPUs, otherwise, every GPU will have
476
+ its own output.
477
+ skip_bias_add: This was added to enable performance optimizations where
478
+ bias can be fused with other element-wise operations. we
479
+ skip adding bias but instead return it.
480
+ params_dtype: Data type for the parameters.
481
+ quant_config: Quantization configure.
482
+ prefix: The name of the layer in the state dict, including all parents
483
+ (e.g. model.layers.0.qkv_proj)
484
+ """
485
+
486
+ def __init__(
487
+ self,
488
+ input_size: int,
489
+ output_sizes: List[int],
490
+ bias: bool = True,
491
+ gather_output: bool = False,
492
+ skip_bias_add: bool = False,
493
+ params_dtype: Optional[torch.dtype] = None,
494
+ quant_config: Optional[QuantizationConfig] = None,
495
+ prefix: str = "",
496
+ tp_rank: Optional[int] = None,
497
+ tp_size: Optional[int] = None,
498
+ use_presharded_weights: bool = False,
499
+ ):
500
+ self.output_sizes = output_sizes
501
+ if tp_rank is None:
502
+ tp_rank = get_tensor_model_parallel_rank()
503
+ if tp_size is None:
504
+ tp_size = get_tensor_model_parallel_world_size()
505
+ self.tp_rank, self.tp_size = tp_rank, tp_size
506
+ assert all(output_size % tp_size == 0 for output_size in output_sizes)
507
+ self.use_presharded_weights = use_presharded_weights
508
+ super().__init__(
509
+ input_size=input_size,
510
+ output_size=sum(output_sizes),
511
+ bias=bias,
512
+ gather_output=gather_output,
513
+ skip_bias_add=skip_bias_add,
514
+ params_dtype=params_dtype,
515
+ quant_config=quant_config,
516
+ prefix=prefix,
517
+ tp_rank=tp_rank,
518
+ tp_size=tp_size,
519
+ use_presharded_weights=use_presharded_weights,
520
+ )
521
+ self.prefix = prefix
522
+
523
+ def weight_loader(
524
+ self,
525
+ param: Parameter,
526
+ loaded_weight: torch.Tensor,
527
+ loaded_shard_id: Optional[int] = None,
528
+ ):
529
+
530
+ # Special case for GGUF
531
+ # initialize GGUF param after we know the quantize type
532
+ is_gguf_weight = getattr(param, "is_gguf_weight", False)
533
+ is_gguf_weight_type = getattr(param, "is_gguf_weight_type", False)
534
+ if is_gguf_weight_type:
535
+ param.data[loaded_shard_id].copy_(loaded_weight)
536
+ param.shard_weight_type[loaded_shard_id] = loaded_weight.item()
537
+ return
538
+
539
+ if is_gguf_weight:
540
+ output_dim = getattr(param, "output_dim", None)
541
+ shard_size = loaded_weight.size(output_dim) // self.tp_size
542
+ start_idx = self.tp_rank * shard_size
543
+
544
+ loaded_weight = loaded_weight.narrow(output_dim, start_idx, shard_size)
545
+
546
+ param.shard_id.append(loaded_shard_id)
547
+ param.shard_id_map[loaded_shard_id] = len(param.data_container)
548
+ param.data_container.append(loaded_weight)
549
+ if len(param.data_container) == 2:
550
+ self.qweight = param.materialize_nested()
551
+ return
552
+
553
+ param_data = param.data
554
+ output_dim = getattr(param, "output_dim", None)
555
+ # Special case for AQLM codebooks.
556
+ is_metadata = getattr(param, "is_metadata", False)
557
+ # Special case for per-tensor scale to load scalar into fused array.
558
+ needs_scalar_to_array = getattr(param, "needs_scalar_to_array", False)
559
+
560
+ if loaded_shard_id is None:
561
+ # Loaded weight is already fused on disk (qkv/mlp).
562
+ if output_dim is None:
563
+ if needs_scalar_to_array:
564
+ param_data, loaded_weight = adjust_scalar_to_fused_array(
565
+ param_data, loaded_weight, 0
566
+ )
567
+
568
+ assert param_data.shape == loaded_weight.shape
569
+ param_data.copy_(loaded_weight)
570
+ return
571
+ current_shard_offset = 0
572
+ shard_offsets: List[Tuple[int, int, int]] = []
573
+ for i, output_size in enumerate(self.output_sizes):
574
+ shard_offsets.append((i, current_shard_offset, output_size))
575
+ current_shard_offset += output_size
576
+ packed_dim = getattr(param, "packed_dim", None)
577
+
578
+ use_bitsandbytes_4bit = getattr(param, "use_bitsandbytes_4bit", False)
579
+ for shard_id, shard_offset, shard_size in shard_offsets:
580
+ # Special case for Quantization.
581
+ # If quantized, we need to adjust the offset and size to account
582
+ # for the packing.
583
+ if packed_dim == output_dim:
584
+ shard_size = shard_size // param.pack_factor
585
+ shard_offset = shard_offset // param.pack_factor
586
+ # Special case for Marlin.
587
+ shard_size, shard_offset = adjust_marlin_shard(
588
+ param, shard_size, shard_offset
589
+ )
590
+
591
+ if use_bitsandbytes_4bit:
592
+ index = list(itertools.accumulate([0] + self.output_sizes))
593
+ orig_offsets = {
594
+ str(i): (index[i], size)
595
+ for i, size in enumerate(self.output_sizes)
596
+ }
597
+ orig_offsets["total"] = (self.output_size, 0)
598
+ shard_size, shard_offset = adjust_bitsandbytes_4bit_shard(
599
+ param, orig_offsets, str(shard_id)
600
+ )
601
+
602
+ loaded_weight_shard = loaded_weight.narrow(
603
+ output_dim, shard_offset, shard_size
604
+ )
605
+ self.weight_loader(param, loaded_weight_shard, shard_id)
606
+ return
607
+
608
+ assert loaded_shard_id < len(self.output_sizes)
609
+ if output_dim is not None:
610
+ shard_offset = sum(self.output_sizes[:loaded_shard_id]) // self.tp_size
611
+ shard_size = self.output_sizes[loaded_shard_id] // self.tp_size
612
+ # Special case for quantization.
613
+ # If quantized, we need to adjust the offset and size to account
614
+ # for the packing.
615
+ packed_dim = getattr(param, "packed_dim", None)
616
+ if packed_dim == output_dim:
617
+ shard_size = shard_size // param.pack_factor
618
+ shard_offset = shard_offset // param.pack_factor
619
+ # Special case for Marlin.
620
+ shard_size, shard_offset = adjust_marlin_shard(
621
+ param, shard_size, shard_offset
622
+ )
623
+
624
+ use_bitsandbytes_4bit = getattr(param, "use_bitsandbytes_4bit", False)
625
+ if use_bitsandbytes_4bit:
626
+ shard_size = loaded_weight.shape[output_dim]
627
+ shard_offset = loaded_weight.shape[output_dim] * loaded_shard_id
628
+
629
+ param_data = param_data.narrow(output_dim, shard_offset, shard_size)
630
+ start_idx = self.tp_rank * shard_size
631
+ # bitsandbytes loads the weights of the specific portion
632
+ # no need to narrow here
633
+ if not use_bitsandbytes_4bit and not self.use_presharded_weights:
634
+ loaded_weight = loaded_weight.narrow(output_dim, start_idx, shard_size)
635
+ # Special case for AQLM codebooks.
636
+ elif is_metadata:
637
+ # metadata indicates fixed size concatenated along dim 0
638
+ shard_size = loaded_weight.shape[0]
639
+ shard_offset = loaded_shard_id * shard_size
640
+ param_data = param_data.narrow(0, shard_offset, shard_size)
641
+
642
+ # Special case for per-tensor scales in fused case.
643
+ elif needs_scalar_to_array:
644
+ param_data, loaded_weight = adjust_scalar_to_fused_array(
645
+ param_data, loaded_weight, loaded_shard_id
646
+ )
647
+
648
+ else:
649
+ ignore_warning = getattr(param, "ignore_warning", False)
650
+ if not ignore_warning:
651
+ logger.warning(
652
+ "Loading a weight without `output_dim` attribute in "
653
+ "MergedColumnParallelLinear, assume the weight is "
654
+ "the same for all partitions."
655
+ )
656
+
657
+ assert param_data.shape == loaded_weight.shape
658
+ param_data.copy_(loaded_weight)
659
+
660
+ def _load_fused_module_from_checkpoint(
661
+ self, param: BasevLLMParameter, loaded_weight: torch.Tensor
662
+ ):
663
+ """
664
+ Handle special case for models where MLP layers are already
665
+ fused on disk. In this case, we have no shard id. This function
666
+ determmines the shard id by splitting these layers and then calls
667
+ the weight loader using the shard id.
668
+
669
+ An example of a model with these fused layers:
670
+ https://huggingface.co/microsoft/Phi-3-mini-4k-instruct
671
+ """
672
+
673
+ current_shard_offset = 0
674
+ shard_offsets: List[Tuple[int, int, int]] = []
675
+ for i, output_size in enumerate(self.output_sizes):
676
+ shard_offsets.append((i, current_shard_offset, output_size))
677
+ current_shard_offset += output_size
678
+
679
+ for shard_id, shard_offset, shard_size in shard_offsets:
680
+ # Special case for Quantization.
681
+ # If quantized, we need to adjust the offset and size to account
682
+ # for the packing.
683
+ if (
684
+ isinstance(param, (PackedColumnParameter, PackedvLLMParameter))
685
+ and param.packed_dim == param.output_dim
686
+ ):
687
+ shard_size, shard_offset = param.adjust_shard_indexes_for_packing(
688
+ shard_size=shard_size, shard_offset=shard_offset
689
+ )
690
+
691
+ loaded_weight_shard = loaded_weight.narrow(
692
+ param.output_dim, shard_offset, shard_size
693
+ )
694
+ self.weight_loader_v2(param, loaded_weight_shard, shard_id)
695
+
696
+ def weight_loader_v2(
697
+ self,
698
+ param: BasevLLMParameter,
699
+ loaded_weight: torch.Tensor,
700
+ loaded_shard_id: Optional[int] = None,
701
+ ):
702
+ if loaded_shard_id is None:
703
+ if isinstance(param, PerTensorScaleParameter):
704
+ param.load_merged_column_weight(
705
+ loaded_weight=loaded_weight,
706
+ shard_id=0,
707
+ tp_rank=self.tp_rank,
708
+ tp_size=self.tp_size,
709
+ )
710
+ return
711
+ elif type(param) in (RowvLLMParameter, BasevLLMParameter):
712
+ param.load_merged_column_weight(
713
+ loaded_weight=loaded_weight,
714
+ tp_rank=self.tp_rank,
715
+ tp_size=self.tp_size,
716
+ )
717
+ return
718
+ # TODO: @dsikka - move to parameter.py
719
+ self._load_fused_module_from_checkpoint(param, loaded_weight)
720
+ return
721
+
722
+ assert loaded_shard_id < len(self.output_sizes)
723
+
724
+ if isinstance(param, BlockQuantScaleParameter):
725
+ weight_block_size = self.quant_method.quant_config.weight_block_size
726
+ block_n, _ = weight_block_size[0], weight_block_size[1]
727
+ shard_offset = (
728
+ (sum(self.output_sizes[:loaded_shard_id]) + block_n - 1) // block_n
729
+ ) // self.tp_size
730
+ shard_size = (
731
+ (self.output_sizes[loaded_shard_id] + block_n - 1)
732
+ // block_n
733
+ // self.tp_size
734
+ )
735
+ else:
736
+ shard_offset = sum(self.output_sizes[:loaded_shard_id]) // self.tp_size
737
+ shard_size = self.output_sizes[loaded_shard_id] // self.tp_size
738
+
739
+ param.load_merged_column_weight(
740
+ loaded_weight=loaded_weight,
741
+ shard_id=loaded_shard_id,
742
+ shard_offset=shard_offset,
743
+ shard_size=shard_size,
744
+ use_presharded_weights=self.use_presharded_weights,
745
+ tp_rank=self.tp_rank,
746
+ tp_size=self.tp_size,
747
+ )
748
+
749
+
750
+ class QKVParallelLinear(ColumnParallelLinear):
751
+ """Linear layers for the attention's QKV transformation.
752
+
753
+ Linear layers for the linear transformation of the query, key, and value
754
+ vectors in the attention layer. The weight matrix is concatenated along
755
+ the output dimension. The layer is parallelized along the head dimension.
756
+ When the number of key/value heads is smaller than the number of query
757
+ heads (e.g., multi-query/grouped-query attention), the key/value head may
758
+ be replicated while the query heads are partitioned.
759
+
760
+ Args:
761
+ hidden_size: input hidden state size of the transformer.
762
+ head_size: size of each attention head.
763
+ total_num_heads: total number of attention query heads.
764
+ total_num_kv_heads: total number of attention key/value heads. If
765
+ None, assume total_num_kv_heads = total_num_heads.
766
+ bias: If true, add bias.
767
+ skip_bias_add: This was added to enable performance optimizations where
768
+ bias can be fused with other element-wise operations. we
769
+ skip adding bias but instead return it.
770
+ params_dtype: Data type for the parameters.
771
+ quant_config: Quantization configure.
772
+ prefix: The name of the layer in the state dict, including all parents
773
+ (e.g. model.layers.0.qkv_proj)
774
+ """
775
+
776
+ def __init__(
777
+ self,
778
+ hidden_size: int,
779
+ head_size: int,
780
+ total_num_heads: int,
781
+ total_num_kv_heads: Optional[int] = None,
782
+ bias: bool = True,
783
+ skip_bias_add: bool = False,
784
+ params_dtype: Optional[torch.dtype] = None,
785
+ quant_config: Optional[QuantizationConfig] = None,
786
+ prefix: str = "",
787
+ tp_rank: Optional[int] = None,
788
+ tp_size: Optional[int] = None,
789
+ load_presharded_attn: bool = False,
790
+ ):
791
+ self.hidden_size = hidden_size
792
+ self.head_size = head_size
793
+ self.total_num_heads = total_num_heads
794
+ if total_num_kv_heads is None:
795
+ total_num_kv_heads = total_num_heads
796
+ self.total_num_kv_heads = total_num_kv_heads
797
+ # Divide the weight matrix along the last dimension.
798
+ if tp_rank is None:
799
+ tp_rank = get_tensor_model_parallel_rank()
800
+ if tp_size is None:
801
+ tp_size = get_tensor_model_parallel_world_size()
802
+ self.tp_rank, self.tp_size = tp_rank, tp_size
803
+ self.num_heads = divide(self.total_num_heads, tp_size)
804
+ if tp_size >= self.total_num_kv_heads:
805
+ self.num_kv_heads = 1
806
+ self.num_kv_head_replicas = divide(tp_size, self.total_num_kv_heads)
807
+ else:
808
+ self.num_kv_heads = divide(self.total_num_kv_heads, tp_size)
809
+ self.num_kv_head_replicas = 1
810
+ self.q_proj_shard_size = self.num_heads * self.head_size
811
+ self.kv_proj_shard_size = self.num_kv_heads * self.head_size
812
+ input_size = self.hidden_size
813
+ output_size = (
814
+ (self.num_heads + 2 * self.num_kv_heads) * tp_size * self.head_size
815
+ )
816
+ self.output_sizes = [
817
+ self.num_heads * self.head_size * tp_size, # q_proj
818
+ self.num_kv_heads * self.head_size * tp_size, # k_proj
819
+ self.num_kv_heads * self.head_size * tp_size, # v_proj
820
+ ]
821
+ self.use_presharded_weights = load_presharded_attn
822
+
823
+ super().__init__(
824
+ input_size=input_size,
825
+ output_size=output_size,
826
+ bias=bias,
827
+ gather_output=False,
828
+ skip_bias_add=skip_bias_add,
829
+ params_dtype=params_dtype,
830
+ quant_config=quant_config,
831
+ prefix=prefix,
832
+ tp_rank=tp_rank,
833
+ tp_size=tp_size,
834
+ use_presharded_weights=self.use_presharded_weights,
835
+ )
836
+
837
+ def _get_shard_offset_mapping(self, loaded_shard_id: str):
838
+ shard_offset_mapping = {
839
+ "q": 0,
840
+ "k": self.num_heads * self.head_size,
841
+ "v": (self.num_heads + self.num_kv_heads) * self.head_size,
842
+ "total": (self.num_heads + 2 * self.num_kv_heads) * self.head_size,
843
+ }
844
+ return shard_offset_mapping.get(loaded_shard_id)
845
+
846
+ def _get_shard_size_mapping(self, loaded_shard_id: str):
847
+ shard_size_mapping = {
848
+ "q": self.num_heads * self.head_size,
849
+ "k": self.num_kv_heads * self.head_size,
850
+ "v": self.num_kv_heads * self.head_size,
851
+ }
852
+ return shard_size_mapping.get(loaded_shard_id)
853
+
854
+ def _load_fused_module_from_checkpoint(
855
+ self, param: BasevLLMParameter, loaded_weight: torch.Tensor
856
+ ):
857
+ """
858
+ Handle special case for models where QKV layers are already
859
+ fused on disk. In this case, we have no shard id. This function
860
+ determmines the shard id by splitting these layers and then calls
861
+ the weight loader using the shard id.
862
+
863
+ An example of a model with these fused layers:
864
+ https://huggingface.co/microsoft/Phi-3-mini-4k-instruct
865
+ """
866
+ shard_offsets = [
867
+ # (shard_id, shard_offset, shard_size)
868
+ ("q", 0, self.total_num_heads * self.head_size),
869
+ (
870
+ "k",
871
+ self.total_num_heads * self.head_size,
872
+ self.total_num_kv_heads * self.head_size,
873
+ ),
874
+ (
875
+ "v",
876
+ (self.total_num_heads + self.total_num_kv_heads) * self.head_size,
877
+ self.total_num_kv_heads * self.head_size,
878
+ ),
879
+ ]
880
+
881
+ for shard_id, shard_offset, shard_size in shard_offsets:
882
+ # Special case for Quantization.
883
+ # If quantized, we need to adjust the offset and size to account
884
+ # for the packing.
885
+ if (
886
+ isinstance(param, (PackedColumnParameter, PackedvLLMParameter))
887
+ and param.packed_dim == param.output_dim
888
+ ):
889
+ shard_size, shard_offset = param.adjust_shard_indexes_for_packing(
890
+ shard_size=shard_size, shard_offset=shard_offset
891
+ )
892
+
893
+ if not self.use_presharded_weights:
894
+ loaded_weight_shard = loaded_weight.narrow(
895
+ param.output_dim, shard_offset, shard_size
896
+ )
897
+ self.weight_loader_v2(param, loaded_weight_shard, shard_id)
898
+
899
+ def weight_loader_v2(
900
+ self,
901
+ param: BasevLLMParameter,
902
+ loaded_weight: torch.Tensor,
903
+ loaded_shard_id: Optional[str] = None,
904
+ ):
905
+ if loaded_shard_id is None: # special case for certain models
906
+ if isinstance(param, PerTensorScaleParameter):
907
+ param.load_qkv_weight(loaded_weight=loaded_weight, shard_id=0)
908
+ return
909
+ elif type(param) in (RowvLLMParameter, BasevLLMParameter):
910
+ param.load_qkv_weight(loaded_weight=loaded_weight)
911
+ return
912
+ # TODO: @dsikka - move to parameter.py
913
+ self._load_fused_module_from_checkpoint(param, loaded_weight)
914
+ return
915
+
916
+ assert loaded_shard_id in ["q", "k", "v"]
917
+
918
+ shard_offset = self._get_shard_offset_mapping(loaded_shard_id)
919
+ shard_size = self._get_shard_size_mapping(loaded_shard_id)
920
+
921
+ if isinstance(param, BlockQuantScaleParameter):
922
+ weight_block_size = self.quant_method.quant_config.weight_block_size
923
+ block_n, _ = weight_block_size[0], weight_block_size[1]
924
+ shard_offset = (shard_offset + block_n - 1) // block_n
925
+ shard_size = (shard_size + block_n - 1) // block_n
926
+
927
+ param.load_qkv_weight(
928
+ loaded_weight=loaded_weight,
929
+ num_heads=self.num_kv_head_replicas,
930
+ shard_id=loaded_shard_id,
931
+ shard_offset=shard_offset,
932
+ shard_size=shard_size,
933
+ tp_rank=self.tp_rank,
934
+ use_presharded_weights=self.use_presharded_weights,
935
+ )
936
+
937
+ def weight_loader(
938
+ self,
939
+ param: Parameter,
940
+ loaded_weight: torch.Tensor,
941
+ loaded_shard_id: Optional[str] = None,
942
+ ):
943
+
944
+ # Special case for GGUF
945
+ # initialize GGUF param after we know the quantize type
946
+ is_gguf_weight = getattr(param, "is_gguf_weight", False)
947
+ is_gguf_weight_type = getattr(param, "is_gguf_weight_type", False)
948
+ if is_gguf_weight_type and loaded_shard_id is not None:
949
+ idx_map = {"q": 0, "k": 1, "v": 2}
950
+ param.data[idx_map[loaded_shard_id]].copy_(loaded_weight)
951
+ param.shard_weight_type[loaded_shard_id] = loaded_weight.item()
952
+ return
953
+
954
+ if is_gguf_weight:
955
+ output_dim = getattr(param, "output_dim", None)
956
+ shard_size = loaded_weight.size(output_dim) // self.tp_size
957
+ start_idx = self.tp_rank * shard_size
958
+
959
+ loaded_weight = loaded_weight.narrow(output_dim, start_idx, shard_size)
960
+
961
+ param.shard_id.append(loaded_shard_id)
962
+ param.shard_id_map[loaded_shard_id] = len(param.data_container)
963
+ param.data_container.append(loaded_weight)
964
+ if len(param.data_container) == 3:
965
+ self.qweight = param.materialize_nested()
966
+ return
967
+
968
+ param_data = param.data
969
+ output_dim = getattr(param, "output_dim", None)
970
+ # Special case for AQLM codebooks.
971
+ is_metadata = getattr(param, "is_metadata", False)
972
+
973
+ # Special case for per-tensor scales in fused case.
974
+ needs_scalar_to_array = getattr(param, "needs_scalar_to_array", False)
975
+
976
+ if loaded_shard_id is None:
977
+ # Loaded weight is already fused on disk (qkv/mlp).
978
+ if output_dim is None:
979
+ if needs_scalar_to_array:
980
+ param_data, loaded_weight = adjust_scalar_to_fused_array(
981
+ param_data, loaded_weight, 0
982
+ )
983
+
984
+ assert param_data.shape == loaded_weight.shape
985
+ param_data.copy_(loaded_weight)
986
+ return
987
+ shard_offsets = [
988
+ # (shard_id, shard_offset, shard_size)
989
+ ("q", 0, self.total_num_heads * self.head_size),
990
+ (
991
+ "k",
992
+ self.total_num_heads * self.head_size,
993
+ self.total_num_kv_heads * self.head_size,
994
+ ),
995
+ (
996
+ "v",
997
+ (self.total_num_heads + self.total_num_kv_heads) * self.head_size,
998
+ self.total_num_kv_heads * self.head_size,
999
+ ),
1000
+ ]
1001
+ use_bitsandbytes_4bit = getattr(param, "use_bitsandbytes_4bit", False)
1002
+
1003
+ packed_dim = getattr(param, "packed_dim", None)
1004
+ for shard_id, shard_offset, shard_size in shard_offsets:
1005
+ # Special case for Quantized Weights.
1006
+ # If quantized, we need to adjust the offset and size to account
1007
+ # for the packing.
1008
+ if packed_dim == output_dim:
1009
+ shard_size = shard_size // param.pack_factor
1010
+ shard_offset = shard_offset // param.pack_factor
1011
+
1012
+ # Special case for Marlin.
1013
+ shard_size, shard_offset = adjust_marlin_shard(
1014
+ param, shard_size, shard_offset
1015
+ )
1016
+
1017
+ if use_bitsandbytes_4bit:
1018
+ orig_qkv_offsets = {
1019
+ "q": (0, self.total_num_heads * self.head_size),
1020
+ "k": (
1021
+ self.total_num_heads * self.head_size,
1022
+ self.total_num_kv_heads * self.head_size,
1023
+ ),
1024
+ "v": (
1025
+ (self.total_num_heads + self.total_num_kv_heads)
1026
+ * self.head_size,
1027
+ self.total_num_kv_heads * self.head_size,
1028
+ ),
1029
+ "total": (
1030
+ (self.total_num_heads + 2 * self.total_num_kv_heads)
1031
+ * self.head_size,
1032
+ 0,
1033
+ ),
1034
+ }
1035
+
1036
+ shard_size, shard_offset = adjust_bitsandbytes_4bit_shard(
1037
+ param, orig_qkv_offsets, shard_id
1038
+ )
1039
+
1040
+ if not self.use_presharded_weights:
1041
+ loaded_weight_shard = loaded_weight.narrow(
1042
+ output_dim, shard_offset, shard_size
1043
+ )
1044
+ self.weight_loader(param, loaded_weight_shard, shard_id)
1045
+ return
1046
+
1047
+ assert loaded_shard_id in ["q", "k", "v"]
1048
+
1049
+ # If output dim is defined, use the default loading process.
1050
+ if output_dim is not None:
1051
+ if loaded_shard_id == "q":
1052
+ shard_offset = 0
1053
+ shard_size = self.num_heads * self.head_size
1054
+ elif loaded_shard_id == "k":
1055
+ shard_offset = self.num_heads * self.head_size
1056
+ shard_size = self.num_kv_heads * self.head_size
1057
+ elif loaded_shard_id == "v":
1058
+ shard_offset = (self.num_heads + self.num_kv_heads) * self.head_size
1059
+ shard_size = self.num_kv_heads * self.head_size
1060
+ # Special case for Quantized Weights.
1061
+ # If quantized, we need to adjust the offset and size to account
1062
+ # for the packing.
1063
+ packed_dim = getattr(param, "packed_dim", None)
1064
+ if packed_dim == output_dim:
1065
+ shard_size = shard_size // param.pack_factor
1066
+ shard_offset = shard_offset // param.pack_factor
1067
+
1068
+ # Special case for Marlin.
1069
+ shard_size, shard_offset = adjust_marlin_shard(
1070
+ param, shard_size, shard_offset
1071
+ )
1072
+
1073
+ use_bitsandbytes_4bit = getattr(param, "use_bitsandbytes_4bit", False)
1074
+ if use_bitsandbytes_4bit:
1075
+ orig_qkv_offsets = {
1076
+ "q": (0, self.num_heads * self.head_size),
1077
+ "k": (
1078
+ self.num_heads * self.head_size,
1079
+ self.num_kv_heads * self.head_size,
1080
+ ),
1081
+ "v": (
1082
+ (self.num_heads + self.num_kv_heads) * self.head_size,
1083
+ self.num_kv_heads * self.head_size,
1084
+ ),
1085
+ "total": (
1086
+ (self.num_heads + 2 * self.num_kv_heads) * self.head_size,
1087
+ 0,
1088
+ ),
1089
+ }
1090
+ shard_size, shard_offset = adjust_bitsandbytes_4bit_shard(
1091
+ param, orig_qkv_offsets, loaded_shard_id
1092
+ )
1093
+
1094
+ param_data = param_data.narrow(output_dim, shard_offset, shard_size)
1095
+ if loaded_shard_id == "q":
1096
+ shard_id = self.tp_rank
1097
+ else:
1098
+ shard_id = self.tp_rank // self.num_kv_head_replicas
1099
+ start_idx = shard_id * shard_size
1100
+
1101
+ # bitsandbytes loads the weights of the specific portion
1102
+ # no need to narrow here
1103
+ if not use_bitsandbytes_4bit and not self.use_presharded_weights:
1104
+ loaded_weight = loaded_weight.narrow(output_dim, start_idx, shard_size)
1105
+
1106
+ # Special case for for AQLM codebooks.
1107
+ elif is_metadata:
1108
+ # metadata indicates fixed size concatenated along dim 0
1109
+ shard_size = loaded_weight.shape[0]
1110
+ shard_index = ["q", "k", "v"].index(loaded_shard_id)
1111
+ param_data = param_data.narrow(0, shard_index * shard_size, shard_size)
1112
+ # Special case for per-tensor scales in fused case.
1113
+ elif needs_scalar_to_array:
1114
+ param_data, loaded_weight = adjust_scalar_to_fused_array(
1115
+ param_data, loaded_weight, loaded_shard_id
1116
+ )
1117
+ else:
1118
+ ignore_warning = getattr(param, "ignore_warning", False)
1119
+ if not ignore_warning:
1120
+ logger.warning(
1121
+ "Loading a weight without `output_dim` attribute in "
1122
+ "QKVParallelLinear, assume the weight is the same "
1123
+ "for all partitions."
1124
+ )
1125
+
1126
+ assert param_data.shape == loaded_weight.shape
1127
+ param_data.copy_(loaded_weight)
1128
+
1129
+
1130
+ class RowParallelLinear(LinearBase):
1131
+ """Linear layer with row parallelism.
1132
+
1133
+ The linear layer is defined as Y = XA + b. A is parallelized along
1134
+ its first dimension and X along its second dimension as:
1135
+ - -
1136
+ | A_1 |
1137
+ | . |
1138
+ A = | . | X = [X_1, ..., X_p]
1139
+ | . |
1140
+ | A_p |
1141
+ - -
1142
+ Arguments:
1143
+ input_size: first dimension of matrix A.
1144
+ output_size: second dimension of matrix A.
1145
+ bias: If true, add bias. Note that bias is not parallelized.
1146
+ input_is_parallel: If true, we assume that the input is already
1147
+ split across the GPUs and we do not split
1148
+ again.
1149
+ skip_bias_add: This was added to enable performance optimization where
1150
+ bias can be fused with other element-wise operations.
1151
+ We skip adding bias but instead return it.
1152
+ params_dtype: Data type for the parameters.
1153
+ quant_config: Quantization configure.
1154
+ """
1155
+
1156
+ def __init__(
1157
+ self,
1158
+ input_size: int,
1159
+ output_size: int,
1160
+ bias: bool = True,
1161
+ input_is_parallel: bool = True,
1162
+ skip_bias_add: bool = False,
1163
+ params_dtype: Optional[torch.dtype] = None,
1164
+ reduce_results: bool = True,
1165
+ quant_config: Optional[QuantizationConfig] = None,
1166
+ prefix: str = "",
1167
+ tp_rank: Optional[int] = None,
1168
+ tp_size: Optional[int] = None,
1169
+ use_presharded_weights: bool = False,
1170
+ ):
1171
+ super().__init__(
1172
+ input_size, output_size, skip_bias_add, params_dtype, quant_config, prefix
1173
+ )
1174
+
1175
+ self.input_is_parallel = input_is_parallel
1176
+ self.reduce_results = reduce_results
1177
+
1178
+ # Divide the weight matrix along the last dimension.
1179
+ if tp_rank is None:
1180
+ tp_rank = get_tensor_model_parallel_rank()
1181
+ if tp_size is None:
1182
+ tp_size = get_tensor_model_parallel_world_size()
1183
+ self.tp_rank, self.tp_size = tp_rank, tp_size
1184
+ self.input_size_per_partition = divide(input_size, self.tp_size)
1185
+ assert self.quant_method is not None
1186
+ self.use_presharded_weights = use_presharded_weights
1187
+
1188
+ self.quant_method.create_weights(
1189
+ layer=self,
1190
+ input_size_per_partition=self.input_size_per_partition,
1191
+ output_partition_sizes=[self.output_size],
1192
+ input_size=self.input_size,
1193
+ output_size=self.output_size,
1194
+ params_dtype=self.params_dtype,
1195
+ weight_loader=(
1196
+ self.weight_loader_v2
1197
+ if self.quant_method.__class__.__name__ in WEIGHT_LOADER_V2_SUPPORTED
1198
+ else self.weight_loader
1199
+ ),
1200
+ )
1201
+ if not reduce_results and (bias and not skip_bias_add):
1202
+ raise ValueError(
1203
+ "When not reduce the results, adding bias to the "
1204
+ "results can lead to incorrect results"
1205
+ )
1206
+
1207
+ if bias:
1208
+ self.bias = Parameter(torch.empty(self.output_size, dtype=params_dtype))
1209
+ set_weight_attrs(
1210
+ self.bias,
1211
+ {
1212
+ "output_dim": 0,
1213
+ "weight_loader": self.weight_loader,
1214
+ },
1215
+ )
1216
+ else:
1217
+ self.register_parameter("bias", None)
1218
+
1219
+ def weight_loader(self, param: Parameter, loaded_weight: torch.Tensor):
1220
+ input_dim = getattr(param, "input_dim", None)
1221
+ use_bitsandbytes_4bit = getattr(param, "use_bitsandbytes_4bit", False)
1222
+
1223
+ # Special case for GGUF
1224
+ is_gguf_weight = getattr(param, "is_gguf_weight", False)
1225
+ is_gguf_weight_type = getattr(param, "is_gguf_weight_type", False)
1226
+ if is_gguf_weight_type:
1227
+ param.weight_type = loaded_weight.item()
1228
+
1229
+ # Materialize GGUF UninitializedParameter
1230
+ if is_gguf_weight and isinstance(param, UninitializedParameter):
1231
+ weight_shape = list(loaded_weight.shape)
1232
+ if input_dim:
1233
+ weight_shape[input_dim] = weight_shape[input_dim] // self.tp_size
1234
+ param.materialize(tuple(weight_shape), dtype=loaded_weight.dtype)
1235
+
1236
+ param_data = param.data
1237
+ # bitsandbytes loads the weights of the specific portion
1238
+ # no need to narrow here
1239
+ if (
1240
+ input_dim is not None
1241
+ and not use_bitsandbytes_4bit
1242
+ and not self.use_presharded_weights
1243
+ ):
1244
+ shard_size = param_data.shape[input_dim]
1245
+ start_idx = self.tp_rank * shard_size
1246
+ loaded_weight = loaded_weight.narrow(input_dim, start_idx, shard_size)
1247
+
1248
+ # Special case for loading scales off disk, which often do not
1249
+ # have a shape (such as in the case of AutoFP8).
1250
+ if len(loaded_weight.shape) == 0:
1251
+ loaded_weight = loaded_weight.reshape(1)
1252
+
1253
+ assert param_data.shape == loaded_weight.shape
1254
+ param_data.copy_(loaded_weight)
1255
+
1256
+ def weight_loader_v2(self, param: BasevLLMParameter, loaded_weight: torch.Tensor):
1257
+
1258
+ # Special case for loading scales off disk, which often do not
1259
+ # have a shape (such as in the case of AutoFP8).
1260
+ if len(loaded_weight.shape) == 0:
1261
+ assert loaded_weight.numel() == 1
1262
+ loaded_weight = loaded_weight.reshape(1)
1263
+
1264
+ if isinstance(param, RowvLLMParameter):
1265
+ # This `BasevLLMParameter` is defined in sglang/srt/layers/parameter.py,
1266
+ # It supports additional parameters like tp_rank and use_presharded_weights.
1267
+ param.load_row_parallel_weight(
1268
+ loaded_weight,
1269
+ tp_rank=self.tp_rank,
1270
+ use_presharded_weights=self.use_presharded_weights,
1271
+ )
1272
+ else:
1273
+ # `params` is defined in `vllm/model_executor/parameter.py`,
1274
+ # It does not support additional parameters.
1275
+ param.load_row_parallel_weight(loaded_weight)
1276
+
1277
+ def forward(self, input_):
1278
+ if self.input_is_parallel:
1279
+ input_parallel = input_
1280
+ else:
1281
+ splitted_input = split_tensor_along_last_dim(
1282
+ input_, num_partitions=self.tp_size
1283
+ )
1284
+ input_parallel = splitted_input[self.tp_rank].contiguous()
1285
+
1286
+ # Matrix multiply.
1287
+ assert self.quant_method is not None
1288
+ # Only fuse bias add into GEMM for rank 0 (this ensures that
1289
+ # bias will not get added more than once in TP>1 case)
1290
+ bias_ = None if (self.tp_rank > 0 or self.skip_bias_add) else self.bias
1291
+ output_parallel = self.quant_method.apply(self, input_parallel, bias=bias_)
1292
+ if self.reduce_results and self.tp_size > 1:
1293
+ output = tensor_model_parallel_all_reduce(output_parallel)
1294
+ else:
1295
+ output = output_parallel
1296
+
1297
+ output_bias = self.bias if self.skip_bias_add else None
1298
+
1299
+ return output, output_bias
1300
+
1301
+ def extra_repr(self) -> str:
1302
+ s = f"input_features={self.input_size_per_partition}"
1303
+ s += f", output_features={self.output_size}"
1304
+ s += f", bias={self.bias is not None}"
1305
+ s += f", tp_size={self.tp_size}"
1306
+ s += f", reduce_results={self.reduce_results}"
1307
+ return s
lib/python3.12/site-packages/sglang/srt/layers/logits_processor.py ADDED
@@ -0,0 +1,586 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023-2024 SGLang Team
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+ # ==============================================================================
14
+ """Logits processing."""
15
+
16
+ import dataclasses
17
+ import logging
18
+ from typing import List, Optional, Union
19
+
20
+ import torch
21
+ import triton
22
+ import triton.language as tl
23
+ from torch import nn
24
+
25
+ from sglang.srt.distributed import (
26
+ get_tensor_model_parallel_rank,
27
+ get_tensor_model_parallel_world_size,
28
+ tensor_model_parallel_all_gather,
29
+ )
30
+ from sglang.srt.layers.dp_attention import (
31
+ dp_gather_replicate,
32
+ dp_scatter,
33
+ get_attention_dp_rank,
34
+ get_attention_dp_size,
35
+ )
36
+ from sglang.srt.layers.vocab_parallel_embedding import VocabParallelEmbedding
37
+ from sglang.srt.managers.schedule_batch import global_server_args_dict
38
+ from sglang.srt.model_executor.forward_batch_info import (
39
+ CaptureHiddenMode,
40
+ ForwardBatch,
41
+ ForwardMode,
42
+ )
43
+ from sglang.srt.utils import dump_to_file
44
+
45
+ logger = logging.getLogger(__name__)
46
+
47
+
48
+ @dataclasses.dataclass
49
+ class LogitsProcessorOutput:
50
+ ## Part 1: This part will be assigned in python/sglang/srt/layers/logits_processor.py::LogitsProcessor
51
+ # The logits of the next tokens. shape: [#seq, vocab_size]
52
+ next_token_logits: torch.Tensor
53
+ # Used by speculative decoding (EAGLE)
54
+ # The last hidden layers
55
+ hidden_states: Optional[torch.Tensor] = None
56
+
57
+ ## Part 2: This part will be assigned in python/sglang/srt/layers/sampler.py::Sampler
58
+ # The logprobs of the next tokens. shape: [#seq]
59
+ next_token_logprobs: Optional[torch.Tensor] = None
60
+ # The logprobs and ids of the top-k tokens in output positions. shape: [#seq, k]
61
+ next_token_top_logprobs_val: Optional[List] = None
62
+ next_token_top_logprobs_idx: Optional[List] = None
63
+ # The logprobs and ids of the requested token ids in output positions. shape: [#seq, n] (n is the number of requested token ids)
64
+ next_token_token_ids_logprobs_val: Optional[List] = None
65
+ next_token_token_ids_logprobs_idx: Optional[List] = None
66
+
67
+ ## Part 3: Prefill-only. This part will be assigned in python/sglang/srt/layers/logits_processor.py::LogitsProcessor
68
+ # The logprobs of input tokens. shape: [#token]
69
+ input_token_logprobs: Optional[torch.Tensor] = None
70
+ # The logprobs and ids of the top-k tokens in input positions. shape: [#seq, #token, k]
71
+ input_top_logprobs_val: List = None
72
+ input_top_logprobs_idx: List = None
73
+ # The logprobs and ids of the requested token ids in input positions. shape: [#seq, n] (n is the number of requested token ids)
74
+ input_token_ids_logprobs_val: Optional[List] = None
75
+ input_token_ids_logprobs_idx: Optional[List] = None
76
+
77
+
78
+ @dataclasses.dataclass
79
+ class LogitsMetadata:
80
+ forward_mode: ForwardMode
81
+ capture_hidden_mode: CaptureHiddenMode = CaptureHiddenMode.NULL
82
+
83
+ extend_return_logprob: bool = False
84
+ extend_return_top_logprob: bool = False
85
+ extend_token_ids_logprob: bool = False
86
+ extend_seq_lens: Optional[torch.Tensor] = None
87
+ extend_seq_lens_cpu: Optional[List[int]] = None
88
+ extend_logprob_start_lens_cpu: Optional[List[int]] = None
89
+ extend_logprob_pruned_lens_cpu: Optional[List[int]] = None
90
+ top_logprobs_nums: Optional[List[int]] = None
91
+ extend_input_logprob_token_ids_gpu: Optional[torch.Tensor] = None
92
+ token_ids_logprobs: Optional[List[List[int]]] = None
93
+
94
+ # logits and logprobs post processing
95
+ temp_scaled_logprobs: bool = False
96
+ temperature: torch.Tensor = None
97
+ top_p_normalized_logprobs: bool = False
98
+ top_p: torch.Tensor = None
99
+
100
+ # DP attention metadata. Not needed when DP attention is not used.
101
+ # Number of tokens in the request.
102
+ global_num_tokens_gpu: Optional[torch.Tensor] = None
103
+ # The start position of local hidden states.
104
+ dp_local_start_pos: Optional[torch.Tensor] = None
105
+ dp_local_num_tokens: Optional[torch.Tensor] = None
106
+ gathered_buffer: Optional[torch.Tensor] = None
107
+ # Buffer to gather logits from all ranks.
108
+ forward_batch_gathered_buffer: Optional[torch.Tensor] = None
109
+ # Number of tokens to sample per DP rank
110
+ global_num_tokens_for_logprob_cpu: Optional[torch.Tensor] = None
111
+ global_num_tokens_for_logprob_gpu: Optional[torch.Tensor] = None
112
+
113
+ # for padding
114
+ padded_static_len: int = -1
115
+
116
+ @classmethod
117
+ def from_forward_batch(cls, forward_batch: ForwardBatch):
118
+ if (
119
+ forward_batch.forward_mode.is_extend()
120
+ and forward_batch.return_logprob
121
+ and not forward_batch.forward_mode.is_target_verify()
122
+ ):
123
+ extend_return_top_logprob = any(
124
+ x > 0 for x in forward_batch.top_logprobs_nums
125
+ )
126
+ extend_token_ids_logprob = any(
127
+ x is not None for x in forward_batch.token_ids_logprobs
128
+ )
129
+ extend_return_logprob = False
130
+ extend_logprob_pruned_lens_cpu = []
131
+ for extend_len, start_len in zip(
132
+ forward_batch.extend_seq_lens_cpu,
133
+ forward_batch.extend_logprob_start_lens_cpu,
134
+ ):
135
+ if extend_len - start_len > 0:
136
+ extend_return_logprob = True
137
+ extend_logprob_pruned_lens_cpu.append(extend_len - start_len)
138
+ else:
139
+ extend_return_logprob = extend_return_top_logprob = (
140
+ extend_token_ids_logprob
141
+ ) = extend_logprob_pruned_lens_cpu = False
142
+
143
+ return cls(
144
+ forward_mode=forward_batch.forward_mode,
145
+ capture_hidden_mode=forward_batch.capture_hidden_mode,
146
+ extend_return_logprob=extend_return_logprob,
147
+ extend_return_top_logprob=extend_return_top_logprob,
148
+ extend_token_ids_logprob=extend_token_ids_logprob,
149
+ extend_seq_lens=forward_batch.extend_seq_lens,
150
+ extend_seq_lens_cpu=forward_batch.extend_seq_lens_cpu,
151
+ extend_logprob_start_lens_cpu=forward_batch.extend_logprob_start_lens_cpu,
152
+ extend_logprob_pruned_lens_cpu=extend_logprob_pruned_lens_cpu,
153
+ top_logprobs_nums=forward_batch.top_logprobs_nums,
154
+ token_ids_logprobs=forward_batch.token_ids_logprobs,
155
+ extend_input_logprob_token_ids_gpu=forward_batch.extend_input_logprob_token_ids_gpu,
156
+ padded_static_len=forward_batch.padded_static_len,
157
+ global_num_tokens_gpu=forward_batch.global_num_tokens_gpu,
158
+ dp_local_start_pos=forward_batch.dp_local_start_pos,
159
+ dp_local_num_tokens=forward_batch.dp_local_num_tokens,
160
+ gathered_buffer=forward_batch.gathered_buffer,
161
+ forward_batch_gathered_buffer=forward_batch.gathered_buffer,
162
+ global_num_tokens_for_logprob_cpu=forward_batch.global_num_tokens_for_logprob_cpu,
163
+ global_num_tokens_for_logprob_gpu=forward_batch.global_num_tokens_for_logprob_gpu,
164
+ )
165
+
166
+ def compute_dp_attention_metadata(self, hidden_states: torch.Tensor):
167
+ if self.global_num_tokens_for_logprob_cpu is None:
168
+ # we are capturing cuda graph
169
+ return
170
+
171
+ cumtokens = torch.cumsum(self.global_num_tokens_for_logprob_gpu, dim=0)
172
+ dp_rank = get_attention_dp_rank()
173
+ if dp_rank == 0:
174
+ dp_local_start_pos = torch.zeros_like(
175
+ self.global_num_tokens_for_logprob_gpu[0]
176
+ )
177
+ else:
178
+ dp_local_start_pos = cumtokens[dp_rank - 1]
179
+ dp_local_num_tokens = self.global_num_tokens_for_logprob_gpu[dp_rank]
180
+ gathered_buffer = torch.zeros(
181
+ (
182
+ sum(self.global_num_tokens_for_logprob_cpu),
183
+ hidden_states.shape[1],
184
+ ),
185
+ dtype=hidden_states.dtype,
186
+ device=hidden_states.device,
187
+ )
188
+
189
+ self.dp_local_start_pos = dp_local_start_pos
190
+ self.dp_local_num_tokens = dp_local_num_tokens
191
+ self.gathered_buffer = gathered_buffer
192
+
193
+
194
+ class LogitsProcessor(nn.Module):
195
+ def __init__(
196
+ self, config, skip_all_gather: bool = False, logit_scale: Optional[float] = None
197
+ ):
198
+ super().__init__()
199
+ self.config = config
200
+ self.logit_scale = logit_scale
201
+ self.do_tensor_parallel_all_gather = (
202
+ not skip_all_gather and get_tensor_model_parallel_world_size() > 1
203
+ )
204
+ self.do_tensor_parallel_all_gather_dp_attn = (
205
+ self.do_tensor_parallel_all_gather and get_attention_dp_size() != 1
206
+ )
207
+ self.final_logit_softcapping = getattr(
208
+ self.config, "final_logit_softcapping", None
209
+ )
210
+ if (
211
+ self.final_logit_softcapping is not None
212
+ and self.final_logit_softcapping < 0
213
+ ):
214
+ self.final_logit_softcapping = None
215
+
216
+ self.debug_tensor_dump_output_folder = global_server_args_dict.get(
217
+ "debug_tensor_dump_output_folder", None
218
+ )
219
+
220
+ def forward(
221
+ self,
222
+ input_ids,
223
+ hidden_states,
224
+ lm_head: VocabParallelEmbedding,
225
+ logits_metadata: Union[LogitsMetadata, ForwardBatch],
226
+ aux_hidden_states: Optional[torch.Tensor] = None,
227
+ ) -> LogitsProcessorOutput:
228
+ if isinstance(logits_metadata, ForwardBatch):
229
+ logits_metadata = LogitsMetadata.from_forward_batch(logits_metadata)
230
+ # Get the last hidden states and last logits for the next token prediction
231
+ if (
232
+ logits_metadata.forward_mode.is_decode_or_idle()
233
+ or logits_metadata.forward_mode.is_target_verify()
234
+ ):
235
+ pruned_states = hidden_states
236
+ if aux_hidden_states is not None:
237
+ aux_pruned_states = [hidden for hidden in aux_hidden_states]
238
+ sample_indices = None
239
+ input_logprob_indices = None
240
+ elif (
241
+ logits_metadata.forward_mode.is_extend()
242
+ and not logits_metadata.extend_return_logprob
243
+ ):
244
+ # Prefill without input logprobs.
245
+ if logits_metadata.padded_static_len < 0:
246
+ last_index = torch.cumsum(logits_metadata.extend_seq_lens, dim=0) - 1
247
+ else:
248
+ # If padding_static length is 5 and extended_seq_lens is [2, 3],
249
+ # then our batch looks like [t00, t01, p, p, p, t10, t11, t12, p, p]
250
+ # and this retrieves t01 and t12, which are the valid last tokens
251
+ idx = torch.arange(
252
+ len(logits_metadata.extend_seq_lens),
253
+ device=logits_metadata.extend_seq_lens.device,
254
+ )
255
+ last_index = (
256
+ idx * logits_metadata.padded_static_len
257
+ + logits_metadata.extend_seq_lens
258
+ - 1
259
+ )
260
+ pruned_states = hidden_states[last_index]
261
+ if aux_hidden_states is not None:
262
+ aux_pruned_states = [hidden[last_index] for hidden in aux_hidden_states]
263
+ sample_indices = None
264
+ input_logprob_indices = None
265
+ else:
266
+ # Input logprobs are required.
267
+ # Find 3 different indices.
268
+ # 1. pruned_states: hidden states that we want logprobs from.
269
+ # 2. sample_indices: Indices that have sampled tokens.
270
+ # 3. input_logprob_indices: Indices that have input logprob tokens.
271
+ sample_index_pt = -1
272
+ sample_indices = []
273
+ input_logprob_indices_pt = 0
274
+ input_logprob_indices = []
275
+ pt, pruned_states = 0, []
276
+ for extend_logprob_start_len, extend_len in zip(
277
+ logits_metadata.extend_logprob_start_lens_cpu,
278
+ logits_metadata.extend_seq_lens_cpu,
279
+ ):
280
+ # It can happen in chunked prefill. We still need to sample 1 token,
281
+ # But we don't want to include it in input logprob.
282
+ if extend_len == extend_logprob_start_len:
283
+ start_len = extend_logprob_start_len - 1
284
+ else:
285
+ start_len = extend_logprob_start_len
286
+
287
+ # We always need at least 1 token to sample because that's required
288
+ # by a caller.
289
+ assert extend_len > start_len
290
+ pruned_states.append(hidden_states[pt + start_len : pt + extend_len])
291
+ pt += extend_len
292
+ sample_index_pt += extend_len - start_len
293
+ sample_indices.append(sample_index_pt)
294
+ input_logprob_indices.extend(
295
+ [
296
+ input_logprob_indices_pt + i
297
+ for i in range(extend_len - extend_logprob_start_len)
298
+ ]
299
+ )
300
+ input_logprob_indices_pt += extend_len - start_len
301
+
302
+ pruned_states = torch.cat(pruned_states)
303
+ sample_indices = torch.tensor(
304
+ sample_indices, device=pruned_states.device, dtype=torch.int64
305
+ )
306
+ input_logprob_indices = torch.tensor(
307
+ input_logprob_indices, device=pruned_states.device, dtype=torch.int64
308
+ )
309
+
310
+ # Compute logits for both input and sampled tokens.
311
+ logits = self._get_logits(pruned_states, lm_head, logits_metadata)
312
+ sampled_logits = (
313
+ logits[sample_indices] if sample_indices is not None else logits
314
+ )
315
+
316
+ if self.debug_tensor_dump_output_folder:
317
+ assert (
318
+ not self.do_tensor_parallel_all_gather or get_attention_dp_size() == 1
319
+ ), "dp attention + sharded lm_head doesn't support full logits"
320
+ full_logits = self._get_logits(hidden_states, lm_head, logits_metadata)
321
+ dump_to_file(self.debug_tensor_dump_output_folder, "logits", full_logits)
322
+
323
+ hidden_states_to_store: Optional[torch.Tensor] = None
324
+ if logits_metadata.capture_hidden_mode.need_capture():
325
+ if logits_metadata.capture_hidden_mode.is_full():
326
+ if aux_hidden_states is not None:
327
+ aux_hidden_states = torch.cat(aux_hidden_states, dim=-1)
328
+ hidden_states_to_store = aux_hidden_states
329
+ else:
330
+ hidden_states_to_store = hidden_states
331
+ elif logits_metadata.capture_hidden_mode.is_last():
332
+ # Get the last token hidden states. If sample_indices is None,
333
+ # pruned states only contain the last tokens already.
334
+ if aux_hidden_states is not None:
335
+ aux_pruned_states = torch.cat(aux_pruned_states, dim=-1)
336
+ hidden_states_to_store = (
337
+ aux_pruned_states[sample_indices]
338
+ if sample_indices is not None
339
+ else aux_pruned_states
340
+ )
341
+ else:
342
+ hidden_states_to_store = (
343
+ pruned_states[sample_indices]
344
+ if sample_indices is not None
345
+ else pruned_states
346
+ )
347
+ else:
348
+ assert False, "Should never reach"
349
+
350
+ if not logits_metadata.extend_return_logprob:
351
+ # Decode mode or extend mode without return_logprob.
352
+ return LogitsProcessorOutput(
353
+ next_token_logits=sampled_logits,
354
+ hidden_states=hidden_states_to_store,
355
+ )
356
+ else:
357
+ input_logprobs = logits[input_logprob_indices]
358
+ del hidden_states, logits
359
+
360
+ # Normalize the logprob w/o temperature, top-p
361
+ pruned_lens = torch.tensor(
362
+ logits_metadata.extend_logprob_pruned_lens_cpu,
363
+ device=input_logprobs.device,
364
+ )
365
+ if logits_metadata.temp_scaled_logprobs:
366
+ logits_metadata.temperature = torch.repeat_interleave(
367
+ logits_metadata.temperature.view(-1),
368
+ pruned_lens,
369
+ ).view(-1, 1)
370
+ if logits_metadata.top_p_normalized_logprobs:
371
+ logits_metadata.top_p = torch.repeat_interleave(
372
+ logits_metadata.top_p,
373
+ pruned_lens,
374
+ )
375
+ input_logprobs = self.compute_temp_top_p_normalized_logprobs(
376
+ input_logprobs, logits_metadata
377
+ )
378
+
379
+ # Get the logprob of top-k tokens
380
+ if logits_metadata.extend_return_top_logprob:
381
+ (
382
+ input_top_logprobs_val,
383
+ input_top_logprobs_idx,
384
+ ) = self.get_top_logprobs(input_logprobs, logits_metadata)
385
+ else:
386
+ input_top_logprobs_val = input_top_logprobs_idx = None
387
+
388
+ # Get the logprob of given token id
389
+ if logits_metadata.extend_token_ids_logprob:
390
+ (
391
+ input_token_ids_logprobs_val,
392
+ input_token_ids_logprobs_idx,
393
+ ) = self.get_token_ids_logprobs(input_logprobs, logits_metadata)
394
+ else:
395
+ input_token_ids_logprobs_val = input_token_ids_logprobs_idx = None
396
+
397
+ input_token_logprobs = input_logprobs[
398
+ torch.arange(input_logprobs.shape[0], device=input_logprobs.device),
399
+ logits_metadata.extend_input_logprob_token_ids_gpu,
400
+ ]
401
+
402
+ return LogitsProcessorOutput(
403
+ next_token_logits=sampled_logits,
404
+ input_token_logprobs=input_token_logprobs,
405
+ input_top_logprobs_val=input_top_logprobs_val,
406
+ input_top_logprobs_idx=input_top_logprobs_idx,
407
+ hidden_states=hidden_states_to_store,
408
+ input_token_ids_logprobs_val=input_token_ids_logprobs_val,
409
+ input_token_ids_logprobs_idx=input_token_ids_logprobs_idx,
410
+ )
411
+
412
+ def _get_logits(
413
+ self,
414
+ hidden_states: torch.Tensor,
415
+ lm_head: VocabParallelEmbedding,
416
+ logits_metadata: LogitsMetadata,
417
+ embedding_bias: Optional[torch.Tensor] = None,
418
+ ) -> torch.Tensor:
419
+ """Get logits from hidden_states.
420
+
421
+ If sampled_logits_only is True, it means hidden_states only contain the
422
+ last position (e.g., extend without input logprobs). The caller should
423
+ guarantee the given hidden_states follow this constraint.
424
+ """
425
+ if self.do_tensor_parallel_all_gather_dp_attn:
426
+ logits_metadata.compute_dp_attention_metadata(hidden_states)
427
+ hidden_states, local_hidden_states = (
428
+ logits_metadata.gathered_buffer,
429
+ hidden_states.clone(),
430
+ )
431
+ dp_gather_replicate(hidden_states, local_hidden_states, logits_metadata)
432
+
433
+ if hasattr(lm_head, "weight"):
434
+ logits = torch.matmul(
435
+ hidden_states.to(lm_head.weight.dtype), lm_head.weight.T
436
+ )
437
+ else:
438
+ # GGUF models
439
+ logits = lm_head.quant_method.apply(lm_head, hidden_states, embedding_bias)
440
+
441
+ if self.logit_scale is not None:
442
+ logits.mul_(self.logit_scale)
443
+
444
+ if self.do_tensor_parallel_all_gather:
445
+ logits = tensor_model_parallel_all_gather(logits)
446
+
447
+ if self.do_tensor_parallel_all_gather_dp_attn:
448
+ logits, global_logits = (
449
+ torch.empty(
450
+ (local_hidden_states.shape[0], logits.shape[1]),
451
+ device=logits.device,
452
+ dtype=logits.dtype,
453
+ ),
454
+ logits,
455
+ )
456
+ dp_scatter(logits, global_logits, logits_metadata)
457
+
458
+ logits = logits[:, : self.config.vocab_size].float()
459
+
460
+ if self.final_logit_softcapping:
461
+ fused_softcap(logits, self.final_logit_softcapping)
462
+
463
+ return logits
464
+
465
+ @staticmethod
466
+ def get_top_logprobs(all_logprobs: torch.Tensor, logits_metadata: LogitsMetadata):
467
+ max_k = max(logits_metadata.top_logprobs_nums)
468
+ ret = all_logprobs.topk(max_k, dim=1)
469
+ values = ret.values.tolist()
470
+ indices = ret.indices.tolist()
471
+
472
+ input_top_logprobs_val, input_top_logprobs_idx = [], []
473
+
474
+ pt = 0
475
+ for k, pruned_len in zip(
476
+ logits_metadata.top_logprobs_nums,
477
+ logits_metadata.extend_logprob_pruned_lens_cpu,
478
+ ):
479
+ if pruned_len <= 0:
480
+ input_top_logprobs_val.append([])
481
+ input_top_logprobs_idx.append([])
482
+ continue
483
+
484
+ input_top_logprobs_val.append(
485
+ [values[pt + j][:k] for j in range(pruned_len)]
486
+ )
487
+ input_top_logprobs_idx.append(
488
+ [indices[pt + j][:k] for j in range(pruned_len)]
489
+ )
490
+ pt += pruned_len
491
+
492
+ return input_top_logprobs_val, input_top_logprobs_idx
493
+
494
+ @staticmethod
495
+ def get_token_ids_logprobs(
496
+ all_logprobs: torch.Tensor, logits_metadata: LogitsMetadata
497
+ ):
498
+ input_token_ids_logprobs_val, input_token_ids_logprobs_idx = [], []
499
+ pt = 0
500
+ for token_ids, pruned_len in zip(
501
+ logits_metadata.token_ids_logprobs,
502
+ logits_metadata.extend_logprob_pruned_lens_cpu,
503
+ ):
504
+ if pruned_len <= 0:
505
+ input_token_ids_logprobs_val.append([])
506
+ input_token_ids_logprobs_idx.append([])
507
+ continue
508
+
509
+ input_token_ids_logprobs_val.append(
510
+ [all_logprobs[pt + j, token_ids].tolist() for j in range(pruned_len)]
511
+ )
512
+ input_token_ids_logprobs_idx.append([token_ids for _ in range(pruned_len)])
513
+ pt += pruned_len
514
+
515
+ return input_token_ids_logprobs_val, input_token_ids_logprobs_idx
516
+
517
+ @staticmethod
518
+ def compute_temp_top_p_normalized_logprobs(
519
+ last_logits: torch.Tensor, logits_metadata: LogitsMetadata
520
+ ) -> torch.Tensor:
521
+ """
522
+ compute logprobs for the output token from the given logits.
523
+
524
+ Returns:
525
+ torch.Tensor: logprobs from logits
526
+ """
527
+ # Scale logits if temperature scaling is enabled
528
+ if logits_metadata.temp_scaled_logprobs:
529
+ last_logits = last_logits / logits_metadata.temperature
530
+
531
+ # Normalize logprobs if top_p normalization is enabled
532
+ # NOTE: only normalize logprobs when top_p is set and not equal to 1.0
533
+ if (
534
+ logits_metadata.top_p_normalized_logprobs
535
+ and (logits_metadata.top_p != 1.0).any()
536
+ ):
537
+ from sglang.srt.layers.sampler import top_p_normalize_probs_torch
538
+
539
+ probs = torch.softmax(last_logits, dim=-1)
540
+ del last_logits
541
+ probs = top_p_normalize_probs_torch(probs, logits_metadata.top_p)
542
+ return torch.log(probs)
543
+ else:
544
+ return torch.nn.functional.log_softmax(last_logits, dim=-1)
545
+
546
+
547
+ @triton.jit
548
+ def fused_softcap_kernel(
549
+ full_logits_ptr,
550
+ softcapping_value,
551
+ n_elements,
552
+ BLOCK_SIZE: tl.constexpr,
553
+ ):
554
+ pid = tl.program_id(0).to(tl.int64)
555
+ block_start = pid * BLOCK_SIZE
556
+ offsets = block_start + tl.arange(0, BLOCK_SIZE)
557
+ mask = offsets < n_elements
558
+
559
+ # Load values
560
+ x = tl.load(full_logits_ptr + offsets, mask=mask)
561
+
562
+ # Perform operations in-place
563
+ x = x / softcapping_value
564
+
565
+ # Manual tanh implementation using exp
566
+ exp2x = tl.exp(2 * x)
567
+ x = (exp2x - 1) / (exp2x + 1)
568
+
569
+ x = x * softcapping_value
570
+
571
+ # Store result
572
+ tl.store(full_logits_ptr + offsets, x, mask=mask)
573
+
574
+
575
+ def fused_softcap(full_logits, final_logit_softcapping):
576
+ n_elements = full_logits.numel()
577
+ BLOCK_SIZE = 1024
578
+ grid = ((n_elements + BLOCK_SIZE - 1) // BLOCK_SIZE, 1, 1)
579
+
580
+ fused_softcap_kernel[grid](
581
+ full_logits_ptr=full_logits,
582
+ softcapping_value=final_logit_softcapping,
583
+ n_elements=n_elements,
584
+ BLOCK_SIZE=BLOCK_SIZE,
585
+ )
586
+ return full_logits
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_native.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Torch-native implementation for FusedMoE. This is used for torch.compile.
3
+ It is based on https://github.com/pytorch-labs/gpt-fast/blob/32971d3129541c5bfb4f715abc33d1c5f408d204/mixtral-moe/model.py#L204
4
+ """
5
+
6
+ from typing import Callable, Optional
7
+
8
+ import torch
9
+ from torch.nn import functional as F
10
+
11
+ from sglang.srt.layers.activation import GeluAndMul, SiluAndMul
12
+ from sglang.srt.layers.moe.topk import select_experts
13
+
14
+
15
+ def fused_moe_forward_native(
16
+ layer: torch.nn.Module,
17
+ x: torch.Tensor,
18
+ use_grouped_topk: bool,
19
+ top_k: int,
20
+ router_logits: torch.Tensor,
21
+ renormalize: bool,
22
+ topk_group: Optional[int] = None,
23
+ num_expert_group: Optional[int] = None,
24
+ custom_routing_function: Optional[Callable] = None,
25
+ correction_bias: Optional[torch.Tensor] = None,
26
+ activation: str = "silu",
27
+ apply_router_weight_on_input: bool = False,
28
+ inplace: bool = True,
29
+ no_combine: bool = False,
30
+ routed_scaling_factor: Optional[float] = None,
31
+ ) -> torch.Tensor:
32
+
33
+ if apply_router_weight_on_input:
34
+ raise NotImplementedError()
35
+
36
+ topk_weights, topk_ids = select_experts(
37
+ hidden_states=x,
38
+ router_logits=router_logits,
39
+ use_grouped_topk=use_grouped_topk,
40
+ top_k=top_k,
41
+ renormalize=renormalize,
42
+ topk_group=topk_group,
43
+ num_expert_group=num_expert_group,
44
+ custom_routing_function=custom_routing_function,
45
+ correction_bias=correction_bias,
46
+ routed_scaling_factor=routed_scaling_factor,
47
+ torch_native=True,
48
+ )
49
+
50
+ w13_weights = layer.w13_weight[topk_ids]
51
+ w1_weights, w3_weights = torch.chunk(w13_weights, 2, dim=2)
52
+ w2_weights = layer.w2_weight[topk_ids]
53
+ x1 = torch.einsum("ti,taoi -> tao", x, w1_weights)
54
+ if activation == "silu":
55
+ x1 = F.silu(x1)
56
+ elif activation == "gelu":
57
+ x1 = F.gelu(x1)
58
+ else:
59
+ raise ValueError(f"Unsupported activation: {activation=}")
60
+ x3 = torch.einsum("ti, taoi -> tao", x, w3_weights)
61
+ expert_outs = torch.einsum("tao, taio -> tai", (x1 * x3), w2_weights)
62
+ return torch.einsum("tai,ta -> ti", expert_outs, topk_weights.to(expert_outs.dtype))
63
+
64
+
65
+ def moe_forward_native(
66
+ layer: torch.nn.Module,
67
+ x: torch.Tensor,
68
+ use_grouped_topk: bool,
69
+ top_k: int,
70
+ router_logits: torch.Tensor,
71
+ renormalize: bool,
72
+ topk_group: Optional[int] = None,
73
+ num_expert_group: Optional[int] = None,
74
+ custom_routing_function: Optional[Callable] = None,
75
+ correction_bias: Optional[torch.Tensor] = None,
76
+ activation: str = "silu",
77
+ routed_scaling_factor: Optional[float] = None,
78
+ ) -> torch.Tensor:
79
+ topk_weights, topk_ids = select_experts(
80
+ hidden_states=x,
81
+ router_logits=router_logits,
82
+ use_grouped_topk=use_grouped_topk,
83
+ top_k=top_k,
84
+ renormalize=renormalize,
85
+ topk_group=topk_group,
86
+ num_expert_group=num_expert_group,
87
+ custom_routing_function=custom_routing_function,
88
+ correction_bias=correction_bias,
89
+ torch_native=True,
90
+ routed_scaling_factor=routed_scaling_factor,
91
+ )
92
+
93
+ # Ref code from https://huggingface.co/deepseek-ai/DeepSeek-V2/blob/e0828e3cc0a03408724b80c3cc92c8e072db8d01/modeling_deepseek.py#L589
94
+ len_experts = layer.num_experts
95
+
96
+ cnts = topk_ids.new_zeros((topk_ids.shape[0], len_experts))
97
+ cnts.scatter_(1, topk_ids.to(torch.int64), 1)
98
+ tokens_per_expert = cnts.sum(dim=0)
99
+ idxs = topk_ids.view(-1).argsort()
100
+
101
+ sorted_tokens = x[idxs // topk_ids.shape[1]]
102
+ tokens_per_expert = tokens_per_expert.cpu().numpy()
103
+
104
+ if activation == "silu":
105
+ act = SiluAndMul()
106
+ elif activation == "gelu":
107
+ act = GeluAndMul()
108
+ else:
109
+ raise ValueError(f"Unsupported activation: {activation=}")
110
+
111
+ outputs = []
112
+ start_idx = 0
113
+ for i, num_tokens in enumerate(tokens_per_expert):
114
+ end_idx = start_idx + num_tokens
115
+ if num_tokens == 0:
116
+ continue
117
+ tokens_for_this_expert = sorted_tokens[start_idx:end_idx]
118
+
119
+ layer_w13_weight = layer.w13_weight[i]
120
+ layer_w2_weight = layer.w2_weight[i]
121
+
122
+ gate_up = F.linear(tokens_for_this_expert, layer_w13_weight)
123
+ gate_up = act(gate_up)
124
+ expert_out = F.linear(gate_up, layer_w2_weight)
125
+ outputs.append(expert_out)
126
+ start_idx = end_idx
127
+
128
+ outs = torch.cat(outputs, dim=0) if len(outputs) else sorted_tokens.new_empty(0)
129
+ new_x = torch.empty_like(outs)
130
+
131
+ new_x[idxs] = outs
132
+ final_out = (
133
+ new_x.view(*topk_ids.shape, -1)
134
+ .type(topk_weights.dtype)
135
+ .mul_(topk_weights.unsqueeze(dim=-1))
136
+ .sum(dim=1)
137
+ .type(new_x.dtype)
138
+ )
139
+ return final_out
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/__init__.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from contextlib import contextmanager
2
+ from typing import Any, Dict, Optional
3
+
4
+ import sglang.srt.layers.moe.fused_moe_triton.fused_moe # noqa
5
+ from sglang.srt.layers.moe.fused_moe_triton.fused_moe import (
6
+ fused_experts,
7
+ get_config_file_name,
8
+ )
9
+ from sglang.srt.layers.moe.fused_moe_triton.layer import (
10
+ FusedMoE,
11
+ FusedMoEMethodBase,
12
+ FusedMoeWeightScaleSupported,
13
+ )
14
+
15
+ _config: Optional[Dict[str, Any]] = None
16
+
17
+
18
+ @contextmanager
19
+ def override_config(config):
20
+ global _config
21
+ old_config = _config
22
+ _config = config
23
+ yield
24
+ _config = old_config
25
+
26
+
27
+ def get_config() -> Optional[Dict[str, Any]]:
28
+ return _config
29
+
30
+
31
+ __all__ = [
32
+ "FusedMoE",
33
+ "FusedMoEMethodBase",
34
+ "FusedMoeWeightScaleSupported",
35
+ "override_config",
36
+ "get_config",
37
+ "fused_moe",
38
+ "fused_experts",
39
+ "get_config_file_name",
40
+ ]
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=14336,device_name=NVIDIA_A100-SXM4-80GB,dtype=int8_w8a16.json ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "BLOCK_SIZE_M": 16,
4
+ "BLOCK_SIZE_N": 32,
5
+ "BLOCK_SIZE_K": 128,
6
+ "GROUP_SIZE_M": 1,
7
+ "num_warps": 4,
8
+ "num_stages": 4
9
+ },
10
+ "2": {
11
+ "BLOCK_SIZE_M": 16,
12
+ "BLOCK_SIZE_N": 32,
13
+ "BLOCK_SIZE_K": 128,
14
+ "GROUP_SIZE_M": 64,
15
+ "num_warps": 4,
16
+ "num_stages": 3
17
+ },
18
+ "4": {
19
+ "BLOCK_SIZE_M": 16,
20
+ "BLOCK_SIZE_N": 32,
21
+ "BLOCK_SIZE_K": 128,
22
+ "GROUP_SIZE_M": 1,
23
+ "num_warps": 4,
24
+ "num_stages": 4
25
+ },
26
+ "8": {
27
+ "BLOCK_SIZE_M": 16,
28
+ "BLOCK_SIZE_N": 32,
29
+ "BLOCK_SIZE_K": 256,
30
+ "GROUP_SIZE_M": 32,
31
+ "num_warps": 4,
32
+ "num_stages": 3
33
+ },
34
+ "16": {
35
+ "BLOCK_SIZE_M": 16,
36
+ "BLOCK_SIZE_N": 32,
37
+ "BLOCK_SIZE_K": 128,
38
+ "GROUP_SIZE_M": 1,
39
+ "num_warps": 4,
40
+ "num_stages": 4
41
+ },
42
+ "24": {
43
+ "BLOCK_SIZE_M": 16,
44
+ "BLOCK_SIZE_N": 64,
45
+ "BLOCK_SIZE_K": 64,
46
+ "GROUP_SIZE_M": 16,
47
+ "num_warps": 4,
48
+ "num_stages": 5
49
+ },
50
+ "32": {
51
+ "BLOCK_SIZE_M": 16,
52
+ "BLOCK_SIZE_N": 32,
53
+ "BLOCK_SIZE_K": 256,
54
+ "GROUP_SIZE_M": 1,
55
+ "num_warps": 4,
56
+ "num_stages": 2
57
+ },
58
+ "48": {
59
+ "BLOCK_SIZE_M": 64,
60
+ "BLOCK_SIZE_N": 64,
61
+ "BLOCK_SIZE_K": 64,
62
+ "GROUP_SIZE_M": 1,
63
+ "num_warps": 4,
64
+ "num_stages": 3
65
+ },
66
+ "64": {
67
+ "BLOCK_SIZE_M": 64,
68
+ "BLOCK_SIZE_N": 64,
69
+ "BLOCK_SIZE_K": 64,
70
+ "GROUP_SIZE_M": 1,
71
+ "num_warps": 4,
72
+ "num_stages": 3
73
+ },
74
+ "96": {
75
+ "BLOCK_SIZE_M": 32,
76
+ "BLOCK_SIZE_N": 128,
77
+ "BLOCK_SIZE_K": 128,
78
+ "GROUP_SIZE_M": 1,
79
+ "num_warps": 4,
80
+ "num_stages": 3
81
+ },
82
+ "128": {
83
+ "BLOCK_SIZE_M": 64,
84
+ "BLOCK_SIZE_N": 64,
85
+ "BLOCK_SIZE_K": 64,
86
+ "GROUP_SIZE_M": 16,
87
+ "num_warps": 4,
88
+ "num_stages": 3
89
+ },
90
+ "256": {
91
+ "BLOCK_SIZE_M": 64,
92
+ "BLOCK_SIZE_N": 64,
93
+ "BLOCK_SIZE_K": 64,
94
+ "GROUP_SIZE_M": 32,
95
+ "num_warps": 4,
96
+ "num_stages": 4
97
+ },
98
+ "512": {
99
+ "BLOCK_SIZE_M": 64,
100
+ "BLOCK_SIZE_N": 256,
101
+ "BLOCK_SIZE_K": 64,
102
+ "GROUP_SIZE_M": 32,
103
+ "num_warps": 4,
104
+ "num_stages": 4
105
+ },
106
+ "1024": {
107
+ "BLOCK_SIZE_M": 64,
108
+ "BLOCK_SIZE_N": 256,
109
+ "BLOCK_SIZE_K": 64,
110
+ "GROUP_SIZE_M": 64,
111
+ "num_warps": 4,
112
+ "num_stages": 4
113
+ },
114
+ "1536": {
115
+ "BLOCK_SIZE_M": 64,
116
+ "BLOCK_SIZE_N": 256,
117
+ "BLOCK_SIZE_K": 64,
118
+ "GROUP_SIZE_M": 64,
119
+ "num_warps": 4,
120
+ "num_stages": 4
121
+ },
122
+ "2048": {
123
+ "BLOCK_SIZE_M": 64,
124
+ "BLOCK_SIZE_N": 256,
125
+ "BLOCK_SIZE_K": 64,
126
+ "GROUP_SIZE_M": 32,
127
+ "num_warps": 4,
128
+ "num_stages": 4
129
+ },
130
+ "3072": {
131
+ "BLOCK_SIZE_M": 64,
132
+ "BLOCK_SIZE_N": 256,
133
+ "BLOCK_SIZE_K": 64,
134
+ "GROUP_SIZE_M": 32,
135
+ "num_warps": 4,
136
+ "num_stages": 4
137
+ },
138
+ "4096": {
139
+ "BLOCK_SIZE_M": 64,
140
+ "BLOCK_SIZE_N": 256,
141
+ "BLOCK_SIZE_K": 64,
142
+ "GROUP_SIZE_M": 16,
143
+ "num_warps": 4,
144
+ "num_stages": 4
145
+ }
146
+ }
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=14336,device_name=NVIDIA_A100-SXM4-80GB.json ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "BLOCK_SIZE_M": 16,
4
+ "BLOCK_SIZE_N": 64,
5
+ "BLOCK_SIZE_K": 256,
6
+ "GROUP_SIZE_M": 16,
7
+ "num_warps": 4,
8
+ "num_stages": 4
9
+ },
10
+ "2": {
11
+ "BLOCK_SIZE_M": 16,
12
+ "BLOCK_SIZE_N": 64,
13
+ "BLOCK_SIZE_K": 256,
14
+ "GROUP_SIZE_M": 32,
15
+ "num_warps": 4,
16
+ "num_stages": 4
17
+ },
18
+ "4": {
19
+ "BLOCK_SIZE_M": 16,
20
+ "BLOCK_SIZE_N": 64,
21
+ "BLOCK_SIZE_K": 256,
22
+ "GROUP_SIZE_M": 16,
23
+ "num_warps": 4,
24
+ "num_stages": 4
25
+ },
26
+ "8": {
27
+ "BLOCK_SIZE_M": 16,
28
+ "BLOCK_SIZE_N": 64,
29
+ "BLOCK_SIZE_K": 256,
30
+ "GROUP_SIZE_M": 32,
31
+ "num_warps": 4,
32
+ "num_stages": 4
33
+ },
34
+ "16": {
35
+ "BLOCK_SIZE_M": 16,
36
+ "BLOCK_SIZE_N": 64,
37
+ "BLOCK_SIZE_K": 256,
38
+ "GROUP_SIZE_M": 64,
39
+ "num_warps": 4,
40
+ "num_stages": 4
41
+ },
42
+ "24": {
43
+ "BLOCK_SIZE_M": 32,
44
+ "BLOCK_SIZE_N": 64,
45
+ "BLOCK_SIZE_K": 128,
46
+ "GROUP_SIZE_M": 16,
47
+ "num_warps": 4,
48
+ "num_stages": 5
49
+ },
50
+ "32": {
51
+ "BLOCK_SIZE_M": 32,
52
+ "BLOCK_SIZE_N": 64,
53
+ "BLOCK_SIZE_K": 128,
54
+ "GROUP_SIZE_M": 1,
55
+ "num_warps": 4,
56
+ "num_stages": 5
57
+ },
58
+ "48": {
59
+ "BLOCK_SIZE_M": 32,
60
+ "BLOCK_SIZE_N": 64,
61
+ "BLOCK_SIZE_K": 64,
62
+ "GROUP_SIZE_M": 16,
63
+ "num_warps": 4,
64
+ "num_stages": 5
65
+ },
66
+ "64": {
67
+ "BLOCK_SIZE_M": 64,
68
+ "BLOCK_SIZE_N": 64,
69
+ "BLOCK_SIZE_K": 128,
70
+ "GROUP_SIZE_M": 1,
71
+ "num_warps": 4,
72
+ "num_stages": 4
73
+ },
74
+ "96": {
75
+ "BLOCK_SIZE_M": 32,
76
+ "BLOCK_SIZE_N": 256,
77
+ "BLOCK_SIZE_K": 64,
78
+ "GROUP_SIZE_M": 16,
79
+ "num_warps": 4,
80
+ "num_stages": 5
81
+ },
82
+ "128": {
83
+ "BLOCK_SIZE_M": 64,
84
+ "BLOCK_SIZE_N": 128,
85
+ "BLOCK_SIZE_K": 64,
86
+ "GROUP_SIZE_M": 64,
87
+ "num_warps": 4,
88
+ "num_stages": 4
89
+ },
90
+ "256": {
91
+ "BLOCK_SIZE_M": 128,
92
+ "BLOCK_SIZE_N": 128,
93
+ "BLOCK_SIZE_K": 64,
94
+ "GROUP_SIZE_M": 16,
95
+ "num_warps": 8,
96
+ "num_stages": 4
97
+ },
98
+ "512": {
99
+ "BLOCK_SIZE_M": 128,
100
+ "BLOCK_SIZE_N": 128,
101
+ "BLOCK_SIZE_K": 64,
102
+ "GROUP_SIZE_M": 64,
103
+ "num_warps": 4,
104
+ "num_stages": 3
105
+ },
106
+ "1024": {
107
+ "BLOCK_SIZE_M": 128,
108
+ "BLOCK_SIZE_N": 128,
109
+ "BLOCK_SIZE_K": 64,
110
+ "GROUP_SIZE_M": 64,
111
+ "num_warps": 4,
112
+ "num_stages": 3
113
+ },
114
+ "1536": {
115
+ "BLOCK_SIZE_M": 128,
116
+ "BLOCK_SIZE_N": 128,
117
+ "BLOCK_SIZE_K": 64,
118
+ "GROUP_SIZE_M": 16,
119
+ "num_warps": 4,
120
+ "num_stages": 3
121
+ },
122
+ "2048": {
123
+ "BLOCK_SIZE_M": 128,
124
+ "BLOCK_SIZE_N": 128,
125
+ "BLOCK_SIZE_K": 64,
126
+ "GROUP_SIZE_M": 32,
127
+ "num_warps": 4,
128
+ "num_stages": 3
129
+ },
130
+ "3072": {
131
+ "BLOCK_SIZE_M": 128,
132
+ "BLOCK_SIZE_N": 128,
133
+ "BLOCK_SIZE_K": 64,
134
+ "GROUP_SIZE_M": 16,
135
+ "num_warps": 4,
136
+ "num_stages": 3
137
+ },
138
+ "4096": {
139
+ "BLOCK_SIZE_M": 128,
140
+ "BLOCK_SIZE_N": 128,
141
+ "BLOCK_SIZE_K": 64,
142
+ "GROUP_SIZE_M": 16,
143
+ "num_warps": 4,
144
+ "num_stages": 3
145
+ }
146
+ }
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=7168,device_name=NVIDIA_A100-SXM4-80GB,dtype=int8_w8a16.json ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "BLOCK_SIZE_M": 16,
4
+ "BLOCK_SIZE_N": 32,
5
+ "BLOCK_SIZE_K": 256,
6
+ "GROUP_SIZE_M": 16,
7
+ "num_warps": 4,
8
+ "num_stages": 3
9
+ },
10
+ "2": {
11
+ "BLOCK_SIZE_M": 16,
12
+ "BLOCK_SIZE_N": 32,
13
+ "BLOCK_SIZE_K": 256,
14
+ "GROUP_SIZE_M": 16,
15
+ "num_warps": 4,
16
+ "num_stages": 3
17
+ },
18
+ "4": {
19
+ "BLOCK_SIZE_M": 16,
20
+ "BLOCK_SIZE_N": 32,
21
+ "BLOCK_SIZE_K": 256,
22
+ "GROUP_SIZE_M": 16,
23
+ "num_warps": 4,
24
+ "num_stages": 3
25
+ },
26
+ "8": {
27
+ "BLOCK_SIZE_M": 16,
28
+ "BLOCK_SIZE_N": 32,
29
+ "BLOCK_SIZE_K": 256,
30
+ "GROUP_SIZE_M": 32,
31
+ "num_warps": 4,
32
+ "num_stages": 3
33
+ },
34
+ "16": {
35
+ "BLOCK_SIZE_M": 16,
36
+ "BLOCK_SIZE_N": 32,
37
+ "BLOCK_SIZE_K": 256,
38
+ "GROUP_SIZE_M": 32,
39
+ "num_warps": 4,
40
+ "num_stages": 3
41
+ },
42
+ "24": {
43
+ "BLOCK_SIZE_M": 16,
44
+ "BLOCK_SIZE_N": 32,
45
+ "BLOCK_SIZE_K": 256,
46
+ "GROUP_SIZE_M": 1,
47
+ "num_warps": 4,
48
+ "num_stages": 3
49
+ },
50
+ "32": {
51
+ "BLOCK_SIZE_M": 16,
52
+ "BLOCK_SIZE_N": 32,
53
+ "BLOCK_SIZE_K": 256,
54
+ "GROUP_SIZE_M": 1,
55
+ "num_warps": 4,
56
+ "num_stages": 3
57
+ },
58
+ "48": {
59
+ "BLOCK_SIZE_M": 16,
60
+ "BLOCK_SIZE_N": 32,
61
+ "BLOCK_SIZE_K": 128,
62
+ "GROUP_SIZE_M": 1,
63
+ "num_warps": 4,
64
+ "num_stages": 3
65
+ },
66
+ "64": {
67
+ "BLOCK_SIZE_M": 32,
68
+ "BLOCK_SIZE_N": 128,
69
+ "BLOCK_SIZE_K": 128,
70
+ "GROUP_SIZE_M": 1,
71
+ "num_warps": 4,
72
+ "num_stages": 3
73
+ },
74
+ "96": {
75
+ "BLOCK_SIZE_M": 32,
76
+ "BLOCK_SIZE_N": 128,
77
+ "BLOCK_SIZE_K": 128,
78
+ "GROUP_SIZE_M": 1,
79
+ "num_warps": 4,
80
+ "num_stages": 3
81
+ },
82
+ "128": {
83
+ "BLOCK_SIZE_M": 128,
84
+ "BLOCK_SIZE_N": 32,
85
+ "BLOCK_SIZE_K": 128,
86
+ "GROUP_SIZE_M": 1,
87
+ "num_warps": 4,
88
+ "num_stages": 3
89
+ },
90
+ "256": {
91
+ "BLOCK_SIZE_M": 64,
92
+ "BLOCK_SIZE_N": 64,
93
+ "BLOCK_SIZE_K": 64,
94
+ "GROUP_SIZE_M": 1,
95
+ "num_warps": 4,
96
+ "num_stages": 3
97
+ },
98
+ "512": {
99
+ "BLOCK_SIZE_M": 64,
100
+ "BLOCK_SIZE_N": 256,
101
+ "BLOCK_SIZE_K": 64,
102
+ "GROUP_SIZE_M": 16,
103
+ "num_warps": 4,
104
+ "num_stages": 4
105
+ },
106
+ "1024": {
107
+ "BLOCK_SIZE_M": 64,
108
+ "BLOCK_SIZE_N": 256,
109
+ "BLOCK_SIZE_K": 64,
110
+ "GROUP_SIZE_M": 16,
111
+ "num_warps": 4,
112
+ "num_stages": 4
113
+ },
114
+ "1536": {
115
+ "BLOCK_SIZE_M": 64,
116
+ "BLOCK_SIZE_N": 256,
117
+ "BLOCK_SIZE_K": 64,
118
+ "GROUP_SIZE_M": 32,
119
+ "num_warps": 4,
120
+ "num_stages": 4
121
+ },
122
+ "2048": {
123
+ "BLOCK_SIZE_M": 64,
124
+ "BLOCK_SIZE_N": 256,
125
+ "BLOCK_SIZE_K": 64,
126
+ "GROUP_SIZE_M": 32,
127
+ "num_warps": 4,
128
+ "num_stages": 4
129
+ },
130
+ "3072": {
131
+ "BLOCK_SIZE_M": 64,
132
+ "BLOCK_SIZE_N": 256,
133
+ "BLOCK_SIZE_K": 64,
134
+ "GROUP_SIZE_M": 64,
135
+ "num_warps": 4,
136
+ "num_stages": 4
137
+ },
138
+ "4096": {
139
+ "BLOCK_SIZE_M": 64,
140
+ "BLOCK_SIZE_N": 256,
141
+ "BLOCK_SIZE_K": 64,
142
+ "GROUP_SIZE_M": 32,
143
+ "num_warps": 4,
144
+ "num_stages": 4
145
+ },
146
+ "5120": {
147
+ "BLOCK_SIZE_M": 64,
148
+ "BLOCK_SIZE_N": 256,
149
+ "BLOCK_SIZE_K": 64,
150
+ "GROUP_SIZE_M": 32,
151
+ "num_warps": 4,
152
+ "num_stages": 4
153
+ },
154
+ "9216": {
155
+ "BLOCK_SIZE_M": 64,
156
+ "BLOCK_SIZE_N": 256,
157
+ "BLOCK_SIZE_K": 64,
158
+ "GROUP_SIZE_M": 32,
159
+ "num_warps": 4,
160
+ "num_stages": 3
161
+ },
162
+ "13312": {
163
+ "BLOCK_SIZE_M": 64,
164
+ "BLOCK_SIZE_N": 256,
165
+ "BLOCK_SIZE_K": 64,
166
+ "GROUP_SIZE_M": 16,
167
+ "num_warps": 4,
168
+ "num_stages": 4
169
+ },
170
+ "17408": {
171
+ "BLOCK_SIZE_M": 64,
172
+ "BLOCK_SIZE_N": 256,
173
+ "BLOCK_SIZE_K": 64,
174
+ "GROUP_SIZE_M": 16,
175
+ "num_warps": 4,
176
+ "num_stages": 4
177
+ },
178
+ "25600": {
179
+ "BLOCK_SIZE_M": 64,
180
+ "BLOCK_SIZE_N": 256,
181
+ "BLOCK_SIZE_K": 64,
182
+ "GROUP_SIZE_M": 16,
183
+ "num_warps": 4,
184
+ "num_stages": 4
185
+ },
186
+ "33792": {
187
+ "BLOCK_SIZE_M": 64,
188
+ "BLOCK_SIZE_N": 256,
189
+ "BLOCK_SIZE_K": 64,
190
+ "GROUP_SIZE_M": 16,
191
+ "num_warps": 4,
192
+ "num_stages": 4
193
+ },
194
+ "41984": {
195
+ "BLOCK_SIZE_M": 64,
196
+ "BLOCK_SIZE_N": 256,
197
+ "BLOCK_SIZE_K": 64,
198
+ "GROUP_SIZE_M": 16,
199
+ "num_warps": 4,
200
+ "num_stages": 4
201
+ },
202
+ "50176": {
203
+ "BLOCK_SIZE_M": 64,
204
+ "BLOCK_SIZE_N": 256,
205
+ "BLOCK_SIZE_K": 64,
206
+ "GROUP_SIZE_M": 16,
207
+ "num_warps": 4,
208
+ "num_stages": 4
209
+ },
210
+ "58368": {
211
+ "BLOCK_SIZE_M": 64,
212
+ "BLOCK_SIZE_N": 256,
213
+ "BLOCK_SIZE_K": 64,
214
+ "GROUP_SIZE_M": 16,
215
+ "num_warps": 4,
216
+ "num_stages": 4
217
+ }
218
+ }
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=1,N=7168,device_name=NVIDIA_A100-SXM4-80GB.json ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "BLOCK_SIZE_M": 16,
4
+ "BLOCK_SIZE_N": 64,
5
+ "BLOCK_SIZE_K": 64,
6
+ "GROUP_SIZE_M": 32,
7
+ "num_warps": 4,
8
+ "num_stages": 5
9
+ },
10
+ "2": {
11
+ "BLOCK_SIZE_M": 16,
12
+ "BLOCK_SIZE_N": 64,
13
+ "BLOCK_SIZE_K": 256,
14
+ "GROUP_SIZE_M": 1,
15
+ "num_warps": 4,
16
+ "num_stages": 4
17
+ },
18
+ "4": {
19
+ "BLOCK_SIZE_M": 16,
20
+ "BLOCK_SIZE_N": 64,
21
+ "BLOCK_SIZE_K": 256,
22
+ "GROUP_SIZE_M": 32,
23
+ "num_warps": 4,
24
+ "num_stages": 4
25
+ },
26
+ "8": {
27
+ "BLOCK_SIZE_M": 16,
28
+ "BLOCK_SIZE_N": 64,
29
+ "BLOCK_SIZE_K": 256,
30
+ "GROUP_SIZE_M": 32,
31
+ "num_warps": 4,
32
+ "num_stages": 4
33
+ },
34
+ "16": {
35
+ "BLOCK_SIZE_M": 16,
36
+ "BLOCK_SIZE_N": 64,
37
+ "BLOCK_SIZE_K": 256,
38
+ "GROUP_SIZE_M": 64,
39
+ "num_warps": 4,
40
+ "num_stages": 4
41
+ },
42
+ "24": {
43
+ "BLOCK_SIZE_M": 32,
44
+ "BLOCK_SIZE_N": 64,
45
+ "BLOCK_SIZE_K": 64,
46
+ "GROUP_SIZE_M": 1,
47
+ "num_warps": 4,
48
+ "num_stages": 5
49
+ },
50
+ "32": {
51
+ "BLOCK_SIZE_M": 32,
52
+ "BLOCK_SIZE_N": 64,
53
+ "BLOCK_SIZE_K": 64,
54
+ "GROUP_SIZE_M": 1,
55
+ "num_warps": 4,
56
+ "num_stages": 5
57
+ },
58
+ "48": {
59
+ "BLOCK_SIZE_M": 64,
60
+ "BLOCK_SIZE_N": 64,
61
+ "BLOCK_SIZE_K": 64,
62
+ "GROUP_SIZE_M": 1,
63
+ "num_warps": 4,
64
+ "num_stages": 4
65
+ },
66
+ "64": {
67
+ "BLOCK_SIZE_M": 64,
68
+ "BLOCK_SIZE_N": 64,
69
+ "BLOCK_SIZE_K": 128,
70
+ "GROUP_SIZE_M": 32,
71
+ "num_warps": 4,
72
+ "num_stages": 4
73
+ },
74
+ "96": {
75
+ "BLOCK_SIZE_M": 64,
76
+ "BLOCK_SIZE_N": 128,
77
+ "BLOCK_SIZE_K": 64,
78
+ "GROUP_SIZE_M": 64,
79
+ "num_warps": 4,
80
+ "num_stages": 4
81
+ },
82
+ "128": {
83
+ "BLOCK_SIZE_M": 64,
84
+ "BLOCK_SIZE_N": 128,
85
+ "BLOCK_SIZE_K": 64,
86
+ "GROUP_SIZE_M": 64,
87
+ "num_warps": 4,
88
+ "num_stages": 4
89
+ },
90
+ "256": {
91
+ "BLOCK_SIZE_M": 64,
92
+ "BLOCK_SIZE_N": 256,
93
+ "BLOCK_SIZE_K": 128,
94
+ "GROUP_SIZE_M": 1,
95
+ "num_warps": 8,
96
+ "num_stages": 3
97
+ },
98
+ "512": {
99
+ "BLOCK_SIZE_M": 64,
100
+ "BLOCK_SIZE_N": 128,
101
+ "BLOCK_SIZE_K": 64,
102
+ "GROUP_SIZE_M": 16,
103
+ "num_warps": 4,
104
+ "num_stages": 3
105
+ },
106
+ "1024": {
107
+ "BLOCK_SIZE_M": 128,
108
+ "BLOCK_SIZE_N": 128,
109
+ "BLOCK_SIZE_K": 64,
110
+ "GROUP_SIZE_M": 32,
111
+ "num_warps": 8,
112
+ "num_stages": 4
113
+ },
114
+ "1536": {
115
+ "BLOCK_SIZE_M": 128,
116
+ "BLOCK_SIZE_N": 128,
117
+ "BLOCK_SIZE_K": 64,
118
+ "GROUP_SIZE_M": 32,
119
+ "num_warps": 4,
120
+ "num_stages": 3
121
+ },
122
+ "2048": {
123
+ "BLOCK_SIZE_M": 128,
124
+ "BLOCK_SIZE_N": 128,
125
+ "BLOCK_SIZE_K": 64,
126
+ "GROUP_SIZE_M": 16,
127
+ "num_warps": 4,
128
+ "num_stages": 3
129
+ },
130
+ "3072": {
131
+ "BLOCK_SIZE_M": 128,
132
+ "BLOCK_SIZE_N": 128,
133
+ "BLOCK_SIZE_K": 64,
134
+ "GROUP_SIZE_M": 16,
135
+ "num_warps": 4,
136
+ "num_stages": 3
137
+ },
138
+ "4096": {
139
+ "BLOCK_SIZE_M": 128,
140
+ "BLOCK_SIZE_N": 128,
141
+ "BLOCK_SIZE_K": 64,
142
+ "GROUP_SIZE_M": 16,
143
+ "num_warps": 4,
144
+ "num_stages": 3
145
+ },
146
+ "5120": {
147
+ "BLOCK_SIZE_M": 128,
148
+ "BLOCK_SIZE_N": 128,
149
+ "BLOCK_SIZE_K": 64,
150
+ "GROUP_SIZE_M": 16,
151
+ "num_warps": 4,
152
+ "num_stages": 3
153
+ },
154
+ "9216": {
155
+ "BLOCK_SIZE_M": 128,
156
+ "BLOCK_SIZE_N": 128,
157
+ "BLOCK_SIZE_K": 64,
158
+ "GROUP_SIZE_M": 16,
159
+ "num_warps": 4,
160
+ "num_stages": 3
161
+ },
162
+ "13312": {
163
+ "BLOCK_SIZE_M": 128,
164
+ "BLOCK_SIZE_N": 128,
165
+ "BLOCK_SIZE_K": 64,
166
+ "GROUP_SIZE_M": 16,
167
+ "num_warps": 4,
168
+ "num_stages": 3
169
+ },
170
+ "17408": {
171
+ "BLOCK_SIZE_M": 128,
172
+ "BLOCK_SIZE_N": 128,
173
+ "BLOCK_SIZE_K": 64,
174
+ "GROUP_SIZE_M": 16,
175
+ "num_warps": 4,
176
+ "num_stages": 3
177
+ },
178
+ "25600": {
179
+ "BLOCK_SIZE_M": 128,
180
+ "BLOCK_SIZE_N": 128,
181
+ "BLOCK_SIZE_K": 64,
182
+ "GROUP_SIZE_M": 16,
183
+ "num_warps": 4,
184
+ "num_stages": 3
185
+ },
186
+ "33792": {
187
+ "BLOCK_SIZE_M": 128,
188
+ "BLOCK_SIZE_N": 128,
189
+ "BLOCK_SIZE_K": 64,
190
+ "GROUP_SIZE_M": 16,
191
+ "num_warps": 4,
192
+ "num_stages": 3
193
+ },
194
+ "41984": {
195
+ "BLOCK_SIZE_M": 128,
196
+ "BLOCK_SIZE_N": 128,
197
+ "BLOCK_SIZE_K": 64,
198
+ "GROUP_SIZE_M": 16,
199
+ "num_warps": 4,
200
+ "num_stages": 3
201
+ },
202
+ "50176": {
203
+ "BLOCK_SIZE_M": 128,
204
+ "BLOCK_SIZE_N": 128,
205
+ "BLOCK_SIZE_K": 64,
206
+ "GROUP_SIZE_M": 16,
207
+ "num_warps": 4,
208
+ "num_stages": 3
209
+ },
210
+ "58368": {
211
+ "BLOCK_SIZE_M": 128,
212
+ "BLOCK_SIZE_N": 128,
213
+ "BLOCK_SIZE_K": 64,
214
+ "GROUP_SIZE_M": 16,
215
+ "num_warps": 4,
216
+ "num_stages": 3
217
+ }
218
+ }
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=128,N=192,device_name=NVIDIA_H20.json ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "BLOCK_SIZE_M": 16,
4
+ "BLOCK_SIZE_N": 64,
5
+ "BLOCK_SIZE_K": 64,
6
+ "GROUP_SIZE_M": 1,
7
+ "num_warps": 4,
8
+ "num_stages": 5
9
+ },
10
+ "2": {
11
+ "BLOCK_SIZE_M": 16,
12
+ "BLOCK_SIZE_N": 128,
13
+ "BLOCK_SIZE_K": 64,
14
+ "GROUP_SIZE_M": 16,
15
+ "num_warps": 4,
16
+ "num_stages": 5
17
+ },
18
+ "4": {
19
+ "BLOCK_SIZE_M": 16,
20
+ "BLOCK_SIZE_N": 64,
21
+ "BLOCK_SIZE_K": 64,
22
+ "GROUP_SIZE_M": 32,
23
+ "num_warps": 4,
24
+ "num_stages": 4
25
+ },
26
+ "8": {
27
+ "BLOCK_SIZE_M": 16,
28
+ "BLOCK_SIZE_N": 128,
29
+ "BLOCK_SIZE_K": 64,
30
+ "GROUP_SIZE_M": 1,
31
+ "num_warps": 4,
32
+ "num_stages": 4
33
+ },
34
+ "16": {
35
+ "BLOCK_SIZE_M": 16,
36
+ "BLOCK_SIZE_N": 128,
37
+ "BLOCK_SIZE_K": 64,
38
+ "GROUP_SIZE_M": 16,
39
+ "num_warps": 4,
40
+ "num_stages": 3
41
+ },
42
+ "24": {
43
+ "BLOCK_SIZE_M": 16,
44
+ "BLOCK_SIZE_N": 128,
45
+ "BLOCK_SIZE_K": 64,
46
+ "GROUP_SIZE_M": 32,
47
+ "num_warps": 4,
48
+ "num_stages": 3
49
+ },
50
+ "32": {
51
+ "BLOCK_SIZE_M": 16,
52
+ "BLOCK_SIZE_N": 128,
53
+ "BLOCK_SIZE_K": 64,
54
+ "GROUP_SIZE_M": 64,
55
+ "num_warps": 4,
56
+ "num_stages": 3
57
+ },
58
+ "48": {
59
+ "BLOCK_SIZE_M": 16,
60
+ "BLOCK_SIZE_N": 128,
61
+ "BLOCK_SIZE_K": 64,
62
+ "GROUP_SIZE_M": 32,
63
+ "num_warps": 4,
64
+ "num_stages": 3
65
+ },
66
+ "64": {
67
+ "BLOCK_SIZE_M": 16,
68
+ "BLOCK_SIZE_N": 128,
69
+ "BLOCK_SIZE_K": 64,
70
+ "GROUP_SIZE_M": 1,
71
+ "num_warps": 4,
72
+ "num_stages": 3
73
+ },
74
+ "96": {
75
+ "BLOCK_SIZE_M": 16,
76
+ "BLOCK_SIZE_N": 128,
77
+ "BLOCK_SIZE_K": 64,
78
+ "GROUP_SIZE_M": 1,
79
+ "num_warps": 4,
80
+ "num_stages": 3
81
+ },
82
+ "128": {
83
+ "BLOCK_SIZE_M": 16,
84
+ "BLOCK_SIZE_N": 128,
85
+ "BLOCK_SIZE_K": 64,
86
+ "GROUP_SIZE_M": 1,
87
+ "num_warps": 4,
88
+ "num_stages": 3
89
+ },
90
+ "256": {
91
+ "BLOCK_SIZE_M": 16,
92
+ "BLOCK_SIZE_N": 128,
93
+ "BLOCK_SIZE_K": 64,
94
+ "GROUP_SIZE_M": 32,
95
+ "num_warps": 4,
96
+ "num_stages": 3
97
+ },
98
+ "512": {
99
+ "BLOCK_SIZE_M": 64,
100
+ "BLOCK_SIZE_N": 128,
101
+ "BLOCK_SIZE_K": 64,
102
+ "GROUP_SIZE_M": 1,
103
+ "num_warps": 8,
104
+ "num_stages": 3
105
+ },
106
+ "1024": {
107
+ "BLOCK_SIZE_M": 64,
108
+ "BLOCK_SIZE_N": 128,
109
+ "BLOCK_SIZE_K": 64,
110
+ "GROUP_SIZE_M": 16,
111
+ "num_warps": 4,
112
+ "num_stages": 3
113
+ },
114
+ "1536": {
115
+ "BLOCK_SIZE_M": 64,
116
+ "BLOCK_SIZE_N": 128,
117
+ "BLOCK_SIZE_K": 64,
118
+ "GROUP_SIZE_M": 32,
119
+ "num_warps": 4,
120
+ "num_stages": 3
121
+ },
122
+ "2048": {
123
+ "BLOCK_SIZE_M": 64,
124
+ "BLOCK_SIZE_N": 128,
125
+ "BLOCK_SIZE_K": 64,
126
+ "GROUP_SIZE_M": 1,
127
+ "num_warps": 4,
128
+ "num_stages": 3
129
+ },
130
+ "3072": {
131
+ "BLOCK_SIZE_M": 64,
132
+ "BLOCK_SIZE_N": 64,
133
+ "BLOCK_SIZE_K": 64,
134
+ "GROUP_SIZE_M": 16,
135
+ "num_warps": 4,
136
+ "num_stages": 2
137
+ },
138
+ "4096": {
139
+ "BLOCK_SIZE_M": 64,
140
+ "BLOCK_SIZE_N": 128,
141
+ "BLOCK_SIZE_K": 64,
142
+ "GROUP_SIZE_M": 1,
143
+ "num_warps": 4,
144
+ "num_stages": 2
145
+ }
146
+ }
lib/python3.12/site-packages/sglang/srt/layers/moe/fused_moe_triton/configs/E=128,N=384,device_name=NVIDIA_H20.json ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "1": {
3
+ "BLOCK_SIZE_M": 16,
4
+ "BLOCK_SIZE_N": 64,
5
+ "BLOCK_SIZE_K": 64,
6
+ "GROUP_SIZE_M": 1,
7
+ "num_warps": 4,
8
+ "num_stages": 4
9
+ },
10
+ "2": {
11
+ "BLOCK_SIZE_M": 16,
12
+ "BLOCK_SIZE_N": 64,
13
+ "BLOCK_SIZE_K": 64,
14
+ "GROUP_SIZE_M": 1,
15
+ "num_warps": 4,
16
+ "num_stages": 4
17
+ },
18
+ "4": {
19
+ "BLOCK_SIZE_M": 16,
20
+ "BLOCK_SIZE_N": 64,
21
+ "BLOCK_SIZE_K": 64,
22
+ "GROUP_SIZE_M": 64,
23
+ "num_warps": 4,
24
+ "num_stages": 5
25
+ },
26
+ "8": {
27
+ "BLOCK_SIZE_M": 16,
28
+ "BLOCK_SIZE_N": 128,
29
+ "BLOCK_SIZE_K": 64,
30
+ "GROUP_SIZE_M": 1,
31
+ "num_warps": 4,
32
+ "num_stages": 3
33
+ },
34
+ "16": {
35
+ "BLOCK_SIZE_M": 16,
36
+ "BLOCK_SIZE_N": 64,
37
+ "BLOCK_SIZE_K": 64,
38
+ "GROUP_SIZE_M": 1,
39
+ "num_warps": 4,
40
+ "num_stages": 4
41
+ },
42
+ "24": {
43
+ "BLOCK_SIZE_M": 16,
44
+ "BLOCK_SIZE_N": 64,
45
+ "BLOCK_SIZE_K": 64,
46
+ "GROUP_SIZE_M": 16,
47
+ "num_warps": 4,
48
+ "num_stages": 3
49
+ },
50
+ "32": {
51
+ "BLOCK_SIZE_M": 16,
52
+ "BLOCK_SIZE_N": 128,
53
+ "BLOCK_SIZE_K": 64,
54
+ "GROUP_SIZE_M": 32,
55
+ "num_warps": 4,
56
+ "num_stages": 3
57
+ },
58
+ "48": {
59
+ "BLOCK_SIZE_M": 16,
60
+ "BLOCK_SIZE_N": 64,
61
+ "BLOCK_SIZE_K": 128,
62
+ "GROUP_SIZE_M": 1,
63
+ "num_warps": 4,
64
+ "num_stages": 3
65
+ },
66
+ "64": {
67
+ "BLOCK_SIZE_M": 16,
68
+ "BLOCK_SIZE_N": 64,
69
+ "BLOCK_SIZE_K": 64,
70
+ "GROUP_SIZE_M": 1,
71
+ "num_warps": 4,
72
+ "num_stages": 4
73
+ },
74
+ "96": {
75
+ "BLOCK_SIZE_M": 16,
76
+ "BLOCK_SIZE_N": 128,
77
+ "BLOCK_SIZE_K": 64,
78
+ "GROUP_SIZE_M": 1,
79
+ "num_warps": 4,
80
+ "num_stages": 3
81
+ },
82
+ "128": {
83
+ "BLOCK_SIZE_M": 16,
84
+ "BLOCK_SIZE_N": 128,
85
+ "BLOCK_SIZE_K": 64,
86
+ "GROUP_SIZE_M": 1,
87
+ "num_warps": 4,
88
+ "num_stages": 3
89
+ },
90
+ "256": {
91
+ "BLOCK_SIZE_M": 16,
92
+ "BLOCK_SIZE_N": 128,
93
+ "BLOCK_SIZE_K": 64,
94
+ "GROUP_SIZE_M": 16,
95
+ "num_warps": 4,
96
+ "num_stages": 3
97
+ },
98
+ "512": {
99
+ "BLOCK_SIZE_M": 64,
100
+ "BLOCK_SIZE_N": 128,
101
+ "BLOCK_SIZE_K": 64,
102
+ "GROUP_SIZE_M": 1,
103
+ "num_warps": 8,
104
+ "num_stages": 3
105
+ },
106
+ "1024": {
107
+ "BLOCK_SIZE_M": 64,
108
+ "BLOCK_SIZE_N": 64,
109
+ "BLOCK_SIZE_K": 64,
110
+ "GROUP_SIZE_M": 64,
111
+ "num_warps": 4,
112
+ "num_stages": 4
113
+ },
114
+ "1536": {
115
+ "BLOCK_SIZE_M": 64,
116
+ "BLOCK_SIZE_N": 128,
117
+ "BLOCK_SIZE_K": 64,
118
+ "GROUP_SIZE_M": 1,
119
+ "num_warps": 4,
120
+ "num_stages": 3
121
+ },
122
+ "2048": {
123
+ "BLOCK_SIZE_M": 64,
124
+ "BLOCK_SIZE_N": 64,
125
+ "BLOCK_SIZE_K": 64,
126
+ "GROUP_SIZE_M": 1,
127
+ "num_warps": 4,
128
+ "num_stages": 3
129
+ },
130
+ "3072": {
131
+ "BLOCK_SIZE_M": 64,
132
+ "BLOCK_SIZE_N": 64,
133
+ "BLOCK_SIZE_K": 64,
134
+ "GROUP_SIZE_M": 32,
135
+ "num_warps": 4,
136
+ "num_stages": 3
137
+ },
138
+ "4096": {
139
+ "BLOCK_SIZE_M": 64,
140
+ "BLOCK_SIZE_N": 128,
141
+ "BLOCK_SIZE_K": 64,
142
+ "GROUP_SIZE_M": 64,
143
+ "num_warps": 4,
144
+ "num_stages": 4
145
+ }
146
+ }