main
py 387 lines 13.4 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Shared Step decoder blocks and the Step1 text model."""
4
5 from __future__ import annotations
6
7 import math
8 from collections.abc import Iterable
9
10 import torch
11 from torch import nn
12
13 from vllm.config import CacheConfig, VllmConfig
14 from vllm.distributed import (
15 get_pp_group,
16 get_tensor_model_parallel_rank,
17 get_tensor_model_parallel_world_size,
18 )
19 from vllm.model_executor.layers.activation import SiluAndMul
20 from vllm.model_executor.layers.attention import Attention
21 from vllm.model_executor.layers.layernorm import RMSNorm
22 from vllm.model_executor.layers.linear import (
23 MergedColumnParallelLinear,
24 QKVParallelLinear,
25 RowParallelLinear,
26 )
27 from vllm.model_executor.layers.logits_processor import LogitsProcessor
28 from vllm.model_executor.layers.quantization import QuantizationConfig
29 from vllm.model_executor.layers.vocab_parallel_embedding import (
30 ParallelLMHead,
31 VocabParallelEmbedding,
32 )
33 from vllm.model_executor.models.interfaces import (
34 EagleModelMixin,
35 SupportsEagle,
36 SupportsEagle3,
37 SupportsPP,
38 )
39 from vllm.model_executor.models.utils import (
40 AutoWeightsLoader,
41 PPMissingLayer,
42 WeightsMapper,
43 make_empty_intermediate_tensors_factory,
44 make_layers,
45 maybe_prefix,
46 )
47 from vllm.sequence import IntermediateTensors
48 from vllm.v1.attention.backend import AttentionType
49
50
51 def _get_step_alibi_slopes(total_num_heads: int) -> torch.Tensor:
52 """Reference ALiBi slopes used by Step models."""
53 closest_power_of_2 = 2 ** math.floor(math.log2(total_num_heads))
54 base = torch.tensor(
55 2 ** (-8.0 / closest_power_of_2),
56 dtype=torch.float32,
57 )
58 slopes = torch.pow(
59 base,
60 torch.arange(1, 1 + closest_power_of_2, dtype=torch.int32),
61 )
62 if closest_power_of_2 != total_num_heads:
63 extra_base = torch.tensor(
64 2 ** (-4.0 / closest_power_of_2),
65 dtype=torch.float32,
66 )
67 num_remaining_heads = total_num_heads - closest_power_of_2
68 extra_powers = torch.arange(
69 1,
70 1 + 2 * num_remaining_heads,
71 2,
72 dtype=torch.int32,
73 )
74 slopes = torch.cat(
75 [slopes, torch.pow(extra_base, extra_powers)],
76 dim=0,
77 )
78 return slopes
79
80
81 class StepAttention(nn.Module):
82 def __init__(
83 self,
84 config,
85 cache_config: CacheConfig | None = None,
86 quant_config: QuantizationConfig | None = None,
87 prefix: str = "",
88 ):
89 super().__init__()
90 self.hidden_size = config.hidden_size
91 tp_size = get_tensor_model_parallel_world_size()
92 self.total_num_heads = config.num_attention_heads
93 assert self.total_num_heads % tp_size == 0
94 self.num_heads = self.total_num_heads // tp_size
95 self.head_dim = self.hidden_size // self.total_num_heads
96
97 total_num_kv_heads = getattr(
98 config, "num_attention_groups", getattr(config, "num_key_value_heads", 1)
99 )
100 if total_num_kv_heads is None or total_num_kv_heads <= 0:
101 total_num_kv_heads = 1
102 self.total_num_kv_heads = total_num_kv_heads
103 if self.total_num_kv_heads >= tp_size:
104 assert self.total_num_kv_heads % tp_size == 0
105 else:
106 assert tp_size % self.total_num_kv_heads == 0
107 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
108
109 self.qkv_proj = QKVParallelLinear(
110 hidden_size=self.hidden_size,
111 head_size=self.head_dim,
112 total_num_heads=self.total_num_heads,
113 total_num_kv_heads=self.total_num_kv_heads,
114 bias=getattr(config, "attention_bias", False),
115 quant_config=quant_config,
116 prefix=f"{prefix}.qkv_proj",
117 )
118 self.q_size = self.num_heads * self.head_dim
119 self.kv_size = self.num_kv_heads * self.head_dim
120
121 self.o_proj = RowParallelLinear(
122 input_size=self.total_num_heads * self.head_dim,
123 output_size=self.hidden_size,
124 bias=getattr(config, "attention_bias", False),
125 quant_config=quant_config,
126 prefix=f"{prefix}.o_proj",
127 )
128
129 tp_rank = get_tensor_model_parallel_rank()
130 head_start = tp_rank * self.num_heads
131 head_end = (tp_rank + 1) * self.num_heads
132 alibi_slopes = _get_step_alibi_slopes(self.total_num_heads)[head_start:head_end]
133 alibi_slopes = alibi_slopes.tolist()
134
135 self.scale = self.head_dim**-0.5
136 self.attn = Attention(
137 self.num_heads,
138 self.head_dim,
139 self.scale,
140 num_kv_heads=self.num_kv_heads,
141 cache_config=cache_config,
142 quant_config=quant_config,
143 alibi_slopes=alibi_slopes,
144 prefix=f"{prefix}.attn",
145 use_alibi_sqrt=True,
146 attn_type=AttentionType.DECODER,
147 )
148
149 def forward(
150 self,
151 hidden_states: torch.Tensor,
152 ) -> torch.Tensor:
153 qkv, _ = self.qkv_proj(hidden_states)
154 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
155 attn_output = self.attn(q, k, v)
156 output, _ = self.o_proj(attn_output)
157 return output
158
159
160 class StepMLP(nn.Module):
161 def __init__(
162 self,
163 hidden_size: int,
164 intermediate_size: int,
165 quant_config: QuantizationConfig | None = None,
166 prefix: str = "",
167 bias: bool = False,
168 ):
169 super().__init__()
170 self.gate_up_proj = MergedColumnParallelLinear(
171 input_size=hidden_size,
172 output_sizes=[intermediate_size, intermediate_size],
173 bias=bias,
174 quant_config=quant_config,
175 prefix=f"{prefix}.gate_up_proj",
176 )
177 self.down_proj = RowParallelLinear(
178 input_size=intermediate_size,
179 output_size=hidden_size,
180 bias=bias,
181 quant_config=quant_config,
182 prefix=f"{prefix}.down_proj",
183 )
184 self.act_fn = SiluAndMul()
185
186 def forward(self, x: torch.Tensor) -> torch.Tensor:
187 x, _ = self.gate_up_proj(x)
188 x = self.act_fn(x)
189 x, _ = self.down_proj(x)
190 return x
191
192
193 class StepDecoderLayer(nn.Module):
194 def __init__(self, vllm_config: VllmConfig, prefix: str = ""):
195 super().__init__()
196 config = vllm_config.model_config.hf_config
197 cache_config = vllm_config.cache_config
198 quant_config = vllm_config.quant_config
199
200 self.hidden_size = config.hidden_size
201 self.self_attn = StepAttention(
202 config=config,
203 cache_config=cache_config,
204 quant_config=quant_config,
205 prefix=f"{prefix}.self_attn",
206 )
207 self.mlp = StepMLP(
208 hidden_size=self.hidden_size,
209 intermediate_size=config.intermediate_size,
210 quant_config=quant_config,
211 prefix=f"{prefix}.mlp",
212 bias=getattr(config, "mlp_bias", False),
213 )
214 self.input_layernorm = RMSNorm(
215 self.hidden_size,
216 eps=config.rms_norm_eps,
217 )
218 self.post_attention_layernorm = RMSNorm(
219 self.hidden_size,
220 eps=config.rms_norm_eps,
221 )
222
223 def forward(
224 self,
225 positions: torch.Tensor,
226 hidden_states: torch.Tensor,
227 residual: torch.Tensor | None,
228 ) -> tuple[torch.Tensor, torch.Tensor]:
229 if residual is None:
230 residual = hidden_states
231 hidden_states = self.input_layernorm(hidden_states)
232 else:
233 hidden_states, residual = self.input_layernorm(hidden_states, residual)
234 hidden_states = self.self_attn(hidden_states=hidden_states)
235 hidden_states, residual = self.post_attention_layernorm(hidden_states, residual)
236 hidden_states = self.mlp(hidden_states)
237 return hidden_states, residual
238
239
240 class StepDecoderModel(nn.Module, EagleModelMixin):
241 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
242 super().__init__()
243 config = vllm_config.model_config.hf_config
244 quant_config = vllm_config.quant_config
245
246 self.config = config
247 self.quant_config = quant_config
248 # Need embed_tokens on first rank, and also on last rank if tie_word_embeddings
249 if get_pp_group().is_first_rank or (
250 config.tie_word_embeddings and get_pp_group().is_last_rank
251 ):
252 self.embed_tokens = VocabParallelEmbedding(
253 config.vocab_size,
254 config.hidden_size,
255 quant_config=quant_config,
256 )
257 else:
258 self.embed_tokens = PPMissingLayer()
259 self.start_layer, self.end_layer, self.layers = make_layers(
260 config.num_hidden_layers,
261 lambda prefix: StepDecoderLayer(vllm_config=vllm_config, prefix=prefix),
262 prefix=maybe_prefix(prefix, "layers"),
263 )
264 if get_pp_group().is_last_rank:
265 self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
266 else:
267 self.norm = PPMissingLayer()
268
269 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
270 ["hidden_states", "residual"],
271 config.hidden_size,
272 )
273
274 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
275 return self.embed_tokens(input_ids)
276
277 def forward(
278 self,
279 input_ids: torch.Tensor | None,
280 positions: torch.Tensor,
281 intermediate_tensors: IntermediateTensors | None,
282 inputs_embeds: torch.Tensor | None = None,
283 ) -> torch.Tensor | IntermediateTensors | tuple[torch.Tensor, list[torch.Tensor]]:
284 if get_pp_group().is_first_rank:
285 if inputs_embeds is not None:
286 hidden_states = inputs_embeds
287 else:
288 assert input_ids is not None
289 hidden_states = self.embed_input_ids(input_ids)
290 residual = None
291 else:
292 assert intermediate_tensors is not None
293 hidden_states = intermediate_tensors["hidden_states"]
294 residual = intermediate_tensors["residual"]
295
296 aux_hidden_states = self._maybe_add_hidden_state([], 0, hidden_states, residual)
297 for idx, layer in enumerate(self.layers[self.start_layer : self.end_layer]):
298 hidden_states, residual = layer(positions, hidden_states, residual)
299 self._maybe_add_hidden_state(
300 aux_hidden_states, idx + 1, hidden_states, residual
301 )
302
303 if not get_pp_group().is_last_rank:
304 return IntermediateTensors(
305 {"hidden_states": hidden_states, "residual": residual}
306 )
307
308 hidden_states, _ = self.norm(hidden_states, residual)
309 if aux_hidden_states:
310 return hidden_states, aux_hidden_states
311 return hidden_states
312
313
314 class Step1ForCausalLM(nn.Module, SupportsPP, SupportsEagle, SupportsEagle3):
315 hf_to_vllm_mapper = WeightsMapper(
316 orig_to_new_stacked={
317 # weight_name: (param_name, shard_id)
318 ".q_proj": (".qkv_proj", "q"),
319 ".k_proj": (".qkv_proj", "k"),
320 ".v_proj": (".qkv_proj", "v"),
321 ".gate_proj": (".gate_up_proj", 0),
322 ".up_proj": (".gate_up_proj", 1),
323 }
324 )
325 packed_modules_mapping = {
326 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
327 "gate_up_proj": ["gate_proj", "up_proj"],
328 }
329
330 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
331 super().__init__()
332 config = vllm_config.model_config.hf_config
333 quant_config = vllm_config.quant_config
334
335 self.config = config
336 self.quant_config = quant_config
337 self.model = StepDecoderModel(
338 vllm_config=vllm_config,
339 prefix=maybe_prefix(prefix, "model"),
340 )
341
342 if get_pp_group().is_last_rank:
343 self.lm_head = ParallelLMHead(
344 config.vocab_size,
345 config.hidden_size,
346 quant_config=quant_config,
347 prefix=maybe_prefix(prefix, "lm_head"),
348 )
349 if getattr(config, "tie_word_embeddings", True):
350 self.lm_head = self.lm_head.tie_weights(self.model.embed_tokens)
351 self.logits_processor = LogitsProcessor(config.vocab_size)
352 else:
353 self.lm_head = PPMissingLayer()
354 self.logits_processor = None # type: ignore[assignment]
355
356 self.make_empty_intermediate_tensors = (
357 self.model.make_empty_intermediate_tensors
358 )
359
360 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
361 return self.model.embed_input_ids(input_ids)
362
363 def forward(
364 self,
365 input_ids: torch.LongTensor | None,
366 positions: torch.Tensor,
367 intermediate_tensors: IntermediateTensors | None,
368 inputs_embeds: torch.Tensor | None = None,
369 ) -> torch.Tensor | IntermediateTensors | tuple[torch.Tensor, list[torch.Tensor]]:
370 return self.model(
371 input_ids,
372 positions,
373 intermediate_tensors,
374 inputs_embeds=inputs_embeds,
375 )
376
377 def compute_logits(
378 self,
379 hidden_states: torch.Tensor,
380 ) -> torch.Tensor | None:
381 if not get_pp_group().is_last_rank:
382 return None
383 return self.logits_processor(self.lm_head, hidden_states)
384
385 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
386 loader = AutoWeightsLoader(self)
387 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)