main
py 373 lines 13.5 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # Copyright 2024 The vLLM team.
5 # Copyright 2024 Google Inc. HuggingFace Inc. team. All rights reserved.
6 #
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License");
9 # you may not use this file except in compliance with the License.
10 # You may obtain a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS,
16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 # See the License for the specific language governing permissions and
18 # limitations under the License.
19 from collections.abc import Iterable
20 from itertools import islice
21
22 import torch
23 from torch import nn
24 from transformers import Gemma2Config
25
26 from vllm.compilation.decorators import support_torch_compile
27 from vllm.config import CacheConfig, VllmConfig
28 from vllm.distributed import get_pp_group, get_tensor_model_parallel_world_size
29 from vllm.logger import init_logger
30 from vllm.model_executor.layers.activation import GeluAndMul
31 from vllm.model_executor.layers.attention import Attention
32 from vllm.model_executor.layers.layernorm import GemmaRMSNorm
33 from vllm.model_executor.layers.linear import (
34 MergedColumnParallelLinear,
35 QKVParallelLinear,
36 RowParallelLinear,
37 )
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.rotary_embedding import get_rope
41 from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
42 from vllm.sequence import IntermediateTensors
43
44 from .interfaces import SupportsLoRA, SupportsPP
45 from .utils import (
46 AutoWeightsLoader,
47 WeightsMapper,
48 extract_layer_index,
49 make_empty_intermediate_tensors_factory,
50 make_layers,
51 maybe_prefix,
52 )
53
54 logger = init_logger(__name__)
55
56
57 class Gemma2MLP(nn.Module):
58 def __init__(
59 self,
60 hidden_size: int,
61 intermediate_size: int,
62 hidden_activation: str,
63 quant_config: QuantizationConfig | None = None,
64 prefix: str = "",
65 ) -> None:
66 super().__init__()
67 self.gate_up_proj = MergedColumnParallelLinear(
68 hidden_size,
69 [intermediate_size] * 2,
70 bias=False,
71 quant_config=quant_config,
72 prefix=f"{prefix}.gate_up_proj",
73 )
74 self.down_proj = RowParallelLinear(
75 intermediate_size,
76 hidden_size,
77 bias=False,
78 quant_config=quant_config,
79 prefix=f"{prefix}.down_proj",
80 )
81 if not (hidden_activation == "gelu_pytorch_tanh"):
82 raise ValueError(
83 "Gemma2 uses `gelu_pytorch_tanh` as the hidden activation "
84 "function. Please set `hidden_activation` to `gelu_pytorch_tanh`."
85 )
86 self.act_fn = GeluAndMul(approximate="tanh")
87
88 def forward(self, x: torch.Tensor) -> torch.Tensor:
89 gate_up, _ = self.gate_up_proj(x)
90 x = self.act_fn(gate_up)
91 x, _ = self.down_proj(x)
92 return x
93
94
95 class Gemma2Attention(nn.Module):
96 def __init__(
97 self,
98 config: Gemma2Config,
99 hidden_size: int,
100 num_heads: int,
101 num_kv_heads: int,
102 head_dim: int,
103 max_position_embeddings: int,
104 cache_config: CacheConfig | None = None,
105 quant_config: QuantizationConfig | None = None,
106 attn_logits_soft_cap: float | None = None,
107 prefix: str = "",
108 ) -> None:
109 super().__init__()
110 self.config = config
111 self.hidden_size = hidden_size
112 tp_size = get_tensor_model_parallel_world_size()
113 self.total_num_heads = num_heads
114 assert self.total_num_heads % tp_size == 0
115 self.num_heads = self.total_num_heads // tp_size
116 self.total_num_kv_heads = num_kv_heads
117 if self.total_num_kv_heads >= tp_size:
118 # Number of KV heads is greater than TP size, so we partition
119 # the KV heads across multiple tensor parallel GPUs.
120 assert self.total_num_kv_heads % tp_size == 0
121 else:
122 # Number of KV heads is less than TP size, so we replicate
123 # the KV heads across multiple tensor parallel GPUs.
124 assert tp_size % self.total_num_kv_heads == 0
125 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
126 self.head_dim = head_dim
127 self.q_size = self.num_heads * self.head_dim
128 self.kv_size = self.num_kv_heads * self.head_dim
129 self.scaling = config.query_pre_attn_scalar**-0.5
130
131 self.qkv_proj = QKVParallelLinear(
132 hidden_size,
133 self.head_dim,
134 self.total_num_heads,
135 self.total_num_kv_heads,
136 bias=config.attention_bias,
137 quant_config=quant_config,
138 prefix=f"{prefix}.qkv_proj",
139 )
140 self.o_proj = RowParallelLinear(
141 self.total_num_heads * self.head_dim,
142 hidden_size,
143 bias=config.attention_bias,
144 quant_config=quant_config,
145 prefix=f"{prefix}.o_proj",
146 )
147 self.rotary_emb = get_rope(
148 self.head_dim,
149 max_position=max_position_embeddings,
150 rope_parameters=config.rope_parameters,
151 is_neox_style=True,
152 )
153
154 layer_idx = extract_layer_index(prefix)
155 is_sliding = config.layer_types[layer_idx] == "sliding_attention"
156 sliding_window = config.sliding_window if is_sliding else None
157
158 self.attn = Attention(
159 self.num_heads,
160 self.head_dim,
161 self.scaling,
162 num_kv_heads=self.num_kv_heads,
163 cache_config=cache_config,
164 quant_config=quant_config,
165 logits_soft_cap=attn_logits_soft_cap,
166 per_layer_sliding_window=sliding_window,
167 prefix=f"{prefix}.attn",
168 )
169
170 def forward(
171 self,
172 positions: torch.Tensor,
173 hidden_states: torch.Tensor,
174 ) -> torch.Tensor:
175 qkv, _ = self.qkv_proj(hidden_states)
176 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
177 q, k = self.rotary_emb(positions, q, k)
178 attn_output = self.attn(q, k, v)
179 output, _ = self.o_proj(attn_output)
180 return output
181
182
183 class Gemma2DecoderLayer(nn.Module):
184 def __init__(
185 self,
186 config: Gemma2Config,
187 cache_config: CacheConfig | None = None,
188 quant_config: QuantizationConfig | None = None,
189 prefix: str = "",
190 ) -> None:
191 super().__init__()
192 self.hidden_size = config.hidden_size
193 self.self_attn = Gemma2Attention(
194 config=config,
195 hidden_size=self.hidden_size,
196 num_heads=config.num_attention_heads,
197 num_kv_heads=config.num_key_value_heads,
198 head_dim=config.head_dim,
199 max_position_embeddings=config.max_position_embeddings,
200 cache_config=cache_config,
201 quant_config=quant_config,
202 attn_logits_soft_cap=config.attn_logit_softcapping,
203 prefix=f"{prefix}.self_attn",
204 )
205 self.hidden_size = config.hidden_size
206 self.mlp = Gemma2MLP(
207 hidden_size=self.hidden_size,
208 intermediate_size=config.intermediate_size,
209 hidden_activation=config.hidden_activation,
210 quant_config=quant_config,
211 prefix=f"{prefix}.mlp",
212 )
213 self.input_layernorm = GemmaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
214 self.post_attention_layernorm = GemmaRMSNorm(
215 config.hidden_size, eps=config.rms_norm_eps
216 )
217 self.pre_feedforward_layernorm = GemmaRMSNorm(
218 config.hidden_size, eps=config.rms_norm_eps
219 )
220 self.post_feedforward_layernorm = GemmaRMSNorm(
221 config.hidden_size, eps=config.rms_norm_eps
222 )
223
224 def forward(
225 self,
226 positions: torch.Tensor,
227 hidden_states: torch.Tensor,
228 residual: torch.Tensor | None,
229 ) -> tuple[torch.Tensor, torch.Tensor]:
230 if residual is None:
231 residual = hidden_states
232 hidden_states = self.input_layernorm(hidden_states)
233 else:
234 hidden_states, residual = self.input_layernorm(hidden_states, residual)
235 hidden_states = self.self_attn(
236 positions=positions,
237 hidden_states=hidden_states,
238 )
239 hidden_states = self.post_attention_layernorm(hidden_states)
240
241 hidden_states, residual = self.pre_feedforward_layernorm(
242 hidden_states, residual
243 )
244 hidden_states = self.mlp(hidden_states)
245 hidden_states = self.post_feedforward_layernorm(hidden_states)
246 return hidden_states, residual
247
248
249 @support_torch_compile
250 class Gemma2Model(nn.Module):
251 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
252 super().__init__()
253 config = vllm_config.model_config.hf_config
254 cache_config = vllm_config.cache_config
255 quant_config = vllm_config.quant_config
256 self.config = config
257 self.quant_config = quant_config
258
259 self.embed_tokens = VocabParallelEmbedding(
260 config.vocab_size,
261 config.hidden_size,
262 )
263 self.start_layer, self.end_layer, self.layers = make_layers(
264 config.num_hidden_layers,
265 lambda prefix: Gemma2DecoderLayer(
266 config, cache_config, quant_config, prefix=prefix
267 ),
268 prefix=f"{prefix}.layers",
269 )
270 self.norm = GemmaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
271
272 # Normalize the embedding by sqrt(hidden_size)
273 # The normalizer's data type should be downcasted to the model's
274 # data type such as bfloat16, not float32.
275 # See https://github.com/huggingface/transformers/pull/29402
276 normalizer = self.config.hidden_size**0.5
277 self.register_buffer("normalizer", torch.tensor(normalizer), persistent=False)
278 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
279 ["hidden_states", "residual"], config.hidden_size
280 )
281
282 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
283 return self.embed_tokens(input_ids) * self.normalizer
284
285 def forward(
286 self,
287 input_ids: torch.Tensor | None,
288 positions: torch.Tensor,
289 intermediate_tensors: IntermediateTensors | None,
290 inputs_embeds: torch.Tensor | None = None,
291 ) -> torch.Tensor | IntermediateTensors:
292 if get_pp_group().is_first_rank:
293 if inputs_embeds is not None:
294 hidden_states = inputs_embeds
295 else:
296 hidden_states = self.embed_input_ids(input_ids)
297 residual = None
298 else:
299 assert intermediate_tensors is not None
300 hidden_states = intermediate_tensors["hidden_states"]
301 residual = intermediate_tensors["residual"]
302 for layer in islice(self.layers, self.start_layer, self.end_layer):
303 hidden_states, residual = layer(
304 positions,
305 hidden_states,
306 residual,
307 )
308 if not get_pp_group().is_last_rank:
309 return IntermediateTensors(
310 {"hidden_states": hidden_states, "residual": residual}
311 )
312 hidden_states, _ = self.norm(hidden_states, residual)
313 return hidden_states
314
315
316 class Gemma2ForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
317 hf_to_vllm_mapper = WeightsMapper(
318 orig_to_new_stacked={
319 # weight_name: (param_name, shard_id)
320 ".q_proj": (".qkv_proj", "q"),
321 ".k_proj": (".qkv_proj", "k"),
322 ".v_proj": (".qkv_proj", "v"),
323 ".gate_proj": (".gate_up_proj", 0),
324 ".up_proj": (".gate_up_proj", 1),
325 }
326 )
327 packed_modules_mapping = {
328 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
329 "gate_up_proj": ["gate_proj", "up_proj"],
330 }
331
332 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
333 config = vllm_config.model_config.hf_config
334 quant_config = vllm_config.quant_config
335
336 super().__init__()
337 self.config = config
338 self.quant_config = quant_config
339 self.model = Gemma2Model(
340 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
341 )
342 self.logits_processor = LogitsProcessor(
343 config.vocab_size, soft_cap=config.final_logit_softcapping
344 )
345 self.make_empty_intermediate_tensors = (
346 self.model.make_empty_intermediate_tensors
347 )
348
349 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
350 return self.model.embed_input_ids(input_ids)
351
352 def forward(
353 self,
354 input_ids: torch.Tensor | None,
355 positions: torch.Tensor,
356 intermediate_tensors: IntermediateTensors | None = None,
357 inputs_embeds: torch.Tensor | None = None,
358 ) -> torch.Tensor | IntermediateTensors:
359 hidden_states = self.model(
360 input_ids, positions, intermediate_tensors, inputs_embeds
361 )
362 return hidden_states
363
364 def compute_logits(
365 self,
366 hidden_states: torch.Tensor,
367 ) -> torch.Tensor | None:
368 logits = self.logits_processor(self.model.embed_tokens, hidden_states)
369 return logits
370
371 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
372 loader = AutoWeightsLoader(self)
373 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)