"vscode:/vscode.git/clone" did not exist on "a0490be8f1f232ef1350234c899bc5159c1491cd"
modernbert.py 16 KB
Newer Older
xsank's avatar
xsank committed
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
from collections.abc import Iterable
xsank's avatar
xsank committed
4
5
6
7

import torch
from torch import nn
from transformers import ModernBertConfig
8
from transformers.activations import ACT2FN
xsank's avatar
xsank committed
9

10
from vllm.compilation.decorators import support_torch_compile
11
from vllm.config import ModelConfig, VllmConfig
xsank's avatar
xsank committed
12
from vllm.distributed import get_tensor_model_parallel_world_size
13
14
15
from vllm.model_executor.layers.attention.encoder_only_attention import (
    EncoderOnlyAttention,
)
16
from vllm.model_executor.layers.linear import QKVParallelLinear, RowParallelLinear
17
from vllm.model_executor.layers.pooler import DispatchPooler
18
from vllm.model_executor.layers.pooler.activations import LambdaPoolerActivation
19
from vllm.model_executor.layers.pooler.seqwise import (
20
    EmbeddingPoolerHead,
21
22
    SequencePooler,
    get_seq_pooling_method,
23
)
24
from vllm.model_executor.layers.pooler.tokwise import pooler_for_token_classify
25
from vllm.model_executor.layers.rotary_embedding import get_rope
26
from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
xsank's avatar
xsank committed
27
from vllm.model_executor.model_loader.weight_utils import default_weight_loader
28
from vllm.sequence import IntermediateTensors
xsank's avatar
xsank committed
29

30
from .interfaces import SupportsCrossEncoding
31
from .interfaces_base import attn_type, default_pooling_type
32
from .utils import AutoWeightsLoader, WeightsMapper, maybe_prefix
xsank's avatar
xsank committed
33
34
35
36
37
38


class ModernBertEmbeddings(nn.Module):
    def __init__(self, config: ModernBertConfig):
        super().__init__()
        self.config = config
39
40
41
        self.tok_embeddings = VocabParallelEmbedding(
            config.vocab_size, config.hidden_size
        )
42
43
44
45
        eps = (
            getattr(config, "norm_eps", None)
            or getattr(config, "layer_norm_eps", None)
            or 1e-5
46
        )
47
        self.norm = nn.LayerNorm(config.hidden_size, eps=eps, bias=config.norm_bias)
xsank's avatar
xsank committed
48

49
    def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
50
51
        return self.tok_embeddings(input_ids)

xsank's avatar
xsank committed
52
53
54
    def forward(
        self,
        input_ids: torch.Tensor,
55
        inputs_embeds: torch.Tensor | None = None,
xsank's avatar
xsank committed
56
    ) -> torch.Tensor:
57
        if inputs_embeds is None:
xsank's avatar
xsank committed
58
            inputs_embeds = self.tok_embeddings(input_ids)
59
60
61

        embeddings = self.norm(inputs_embeds)
        return embeddings
xsank's avatar
xsank committed
62
63
64


class ModernBertAttention(nn.Module):
65
66
67
    def __init__(
        self, config: ModernBertConfig, layer_id: int | None = None, prefix: str = ""
    ):
xsank's avatar
xsank committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        super().__init__()
        self.config = config
        self.hidden_size = config.hidden_size
        tp_size = get_tensor_model_parallel_world_size()
        self.layer_id = layer_id
        self.deterministic_flash_attn = config.deterministic_flash_attn
        self.num_heads = config.num_attention_heads
        assert self.num_heads % tp_size == 0
        self.head_dim = config.hidden_size // config.num_attention_heads
        self.all_head_size = self.head_dim * self.num_heads
        self.scaling = self.head_dim**-0.5
        self.Wqkv = QKVParallelLinear(
            config.hidden_size,
            self.head_dim,
            self.num_heads,
            bias=config.attention_bias,
84
            prefix=f"{prefix}.Wqkv",
xsank's avatar
xsank committed
85
86
        )

87
88
89
90
91
92
93
        if layer_types := getattr(config, "layer_types", None):
            # Transformers v5
            layer_type = layer_types[layer_id]
            rope_parameters = config.rope_parameters[layer_type]
            sliding_window: int | None = None
            if layer_type == "sliding_attention":
                sliding_window = config.local_attention // 2
xsank's avatar
xsank committed
94
        else:
95
96
97
98
99
100
101
102
103
104
105
106
            # Transformers v4
            sliding_window = None
            if layer_id % config.global_attn_every_n_layers != 0:
                sliding_window = config.local_attention // 2
                rope_theta = (
                    config.local_rope_theta
                    if config.local_rope_theta is not None
                    else config.global_rope_theta
                )
            else:
                rope_theta = config.global_rope_theta
            rope_parameters = {"rope_type": "default", "rope_theta": rope_theta}
