main
py 425 lines 15.2 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 Solar model compatible with HuggingFace weights."""
26
27 from collections.abc import Iterable
28
29 import torch
30 from torch import nn
31 from transformers import PreTrainedConfig
32
33 from vllm.compilation.decorators import support_torch_compile
34 from vllm.config import CacheConfig, VllmConfig
35 from vllm.distributed import get_pp_group, get_tensor_model_parallel_world_size
36 from vllm.model_executor.layers.activation import SiluAndMul
37 from vllm.model_executor.layers.attention import Attention
38 from vllm.model_executor.layers.layernorm import RMSNorm
39 from vllm.model_executor.layers.linear import (
40 MergedColumnParallelLinear,
41 QKVParallelLinear,
42 RowParallelLinear,
43 )
44 from vllm.model_executor.layers.logits_processor import LogitsProcessor
45 from vllm.model_executor.layers.quantization import QuantizationConfig
46 from vllm.model_executor.layers.rotary_embedding import get_rope
47 from vllm.model_executor.layers.vocab_parallel_embedding import (
48 ParallelLMHead,
49 VocabParallelEmbedding,
50 )
51 from vllm.sequence import IntermediateTensors
52
53 from .interfaces import SupportsLoRA, SupportsPP
54 from .utils import (
55 AutoWeightsLoader,
56 PPMissingLayer,
57 WeightsMapper,
58 make_empty_intermediate_tensors_factory,
59 make_layers,
60 maybe_prefix,
61 )
62
63
64 class SolarMLP(nn.Module):
65 def __init__(
66 self,
67 hidden_size: int,
68 intermediate_size: int,
69 hidden_act: str,
70 quant_config: QuantizationConfig | None = None,
71 bias: bool = False,
72 prefix: str = "",
73 ) -> None:
74 super().__init__()
75 self.gate_up_proj = MergedColumnParallelLinear(
76 input_size=hidden_size,
77 output_sizes=[intermediate_size] * 2,
78 bias=bias,
79 quant_config=quant_config,
80 prefix=f"{prefix}.gate_up_proj",
81 )
82 self.down_proj = RowParallelLinear(
83 input_size=intermediate_size,
84 output_size=hidden_size,
85 bias=bias,
86 quant_config=quant_config,
87 prefix=f"{prefix}.down_proj",
88 )
89 if hidden_act != "silu":
90 raise ValueError(
91 f"Unsupported activation: {hidden_act}. Only silu is supported for now."
92 )
93 self.act_fn = SiluAndMul()
94
95 def forward(self, x):
96 gate_up, _ = self.gate_up_proj(x)
97 x = self.act_fn(gate_up)
98 x, _ = self.down_proj(x)
99 return x
100
101
102 class SolarAttention(nn.Module):
103 def __init__(
104 self,
105 config: PreTrainedConfig,
106 hidden_size: int,
107 num_heads: int,
108 num_kv_heads: int,
109 max_position_embeddings: int = 8192,
110 quant_config: QuantizationConfig | None = None,
111 bias: bool = False,
112 cache_config: CacheConfig | None = None,
113 prefix: str = "",
114 ) -> None:
115 super().__init__()
116 self.hidden_size = hidden_size
117 tp_size = get_tensor_model_parallel_world_size()
118 self.total_num_heads = num_heads
119 assert self.total_num_heads % tp_size == 0
120 self.num_heads = self.total_num_heads // tp_size
121 self.total_num_kv_heads = num_kv_heads
122 if self.total_num_kv_heads >= tp_size:
123 # Number of KV heads is greater than TP size, so we partition
124 # the KV heads across multiple tensor parallel GPUs.
125 assert self.total_num_kv_heads % tp_size == 0
126 else:
127 # Number of KV heads is less than TP size, so we replicate
128 # the KV heads across multiple tensor parallel GPUs.
129 assert tp_size % self.total_num_kv_heads == 0
130 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
131 # MistralConfig has an optional head_dim introduced by Mistral-Nemo
132 self.head_dim = getattr(config, "head_dim", None)
133 if self.head_dim is None:
134 self.head_dim = self.hidden_size // self.total_num_heads
135 self.q_size = self.num_heads * self.head_dim
136 self.kv_size = self.num_kv_heads * self.head_dim
137 self.scaling = self.head_dim**-0.5
138 self.max_position_embeddings = max_position_embeddings
139
140 self.qkv_proj = QKVParallelLinear(
141 hidden_size=hidden_size,
142 head_size=self.head_dim,
143 total_num_heads=self.total_num_heads,
144 total_num_kv_heads=self.total_num_kv_heads,
145 bias=bias,
146 quant_config=quant_config,
147 prefix=f"{prefix}.qkv_proj",
148 )
149 self.o_proj = RowParallelLinear(
150 input_size=self.total_num_heads * self.head_dim,
151 output_size=hidden_size,
152 bias=bias,
153 quant_config=quant_config,
154 prefix=f"{prefix}.o_proj",
155 )
156
157 self.rotary_emb = get_rope(
158 self.head_dim,
159 max_position=max_position_embeddings,
160 rope_parameters=config.rope_parameters,
161 )
162 self.attn = Attention(
163 self.num_heads,
164 self.head_dim,
165 self.scaling,
166 num_kv_heads=self.num_kv_heads,
167 cache_config=cache_config,
168 quant_config=quant_config,
169 prefix=f"{prefix}.attn",
170 )
171
172 def forward(
173 self,
174 positions: torch.Tensor,
175 hidden_states: torch.Tensor,
176 ) -> torch.Tensor:
177 qkv, _ = self.qkv_proj(hidden_states)
178 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
179 q, k = self.rotary_emb(positions, q, k)
180 attn_output = self.attn(q, k, v)
181 output, _ = self.o_proj(attn_output)
182 return output
183
184
185 class SolarDecoderLayer(nn.Module):
186 def __init__(
187 self,
188 config: PreTrainedConfig,
189 cache_config: CacheConfig | None = None,
190 quant_config: QuantizationConfig | None = None,
191 prefix: str = "",
192 ) -> None:
193 super().__init__()
194 self.hidden_size = config.hidden_size
195 max_position_embeddings = getattr(config, "max_position_embeddings", 8192)
196 # Support abacusai/Smaug-72B-v0.1 with attention_bias
197 attention_bias = getattr(config, "attention_bias", False) or getattr(
198 config, "bias", False
199 )
200 self.self_attn = SolarAttention(
201 config=config,
202 hidden_size=self.hidden_size,
203 num_heads=config.num_attention_heads,
204 num_kv_heads=getattr(
205 config, "num_key_value_heads", config.num_attention_heads
206 ),
207 max_position_embeddings=max_position_embeddings,
208 quant_config=quant_config,
209 bias=attention_bias,
210 cache_config=cache_config,
211 prefix=f"{prefix}.self_attn",
212 )
213 self.mlp = SolarMLP(
214 hidden_size=self.hidden_size,
215 intermediate_size=config.intermediate_size,
216 hidden_act=config.hidden_act,
217 quant_config=quant_config,
218 bias=getattr(config, "mlp_bias", False),
219 prefix=f"{prefix}.mlp",
220 )
221 self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
222 self.post_attention_layernorm = RMSNorm(
223 config.hidden_size, eps=config.rms_norm_eps
224 )
225
226 def forward(
227 self,
228 positions: torch.Tensor,
229 hidden_states: torch.Tensor,
230 residual: torch.Tensor | None,
231 ) -> tuple[torch.Tensor, torch.Tensor]:
232 # Self Attention
233 if residual is None:
234 residual = hidden_states
235 hidden_states = self.input_layernorm(hidden_states)
236 else:
237 hidden_states, residual = self.input_layernorm(hidden_states, residual)
238 hidden_states = self.self_attn(
239 positions=positions,
240 hidden_states=hidden_states,
241 )
242
243 # Fully Connected
244 hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
245 hidden_states = self.mlp(hidden_states)
246 return hidden_states, residual
247
248
249 @support_torch_compile
250 class SolarModel(nn.Module):
251 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
252 super().__init__()
253
254 config = vllm_config.model_config.hf_config
255 cache_config = vllm_config.cache_config
256 quant_config = vllm_config.quant_config
257
258 self.config = config
259 self.quant_config = quant_config
260
261 self.vocab_size = config.vocab_size
262
263 if get_pp_group().is_first_rank or (
264 config.tie_word_embeddings and get_pp_group().is_last_rank
265 ):
266 self.embed_tokens = VocabParallelEmbedding(
267 self.vocab_size,
268 config.hidden_size,
269 )
270 else:
271 self.embed_tokens = PPMissingLayer()
272 self.start_layer, self.end_layer, self.layers = make_layers(
273 config.num_hidden_layers,
274 lambda prefix: SolarDecoderLayer(
275 config=config,
276 cache_config=cache_config,
277 quant_config=quant_config,
278 prefix=prefix,
279 ),
280 prefix=f"{prefix}.layers",
281 )
282 if get_pp_group().is_last_rank:
283 self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
284 else:
285 self.norm = PPMissingLayer()
286
287 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
288 ["hidden_states", "residual"], config.hidden_size
289 )
290
291 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
292 return self.embed_tokens(input_ids)
293
294 def forward(
295 self,
296 input_ids: torch.Tensor | None,
297 positions: torch.Tensor,
298 intermediate_tensors: IntermediateTensors | None,
299 inputs_embeds: torch.Tensor | None = None,
300 ) -> torch.Tensor | IntermediateTensors:
301 if get_pp_group().is_first_rank:
302 if inputs_embeds is not None:
303 hidden_states = inputs_embeds
304 else:
305 hidden_states = self.embed_input_ids(input_ids)
306 residual = None
307 else:
308 assert intermediate_tensors is not None
309 hidden_states = intermediate_tensors["hidden_states"]
310 residual = intermediate_tensors["residual"]
311
312 bskcn_h_1 = None
313 bskcn_h_2 = None
314 bskcn_r_1 = None
315 bskcn_r_2 = None
316 bskcn_tv = self.config.bskcn_tv[0] if self.training else self.config.bskcn_tv[1]
317
318 for i in range(self.start_layer, self.end_layer):
319 if i in self.config.bskcn_1:
320 bskcn_h_1 = hidden_states.clone()
321 assert residual is not None
322 bskcn_r_1 = residual.clone()
323 if i in self.config.bskcn_2:
324 bskcn_h_2 = hidden_states.clone()
325 assert residual is not None
326 bskcn_r_2 = residual.clone()
327 if i in self.config.bskcn_3:
328 hidden_states = bskcn_h_1 * bskcn_tv + hidden_states * (1 - bskcn_tv)
329 residual = bskcn_r_1 * bskcn_tv + residual * (1 - bskcn_tv)
330 if i in self.config.bskcn_4:
331 hidden_states = bskcn_h_2 * bskcn_tv + hidden_states * (1 - bskcn_tv)
332 residual = bskcn_r_2 * bskcn_tv + residual * (1 - bskcn_tv)
333 layer = self.layers[i]
334 hidden_states, residual = layer(
335 positions,
336 hidden_states,
337 residual,
338 )
339
340 if not get_pp_group().is_last_rank:
341 return IntermediateTensors(
342 {"hidden_states": hidden_states, "residual": residual}
343 )
344
345 hidden_states, _ = self.norm(hidden_states, residual)
346 return hidden_states
347
348
349 class SolarForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
350 hf_to_vllm_mapper = WeightsMapper(
351 orig_to_new_stacked={
352 # weight_name: (param_name, shard_id)
353 ".q_proj": (".qkv_proj", "q"),
354 ".k_proj": (".qkv_proj", "k"),
355 ".v_proj": (".qkv_proj", "v"),
356 ".gate_proj": (".gate_up_proj", 0),
357 ".up_proj": (".gate_up_proj", 1),
358 }
359 )
360 packed_modules_mapping = {
361 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
362 "gate_up_proj": ["gate_proj", "up_proj"],
363 }
364 # LoRA specific attributes
365 embedding_modules = {
366 "embed_tokens": "input_embeddings",
367 "lm_head": "output_embeddings",
368 }
369
370 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
371 super().__init__()
372 config = vllm_config.model_config.hf_config
373 quant_config = vllm_config.quant_config
374
375 self.config = config
376
377 self.quant_config = quant_config
378
379 self.model = SolarModel(
380 vllm_config=vllm_config,
381 prefix=maybe_prefix(prefix, "model"),
382 )
383 if get_pp_group().is_last_rank:
384 self.lm_head = ParallelLMHead(
385 config.vocab_size,
386 config.hidden_size,
387 quant_config=quant_config,
388 prefix=maybe_prefix(prefix, "lm_head"),
389 )
390 if config.tie_word_embeddings:
391 self.lm_head = self.lm_head.tie_weights(self.model.embed_tokens)
392
393 logit_scale = getattr(config, "logit_scale", 1.0)
394 self.logits_processor = LogitsProcessor(
395 config.vocab_size, scale=logit_scale
396 )
397 else:
398 self.lm_head = PPMissingLayer()
399
400 self.make_empty_intermediate_tensors = (
401 self.model.make_empty_intermediate_tensors
402 )
403
404 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
405 return self.model.embed_input_ids(input_ids)
406
407 def forward(
408 self,
409 input_ids: torch.Tensor | None,
410 positions: torch.Tensor,
411 intermediate_tensors: IntermediateTensors | None = None,
412 inputs_embeds: torch.Tensor | None = None,
413 ) -> torch.Tensor | IntermediateTensors:
414 model_output = self.model(
415 input_ids, positions, intermediate_tensors, inputs_embeds
416 )
417 return model_output
418
419 def compute_logits(self, hidden_states: torch.Tensor) -> torch.Tensor:
420 logits = self.logits_processor(self.lm_head, hidden_states)
421 return logits
422
423 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
424 loader = AutoWeightsLoader(self)
425 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)