main
py 510 lines 17.3 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 from collections.abc import Iterable
4
5 import torch
6 from torch import nn
7 from transformers import ModernBertConfig
8 from transformers.activations import ACT2FN
9
10 from vllm.compilation.decorators import support_torch_compile
11 from vllm.config import ModelConfig, VllmConfig
12 from vllm.distributed import get_tensor_model_parallel_world_size
13 from vllm.model_executor.layers.attention import (
14 EncoderOnlyAttention,
15 )
16 from vllm.model_executor.layers.linear import (
17 MergedColumnParallelLinear,
18 QKVParallelLinear,
19 RowParallelLinear,
20 )
21 from vllm.model_executor.layers.pooler import DispatchPooler
22 from vllm.model_executor.layers.pooler.seqwise import (
23 EmbeddingPoolerHead,
24 SequencePooler,
25 get_seq_pooling_method,
26 )
27 from vllm.model_executor.layers.pooler.tokwise import pooler_for_token_classify
28 from vllm.model_executor.layers.quantization import QuantizationConfig
29 from vllm.model_executor.layers.rotary_embedding import get_rope
30 from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
31 from vllm.model_executor.model_loader.weight_utils import default_weight_loader
32 from vllm.sequence import IntermediateTensors
33
34 from .interfaces import SupportsCrossEncoding, SupportsLoRA
35 from .interfaces_base import attn_type, default_pooling_type
36 from .utils import AutoWeightsLoader, WeightsMapper, maybe_prefix
37
38
39 class ModernBertEmbeddings(nn.Module):
40 def __init__(self, config: ModernBertConfig):
41 super().__init__()
42 self.config = config
43 self.tok_embeddings = VocabParallelEmbedding(
44 config.vocab_size, config.hidden_size
45 )
46 eps = (
47 getattr(config, "norm_eps", None)
48 or getattr(config, "layer_norm_eps", None)
49 or 1e-5
50 )
51 self.norm = nn.LayerNorm(config.hidden_size, eps=eps, bias=config.norm_bias)
52
53 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
54 return self.tok_embeddings(input_ids)
55
56 def forward(
57 self,
58 input_ids: torch.Tensor,
59 inputs_embeds: torch.Tensor | None = None,
60 ) -> torch.Tensor:
61 if inputs_embeds is None:
62 inputs_embeds = self.tok_embeddings(input_ids)
63
64 embeddings = self.norm(inputs_embeds)
65 return embeddings
66
67
68 class ModernBertAttention(nn.Module):
69 def __init__(
70 self,
71 config: ModernBertConfig,
72 layer_id: int | None = None,
73 prefix: str = "",
74 dtype: torch.dtype | None = None,
75 quant_config: QuantizationConfig | None = None,
76 ):
77 super().__init__()
78 self.config = config
79 self.hidden_size = config.hidden_size
80 tp_size = get_tensor_model_parallel_world_size()
81 self.layer_id = layer_id
82 self.deterministic_flash_attn = config.deterministic_flash_attn
83 self.num_heads = config.num_attention_heads
84 assert self.num_heads % tp_size == 0
85 self.head_dim = config.hidden_size // config.num_attention_heads
86 self.all_head_size = self.head_dim * self.num_heads
87 self.scaling = self.head_dim**-0.5
88 self.Wqkv = QKVParallelLinear(
89 config.hidden_size,
90 self.head_dim,
91 self.num_heads,
92 bias=config.attention_bias,
93 quant_config=quant_config,
94 prefix=f"{prefix}.Wqkv",
95 )
96
97 if layer_types := getattr(config, "layer_types", None):
98 # Transformers v5
99 layer_type = layer_types[layer_id]
100 rope_parameters = config.rope_parameters[layer_type]
101 sliding_window: int | None = None
102 if layer_type == "sliding_attention":
103 # Treats the local attention boundary as inclusive
104 sliding_window = config.sliding_window + 1
105 else:
106 # Transformers v4
107 sliding_window = None
108 if layer_id % config.global_attn_every_n_layers != 0:
109 # ModernBertConfig does not expose sliding_window
110 sliding_window = config.local_attention // 2
111 rope_theta = (
112 config.local_rope_theta
113 if config.local_rope_theta is not None
114 else config.global_rope_theta
115 )
116 else:
117 rope_theta = config.global_rope_theta
118 rope_parameters = {"rope_type": "default", "rope_theta": rope_theta}
119
120 self.rotary_emb = get_rope(
121 head_size=self.head_dim,
122 max_position=config.max_position_embeddings,
123 rope_parameters=rope_parameters,
124 dtype=dtype,
125 )
126 self.attn = EncoderOnlyAttention(
127 self.num_heads,
128 self.head_dim,
129 self.scaling,
130 prefix=f"{layer_id}.attn",
131 per_layer_sliding_window=sliding_window,
132 )
133 self.Wo = RowParallelLinear(
134 config.hidden_size,
135 config.hidden_size,
136 bias=config.attention_bias,
137 quant_config=quant_config,
138 prefix=f"{prefix}.Wo",
139 )
140
141 def forward(
142 self,
143 hidden_states: torch.Tensor,
144 position_ids: torch.Tensor,
145 ) -> torch.Tensor:
146 qkv, _ = self.Wqkv(hidden_states)
147 q, k, v = qkv.split([self.all_head_size] * 3, dim=-1)
148 q, k = self.rotary_emb(position_ids, q, k)
149 attn_outputs = self.attn(q, k, v)
150 hidden_states = attn_outputs
151 hidden_states, _ = self.Wo(hidden_states)
152 return hidden_states
153
154
155 class ModernBertMLP(nn.Module):
156 def __init__(
157 self,
158 config: ModernBertConfig,
159 prefix: str = "",
160 quant_config: QuantizationConfig | None = None,
161 ):
162 super().__init__()
163 self.config = config
164 self.Wi = MergedColumnParallelLinear(
165 config.hidden_size,
166 [int(config.intermediate_size)] * 2,
167 bias=config.mlp_bias,
168 quant_config=quant_config,
169 prefix=f"{prefix}.Wi",
170 )
171 self.act = ACT2FN[config.hidden_activation]
172 self.Wo = RowParallelLinear(
173 config.intermediate_size,
174 config.hidden_size,
175 bias=config.mlp_bias,
176 quant_config=quant_config,
177 prefix=f"{prefix}.Wo",
178 )
179
180 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
181 input_gate, _ = self.Wi(hidden_states)
182 input, gate = input_gate.chunk(2, dim=-1)
183 return self.Wo(self.act(input) * gate)[0]
184
185
186 class ModernBertLayer(nn.Module):
187 def __init__(
188 self,
189 config: ModernBertConfig,
190 prefix: str = "",
191 layer_id: int | None = None,
192 dtype: torch.dtype | None = None,
193 quant_config: QuantizationConfig | None = None,
194 ):
195 super().__init__()
196 self.config = config
197 if layer_id == 0:
198 self.attn_norm = nn.Identity()
199 else:
200 self.attn_norm = nn.LayerNorm(
201 config.hidden_size, eps=config.norm_eps, bias=config.norm_bias
202 )
203 self.attn = ModernBertAttention(
204 config=config,
205 layer_id=layer_id,
206 prefix=f"{prefix}.attn",
207 dtype=dtype,
208 quant_config=quant_config,
209 )
210 self.mlp_norm = nn.LayerNorm(
211 config.hidden_size, eps=config.norm_eps, bias=config.norm_bias
212 )
213 self.mlp = ModernBertMLP(
214 config,
215 prefix=f"{prefix}.mlp",
216 quant_config=quant_config,
217 )
218
219 def forward(
220 self,
221 hidden_states: torch.Tensor,
222 position_ids: torch.Tensor,
223 ) -> torch.Tensor:
224 attn_outputs = self.attn(
225 hidden_states=self.attn_norm(hidden_states), position_ids=position_ids
226 )
227 hidden_states = hidden_states + attn_outputs
228 mlp_output = self.mlp(self.mlp_norm(hidden_states))
229 hidden_states = hidden_states + mlp_output
230 return hidden_states
231
232
233 class ModernBertEncoderLayer(nn.Module):
234 def __init__(self, vllm_config: VllmConfig, prefix: str = ""):
235 super().__init__()
236 config = vllm_config.model_config.hf_config
237 dtype = vllm_config.model_config.dtype
238 quant_config = vllm_config.quant_config
239 self.layers = nn.ModuleList(
240 [
241 ModernBertLayer(
242 config=config,
243 layer_id=layer_id,
244 prefix=f"{prefix}.layers.{layer_id}",
245 dtype=dtype,
246 quant_config=quant_config,
247 )
248 for layer_id in range(config.num_hidden_layers)
249 ]
250 )
251
252 def forward(
253 self,
254 hidden_states: torch.Tensor,
255 position_ids: torch.Tensor,
256 ) -> torch.Tensor:
257 for i, layer in enumerate(self.layers):
258 hidden_states = layer(hidden_states, position_ids)
259 return hidden_states
260
261
262 @support_torch_compile
263 @default_pooling_type(seq_pooling_type="CLS")
264 class ModernBertModel(nn.Module, SupportsLoRA):
265 hf_to_vllm_mapper = WeightsMapper(
266 orig_to_new_prefix={
267 "model.layers.": "encoder_layer.layers.",
268 "layers.": "encoder_layer.layers.",
269 "model.": "",
270 }
271 )
272
273 packed_modules_mapping = {
274 "Wqkv": ["Wqkv"],
275 "Wi": ["Wi"],
276 }
277
278 def __init__(
279 self,
280 vllm_config: VllmConfig,
281 prefix: str = "",
282 ):
283 super().__init__()
284 config = vllm_config.model_config.hf_config
285 self.config = config
286 self.embeddings = ModernBertEmbeddings(config)
287 self.encoder_layer = ModernBertEncoderLayer(
288 vllm_config, prefix=f"{prefix}.encoder_layer"
289 )
290 self.final_norm = nn.LayerNorm(
291 config.hidden_size, eps=config.norm_eps, bias=config.norm_bias
292 )
293
294 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
295 return self.embeddings.embed_input_ids(input_ids)
296
297 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
298 weights = self.hf_to_vllm_mapper.apply(weights)
299 params_dict = dict(self.named_parameters())
300 loaded_params: set[str] = set()
301 for name, loaded_weight in weights:
302 if name.endswith(".bias") and name not in params_dict:
303 continue
304 if name not in params_dict:
305 continue
306 param = params_dict[name]
307 weight_loader = getattr(param, "weight_loader", default_weight_loader)
308 weight_loader(param, loaded_weight)
309 loaded_params.add(name)
310 return loaded_params
311
312 def forward(
313 self,
314 input_ids: torch.Tensor,
315 positions: torch.Tensor,
316 intermediate_tensors: IntermediateTensors | None = None,
317 inputs_embeds: torch.Tensor | None = None,
318 ) -> torch.Tensor:
319 if inputs_embeds is not None:
320 hidden_states = inputs_embeds
321 else:
322 hidden_states = self.embeddings(
323 input_ids=input_ids, inputs_embeds=inputs_embeds
324 )
325
326 outputs = self.encoder_layer(
327 hidden_states=hidden_states,
328 position_ids=positions,
329 )
330 norm_outputs = self.final_norm(outputs)
331 return norm_outputs
332
333
334 class ModernBertPooler(SequencePooler):
335 def __init__(self, model_config: ModelConfig):
336 pooler_config = model_config.pooler_config
337 assert pooler_config is not None
338
339 config: ModernBertConfig = model_config.hf_config
340 hf_pooling_type = config.classifier_pooling.upper()
341 # vllm_pooling_type = pooler_config.seq_pooling_type
342 # Currently we don't have a way to see if the user set the pooling type
343 # explicitly or not, so we always use the HF pooling type for now.
344
345 super().__init__(
346 pooling=get_seq_pooling_method(hf_pooling_type),
347 # We set this dummy to avoid adding parameters to nn.Module too early
348 head=nn.Identity(),
349 )
350
351 head_dtype = model_config.head_dtype
352 self.dense = nn.Linear(
353 config.hidden_size,
354 config.hidden_size,
355 config.classifier_bias,
356 dtype=head_dtype,
357 )
358 self.act = nn.GELU()
359 self.norm = nn.LayerNorm(
360 config.hidden_size,
361 eps=config.norm_eps,
362 bias=config.norm_bias,
363 dtype=head_dtype,
364 )
365
366 # Use lambdas so that weights are not registered under `self.head`
367 self.head = EmbeddingPoolerHead(
368 head_dtype=head_dtype,
369 projector=lambda x: self.norm(self.act(self.dense(x))),
370 )
371
372
373 @default_pooling_type(seq_pooling_type="CLS")
374 class ModernBertForSequenceClassification(nn.Module, SupportsCrossEncoding):
375 is_pooling_model = True
376
377 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
378 super().__init__()
379
380 config = vllm_config.model_config.hf_config
381
382 self.config = config
383 self.model = ModernBertModel(
384 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "modernbert")
385 )
386 self.classifier = nn.Linear(
387 config.hidden_size,
388 config.num_labels,
389 dtype=vllm_config.model_config.head_dtype,
390 )
391
392 pooler_config = vllm_config.model_config.pooler_config
393 assert pooler_config is not None
394
395 self.pooling = ModernBertPooler(vllm_config.model_config)
396
397 self.pooler = DispatchPooler.for_seq_cls(
398 pooler_config,
399 pooling=self.pooling,
400 classifier=self.classifier,
401 )
402
403 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
404 return self.model.embed_input_ids(input_ids)
405
406 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
407 self_weights = []
408
409 def weight_filter():
410 for name, weight in weights:
411 if name.startswith("model."):
412 yield name[len("model.") :], weight
413 else:
414 self_weights.append((name, weight))
415
416 self.model.load_weights(weight_filter())
417
418 params_dict = dict(self.named_parameters())
419
420 for name, loaded_weight in self_weights:
421 if name.startswith("classifier"):
422 param = params_dict[name]
423 weight_loader = getattr(param, "weight_loader", default_weight_loader)
424 weight_loader(param, loaded_weight)
425 if name.startswith("head"):
426 param = params_dict["pooling." + name[len("head") + 1 :]]
427 weight_loader = getattr(param, "weight_loader", default_weight_loader)
428 weight_loader(param, loaded_weight)
429
430 def forward(
431 self,
432 input_ids: torch.LongTensor | None,
433 positions: torch.Tensor,
434 intermediate_tensors: IntermediateTensors | None = None,
435 inputs_embeds: torch.Tensor | None = None,
436 ) -> torch.Tensor:
437 return self.model(
438 input_ids=input_ids,
439 inputs_embeds=inputs_embeds,
440 positions=positions,
441 )
442
443
444 class ModernBertPredictionHead(nn.Module):
445 def __init__(self, config):
446 super().__init__()
447 self.config = config
448 self.dense = nn.Linear(
449 config.hidden_size, config.hidden_size, bias=config.classifier_bias
450 )
451 self.act = ACT2FN[config.classifier_activation]
452 self.norm = nn.LayerNorm(
453 config.hidden_size,
454 eps=getattr(config, "norm_eps", 1e-5),
455 bias=getattr(config, "norm_bias", True),
456 )
457
458 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
459 return self.norm(self.act(self.dense(hidden_states)))
460
461
462 @attn_type("encoder_only")
463 @default_pooling_type(tok_pooling_type="ALL")
464 class ModernBertForTokenClassification(nn.Module):
465 is_pooling_model = True
466
467 hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"drop": None})
468
469 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
470 super().__init__()
471 config = vllm_config.model_config.hf_config
472 self.head_dtype = vllm_config.model_config.head_dtype
473 self.num_labels = config.num_labels
474 self.model = ModernBertModel(
475 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "modernbert")
476 )
477 self.head = ModernBertPredictionHead(config)
478 self.classifier = nn.Linear(
479 config.hidden_size, config.num_labels, dtype=self.head_dtype
480 )
481
482 pooler_config = vllm_config.model_config.pooler_config
483 assert pooler_config is not None
484
485 self.pooler = pooler_for_token_classify(pooler_config)
486
487 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
488 return self.model.embed_input_ids(input_ids)
489
490 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
491 loader = AutoWeightsLoader(self)
492 loaded_params = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
493 return loaded_params
494
495 def forward(
496 self,
497 input_ids: torch.Tensor | None,
498 positions: torch.Tensor,
499 intermediate_tensors: IntermediateTensors | None = None,
500 inputs_embeds: torch.Tensor | None = None,
501 ) -> torch.Tensor:
502 hidden_states = self.model(
503 input_ids=input_ids,
504 positions=positions,
505 inputs_embeds=inputs_embeds,
506 intermediate_tensors=intermediate_tensors,
507 )
508 hidden_states = self.head(hidden_states)
509 hidden_states = hidden_states.to(self.head_dtype)
510 return self.classifier(hidden_states)