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