main
py 89 lines 3.65 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # Copyright 2024 The vLLM 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 """Transformers modeling backend mixin for causal language models."""
18
19 from collections.abc import Iterable
20 from typing import TYPE_CHECKING
21
22 import torch
23
24 from vllm.model_executor.layers.logits_processor import LogitsProcessor
25 from vllm.model_executor.layers.vocab_parallel_embedding import (
26 ParallelLMHead,
27 VocabParallelEmbedding,
28 )
29 from vllm.model_executor.models.interfaces_base import VllmModelForTextGeneration
30 from vllm.model_executor.models.utils import PPMissingLayer, maybe_prefix
31
32 from .base import Base
33
34 if TYPE_CHECKING:
35 from vllm.config import VllmConfig
36
37
38 class CausalMixin(VllmModelForTextGeneration, Base):
39 def __init__(self, *, vllm_config: "VllmConfig", prefix: str = ""):
40 # Skip VllmModelForTextGeneration.__init__ and call the next class in MRO
41 super(VllmModelForTextGeneration, self).__init__(
42 vllm_config=vllm_config, prefix=prefix
43 )
44
45 tie_word_embeddings = self._get_tie_word_embeddings()
46
47 if self.pp_group.is_last_rank:
48 self.lm_head = ParallelLMHead(
49 self.text_config.vocab_size,
50 self.text_config.hidden_size,
51 quant_config=self.quant_config,
52 prefix=maybe_prefix(prefix, "lm_head"),
53 )
54 if tie_word_embeddings:
55 for module in self.model.get_input_embeddings().modules():
56 if isinstance(module, VocabParallelEmbedding):
57 self.lm_head = self.lm_head.tie_weights(module)
58 break
59
60 self.logits_processor = LogitsProcessor(
61 self.text_config.vocab_size,
62 scale=getattr(self.text_config, "logit_scale", 1.0),
63 soft_cap=getattr(self.text_config, "final_logit_softcapping", None),
64 )
65 else:
66 self.lm_head = PPMissingLayer()
67
68 def load_weights(self, weights: Iterable[tuple[str, "torch.Tensor"]]) -> set[str]:
69 """A thin wrapper around `Base.load_weights` to handle the lm_head bias."""
70 lm_head_bias = set()
71 load_device = self.vllm_config.load_config.device or self.device_config.device
72
73 def auto_load_lm_head_bias(weights):
74 for name, weight in weights:
75 if name.endswith("lm_head.bias") and self.pp_group.is_last_rank:
76 # load_weights is called outside vLLM's device context,
77 # so we must enter it again when registering the bias.
78 with torch.device(load_device):
79 self.lm_head._register_bias()
80 self.lm_head.bias.weight_loader(self.lm_head.bias, weight)
81 lm_head_bias.add(name)
82 else:
83 yield name, weight
84
85 return super().load_weights(auto_load_lm_head_bias(weights)) | lm_head_bias
86
87 def compute_logits(self, hidden_states: "torch.Tensor") -> "torch.Tensor | None":
88 logits = self.logits_processor(self.lm_head, hidden_states, self.lm_head.bias)
89 return logits