xsank's avatar
xsank committed
107

108
109
110
111
112
        self.rotary_emb = get_rope(
            head_size=self.head_dim,
            max_position=config.max_position_embeddings,
            rope_parameters=rope_parameters,
            dtype=torch.float16,
113
        )
114
115
116
117
118
        self.attn = EncoderOnlyAttention(
            self.num_heads,
            self.head_dim,
            self.scaling,
            prefix=f"{layer_id}.attn",
119
120
121
            per_layer_sliding_window=sliding_window,
        )
        self.Wo = RowParallelLinear(
122
123
124
125
            config.hidden_size,
            config.hidden_size,
            bias=config.attention_bias,
            prefix=f"{prefix}.Wo",
126
        )
xsank's avatar
xsank committed
127
128
129
130

    def forward(
        self,
        hidden_states: torch.Tensor,
131
        position_ids: torch.Tensor,
xsank's avatar
xsank committed
132
133
134
135
136
137
138
139
140
141
142
    ) -> torch.Tensor:
        qkv, _ = self.Wqkv(hidden_states)
        q, k, v = qkv.split([self.all_head_size] * 3, dim=-1)
        q, k = self.rotary_emb(position_ids, q, k)
        attn_outputs = self.attn(q, k, v)
        hidden_states = attn_outputs
        hidden_states, _ = self.Wo(hidden_states)
        return hidden_states


class ModernBertMLP(nn.Module):
143
    def __init__(self, config: ModernBertConfig, prefix: str = ""):
xsank's avatar
xsank committed
144
145
        super().__init__()
        self.config = config
146
147
148
        self.Wi = nn.Linear(
            config.hidden_size, int(config.intermediate_size) * 2, bias=config.mlp_bias
        )
xsank's avatar
xsank committed
149
        self.act = nn.GELU()
150
        self.Wo = RowParallelLinear(
151
152
153
154
            config.intermediate_size,
            config.hidden_size,
            bias=config.mlp_bias,
            prefix=f"{prefix}.Wo",
155
        )
xsank's avatar
xsank committed
156
157
158
159
160
161
162

    def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
        input, gate = self.Wi(hidden_states).chunk(2, dim=-1)
        return self.Wo(self.act(input) * gate)[0]


class ModernBertLayer(nn.Module):
163
    def __init__(
164
        self, config: ModernBertConfig, prefix: str = "", layer_id: int | None = None
165
    ):
xsank's avatar
xsank committed
166
167
168
169
170
        super().__init__()
        self.config = config
        if layer_id == 0:
            self.attn_norm = nn.Identity()
        else:
171
172
173
            self.attn_norm = nn.LayerNorm(
                config.hidden_size, eps=config.norm_eps, bias=config.norm_bias
            )
174
175
176
        self.attn = ModernBertAttention(
            config=config, layer_id=layer_id, prefix=f"{prefix}.attn"
        )
177
178
179
        self.mlp_norm = nn.LayerNorm(
            config.hidden_size, eps=config.norm_eps, bias=config.norm_bias
        )
180
        self.mlp = ModernBertMLP(config, prefix=f"{prefix}.mlp")
xsank's avatar
xsank committed
181
182
183
184

    def forward(
        self,
        hidden_states: torch.Tensor,
185
186
        position_ids: torch.Tensor,
    ) -> torch.Tensor:
187
188
189
        attn_outputs = self.attn(
            hidden_states=self.attn_norm(hidden_states), position_ids=position_ids
        )
xsank's avatar
xsank committed
190
191
192
193
194
195
196
197
198
199
        hidden_states = hidden_states + attn_outputs
        mlp_output = self.mlp(self.mlp_norm(hidden_states))
        hidden_states = hidden_states + mlp_output
        return hidden_states


class ModernBertEncoderLayer(nn.Module):
    def __init__(self, vllm_config: VllmConfig, prefix: str = ""):
        super().__init__()
        config = vllm_config.model_config.hf_config
200
201
        self.layers = nn.ModuleList(
            [
202
203
204
205
206
                ModernBertLayer(
                    config=config,
                    layer_id=layer_id,
                    prefix=f"{prefix}.layers.{layer_id}",
                )
207
208
209
                for layer_id in range(config.num_hidden_layers)
            ]
        )
xsank's avatar
xsank committed
210
211
212
213

    def forward(
        self,
        hidden_states: torch.Tensor,
214
        position_ids: torch.Tensor,
xsank's avatar
xsank committed
215
216
217
218
219
220
    ) -> torch.Tensor:
        for i, layer in enumerate(self.layers):
            hidden_states = layer(hidden_states, position_ids)
        return hidden_states


