main
py 257 lines 9.37 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
6 import torch
7 import torch.nn as nn
8
9 from vllm.compilation.decorators import support_torch_compile
10 from vllm.config import VllmConfig
11 from vllm.model_executor.layers.fused_moe import (
12 fused_moe_make_expert_params_mapping,
13 )
14 from vllm.model_executor.layers.layernorm import RMSNorm
15 from vllm.model_executor.layers.logits_processor import LogitsProcessor
16 from vllm.model_executor.layers.vocab_parallel_embedding import (
17 ParallelLMHead,
18 VocabParallelEmbedding,
19 )
20 from vllm.model_executor.model_loader.weight_utils import (
21 default_weight_loader,
22 maybe_remap_kv_scale_name,
23 )
24 from vllm.model_executor.models.deepseek_v2 import (
25 DeepseekV2DecoderLayer,
26 DeepseekV3ForCausalLM,
27 )
28
29 from .utils import AutoWeightsLoader, maybe_prefix, process_eagle_weight
30
31
32 @support_torch_compile
33 class DeepseekV2Model(nn.Module):
34 def __init__(
35 self,
36 *,
37 vllm_config: VllmConfig,
38 prefix: str = "",
39 start_layer_id: int = 0,
40 ) -> None:
41 super().__init__()
42 assert vllm_config.speculative_config is not None
43 self.config = vllm_config.speculative_config.draft_model_config.hf_config
44 quant_config = vllm_config.quant_config
45 self.vocab_size = self.config.vocab_size
46
47 self.embed_tokens = VocabParallelEmbedding(
48 self.config.vocab_size,
49 self.config.hidden_size,
50 quant_config=quant_config,
51 prefix=maybe_prefix(prefix, "embed_tokens"),
52 )
53
54 self.layers = nn.ModuleList(
55 [
56 DeepseekV2DecoderLayer(
57 vllm_config,
58 prefix=maybe_prefix(prefix, f"layers.{i + start_layer_id}"),
59 config=self.config,
60 )
61 for i in range(self.config.num_hidden_layers)
62 ]
63 )
64
65 self.fc = nn.Linear(
66 self.config.model.hidden_size * 2,
67 self.config.model.hidden_size,
68 bias=False,
69 )
70
71 self.enorm = RMSNorm(self.config.hidden_size, eps=self.config.rms_norm_eps)
72 self.hnorm = RMSNorm(self.config.hidden_size, eps=self.config.rms_norm_eps)
73 self.norm = RMSNorm(self.config.hidden_size, eps=self.config.rms_norm_eps)
74
75 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
76 return self.embed_tokens(input_ids)
77
78 def forward(
79 self,
80 input_ids: torch.Tensor,
81 positions: torch.Tensor,
82 hidden_states: torch.Tensor,
83 ) -> tuple[torch.Tensor, torch.Tensor]:
84 input_embeds = self.embed_tokens(input_ids)
85
86 inputs = torch.cat(
87 [self.enorm(input_embeds), self.hnorm(hidden_states)], dim=-1
88 )
89 hidden_states = self.fc(inputs)
90 residual = None
91 for layer in self.layers:
92 hidden_states, residual = layer(
93 positions,
94 hidden_states,
95 residual,
96 )
97 hidden_states, _ = self.norm(hidden_states, residual)
98 return hidden_states, hidden_states
99
100 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
101 stacked_params_mapping = [
102 # (param_name, shard_name, shard_id)
103 ("gate_up_proj", "gate_proj", 0),
104 ("gate_up_proj", "up_proj", 1),
105 ("fused_qkv_a_proj", "q_a_proj", 0),
106 ("fused_qkv_a_proj", "kv_a_proj_with_mqa", 1),
107 ]
108
109 # Params for weights, fp8 weight scales, fp8 activation scales
110 # (param_name, weight_name, expert_id, shard_id)
111 expert_params_mapping = fused_moe_make_expert_params_mapping(
112 self,
113 ckpt_gate_proj_name="gate_proj",
114 ckpt_down_proj_name="down_proj",
115 ckpt_up_proj_name="up_proj",
116 num_experts=self.config.n_routed_experts,
117 )
118
119 params_dict = dict(self.named_parameters())
120 loaded_params: set[str] = set()
121 for name, loaded_weight in weights:
122 if "rotary_emb.inv_freq" in name:
123 continue
124
125 for param_name, weight_name, shard_id in stacked_params_mapping:
126 # Skip non-stacked layers and experts (experts handled below).
127 if weight_name not in name:
128 continue
129 # We have mlp.experts[0].gate_proj in the checkpoint.
130 # Since we handle the experts below in expert_params_mapping,
131 # we need to skip here BEFORE we update the name, otherwise
132 # name will be updated to mlp.experts[0].gate_up_proj, which
133 # will then be updated below in expert_params_mapping
134 # for mlp.experts[0].gate_gate_up_proj, which breaks load.
135 if ("mlp.experts." in name) and name not in params_dict:
136 continue
137 name_mapped = name.replace(weight_name, param_name)
138
139 # QKV fusion is optional, fall back to normal
140 # weight loading if it's not enabled
141 # if go with fusion option, then update name
142 if (
143 param_name == "fused_qkv_a_proj"
144 ) and name_mapped not in params_dict:
145 continue
146 else:
147 name = name_mapped
148
149 # Skip loading extra bias for GPTQ models.
150 if name.endswith(".bias") and name not in params_dict:
151 continue
152
153 param = params_dict[name]
154 weight_loader = param.weight_loader
155 weight_loader(param, loaded_weight, shard_id)
156 break
157 else:
158 for mapping in expert_params_mapping:
159 param_name, weight_name, expert_id, expert_shard_id = mapping
160 if weight_name not in name:
161 continue
162 name = name.replace(weight_name, param_name)
163
164 param = params_dict[name]
165 weight_loader = param.weight_loader
166 weight_loader(
167 param,
168 loaded_weight,
169 name,
170 shard_id=expert_shard_id,
171 expert_id=expert_id,
172 )
173 break
174 else:
175 # Skip loading extra bias for GPTQ models.
176 if name.endswith(".bias") and name not in params_dict:
177 continue
178
179 # Remapping the name of FP8 kv-scale.
180 remapped_name = maybe_remap_kv_scale_name(name, params_dict)
181 if remapped_name is None:
182 continue
183 name = remapped_name
184
185 param = params_dict[name]
186 weight_loader = getattr(
187 param, "weight_loader", default_weight_loader
188 )
189 weight_loader(param, loaded_weight)
190 loaded_params.add(name)
191 return loaded_params
192
193
194 class EagleDeepseekV3ForCausalLM(DeepseekV3ForCausalLM):
195 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
196 nn.Module.__init__(self)
197 assert vllm_config.speculative_config is not None
198 self.config = vllm_config.speculative_config.draft_model_config.hf_config
199 quant_config = vllm_config.quant_config
200 target_layer_num = vllm_config.model_config.get_num_layers(
201 vllm_config.parallel_config
202 )
203 self.model = DeepseekV2Model(
204 vllm_config=vllm_config,
205 prefix=maybe_prefix(prefix, "model"),
206 start_layer_id=target_layer_num,
207 )
208
209 self.lm_head = ParallelLMHead(
210 self.config.vocab_size,
211 self.config.hidden_size,
212 quant_config=quant_config,
213 prefix=maybe_prefix(prefix, "lm_head"),
214 )
215
216 logit_scale = getattr(self.config, "logit_scale", 1.0)
217 self.logits_processor = LogitsProcessor(
218 self.config.vocab_size, scale=logit_scale
219 )
220
221 # Set MoE hyperparameters
222 self.num_moe_layers = self.config.num_hidden_layers
223 self.set_moe_parameters()
224
225 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
226 return self.model.embed_input_ids(input_ids)
227
228 def forward( # type: ignore[override]
229 self,
230 input_ids: torch.Tensor,
231 positions: torch.Tensor,
232 hidden_states: torch.Tensor,
233 inputs_embeds: torch.Tensor | None = None,
234 ) -> tuple[torch.Tensor, torch.Tensor]:
235 if inputs_embeds is not None:
236 raise NotImplementedError(
237 f"{type(self).__name__} does not support multimodal inputs yet."
238 )
239 return self.model(input_ids, positions, hidden_states)
240
241 def compute_logits(
242 self,
243 hidden_states: torch.Tensor,
244 ) -> torch.Tensor | None:
245 logits = self.logits_processor(self.lm_head, hidden_states)
246 return logits
247
248 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
249 def transform(inputs):
250 name, loaded_weight = inputs
251 if "lm_head" not in name:
252 name = "model." + name
253 process_eagle_weight(self, name)
254 return name, loaded_weight
255
256 loader = AutoWeightsLoader(self)
257 loader.load_weights(map(transform, weights))