main
py 992 lines 33.8 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from collections.abc import Iterable, Set
5 from dataclasses import replace
6
7 import torch
8 from torch import nn
9 from transformers import BertConfig
10
11 from vllm.compilation.decorators import support_torch_compile
12 from vllm.config import CacheConfig, ModelConfig, PoolerConfig, VllmConfig
13 from vllm.distributed import get_tensor_model_parallel_world_size
14 from vllm.model_executor.layers.activation import get_act_fn
15 from vllm.model_executor.layers.attention import (
16 EncoderOnlyAttention,
17 )
18 from vllm.model_executor.layers.linear import (
19 ColumnParallelLinear,
20 QKVParallelLinear,
21 RowParallelLinear,
22 )
23 from vllm.model_executor.layers.pooler import (
24 DispatchPooler,
25 Pooler,
26 PoolingParamsUpdate,
27 )
28 from vllm.model_executor.layers.pooler.seqwise import (
29 EmbeddingPoolerHead,
30 SequencePooler,
31 SequencePoolerOutput,
32 get_seq_pooling_method,
33 )
34 from vllm.model_executor.layers.pooler.tokwise import (
35 pooler_for_token_classify,
36 pooler_for_token_embed,
37 )
38 from vllm.model_executor.layers.quantization import QuantizationConfig
39 from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
40 from vllm.sequence import IntermediateTensors
41 from vllm.tasks import PoolingTask
42 from vllm.v1.pool.metadata import PoolingMetadata
43
44 from .interfaces import SupportsCrossEncoding, SupportsQuant
45 from .interfaces_base import attn_type, default_pooling_type
46 from .utils import AutoWeightsLoader, WeightsMapper, maybe_prefix
47
48
49 class BertEmbedding(nn.Module):
50 def __init__(self, config: BertConfig):
51 super().__init__()
52 self.size = config.hidden_size
53 self.word_embeddings = VocabParallelEmbedding(
54 config.vocab_size, config.hidden_size
55 )
56 self.position_embeddings = VocabParallelEmbedding(
57 config.max_position_embeddings, config.hidden_size
58 )
59 self.token_type_embeddings = VocabParallelEmbedding(
60 config.type_vocab_size, config.hidden_size
61 )
62 self.LayerNorm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
63
64 self.register_buffer(
65 "position_ids",
66 torch.arange(config.max_position_embeddings).unsqueeze(0),
67 )
68 self.position_embedding_type = getattr(
69 config, "position_embedding_type", "absolute"
70 )
71 if self.position_embedding_type != "absolute":
72 raise ValueError(
73 "Only 'absolute' position_embedding_type" + " is supported"
74 )
75
76 def forward(
77 self,
78 input_ids: torch.Tensor,
79 position_ids: torch.Tensor,
80 inputs_embeds: torch.Tensor | None = None,
81 ) -> torch.Tensor:
82 token_type_ids = _decode_token_type_ids(input_ids)
83
84 if inputs_embeds is None:
85 inputs_embeds = self.word_embeddings(input_ids)
86
87 position_embeddings = self.position_embeddings(position_ids)
88
89 token_type_embeddings = self.token_type_embeddings(token_type_ids)
90
91 embeddings = inputs_embeds + token_type_embeddings + position_embeddings
92 embeddings = self.LayerNorm(embeddings)
93 return embeddings
94
95
96 class BertPooler(SequencePooler):
97 def __init__(self, model_config: ModelConfig):
98 pooler_config = model_config.pooler_config
99 assert pooler_config is not None
100 assert pooler_config.seq_pooling_type is not None
101
102 config: BertConfig = model_config.hf_config
103
104 super().__init__(
105 pooling=get_seq_pooling_method(pooler_config.seq_pooling_type),
106 # We set this dummy to avoid adding parameters to nn.Module too early
107 head=nn.Identity(),
108 )
109
110 head_dtype = model_config.head_dtype
111 self.dense = nn.Linear(
112 config.hidden_size,
113 config.hidden_size,
114 dtype=head_dtype,
115 )
116 self.act_fn = nn.Tanh()
117
118 # Keep the model's head layers even when output activation is disabled.
119 # Use lambdas so that weights are not registered under `self.head`
120 self.head = EmbeddingPoolerHead(
121 head_dtype=head_dtype,
122 projector=lambda x: self.act_fn(self.dense(x)),
123 )
124
125
126 class BertEncoder(nn.Module):
127 def __init__(self, vllm_config: VllmConfig, prefix: str = ""):
128 super().__init__()
129 config = vllm_config.model_config.hf_config
130 cache_config = vllm_config.cache_config
131 quant_config = vllm_config.quant_config
132 self.layer = nn.ModuleList(
133 [
134 BertLayer(
135 config=config,
136 cache_config=cache_config,
137 quant_config=quant_config,
138 prefix=f"{prefix}.layer.{layer_idx}",
139 )
140 for layer_idx in range(config.num_hidden_layers)
141 ]
142 )
143
144 def forward(
145 self,
146 hidden_states: torch.Tensor,
147 ) -> torch.Tensor:
148 for layer in self.layer:
149 hidden_states = layer(hidden_states)
150 return hidden_states
151
152
153 class BertLayer(nn.Module):
154 def __init__(
155 self,
156 config: BertConfig,
157 cache_config: CacheConfig | None = None,
158 quant_config: QuantizationConfig | None = None,
159 prefix: str = "",
160 ):
161 super().__init__()
162
163 self.attention = BertAttention(
164 hidden_size=config.hidden_size,
165 num_attention_heads=config.num_attention_heads,
166 layer_norm_eps=config.layer_norm_eps,
167 cache_config=cache_config,
168 quant_config=quant_config,
169 prefix=f"{prefix}.attention",
170 )
171
172 self.intermediate = BertIntermediate(
173 hidden_size=config.hidden_size,
174 intermediate_size=config.intermediate_size,
175 hidden_act=config.hidden_act,
176 quant_config=quant_config,
177 prefix=f"{prefix}.intermediate",
178 )
179
180 self.output = BertOutput(
181 hidden_size=config.hidden_size,
182 intermediate_size=config.intermediate_size,
183 layer_norm_eps=config.layer_norm_eps,
184 quant_config=quant_config,
185 prefix=f"{prefix}.output",
186 )
187
188 def forward(self, hidden_states: torch.Tensor):
189 attn_output = self.attention(hidden_states)
190 intermediate_output = self.intermediate(attn_output)
191 output = self.output(intermediate_output, attn_output)
192 return output
193
194
195 class BertAttention(nn.Module):
196 def __init__(
197 self,
198 hidden_size: int,
199 num_attention_heads: int,
200 layer_norm_eps: float,
201 cache_config: CacheConfig | None = None,
202 quant_config: QuantizationConfig | None = None,
203 prefix: str = "",
204 ):
205 super().__init__()
206
207 self.self = BertSelfAttention(
208 hidden_size=hidden_size,
209 num_attention_heads=num_attention_heads,
210 cache_config=cache_config,
211 quant_config=quant_config,
212 prefix=f"{prefix}.output",
213 )
214
215 self.output = BertSelfOutput(
216 hidden_size=hidden_size,
217 layer_norm_eps=layer_norm_eps,
218 quant_config=quant_config,
219 prefix=f"{prefix}.output",
220 )
221
222 def forward(
223 self,
224 hidden_states: torch.Tensor,
225 ) -> torch.Tensor:
226 self_output = self.self(hidden_states)
227 return self.output(self_output, hidden_states)
228
229
230 class BertSelfAttention(nn.Module):
231 def __init__(
232 self,
233 hidden_size: int,
234 num_attention_heads: int,
235 cache_config: CacheConfig | None = None,
236 quant_config: QuantizationConfig | None = None,
237 prefix: str = "",
238 ):
239 super().__init__()
240 self.hidden_size = hidden_size
241 tp_size = get_tensor_model_parallel_world_size()
242
243 self.total_num_heads = num_attention_heads
244 assert self.total_num_heads % tp_size == 0
245
246 self.num_heads = self.total_num_heads // tp_size
247 self.total_num_kv_heads = self.total_num_heads
248 self.head_dim = self.hidden_size // self.total_num_heads
249 assert self.head_dim * self.total_num_heads == self.hidden_size
250
251 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
252
253 self.q_size = self.num_heads * self.head_dim
254 self.kv_size = self.num_kv_heads * self.head_dim
255 self.scaling = self.head_dim**-0.5
256 self.qkv_proj = QKVParallelLinear(
257 hidden_size=self.hidden_size,
258 head_size=self.head_dim,
259 total_num_heads=self.total_num_heads,
260 total_num_kv_heads=self.total_num_kv_heads,
261 bias=True,
262 quant_config=quant_config,
263 prefix=f"{prefix}.qkv_proj",
264 )
265
266 self.attn = EncoderOnlyAttention(
267 num_heads=self.num_heads,
268 head_size=self.head_dim,
269 scale=self.scaling,
270 num_kv_heads=self.num_kv_heads,
271 cache_config=cache_config,
272 quant_config=quant_config,
273 prefix=f"{prefix}.attn",
274 )
275
276 def forward(
277 self,
278 hidden_states: torch.Tensor,
279 ) -> torch.Tensor:
280 qkv, _ = self.qkv_proj(hidden_states)
281 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
282 output = self.attn(q, k, v)
283 return output
284
285
286 class BertSelfOutput(nn.Module):
287 def __init__(
288 self,
289 hidden_size: int,
290 layer_norm_eps: float,
291 quant_config: QuantizationConfig | None = None,
292 prefix: str = "",
293 ):
294 super().__init__()
295 self.dense = RowParallelLinear(
296 input_size=hidden_size,
297 output_size=hidden_size,
298 bias=True,
299 quant_config=quant_config,
300 prefix=f"{prefix}.dense",
301 )
302 self.LayerNorm = nn.LayerNorm(hidden_size, eps=layer_norm_eps)
303
304 def forward(
305 self, hidden_states: torch.Tensor, input_tensor: torch.Tensor
306 ) -> torch.Tensor:
307 hidden_states, _ = self.dense(hidden_states)
308 hidden_states = self.LayerNorm(hidden_states + input_tensor)
309 return hidden_states
310
311
312 class BertIntermediate(nn.Module):
313 def __init__(
314 self,
315 hidden_size: int,
316 intermediate_size: int,
317 hidden_act: str,
318 quant_config: QuantizationConfig | None = None,
319 prefix: str = "",
320 ):
321 super().__init__()
322 self.dense = ColumnParallelLinear(
323 input_size=hidden_size,
324 output_size=intermediate_size,
325 bias=True,
326 quant_config=quant_config,
327 prefix=f"{prefix}.dense",
328 )
329 self.intermediate_act_fn = get_act_fn(hidden_act)
330
331 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
332 hidden_states, _ = self.dense(hidden_states)
333 hidden_states = self.intermediate_act_fn(hidden_states)
334 return hidden_states
335
336
337 class BertOutput(nn.Module):
338 def __init__(
339 self,
340 hidden_size: int,
341 intermediate_size: int,
342 layer_norm_eps: float,
343 quant_config: QuantizationConfig | None = None,
344 prefix: str = "",
345 ):
346 super().__init__()
347
348 self.dense = RowParallelLinear(
349 input_size=intermediate_size,
350 output_size=hidden_size,
351 bias=True,
352 quant_config=quant_config,
353 prefix=f"{prefix}.dense",
354 )
355
356 self.LayerNorm = nn.LayerNorm(hidden_size, eps=layer_norm_eps)
357
358 def forward(
359 self, hidden_states: torch.Tensor, input_tensor: torch.Tensor
360 ) -> torch.Tensor:
361 hidden_states, _ = self.dense(hidden_states)
362 hidden_states = self.LayerNorm(hidden_states + input_tensor)
363 return hidden_states
364
365
366 @support_torch_compile
367 @default_pooling_type(seq_pooling_type="CLS")
368 class BertModel(nn.Module, SupportsQuant):
369 is_pooling_model = True
370
371 packed_modules_mapping = {"qkv_proj": ["query", "key", "value"]}
372
373 hf_to_vllm_mapper = WeightsMapper(
374 # Original google-bert checkpoints use the legacy `gamma`/`beta`
375 # LayerNorm names; rename to vLLM's `weight`/`bias`.
376 orig_to_new_substr={
377 "LayerNorm.gamma": "LayerNorm.weight",
378 "LayerNorm.beta": "LayerNorm.bias",
379 },
380 orig_to_new_stacked={
381 ".self.query": (".self.qkv_proj", "q"),
382 ".self.key": (".self.qkv_proj", "k"),
383 ".self.value": (".self.qkv_proj", "v"),
384 },
385 orig_to_new_prefix={"pooler.": None},
386 )
387
388 def __init__(
389 self,
390 *,
391 vllm_config: VllmConfig,
392 prefix: str = "",
393 embedding_class: type[nn.Module] = BertEmbedding,
394 ) -> None:
395 super().__init__()
396
397 self.config = vllm_config.model_config.hf_config
398 self.embeddings = embedding_class(self.config)
399 self.encoder = BertEncoder(vllm_config=vllm_config, prefix=f"{prefix}.encoder")
400
401 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
402 return self.embeddings.word_embeddings(input_ids)
403
404 def forward(
405 self,
406 input_ids: torch.Tensor,
407 positions: torch.Tensor,
408 intermediate_tensors: IntermediateTensors | None = None,
409 inputs_embeds: torch.Tensor | None = None,
410 ) -> torch.Tensor:
411 hidden_states = self.embeddings(
412 input_ids=input_ids,
413 position_ids=positions,
414 inputs_embeds=inputs_embeds,
415 )
416
417 return self.encoder(hidden_states)
418
419 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
420 loader = AutoWeightsLoader(self)
421 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
422
423
424 class BertPoolingModel(BertModel):
425 is_pooling_model = True
426
427 # Unlike `BertModel`, this model has a pooler to load weights into.
428 hf_to_vllm_mapper = replace(BertModel.hf_to_vllm_mapper, orig_to_new_prefix={})
429
430 def __init__(
431 self,
432 *,
433 vllm_config: VllmConfig,
434 prefix: str = "",
435 embedding_class: type[nn.Module] = BertEmbedding,
436 ) -> None:
437 super().__init__(
438 vllm_config=vllm_config,
439 prefix=prefix,
440 embedding_class=embedding_class,
441 )
442
443 self.pooler = BertPooler(vllm_config.model_config)
444
445 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
446 loader = AutoWeightsLoader(self)
447 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
448
449
450 @default_pooling_type(seq_pooling_type="CLS")
451 class BertEmbeddingModel(nn.Module, SupportsQuant):
452 """A model that uses Bert to provide embedding functionalities.
453
454 This class encapsulates the BertModel and provides an interface for
455 embedding operations and customized pooling functions.
456
457 Attributes:
458 model: An instance of BertModel used for forward operations.
459 _pooler: An instance of Pooler used for pooling operations.
460
461 """
462
463 is_pooling_model = True
464 embedding_class: type[nn.Module] = BertEmbedding
465
466 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
467 super().__init__()
468
469 pooler_config = vllm_config.model_config.pooler_config
470 assert pooler_config is not None
471
472 self.model = self._build_model(
473 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
474 )
475 self.pooler = self._build_pooler(pooler_config)
476
477 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
478 return self.model.embed_input_ids(input_ids)
479
480 def forward(
481 self,
482 input_ids: torch.Tensor,
483 positions: torch.Tensor,
484 intermediate_tensors: IntermediateTensors | None = None,
485 inputs_embeds: torch.Tensor | None = None,
486 ) -> torch.Tensor:
487 return self.model(
488 input_ids=input_ids,
489 positions=positions,
490 inputs_embeds=inputs_embeds,
491 intermediate_tensors=intermediate_tensors,
492 )
493
494 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
495 weights_list = list(weights)
496
497 orig_to_new_prefix: dict[str, str | None] = {"lm_head.": None}
498 has_model_prefix = any(name.startswith("model.") for name, _ in weights_list)
499 if not has_model_prefix:
500 orig_to_new_prefix[""] = "model."
501 mapper = WeightsMapper(orig_to_new_prefix=orig_to_new_prefix)
502
503 loader = AutoWeightsLoader(self)
504 return loader.load_weights(weights_list, mapper=mapper)
505
506 def _build_model(self, vllm_config: VllmConfig, prefix: str = "") -> BertModel:
507 return BertModel(
508 vllm_config=vllm_config, prefix=prefix, embedding_class=self.embedding_class
509 )
510
511 def _build_pooler(self, pooler_config: PoolerConfig) -> Pooler:
512 return DispatchPooler.for_embedding(pooler_config)
513
514
515 # Here we encode the token type ids together with the input ids.
516 # Since we use int 32 for the input IDs and the vocabulary size
517 # is way lower than 2**31, there is room to encode additional
518 # bits. At the same time, for cross-encoder use cases, the
519 # token type ids are only 0 or 1, requiring only 1 bit.
520 # This means that we can store the token type ids in the 31st
521 # bit. We void the 32nd bit because that would produce a negative
522 # number, which could be used to signal other things.
523 #
524 # The reason for all of this is that all the tensors that are
525 # passed as input to the forward function of a module marked
526 # with @support_torch_compile have to be persistent. So to
527 # avoid adding more persistent tensors in the model runner, we
528 # encode more information in the same persistent tensor.
529 #
530 # Since the *ForClassification module is outside of the BertModel
531 # which is compiled, we can do the encoding here and then separate
532 # the information again in the Embedding layer. Since with bit masks
533 # we can do this entirely with torch operations and without branching,
534 # it works with torch compile.
535
536 TOKEN_TYPE_SHIFT = 30
537
538
539 def _encode_token_type_ids(
540 input_ids: torch.Tensor, token_type_ids: torch.Tensor
541 ) -> None:
542 # input_ids can be padded to the right
543 input_ids[: token_type_ids.shape[0]].bitwise_or_(token_type_ids << TOKEN_TYPE_SHIFT)
544
545
546 def _decode_token_type_ids(input_ids: torch.Tensor) -> torch.Tensor:
547 ids_mask = 1 << TOKEN_TYPE_SHIFT
548 tokens_mask = ~ids_mask
549
550 token_type_ids = (input_ids & ids_mask) >> TOKEN_TYPE_SHIFT
551
552 input_ids.bitwise_and_(tokens_mask)
553
554 return token_type_ids
555
556
557 class BertMLMHead(nn.Module):
558 def __init__(
559 self, hidden_size: int, vocab_size: int, layer_norm_eps: float = 1e-12
560 ):
561 super().__init__()
562 self.dense = nn.Linear(hidden_size, hidden_size)
563 self.activation = nn.GELU()
564 self.layer_norm = nn.LayerNorm(hidden_size, eps=layer_norm_eps)
565 self.decoder = nn.Linear(hidden_size, vocab_size, bias=True)
566
567 def tie_weights_with_embeddings(self, embeddings_weight: torch.Tensor):
568 self.decoder.weight = embeddings_weight
569
570 def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
571 x = self.dense(hidden_states)
572 x = self.activation(x)
573 x = self.layer_norm(x)
574 logits = self.decoder(x)
575 return logits
576
577
578 class SPLADESparsePooler(Pooler):
579 """SPLADE sparse pooling:
580 logits = mlm_head(hidden_states)
581 -> log1p(relu(logits))
582 -> (max|sum over L)
583 -> [V]
584
585 Padding is masked with an attention mask,
586 [CLS]/[SEP] is removed (selected),
587 and then pooled.
588 """
589
590 def __init__(
591 self,
592 mlm_head: nn.Module,
593 cls_token_id: int | None = 101,
594 sep_token_id: int | None = 102,
595 pooling: str = "max",
596 remove_cls_sep: bool = True,
597 ):
598 super().__init__()
599
600 assert pooling in ("max", "sum")
601 self.mlm_head = mlm_head
602 self.cls_token_id = cls_token_id
603 self.sep_token_id = sep_token_id
604 self.pooling = pooling
605 self.remove_cls_sep = remove_cls_sep
606
607 def get_supported_tasks(self) -> Set[PoolingTask]:
608 return {"embed"}
609
610 def get_pooling_updates(self, task: PoolingTask) -> PoolingParamsUpdate:
611 return PoolingParamsUpdate(requires_token_ids=True)
612
613 def forward(
614 self,
615 hidden_states: torch.Tensor,
616 pooling_metadata: PoolingMetadata,
617 ) -> SequencePoolerOutput:
618 lens_tensor = pooling_metadata.prompt_lens
619 lens: list[int] = lens_tensor.tolist()
620 B: int = len(lens)
621
622 prompt_token_ids = pooling_metadata.get_prompt_token_ids_cpu()
623 offset = 0
624 pooled_list: list[torch.Tensor] = []
625
626 for i in range(B):
627 L = int(lens[i])
628 hs = hidden_states[offset : offset + L]
629 token_ids = prompt_token_ids[i]
630
631 start_idx = 0
632 end_idx = L
633 if self.remove_cls_sep:
634 if (
635 self.cls_token_id is not None
636 and int(token_ids[0]) == self.cls_token_id
637 ):
638 start_idx = 1
639 if (
640 self.sep_token_id is not None
641 and int(token_ids[L - 1]) == self.sep_token_id
642 ):
643 end_idx = max(start_idx, L - 1)
644
645 if end_idx <= start_idx:
646 V = int(self.mlm_head.decoder.out_features)
647 pooled_list.append(hs.new_zeros((V,)))
648 offset += L
649 continue
650
651 logits_i = self.mlm_head(hs[start_idx:end_idx])
652 scores_i = torch.log1p(torch.relu(logits_i))
653
654 if self.pooling == "sum":
655 pooled_i = scores_i.sum(dim=0)
656 else: # "max"
657 pooled_i = scores_i.max(dim=0).values
658
659 pooled_list.append(pooled_i.contiguous())
660 offset += L
661
662 return torch.stack(pooled_list, dim=0).contiguous()
663
664
665 @default_pooling_type(seq_pooling_type="CLS")
666 class BertSpladeSparseEmbeddingModel(BertEmbeddingModel):
667 """BertEmbeddingModel + SPLADE sparse embedding.
668 - Make logits by self.mlm_head
669 - pooler: SPLADESparsePooler(mlm_head...)
670 """
671
672 def __init__(
673 self, *, vllm_config: VllmConfig, prefix: str = "", splade_pooling: str = "max"
674 ):
675 super().__init__(vllm_config=vllm_config, prefix=prefix)
676 cfg = vllm_config.model_config.hf_config
677
678 # MLM head
679 self.mlm_head = BertMLMHead(
680 hidden_size=cfg.hidden_size,
681 vocab_size=cfg.vocab_size,
682 layer_norm_eps=getattr(cfg, "layer_norm_eps", 1e-12),
683 )
684
685 self._splade_pooling = splade_pooling
686 pooler_config = vllm_config.model_config.pooler_config
687 assert pooler_config is not None
688 self.pooler = self._build_pooler(pooler_config)
689
690 def _build_pooler(self, pooler_config: PoolerConfig) -> Pooler:
691 cfg = self.model.config
692
693 if not hasattr(self, "mlm_head"):
694 self.mlm_head = BertMLMHead(
695 hidden_size=cfg.hidden_size,
696 vocab_size=cfg.vocab_size,
697 layer_norm_eps=getattr(cfg, "layer_norm_eps", 1e-12),
698 )
699
700 # None of vLLM's built-in sequence pooling types are
701 # applicable so it is overwritten by SPLADESparsePooler
702 pooling_mode = getattr(self, "_splade_pooling", "max")
703
704 cls_id = getattr(cfg, "cls_token_id", None)
705 sep_id = getattr(cfg, "sep_token_id", None)
706
707 return DispatchPooler(
708 {
709 "token_embed": pooler_for_token_embed(pooler_config),
710 "embed": SPLADESparsePooler(
711 mlm_head=self.mlm_head,
712 cls_token_id=cls_id,
713 sep_token_id=sep_id,
714 pooling=pooling_mode, # "max" or "sum"
715 remove_cls_sep=True,
716 ),
717 }
718 )
719
720 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
721 if not hasattr(self, "mlm_head"):
722 cfg = self.model.config
723 self.mlm_head = BertMLMHead(
724 hidden_size=cfg.hidden_size,
725 vocab_size=cfg.vocab_size,
726 layer_norm_eps=getattr(cfg, "layer_norm_eps", 1e-12),
727 )
728
729 def _strip(name: str) -> str:
730 for p in ("model.", "bert."):
731 if name.startswith(p):
732 name = name[len(p) :]
733 return name
734
735 weights_list = list(weights)
736 model_side: list[tuple[str, torch.Tensor]] = []
737 mlm_side: list[tuple[str, torch.Tensor]] = []
738
739 for k, w in weights_list:
740 name = _strip(k)
741 if name.startswith("cls.predictions."):
742 mlm_side.append((name, w))
743 else:
744 model_side.append((name, w))
745
746 loaded: set[str] = set()
747 loaded_model = self.model.load_weights(model_side)
748 loaded.update({"model." + n for n in loaded_model})
749
750 if mlm_side:
751 name_map = {
752 "cls.predictions.transform.dense.weight": "mlm_head.dense.weight",
753 "cls.predictions.transform.dense.bias": "mlm_head.dense.bias",
754 ("cls.predictions.transform.LayerNorm.weight"): (
755 "mlm_head.layer_norm.weight"
756 ),
757 ("cls.predictions.transform.LayerNorm.bias"): (
758 "mlm_head.layer_norm.bias"
759 ),
760 "cls.predictions.decoder.weight": "mlm_head.decoder.weight",
761 "cls.predictions.decoder.bias": "mlm_head.decoder.bias",
762 }
763 remapped = [(name_map[n], w) for n, w in mlm_side if n in name_map]
764 if remapped:
765 loaded_mlm = AutoWeightsLoader(self).load_weights(remapped)
766 loaded.update(loaded_mlm)
767
768 return loaded
769
770
771 @default_pooling_type(seq_pooling_type="CLS")
772 class BertForSequenceClassification(nn.Module, SupportsCrossEncoding, SupportsQuant):
773 """A model that uses Bert to provide embedding functionalities.
774
775 This class encapsulates the BertModel and provides an interface for
776 embedding operations and customized pooling functions.
777
778 Attributes:
779 model: An instance of BertModel used for forward operations.
780 _pooler: An instance of Pooler used for pooling operations.
781
782 """
783
784 is_pooling_model = True
785 embedding_class: type[nn.Module] = BertEmbedding
786
787 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
788 super().__init__()
789 config = vllm_config.model_config.hf_config
790
791 self.num_labels = config.num_labels
792 self.bert = BertPoolingModel(
793 vllm_config=vllm_config,
794 prefix=maybe_prefix(prefix, "bert"),
795 embedding_class=self.embedding_class,
796 )
797 self.classifier = nn.Linear(
798 config.hidden_size,
799 config.num_labels,
800 dtype=vllm_config.model_config.head_dtype,
801 )
802
803 pooler_config = vllm_config.model_config.pooler_config
804 assert pooler_config is not None
805
806 self.pooler = DispatchPooler.for_seq_cls(
807 pooler_config,
808 pooling=self.bert.pooler,
809 classifier=self.classifier,
810 )
811
812 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
813 return self.bert.embed_input_ids(input_ids)
814
815 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
816 loader = AutoWeightsLoader(self)
817 loaded_params = loader.load_weights(weights)
818 return loaded_params
819
820 def forward(
821 self,
822 input_ids: torch.Tensor | None,
823 positions: torch.Tensor,
824 intermediate_tensors: IntermediateTensors | None = None,
825 inputs_embeds: torch.Tensor | None = None,
826 token_type_ids: torch.Tensor | None = None,
827 ) -> torch.Tensor:
828 if token_type_ids is not None:
829 assert self.bert.config.vocab_size < (1 << TOKEN_TYPE_SHIFT)
830 assert input_ids is not None
831 _encode_token_type_ids(input_ids, token_type_ids)
832
833 return self.bert(
834 input_ids=input_ids,
835 positions=positions,
836 inputs_embeds=inputs_embeds,
837 intermediate_tensors=intermediate_tensors,
838 )
839
840
841 @attn_type("encoder_only")
842 @default_pooling_type(tok_pooling_type="ALL")
843 class BertForTokenClassification(nn.Module):
844 is_pooling_model = True
845 embedding_class: type[nn.Module] = BertEmbedding
846
847 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
848 super().__init__()
849 config = vllm_config.model_config.hf_config
850 self.head_dtype = vllm_config.model_config.head_dtype
851 self.num_labels = config.num_labels
852 self.bert = BertModel(
853 vllm_config=vllm_config,
854 prefix=maybe_prefix(prefix, "bert"),
855 embedding_class=self.embedding_class,
856 )
857 self.classifier = nn.Linear(
858 config.hidden_size, config.num_labels, dtype=self.head_dtype
859 )
860
861 pooler_config = vllm_config.model_config.pooler_config
862 assert pooler_config is not None
863
864 self.pooler = pooler_for_token_classify(pooler_config)
865
866 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
867 return self.bert.embed_input_ids(input_ids)
868
869 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
870 loader = AutoWeightsLoader(self)
871 loaded_params = loader.load_weights(weights)
872 return loaded_params
873
874 def forward(
875 self,
876 input_ids: torch.Tensor | None,
877 positions: torch.Tensor,
878 intermediate_tensors: IntermediateTensors | None = None,
879 inputs_embeds: torch.Tensor | None = None,
880 token_type_ids: torch.Tensor | None = None,
881 ) -> torch.Tensor:
882 if token_type_ids is not None:
883 assert self.bert.config.vocab_size < (1 << TOKEN_TYPE_SHIFT)
884 assert input_ids is not None
885 _encode_token_type_ids(input_ids, token_type_ids)
886
887 hidden_states = self.bert(
888 input_ids=input_ids,
889 positions=positions,
890 inputs_embeds=inputs_embeds,
891 intermediate_tensors=intermediate_tensors,
892 )
893
894 hidden_states = hidden_states.to(self.head_dtype)
895 return self.classifier(hidden_states)
896
897
898 @attn_type("encoder_only")
899 @default_pooling_type(tok_pooling_type="ALL")
900 class BertForMaskedLM(nn.Module):
901 """Bert with a masked-language-modeling head on top of ``BertModel``.
902
903 Produces per-token logits over the vocabulary. In vLLM terms this is a
904 token-level pooling model (``tok_pooling_type="ALL"``): the encoder output
905 is projected by the MLM head to ``vocab_size`` logits for every position,
906 and the token pooler returns one vector per token.
907 """
908
909 is_pooling_model = True
910
911 # Map the HF ``cls.predictions.*`` checkpoint names onto our ``mlm_head.*``
912 # submodule. Order matters: the ``None`` (drop) rules and the more specific
913 # names are listed before the broader ``cls.predictions.decoder`` rule so
914 # that substring replacement doesn't rewrite them first.
915 hf_to_vllm_mapper = WeightsMapper(
916 orig_to_new_substr={
917 # Next-sentence-prediction head: not part of masked LM.
918 "cls.seq_relationship": None,
919 # Some checkpoints ship an explicit (tied) decoder bias; we load the
920 # canonical ``cls.predictions.bias`` instead, so drop the duplicate.
921 "cls.predictions.decoder.bias": None,
922 # Legacy LayerNorm affine names in the MLM head transform.
923 "cls.predictions.transform.LayerNorm.gamma": "mlm_head.layer_norm.weight",
924 "cls.predictions.transform.LayerNorm.beta": "mlm_head.layer_norm.bias",
925 "cls.predictions.transform.LayerNorm": "mlm_head.layer_norm",
926 "cls.predictions.transform.dense": "mlm_head.dense",
927 "cls.predictions.decoder": "mlm_head.decoder",
928 # In HF ``cls.predictions.bias`` *is* the decoder bias.
929 "cls.predictions.bias": "mlm_head.decoder.bias",
930 }
931 )
932
933 embedding_class: type[nn.Module] = BertEmbedding
934
935 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
936 super().__init__()
937 config = vllm_config.model_config.hf_config
938 self.bert = BertModel(
939 vllm_config=vllm_config,
940 prefix=maybe_prefix(prefix, "bert"),
941 embedding_class=self.embedding_class,
942 )
943 self.mlm_head = BertMLMHead(
944 hidden_size=config.hidden_size,
945 vocab_size=config.vocab_size,
946 layer_norm_eps=getattr(config, "layer_norm_eps", 1e-12),
947 )
948
949 pooler_config = vllm_config.model_config.pooler_config
950 assert pooler_config is not None
951
952 self.pooler = pooler_for_token_classify(pooler_config)
953
954 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
955 return self.bert.embed_input_ids(input_ids)
956
957 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
958 loader = AutoWeightsLoader(self)
959 loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
960
961 # The MLM decoder shares its weight with the input embeddings. When the
962 # checkpoint relies on `tie_word_embeddings` (e.g. google-bert/*) it
963 # doesn't ship an explicit decoder weight, so tie it here. Copy the
964 # first `vocab_size` rows since VocabParallelEmbedding may pad the vocab.
965 if "mlm_head.decoder.weight" not in loaded:
966 emb = self.bert.embeddings.word_embeddings.weight
967 decoder = self.mlm_head.decoder.weight
968 decoder.data.copy_(emb.data[: decoder.shape[0]])
969 loaded.add("mlm_head.decoder.weight")
970 return loaded
971
972 def forward(
973 self,
974 input_ids: torch.Tensor | None,
975 positions: torch.Tensor,
976 intermediate_tensors: IntermediateTensors | None = None,
977 inputs_embeds: torch.Tensor | None = None,
978 token_type_ids: torch.Tensor | None = None,
979 ) -> torch.Tensor:
980 if token_type_ids is not None:
981 assert self.bert.config.vocab_size < (1 << TOKEN_TYPE_SHIFT)
982 assert input_ids is not None
983 _encode_token_type_ids(input_ids, token_type_ids)
984
985 hidden_states = self.bert(
986 input_ids=input_ids,
987 positions=positions,
988 inputs_embeds=inputs_embeds,
989 intermediate_tensors=intermediate_tensors,
990 )
991
992 return self.mlm_head(hidden_states)