main
py 192 lines 6.5 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
5 from typing import TYPE_CHECKING
6
7 import torch
8 import torch.nn as nn
9
10 from vllm.compilation.decorators import support_torch_compile
11 from vllm.config import VllmConfig
12 from vllm.logger import init_logger
13 from vllm.model_executor.layers.layernorm import RMSNorm
14 from vllm.model_executor.layers.linear import RowParallelLinear
15 from vllm.model_executor.layers.logits_processor import LogitsProcessor
16 from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
17 from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
18 from vllm.model_executor.models.interfaces import (
19 MultiModalEmbeddings,
20 SupportsMultiModalEmbeddings,
21 )
22 from vllm.model_executor.models.llama import LlamaConfig
23 from vllm.model_executor.models.mistral import (
24 MistralDecoderLayer,
25 MistralForCausalLM,
26 MistralModel,
27 )
28 from vllm.model_executor.models.utils import (
29 _merge_multimodal_embeddings,
30 get_draft_quant_config,
31 maybe_prefix,
32 )
33
34 logger = init_logger(__name__)
35
36
37 if TYPE_CHECKING:
38
39 class _EagleMistralModelBase(nn.Module):
40 pass
41
42 class _EagleMistralForCausalLMBase(nn.Module):
43 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
44 raise NotImplementedError
45
46 else:
47 _EagleMistralModelBase = MistralModel
48 _EagleMistralForCausalLMBase = MistralForCausalLM
49
50
51 class EagleMistralDecoderLayer(MistralDecoderLayer):
52 def __init__(
53 self,
54 vllm_config: VllmConfig,
55 prefix: str = "",
56 config: LlamaConfig | None = None,
57 ) -> None:
58 super().__init__(vllm_config, prefix=prefix, config=config)
59
60 def get_quant_config(self, vllm_config: VllmConfig) -> QuantizationConfig | None:
61 return get_draft_quant_config(vllm_config)
62
63
64 @support_torch_compile
65 class EagleMistralModel(_EagleMistralModelBase):
66 def __init__(
67 self,
68 *,
69 vllm_config: VllmConfig,
70 prefix: str = "",
71 start_layer_id: int = 0,
72 ) -> None:
73 # Bypass MistralModel.__init__ to avoid creating duplicate attention
74 # layer entries in the global context.
75 nn.Module.__init__(self)
76 speculative_config = vllm_config.speculative_config
77 assert speculative_config is not None
78 self.config = speculative_config.draft_model_config.hf_config
79 self.vocab_size = self.config.vocab_size
80 # Get drafter's quantization config
81 self.quant_config = get_draft_quant_config(vllm_config)
82
83 self.embed_tokens = VocabParallelEmbedding(
84 self.config.vocab_size,
85 self.config.hidden_size,
86 prefix=maybe_prefix(prefix, "embed_tokens"),
87 quant_config=self.quant_config,
88 )
89
90 self.layers = nn.ModuleList(
91 [
92 EagleMistralDecoderLayer(
93 vllm_config,
94 prefix=maybe_prefix(prefix, f"layers.{i + start_layer_id}"),
95 config=self.config,
96 )
97 for i in range(self.config.num_hidden_layers)
98 ]
99 )
100 self.fc = RowParallelLinear(
101 self.config.hidden_size * 2,
102 self.config.hidden_size,
103 bias=False,
104 input_is_parallel=False,
105 quant_config=self.quant_config,
106 prefix=maybe_prefix(prefix, "fc"),
107 return_bias=False,
108 )
109 self.norm = RMSNorm(self.config.hidden_size, eps=self.config.rms_norm_eps)
110
111 def forward(
112 self,
113 input_ids: torch.Tensor,
114 positions: torch.Tensor,
115 hidden_states: torch.Tensor,
116 inputs_embeds: torch.Tensor | None = None,
117 ) -> tuple[torch.Tensor, torch.Tensor]:
118 if inputs_embeds is None:
119 inputs_embeds = self.embed_input_ids(input_ids)
120 hidden_states = self.fc(torch.cat((inputs_embeds, hidden_states), dim=-1))
121 residual = None
122 for layer in self.layers:
123 hidden_states, residual = layer(
124 positions,
125 hidden_states,
126 residual,
127 )
128 hidden_states, _ = self.norm(hidden_states, residual)
129 return hidden_states, hidden_states
130
131
132 class EagleMistralForCausalLM(
133 _EagleMistralForCausalLMBase, SupportsMultiModalEmbeddings
134 ):
135 mistral_mapping = MistralForCausalLM.mistral_mapping | {
136 "eagle_linear": "model.fc",
137 }
138
139 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
140 # Bypass MistralForCausalLM.__init__ to use the draft model config
141 # and to avoid creating an lm_head.
142 nn.Module.__init__(self)
143 speculative_config = vllm_config.speculative_config
144 assert speculative_config is not None
145 self.config = speculative_config.draft_model_config.hf_config
146 target_layer_num = vllm_config.model_config.get_num_layers(
147 vllm_config.parallel_config
148 )
149 self.model = EagleMistralModel(
150 vllm_config=vllm_config,
151 prefix=maybe_prefix(prefix, "model"),
152 start_layer_id=target_layer_num,
153 )
154
155 logit_scale = getattr(self.config, "logit_scale", 1.0)
156 self.logits_processor = LogitsProcessor(
157 self.config.vocab_size, scale=logit_scale
158 )
159
160 def forward(
161 self,
162 input_ids: torch.Tensor,
163 positions: torch.Tensor,
164 hidden_states: torch.Tensor,
165 inputs_embeds: torch.Tensor | None = None,
166 ) -> tuple[torch.Tensor, torch.Tensor]:
167 return self.model(input_ids, positions, hidden_states, inputs_embeds)
168
169 def embed_input_ids(
170 self,
171 input_ids: torch.Tensor,
172 multimodal_embeddings: MultiModalEmbeddings | None = None,
173 *,
174 is_multimodal: torch.Tensor | None = None,
175 ) -> torch.Tensor:
176 inputs_embeds = super().embed_input_ids(input_ids)
177
178 if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
179 return inputs_embeds
180
181 assert is_multimodal is not None
182
183 return _merge_multimodal_embeddings(
184 inputs_embeds=inputs_embeds,
185 multimodal_embeddings=multimodal_embeddings,
186 is_multimodal=is_multimodal,
187 )
188
189 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
190 # Pretend embed_tokens is loaded; the actual weight is shared
191 # from the target model at runtime by `load_eagle_model`.
192 return super().load_weights(weights) | {"model.embed_tokens.weight"}