221
@support_torch_compile
222
@default_pooling_type(seq_pooling_type="CLS")
xsank's avatar
xsank committed
223
224
class ModernBertModel(nn.Module):
    hf_to_vllm_mapper = WeightsMapper(
225
226
        orig_to_new_prefix={"layers.": "encoder_layer.layers."}
    )
xsank's avatar
xsank committed
227
228
229
230
231
232
233
234
235
236

    def __init__(
        self,
        vllm_config: VllmConfig,
        prefix: str = "",
    ):
        super().__init__()
        config = vllm_config.model_config.hf_config
        self.config = config
        self.embeddings = ModernBertEmbeddings(config)
237
238
239
        self.encoder_layer = ModernBertEncoderLayer(
            vllm_config, prefix=f"{prefix}.encoder_layer"
        )
240
241
242
        self.final_norm = nn.LayerNorm(
            config.hidden_size, eps=config.norm_eps, bias=config.norm_bias
        )
xsank's avatar
xsank committed
243

244
245
    def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
        return self.embeddings.embed_input_ids(input_ids)
246

247
    def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
xsank's avatar
xsank committed
248
249
        weights = self.hf_to_vllm_mapper.apply(weights)
        params_dict = dict(self.named_parameters())
250
        loaded_params: set[str] = set()
xsank's avatar
xsank committed
251
252
253
254
        for name, loaded_weight in weights:
            if name.endswith(".bias") and name not in params_dict:
                continue
            param = params_dict[name]
255
            weight_loader = getattr(param, "weight_loader", default_weight_loader)
xsank's avatar
xsank committed
256
257
258
259
260
261
            weight_loader(param, loaded_weight)
            loaded_params.add(name)
        return loaded_params

    def forward(
        self,
262
263
        input_ids: torch.Tensor,
        positions: torch.Tensor,
264
265
        intermediate_tensors: IntermediateTensors | None = None,
        inputs_embeds: torch.Tensor | None = None,
xsank's avatar
xsank committed
266
267
268
269
    ) -> torch.Tensor:
        if inputs_embeds is not None:
            hidden_states = inputs_embeds
        else:
270
271
272
            hidden_states = self.embeddings(
                input_ids=input_ids, inputs_embeds=inputs_embeds
            )
xsank's avatar
xsank committed
273
274
275

        outputs = self.encoder_layer(
            hidden_states=hidden_states,
276
            position_ids=positions,
xsank's avatar
xsank committed
277
278
279
280
281
        )
        norm_outputs = self.final_norm(outputs)
        return norm_outputs


282
class ModernBertPooler(SequencePooler):
283
284
285
286
287
    def __init__(self, model_config: ModelConfig):
        pooler_config = model_config.pooler_config
        assert pooler_config is not None

        config: ModernBertConfig = model_config.hf_config
288
289
290
291
292
        hf_pooling_type = config.classifier_pooling.upper()
        # vllm_pooling_type = pooler_config.seq_pooling_type
        # Currently we don't have a way to see if the user set the pooling type
        # explicitly or not, so we always use the HF pooling type for now.

293
        super().__init__(
294
            pooling=get_seq_pooling_method(hf_pooling_type),
295
296
            # We set this dummy to avoid adding parameters to nn.Module too early
            head=nn.Identity(),
297
        )
298

299
        head_dtype = model_config.head_dtype
300
        self.dense = nn.Linear(
301
302
303
304
            config.hidden_size,
            config.hidden_size,
            config.classifier_bias,
            dtype=head_dtype,
305
        )
xsank's avatar
xsank committed
306
        self.act = nn.GELU()
307
        self.norm = nn.LayerNorm(
308
309
310
            config.hidden_size,
            eps=config.norm_eps,
            bias=config.norm_bias,
311
            dtype=head_dtype,
312
        )
xsank's avatar
xsank committed
313

314
315
316
        # Use lambdas so that weights are not registered under `self.head`
        self.head = EmbeddingPoolerHead(
            head_dtype=head_dtype,
317
            projector=lambda x: self.dense(x),
318
319
            activation=LambdaPoolerActivation(lambda x: self.norm(self.act(x))),
        )
320

xsank's avatar
xsank committed
321

322
@default_pooling_type(seq_pooling_type="CLS")
323
class ModernBertForSequenceClassification(nn.Module, SupportsCrossEncoding):
324
325
    is_pooling_model = True

xsank's avatar
xsank committed
326
327
    def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
        super().__init__()
328

