main
py 374 lines 12.9 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/bloom/modeling_bloom.py
6 # Copyright 2023 The vLLM team.
7 # Copyright 2022 HuggingFace Inc. team and BigScience workshop.
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License");
10 # you may not use this file except in compliance with the License.
11 # You may obtain a copy of the License at
12 #
13 # http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
20 """Inference-only BLOOM model compatible with HuggingFace weights."""
21
22 import math
23 from collections.abc import Iterable
24 from itertools import islice
25
26 import torch
27 from torch import nn
28 from transformers import BloomConfig
29
30 from vllm.compilation.decorators import support_torch_compile
31 from vllm.config import CacheConfig, VllmConfig
32 from vllm.distributed import (
33 get_pp_group,
34 get_tensor_model_parallel_rank,
35 get_tensor_model_parallel_world_size,
36 )
37 from vllm.model_executor.layers.activation import get_act_fn
38 from vllm.model_executor.layers.attention import Attention
39 from vllm.model_executor.layers.linear import (
40 ColumnParallelLinear,
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.vocab_parallel_embedding import (
47 ParallelLMHead,
48 VocabParallelEmbedding,
49 )
50 from vllm.sequence import IntermediateTensors
51
52 from .interfaces import SupportsPP, SupportsQuant
53 from .utils import (
54 AutoWeightsLoader,
55 make_empty_intermediate_tensors_factory,
56 make_layers,
57 maybe_prefix,
58 )
59
60
61 def _get_alibi_slopes(total_num_heads: int) -> torch.Tensor:
62 closest_power_of_2 = 2 ** math.floor(math.log2(total_num_heads))
63 base = torch.tensor(
64 2 ** (-(2 ** -(math.log2(closest_power_of_2) - 3))),
65 dtype=torch.float32,
66 )
67 powers = torch.arange(1, 1 + closest_power_of_2, dtype=torch.int32)
68 slopes = torch.pow(base, powers)
69
70 if closest_power_of_2 != total_num_heads:
71 extra_base = torch.tensor(
72 2 ** (-(2 ** -(math.log2(2 * closest_power_of_2) - 3))),
73 dtype=torch.float32,
74 )
75 num_remaining_heads = min(
76 closest_power_of_2, total_num_heads - closest_power_of_2
77 )
78 extra_powers = torch.arange(
79 start=1, end=1 + 2 * num_remaining_heads, step=2, dtype=torch.int32
80 )
81 slopes = torch.cat([slopes, torch.pow(extra_base, extra_powers)], dim=0)
82 return slopes
83
84
85 class BloomAttention(nn.Module):
86 def __init__(
87 self,
88 config: BloomConfig,
89 cache_config: CacheConfig | None = None,
90 quant_config: QuantizationConfig | None = None,
91 prefix: str = "",
92 ):
93 super().__init__()
94 self.hidden_size = config.hidden_size
95 self.total_num_heads = config.n_head
96 self.head_dim = self.hidden_size // self.total_num_heads
97 assert self.head_dim * self.total_num_heads == self.hidden_size
98
99 tp_world_size = get_tensor_model_parallel_world_size()
100 assert self.total_num_heads % tp_world_size == 0
101 self.num_heads = self.total_num_heads // tp_world_size
102
103 self.query_key_value = QKVParallelLinear(
104 self.hidden_size,
105 self.head_dim,
106 self.total_num_heads,
107 bias=True,
108 quant_config=quant_config,
109 prefix=f"{prefix}.query_key_value",
110 )
111 self.dense = RowParallelLinear(
112 self.hidden_size,
113 self.hidden_size,
114 bias=True,
115 quant_config=quant_config,
116 prefix=f"{prefix}.dense",
117 )
118
119 # Create the alibi slopes and slice them.
120 tp_rank = get_tensor_model_parallel_rank()
121 head_start = tp_rank * self.num_heads
122 head_end = (tp_rank + 1) * self.num_heads
123 alibi_slopes = _get_alibi_slopes(self.total_num_heads)
124 alibi_slopes = alibi_slopes[head_start:head_end].tolist()
125
126 scaling = self.head_dim**-0.5
127 self.attn = Attention(
128 self.num_heads,
129 self.head_dim,
130 scaling,
131 alibi_slopes=alibi_slopes,
132 cache_config=cache_config,
133 quant_config=quant_config,
134 prefix=f"{prefix}.attn",
135 )
136
137 def forward(
138 self,
139 position_ids: torch.Tensor,
140 hidden_states: torch.Tensor,
141 ) -> torch.Tensor:
142 del position_ids # Unused.
143 qkv, _ = self.query_key_value(hidden_states)
144 q, k, v = qkv.chunk(chunks=3, dim=-1)
145 attn_output = self.attn(q, k, v)
146 output, _ = self.dense(attn_output)
147 return output
148
149
150 class BloomMLP(nn.Module):
151 def __init__(
152 self,
153 config: BloomConfig,
154 quant_config: QuantizationConfig | None = None,
155 prefix: str = "",
156 ):
157 super().__init__()
158 hidden_size = config.hidden_size
159 self.dense_h_to_4h = ColumnParallelLinear(
160 hidden_size,
161 4 * hidden_size,
162 quant_config=quant_config,
163 prefix=f"{prefix}.dense_h_to_4h",
164 )
165 self.gelu_impl = get_act_fn("gelu")
166 self.dense_4h_to_h = RowParallelLinear(
167 4 * hidden_size,
168 hidden_size,
169 quant_config=quant_config,
170 prefix=f"{prefix}.dense_4h_to_h",
171 )
172
173 def forward(self, x: torch.Tensor) -> torch.Tensor:
174 x, _ = self.dense_h_to_4h(x)
175 x = self.gelu_impl(x)
176 x, _ = self.dense_4h_to_h(x)
177 return x
178
179
180 class BloomBlock(nn.Module):
181 def __init__(
182 self,
183 config: BloomConfig,
184 cache_config: CacheConfig | None = None,
185 quant_config: QuantizationConfig | None = None,
186 prefix: str = "",
187 ):
188 super().__init__()
189 hidden_size = config.hidden_size
190
191 self.input_layernorm = nn.LayerNorm(hidden_size, eps=config.layer_norm_epsilon)
192 self.self_attention = BloomAttention(
193 config, cache_config, quant_config, prefix=f"{prefix}.self_attention"
194 )
195 self.post_attention_layernorm = nn.LayerNorm(
196 hidden_size, eps=config.layer_norm_epsilon
197 )
198 self.mlp = BloomMLP(config, quant_config, prefix=f"{prefix}.mlp")
199 self.apply_residual_connection_post_layernorm = (
200 config.apply_residual_connection_post_layernorm
201 )
202
203 def forward(
204 self,
205 position_ids: torch.Tensor,
206 hidden_states: torch.Tensor,
207 ) -> torch.Tensor:
208 # Layer norm at the beginning of the transformer layer.
209 layernorm_output = self.input_layernorm(hidden_states)
210
211 # Layer norm post the self attention.
212 if self.apply_residual_connection_post_layernorm:
213 residual = layernorm_output
214 else:
215 residual = hidden_states
216
217 # Self attention.
218 attention_output = self.self_attention(
219 position_ids=position_ids,
220 hidden_states=layernorm_output,
221 )
222 attention_output = attention_output + residual
223 layernorm_output = self.post_attention_layernorm(attention_output)
224
225 # Get residual
226 if self.apply_residual_connection_post_layernorm:
227 residual = layernorm_output
228 else:
229 residual = attention_output
230
231 # MLP.
232 output = self.mlp(layernorm_output) + residual
233 return output
234
235
236 @support_torch_compile
237 class BloomModel(nn.Module):
238 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
239 super().__init__()
240
241 config = vllm_config.model_config.hf_config
242 cache_config = vllm_config.cache_config
243 quant_config = vllm_config.quant_config
244 self.config = config
245
246 self.embed_dim = config.hidden_size
247
248 # Embedding + LN Embedding
249 self.word_embeddings = VocabParallelEmbedding(
250 config.vocab_size,
251 self.embed_dim,
252 )
253 self.word_embeddings_layernorm = nn.LayerNorm(
254 self.embed_dim, eps=config.layer_norm_epsilon
255 )
256
257 # Transformer blocks
258 self.start_layer, self.end_layer, self.h = make_layers(
259 config.num_hidden_layers,
260 lambda prefix: BloomBlock(
261 config, cache_config, quant_config, prefix=prefix
262 ),
263 prefix=f"{prefix}.h",
264 )
265
266 # Final Layer Norm
267 self.ln_f = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_epsilon)
268 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
269 ["hidden_states"], config.hidden_size
270 )
271
272 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
273 return self.word_embeddings(input_ids)
274
275 def forward(
276 self,
277 input_ids: torch.Tensor | None,
278 position_ids: torch.Tensor,
279 intermediate_tensors: IntermediateTensors | None,
280 inputs_embeds: torch.Tensor | None = None,
281 ) -> torch.Tensor | IntermediateTensors:
282 if get_pp_group().is_first_rank:
283 if inputs_embeds is not None:
284 hidden_states = inputs_embeds
285 else:
286 hidden_states = self.embed_input_ids(input_ids)
287 hidden_states = self.word_embeddings_layernorm(hidden_states)
288 else:
289 assert intermediate_tensors is not None
290 hidden_states = intermediate_tensors["hidden_states"]
291 for layer in islice(self.h, self.start_layer, self.end_layer):
292 hidden_states = layer(position_ids, hidden_states)
293 if not get_pp_group().is_last_rank:
294 return IntermediateTensors({"hidden_states": hidden_states})
295 hidden_states = self.ln_f(hidden_states)
296 return hidden_states
297
298 def _repack_qkv(
299 self, weights: Iterable[tuple[str, torch.Tensor]]
300 ) -> Iterable[tuple[str, torch.Tensor]]:
301 # BLOOM's fused QKV is laid out as (num_heads * 3 * head_size) on its
302 # output dim (0), while vLLM expects (3 * num_heads * head_size).
303 num_heads = self.config.num_attention_heads
304 for name, loaded_weight in weights:
305 if "query_key_value" in name:
306 shape = loaded_weight.shape
307 loaded_weight = loaded_weight.view((num_heads, 3, -1) + shape[1:])
308 loaded_weight = loaded_weight.transpose(0, 1)
309 loaded_weight = loaded_weight.reshape(shape)
310 yield name, loaded_weight
311
312 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
313 loader = AutoWeightsLoader(self)
314 return loader.load_weights(self._repack_qkv(weights))
315
316
317 class BloomForCausalLM(nn.Module, SupportsPP, SupportsQuant):
318 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
319 super().__init__()
320 config = vllm_config.model_config.hf_config
321 quant_config = vllm_config.quant_config
322 self.config = config
323 self.quant_config = quant_config
324 self.transformer = BloomModel(
325 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "transformer")
326 )
327 self.lm_head = ParallelLMHead(
328 self.config.vocab_size,
329 self.config.hidden_size,
330 prefix=maybe_prefix(prefix, "lm_head"),
331 )
332 if self.config.tie_word_embeddings:
333 self.lm_head = self.lm_head.tie_weights(self.transformer.word_embeddings)
334
335 self.logits_processor = LogitsProcessor(config.vocab_size)
336 self.make_empty_intermediate_tensors = (
337 self.transformer.make_empty_intermediate_tensors
338 )
339
340 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
341 return self.transformer.embed_input_ids(input_ids)
342
343 def forward(
344 self,
345 input_ids: torch.Tensor | None,
346 positions: torch.Tensor,
347 intermediate_tensors: IntermediateTensors | None = None,
348 inputs_embeds: torch.Tensor | None = None,
349 ) -> torch.Tensor | IntermediateTensors:
350 hidden_states = self.transformer(
351 input_ids, positions, intermediate_tensors, inputs_embeds
352 )
353 return hidden_states
354
355 def compute_logits(
356 self,
357 hidden_states: torch.Tensor,
358 ) -> torch.Tensor | None:
359 logits = self.logits_processor(self.lm_head, hidden_states)
360 return logits
361
362 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
363 loader = AutoWeightsLoader(self)
364 weights = _add_transformer_prefix(weights)
365 return loader.load_weights(weights)
366
367
368 def _add_transformer_prefix(
369 weights: Iterable[tuple[str, torch.Tensor]],
370 ) -> Iterable[tuple[str, torch.Tensor]]:
371 for name, tensor in weights:
372 if not name.startswith("transformer."):
373 name = "transformer." + name
374 yield name, tensor