main
py 406 lines 14.7 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # Adapted from
5 # https://github.com/huggingface/transformers/blob/v4.28.0/src/transformers/models/llama/modeling_llama.py
6 # Copyright 2023 The vLLM team.
7 # Copyright 2022 EleutherAI and the HuggingFace Inc. team. All rights reserved.
8 #
9 # This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
10 # and OPT implementations in this library. It has been modified from its
11 # original forms to accommodate minor architectural differences compared
12 # to GPT-NeoX and OPT used by the Meta AI team that trained the model.
13 #
14 # Licensed under the Apache License, Version 2.0 (the "License");
15 # you may not use this file except in compliance with the License.
16 # You may obtain a copy of the License at
17 #
18 # http://www.apache.org/licenses/LICENSE-2.0
19 #
20 # Unless required by applicable law or agreed to in writing, software
21 # distributed under the License is distributed on an "AS IS" BASIS,
22 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 # See the License for the specific language governing permissions and
24 # limitations under the License.
25 """Inference-only EagleMiniCPM model compatible with HuggingFace weights."""
26
27 import math
28 from collections.abc import Iterable
29 from typing import TYPE_CHECKING
30
31 import torch
32 from torch import nn
33 from transformers import PreTrainedConfig
34
35 from vllm.compilation.decorators import support_torch_compile
36 from vllm.config import CacheConfig, VllmConfig
37 from vllm.model_executor.layers.layernorm import RMSNorm
38 from vllm.model_executor.layers.logits_processor import LogitsProcessor
39 from vllm.model_executor.layers.quantization import QuantizationConfig
40 from vllm.model_executor.layers.vocab_parallel_embedding import (
41 ParallelLMHead,
42 VocabParallelEmbedding,
43 )
44 from vllm.model_executor.model_loader.weight_utils import default_weight_loader
45 from vllm.sequence import IntermediateTensors
46
47 from .interfaces import SupportsEagle, SupportsLoRA, SupportsPP
48 from .minicpm import MiniCPMAttention as EagleMiniCPMAttention
49 from .minicpm import MiniCPMMLP as EagleMiniCPMMLP
50 from .minicpm import MiniCPMMoE as EagleMiniCPMMoE
51 from .utils import (
52 AutoWeightsLoader,
53 is_pp_missing_parameter,
54 make_empty_intermediate_tensors_factory,
55 maybe_prefix,
56 process_eagle_weight,
57 )
58
59 if TYPE_CHECKING:
60
61 class _EagleMiniCPMSupportsPP:
62 pass
63
64 else:
65 _EagleMiniCPMSupportsPP = SupportsPP
66
67
68 class EagleMiniCPMDecoderLayer(nn.Module):
69 def __init__(
70 self,
71 config: PreTrainedConfig,
72 cache_config: CacheConfig | None = None,
73 quant_config: QuantizationConfig | None = None,
74 prefix: str = "",
75 ) -> None:
76 super().__init__()
77 self.config = config
78 self.cache_config = cache_config
79 self.quant_config = quant_config
80 self.hidden_size = config.hidden_size
81 self.max_position_embeddings = getattr(config, "max_position_embeddings", 8192)
82 self.mup_denominator = getattr(
83 config, "mup_denominator", config.num_hidden_layers
84 )
85 self.prefix = prefix
86 self._init_attn_block()
87 self._init_ffn_block()
88
89 def _init_attn_block(self):
90 self.input_layernorm = RMSNorm(
91 self.config.hidden_size, eps=self.config.rms_norm_eps
92 )
93 self.self_attn = EagleMiniCPMAttention(
94 hidden_size=self.hidden_size,
95 num_heads=self.config.num_attention_heads,
96 num_kv_heads=self.config.num_key_value_heads,
97 rope_parameters=self.config.rope_parameters,
98 max_position_embeddings=self.max_position_embeddings,
99 cache_config=self.cache_config,
100 quant_config=self.quant_config,
101 prefix=f"{self.prefix}.self_attn",
102 )
103
104 def _init_ffn_block(self):
105 self.post_attention_layernorm = RMSNorm(
106 self.config.hidden_size, eps=self.config.rms_norm_eps
107 )
108 self.num_experts = getattr(self.config, "num_experts", 0)
109 if self.num_experts == 0:
110 self.mlp = EagleMiniCPMMLP(
111 hidden_size=self.hidden_size,
112 intermediate_size=self.config.intermediate_size,
113 hidden_act=self.config.hidden_act,
114 hidden_act_param=getattr(self.config, "hidden_act_param", 0.0),
115 quant_config=self.quant_config,
116 )
117 else:
118 self.mlp = EagleMiniCPMMoE(
119 num_experts=self.config.num_experts,
120 top_k=self.config.num_experts_per_tok,
121 hidden_size=self.config.hidden_size,
122 intermediate_size=self.config.intermediate_size,
123 prefix=f"{self.prefix}.mlp",
124 )
125
126 def forward(
127 self,
128 positions: torch.Tensor,
129 hidden_states: torch.Tensor,
130 residual: torch.Tensor | None,
131 ) -> tuple[torch.Tensor, torch.Tensor]:
132 # Self Attention
133 residual = hidden_states
134 hidden_states = self.input_layernorm(hidden_states)
135 hidden_states = self.self_attn(
136 positions=positions,
137 hidden_states=hidden_states,
138 )
139 hidden_states = residual + hidden_states * (
140 self.config.scale_depth / math.sqrt(self.mup_denominator)
141 )
142
143 # Fully Connected
144 residual = hidden_states
145 hidden_states = self.post_attention_layernorm(hidden_states)
146 hidden_states = self.mlp(hidden_states)
147 hidden_states = residual + hidden_states * (
148 self.config.scale_depth / math.sqrt(self.mup_denominator)
149 )
150
151 return hidden_states, None
152
153
154 @support_torch_compile
155 class EagleMiniCPMModel(nn.Module):
156 def __init__(
157 self, *, vllm_config: VllmConfig, prefix: str = "", start_layer: int = 0
158 ):
159 super().__init__()
160
161 speculative_config = vllm_config.speculative_config
162 assert speculative_config is not None
163 config = speculative_config.draft_model_config.hf_config
164 cache_config = vllm_config.cache_config
165 quant_config = vllm_config.quant_config
166
167 self.config = config
168 self.cache_config = cache_config
169 self.quant_config = quant_config
170
171 self.vocab_size = config.vocab_size
172
173 self.fc = torch.nn.Linear(
174 self.config.hidden_size * 2, self.config.hidden_size, bias=False
175 )
176 self.input_norm1 = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
177 self.input_norm2 = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
178 self.embed_tokens = VocabParallelEmbedding(
179 self.vocab_size,
180 config.hidden_size,
181 )
182 self.num_experts = getattr(self.config, "num_experts", 0)
183 self._init_layers(prefix, config, cache_config, quant_config, start_layer)
184 self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
185 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
186 ["hidden_states", "residual"], self.config.hidden_size
187 )
188
189 def _init_layers(
190 self,
191 prefix: str,
192 config: PreTrainedConfig,
193 cache_config: CacheConfig | None,
194 quant_config: QuantizationConfig | None,
195 start_layer: int,
196 ):
197 self.eagle_layers = nn.ModuleList(
198 [
199 EagleMiniCPMDecoderLayer(
200 config,
201 cache_config,
202 quant_config,
203 f"{prefix}.eagle_layers.{i + start_layer}",
204 )
205 for i in range(self.config.num_hidden_layers)
206 ]
207 )
208
209 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
210 embedding = self.embed_tokens(input_ids)
211 return embedding * self.config.scale_emb
212
213 def forward(
214 self,
215 input_ids: torch.Tensor,
216 positions: torch.Tensor,
217 hidden_states: torch.Tensor,
218 ) -> torch.Tensor | IntermediateTensors:
219 input_embeds = self.embed_input_ids(input_ids)
220 input_embeds = self.input_norm1(input_embeds)
221 hidden_states = self.input_norm2(hidden_states)
222
223 hidden_states = self.fc(torch.cat((input_embeds, hidden_states), dim=-1))
224 residual = None
225 for layer in self.eagle_layers:
226 hidden_states, residual = layer(
227 positions,
228 hidden_states,
229 residual,
230 )
231
232 return hidden_states, hidden_states
233
234 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
235 stacked_params_mapping = [
236 # (param_name, shard_name, shard_id)
237 ("qkv_proj", "q_proj", "q"),
238 ("qkv_proj", "k_proj", "k"),
239 ("qkv_proj", "v_proj", "v"),
240 ("gate_up_proj", "gate_proj", 0),
241 ("gate_up_proj", "up_proj", 1),
242 ]
243 expert_params_mapping = [
244 # (param_name, weight_name, expert_id)
245 (
246 "ws" if weight_name in ["w1", "w3"] else "w2s",
247 f"experts.{expert_id}.{weight_name}.weight",
248 expert_id,
249 )
250 for expert_id in range(self.num_experts)
251 for weight_name in ["w1", "w2", "w3"]
252 ]
253 params_dict = dict(self.named_parameters())
254
255 loaded_params: set[str] = set()
256 for name, loaded_weight in weights:
257 if "rotary_emb.inv_freq" in name:
258 continue
259 if "rotary_emb.cos_cached" in name or "rotary_emb.sin_cached" in name:
260 # Models trained using ColossalAI may include these tensors in
261 # the checkpoint. Skip them.
262 continue
263 for param_name, weight_name, shard_id in stacked_params_mapping:
264 if weight_name not in name:
265 continue
266 name = name.replace(weight_name, param_name)
267 # Skip loading extra bias for GPTQ models.
268 if name.endswith(".bias") and name not in params_dict:
269 continue
270 if is_pp_missing_parameter(name, self):
271 continue
272 param = params_dict[name]
273 weight_loader = param.weight_loader
274 weight_loader(param, loaded_weight, shard_id)
275 break
276 else:
277 for param_name, weight_name, expert_id in expert_params_mapping:
278 if weight_name not in name:
279 continue
280 name = name.replace(weight_name, param_name)
281 if is_pp_missing_parameter(name, self):
282 continue
283 param = params_dict[name]
284 weight_loader = param.weight_loader
285 weight_loader(
286 param, loaded_weight, weight_name, expert_id=expert_id
287 )
288 break
289 else:
290 # Skip loading extra bias for GPTQ models.
291 if name.endswith(".bias") and name not in params_dict:
292 continue
293 if is_pp_missing_parameter(name, self):
294 continue
295 param = params_dict[name]
296 weight_loader = getattr(
297 param, "weight_loader", default_weight_loader
298 )
299
300 weight_loader(param, loaded_weight)
301 loaded_params.add(name)
302 return loaded_params
303
304
305 class EagleMiniCPMForCausalLM(
306 nn.Module, SupportsLoRA, _EagleMiniCPMSupportsPP, SupportsEagle
307 ):
308 packed_modules_mapping = {
309 "qkv_proj": [
310 "q_proj",
311 "k_proj",
312 "v_proj",
313 ],
314 "gate_up_proj": [
315 "gate_proj",
316 "up_proj",
317 ],
318 }
319
320 # LoRA specific attributes
321 embedding_modules = {
322 "embed_tokens": "input_embeddings",
323 "lm_head": "output_embeddings",
324 }
325
326 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
327 super().__init__()
328 speculative_config = vllm_config.speculative_config
329 assert speculative_config is not None
330 config = speculative_config.draft_model_config.hf_config
331 cache_config = vllm_config.cache_config
332 quant_config = vllm_config.quant_config
333
334 self.prefix = prefix
335 self.vllm_config = vllm_config
336 self.config = config
337
338 self.cache_config = cache_config
339 self.quant_config = quant_config
340
341 target_layer_num = vllm_config.model_config.get_num_layers(
342 vllm_config.parallel_config
343 )
344
345 self.model = self._init_model(
346 vllm_config=vllm_config,
347 prefix=maybe_prefix(prefix, "model"),
348 start_layer=target_layer_num,
349 )
350
351 self.lm_head = ParallelLMHead(
352 config.vocab_size,
353 config.hidden_size,
354 quant_config=quant_config,
355 prefix=maybe_prefix(prefix, "lm_head"),
356 )
357 if config.tie_word_embeddings:
358 self.lm_head = self.lm_head.tie_weights(self.model.embed_tokens)
359 self.scale_width = self.config.hidden_size / self.config.dim_model_base
360
361 self.logits_processor = LogitsProcessor(config.vocab_size)
362 self.make_empty_intermediate_tensors = (
363 self.model.make_empty_intermediate_tensors
364 )
365
366 def _init_model(
367 self, *, vllm_config: VllmConfig, prefix: str = "", start_layer: int = 0
368 ):
369 return EagleMiniCPMModel(
370 vllm_config=vllm_config, prefix=prefix, start_layer=start_layer
371 )
372
373 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
374 return self.model.embed_input_ids(input_ids)
375
376 def forward(
377 self,
378 input_ids: torch.Tensor,
379 positions: torch.Tensor,
380 hidden_states: torch.Tensor,
381 inputs_embeds: torch.Tensor | None = None,
382 ) -> tuple[torch.Tensor, torch.Tensor]:
383 if inputs_embeds is not None:
384 raise NotImplementedError(
385 f"{type(self).__name__} does not support multimodal inputs yet."
386 )
387 hidden_states, hidden_states2 = self.model(input_ids, positions, hidden_states)
388 hidden_states = hidden_states / self.scale_width
389 hidden_states2 = hidden_states2 / self.scale_width
390 return hidden_states, hidden_states2
391
392 def compute_logits(
393 self,
394 hidden_states: torch.Tensor,
395 ) -> torch.Tensor | None:
396 logits = self.logits_processor(self.lm_head, hidden_states)
397 return logits
398
399 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
400 def transform(inputs):
401 name, loaded_weight = inputs
402 process_eagle_weight(self, name)
403 return name, loaded_weight
404
405 loader = AutoWeightsLoader(self)
406 return loader.load_weights(map(transform, weights))