xsank's avatar
xsank committed
329
        config = vllm_config.model_config.hf_config
330

xsank's avatar
xsank committed
331
        self.config = config
332
333
334
335
336
337
338
339
        self.model = ModernBertModel(
            vllm_config=vllm_config, prefix=maybe_prefix(prefix, "modernbert")
        )
        self.classifier = nn.Linear(
            config.hidden_size,
            config.num_labels,
            dtype=vllm_config.model_config.head_dtype,
        )
340
341
342
343

        pooler_config = vllm_config.model_config.pooler_config
        assert pooler_config is not None

344
        self.pooling = ModernBertPooler(vllm_config.model_config)
345

346
347
348
349
        self.pooler = DispatchPooler.for_seq_cls(
            pooler_config,
            pooling=self.pooling,
            classifier=self.classifier,
350
        )
xsank's avatar
xsank committed
351

352
353
    def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
        return self.model.embed_input_ids(input_ids)
354

355
    def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
xsank's avatar
xsank committed
356
357
358
359
360
        self_weights = []

        def weight_filter():
            for name, weight in weights:
                if name.startswith("model."):
361
                    yield name[len("model.") :], weight
xsank's avatar
xsank committed
362
363
364
365
366
367
368
369
370
371
                else:
                    self_weights.append((name, weight))

        self.model.load_weights(weight_filter())

        params_dict = dict(self.named_parameters())

        for name, loaded_weight in self_weights:
            if name.startswith("classifier"):
                param = params_dict[name]
372
                weight_loader = getattr(param, "weight_loader", default_weight_loader)
xsank's avatar
xsank committed
373
374
                weight_loader(param, loaded_weight)
            if name.startswith("head"):
375
376
                param = params_dict["pooling." + name[len("head") + 1 :]]
                weight_loader = getattr(param, "weight_loader", default_weight_loader)
xsank's avatar
xsank committed
377
378
379
380
                weight_loader(param, loaded_weight)

    def forward(
        self,
381
        input_ids: torch.LongTensor | None,
xsank's avatar
xsank committed
382
        positions: torch.Tensor,
383
384
        intermediate_tensors: IntermediateTensors | None = None,
        inputs_embeds: torch.Tensor | None = None,
xsank's avatar
xsank committed
385
386
387
388
    ) -> torch.Tensor:
        return self.model(
            input_ids=input_ids,
            inputs_embeds=inputs_embeds,
389
            positions=positions,
xsank's avatar
xsank committed
390
        )
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410


class ModernBertPredictionHead(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config
        self.dense = nn.Linear(
            config.hidden_size, config.hidden_size, bias=config.classifier_bias
        )
        self.act = ACT2FN[config.classifier_activation]
        self.norm = nn.LayerNorm(
            config.hidden_size,
            eps=getattr(config, "norm_eps", 1e-5),
            bias=getattr(config, "norm_bias", True),
        )

    def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
        return self.norm(self.act(self.dense(hidden_states)))


411
@attn_type("encoder_only")
412
@default_pooling_type(tok_pooling_type="ALL")
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
class ModernBertForTokenClassification(nn.Module):
    is_pooling_model = True

    def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
        super().__init__()
        config = vllm_config.model_config.hf_config
        self.head_dtype = vllm_config.model_config.head_dtype
        self.num_labels = config.num_labels
        self.model = ModernBertModel(
            vllm_config=vllm_config, prefix=maybe_prefix(prefix, "modernbert")
        )
        self.head = ModernBertPredictionHead(config)
        self.classifier = nn.Linear(
            config.hidden_size, config.num_labels, dtype=self.head_dtype
        )

        pooler_config = vllm_config.model_config.pooler_config
        assert pooler_config is not None

432
        self.pooler = pooler_for_token_classify(pooler_config)
433

434
435
    def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
        return self.model.embed_input_ids(input_ids)
436
437
438
439
440
441
442
443

    def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
        loader = AutoWeightsLoader(self, skip_prefixes=["drop"])
        loaded_params = loader.load_weights(weights)
        return loaded_params

    def forward(
        self,
444
        input_ids: torch.Tensor | None,
445
        positions: torch.Tensor,
446
447
        intermediate_tensors: IntermediateTensors | None = None,
        inputs_embeds: torch.Tensor | None = None,
448
449
450
451
452
453
454
455
456
457
    ) -> torch.Tensor:
        hidden_states = self.model(
            input_ids=input_ids,
            positions=positions,
            inputs_embeds=inputs_embeds,
            intermediate_tensors=intermediate_tensors,
        )
        hidden_states = self.head(hidden_states)
        hidden_states = hidden_states.to(self.head_dtype)
        return self.classifier(hidden_states)