main
py 476 lines 17.7 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # Copyright 2024 Cohere and the HuggingFace Inc. team. All rights reserved.
5 #
6 # This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
7 # and OPT implementations in this library. It has been modified from its
8 # original forms to accommodate minor architectural differences compared
9 # to GPT-NeoX and OPT used by the Meta AI team that trained the model.
10 #
11 # Licensed under the Apache License, Version 2.0 (the "License");
12 # you may not use this file except in compliance with the License.
13 # You may obtain a copy of the License at
14 #
15 # http://www.apache.org/licenses/LICENSE-2.0
16 #
17 # Unless required by applicable law or agreed to in writing, software
18 # distributed under the License is distributed on an "AS IS" BASIS,
19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 # See the License for the specific language governing permissions and
21 # limitations under the License.
22
23 # This file is based on the LLama model definition file in transformers
24 """PyTorch Cohere model."""
25
26 from collections.abc import Iterable
27 from itertools import islice
28
29 import torch
30 from torch import nn
31 from transformers import Cohere2Config, CohereConfig
32
33 from vllm.compilation.decorators import support_torch_compile
34 from vllm.config import CacheConfig, VllmConfig
35 from vllm.distributed import (
36 get_pp_group,
37 get_tensor_model_parallel_world_size,
38 tensor_model_parallel_all_reduce,
39 )
40 from vllm.model_executor.layers.activation import SiluAndMul
41 from vllm.model_executor.layers.attention import Attention
42 from vllm.model_executor.layers.linear import (
43 MergedColumnParallelLinear,
44 QKVParallelLinear,
45 RowParallelLinear,
46 )
47 from vllm.model_executor.layers.logits_processor import LogitsProcessor
48 from vllm.model_executor.layers.quantization import QuantizationConfig
49 from vllm.model_executor.layers.rotary_embedding import get_rope
50 from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
51 from vllm.model_executor.model_loader.weight_utils import row_parallel_weight_loader
52 from vllm.model_executor.utils import set_weight_attrs
53 from vllm.platforms import current_platform
54 from vllm.sequence import IntermediateTensors
55
56 from .interfaces import SupportsLoRA, SupportsPP, SupportsQuant
57 from .utils import (
58 AutoWeightsLoader,
59 WeightsMapper,
60 extract_layer_index,
61 make_empty_intermediate_tensors_factory,
62 make_layers,
63 maybe_prefix,
64 )
65
66
67 @torch.compile(backend=current_platform.simple_compile_backend)
68 def layer_norm_func(hidden_states, weight, variance_epsilon):
69 input_dtype = hidden_states.dtype
70 hidden_states = hidden_states.to(torch.float32)
71 mean = hidden_states.mean(-1, keepdim=True)
72 variance = (hidden_states - mean).pow(2).mean(-1, keepdim=True)
73 hidden_states = (hidden_states - mean) * torch.rsqrt(variance + variance_epsilon)
74 hidden_states = weight.to(torch.float32) * hidden_states
75 return hidden_states.to(input_dtype)
76
77
78 class LayerNorm(nn.Module):
79 def __init__(self, param_shape=None, eps=1e-5):
80 super().__init__()
81 self.weight = nn.Parameter(torch.ones(param_shape))
82 self.variance_epsilon = eps
83 set_weight_attrs(self.weight, {"weight_loader": row_parallel_weight_loader})
84
85 def forward(self, hidden_states, residuals=None):
86 hidden_states = layer_norm_func(
87 hidden_states, self.weight, self.variance_epsilon
88 )
89 return hidden_states, residuals
90
91
92 @torch.compile(backend=current_platform.simple_compile_backend)
93 def rms_norm_func(hidden_states, weight, variance_epsilon):
94 input_dtype = hidden_states.dtype
95 hidden_states = hidden_states.to(torch.float32)
96
97 variance = hidden_states.pow(2).mean(-1, keepdim=True)
98 hidden_states = hidden_states * torch.rsqrt(variance + variance_epsilon)
99
100 hidden_states = weight.to(torch.float32) * hidden_states
101 return hidden_states.to(input_dtype)
102
103
104 class RMSNorm(nn.Module):
105 def __init__(self, param_shape=None, eps=1e-6):
106 super().__init__()
107 self.weight = nn.Parameter(torch.ones(param_shape))
108 self.variance_epsilon = eps
109 set_weight_attrs(self.weight, {"weight_loader": row_parallel_weight_loader})
110
111 def forward(self, hidden_states, residuals=None):
112 hidden_states = rms_norm_func(hidden_states, self.weight, self.variance_epsilon)
113 return hidden_states, residuals
114
115
116 def select_norm_impl(config: CohereConfig) -> tuple[type[nn.Module], float]:
117 """Returns the normalization layer class and epsilon value to use.
118 If `config.rms_norm_eps` is present, use RMSNorm.
119 Otherwise default to LayerNorm with `config.layer_norm_eps`.
120 """
121 rms_eps = getattr(config, "rms_norm_eps", None)
122 if rms_eps is not None:
123 return RMSNorm, rms_eps
124
125 return LayerNorm, config.layer_norm_eps
126
127
128 # Copied from transformers.models.llama.modeling_llama.LlamaMLP Llama->Cohere
129 class CohereMLP(nn.Module):
130 def __init__(
131 self,
132 config: CohereConfig,
133 intermediate_size: int | None = None,
134 quant_config: QuantizationConfig | None = None,
135 # so we can reduce the attention and MLP outputs together
136 reduce_results: bool = False,
137 prefix: str = "",
138 ):
139 super().__init__()
140 self.config = config
141 self.hidden_size = config.hidden_size
142 if intermediate_size is None:
143 self.intermediate_size = config.intermediate_size
144 else:
145 self.intermediate_size = intermediate_size
146 self.gate_up_proj = MergedColumnParallelLinear(
147 self.hidden_size,
148 [self.intermediate_size] * 2,
149 bias=False,
150 quant_config=quant_config,
151 prefix=f"{prefix}.gate_up_proj",
152 )
153 self.down_proj = RowParallelLinear(
154 self.intermediate_size,
155 self.hidden_size,
156 bias=False,
157 quant_config=quant_config,
158 reduce_results=reduce_results,
159 prefix=f"{prefix}.down_proj",
160 )
161 self.act_fn = SiluAndMul()
162
163 def forward(self, x):
164 gate_up, _ = self.gate_up_proj(x)
165 x = self.act_fn(gate_up)
166 x, _ = self.down_proj(x)
167 return x
168
169
170 class CohereAttention(nn.Module):
171 def __init__(
172 self,
173 config: CohereConfig | Cohere2Config,
174 cache_config: CacheConfig | None = None,
175 quant_config: QuantizationConfig | None = None,
176 prefix: str = "",
177 ):
178 super().__init__()
179 tp_size = get_tensor_model_parallel_world_size()
180 self.config = config
181 self.layer_idx = extract_layer_index(prefix)
182 self.attention_dropout = config.attention_dropout
183 self.hidden_size = config.hidden_size
184 self.total_num_heads = config.num_attention_heads
185 self.num_heads = self.total_num_heads // tp_size
186 if hasattr(config, "head_dim"):
187 self.head_dim = config.head_dim
188 else:
189 self.head_dim = self.hidden_size // self.total_num_heads
190 self.total_num_kv_heads = config.num_key_value_heads
191 if self.total_num_kv_heads >= tp_size:
192 # Number of KV heads is greater than TP size, so we partition
193 # the KV heads across multiple tensor parallel GPUs.
194 assert self.total_num_kv_heads % tp_size == 0
195 else:
196 # Number of KV heads is less than TP size, so we replicate
197 # the KV heads across multiple tensor parallel GPUs.
198 assert tp_size % self.total_num_kv_heads == 0
199 self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
200 self.q_size = self.num_heads * self.head_dim
201 self.kv_size = self.num_kv_heads * self.head_dim
202 self.scaling = self.head_dim**-0.5
203 self.max_position_embeddings = getattr(
204 config, "model_max_length", None
205 ) or getattr(config, "max_position_embeddings", 8192)
206 assert isinstance(self.max_position_embeddings, int)
207 self.use_qk_norm = getattr(config, "use_qk_norm", False)
208 self.qkv_proj = QKVParallelLinear(
209 self.hidden_size,
210 self.head_dim,
211 self.total_num_heads,
212 self.total_num_kv_heads,
213 bias=False,
214 quant_config=quant_config,
215 prefix=f"{prefix}.qkv_proj",
216 )
217 self.o_proj = RowParallelLinear(
218 self.total_num_heads * self.head_dim,
219 self.hidden_size,
220 bias=False,
221 quant_config=quant_config,
222 prefix=f"{prefix}.o_proj",
223 # NOTE: reduction will happen in the decoder layer forward
224 # so we can combine the attention and MLP outputs together
225 reduce_results=False,
226 )
227 self.rotary_emb = get_rope(
228 self.head_dim,
229 max_position=self.max_position_embeddings,
230 rope_parameters=config.rope_parameters,
231 is_neox_style=False,
232 )
233
234 # Model v2 has interleaved sliding windows, v1 does not
235 self.v1 = isinstance(config, CohereConfig)
236
237 # cohere swa layer sees [pos - sliding_window, pos], i.e. sliding_window + 1
238 # tokens. vLLM's FlashAttention backend does (value - 1, 0), so we pass
239 # sliding_window + 1 here to match the training convention. The same +1
240 # propagates into the KV-cache eviction formula
241 # (single_type_kv_cache_manager.py), keeping both paths consistent.
242 self.sliding_window = None
243 if not self.v1 and config.layer_types[self.layer_idx] == "sliding_attention":
244 self.sliding_window = config.sliding_window + 1
245
246 self.attn = Attention(
247 self.num_heads,
248 self.head_dim,
249 self.scaling,
250 num_kv_heads=self.num_kv_heads,
251 cache_config=cache_config,
252 quant_config=quant_config,
253 per_layer_sliding_window=self.sliding_window,
254 prefix=f"{prefix}.attn",
255 )
256 norm_cls, norm_eps = select_norm_impl(config)
257 if self.use_qk_norm:
258 self.q_norm = norm_cls(
259 param_shape=(self.num_heads, self.head_dim), eps=norm_eps
260 )
261 self.k_norm = norm_cls(
262 param_shape=(self.num_kv_heads, self.head_dim), eps=norm_eps
263 )
264
265 def _apply_qk_norm(self, q, k):
266 q = q.view(*q.shape[:-1], -1, self.head_dim)
267 k = k.view(*k.shape[:-1], -1, self.head_dim)
268 q, _ = self.q_norm(q)
269 k, _ = self.k_norm(k)
270 q = q.view(*q.shape[:-2], -1)
271 k = k.view(*k.shape[:-2], -1)
272 return q, k
273
274 def forward(
275 self,
276 positions: torch.Tensor,
277 hidden_states: torch.Tensor,
278 ) -> torch.Tensor:
279 qkv, _ = self.qkv_proj(hidden_states)
280 q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
281 if self.use_qk_norm:
282 q, k = self._apply_qk_norm(q, k)
283 if self.v1 or self.sliding_window:
284 q, k = self.rotary_emb(positions, q, k)
285 attn_output = self.attn(q, k, v)
286 output, _ = self.o_proj(attn_output)
287 return output
288
289
290 class CohereDecoderLayer(nn.Module):
291 def __init__(
292 self,
293 config: CohereConfig | Cohere2Config,
294 cache_config: CacheConfig | None = None,
295 quant_config: QuantizationConfig | None = None,
296 prefix: str = "",
297 ):
298 super().__init__()
299 self.hidden_size = config.hidden_size
300 self.tp_size = get_tensor_model_parallel_world_size()
301 self.self_attn = CohereAttention(
302 config,
303 cache_config,
304 quant_config=quant_config,
305 prefix=f"{prefix}.self_attn",
306 )
307 self.mlp = CohereMLP(config, quant_config=quant_config, prefix=f"{prefix}.mlp")
308 norm_cls, norm_eps = select_norm_impl(config)
309 self.input_layernorm = norm_cls(param_shape=(config.hidden_size), eps=norm_eps)
310
311 def forward(
312 self,
313 positions: torch.Tensor,
314 hidden_states: torch.Tensor,
315 residual: torch.Tensor | None,
316 ) -> tuple[torch.Tensor, torch.Tensor]:
317 # Self Attention
318 residual = hidden_states
319 hidden_states, residual = self.input_layernorm(hidden_states, residual)
320 hidden_states_attention = self.self_attn(
321 positions=positions,
322 hidden_states=hidden_states,
323 )
324 hidden_states_mlp = self.mlp(hidden_states)
325 parallel_block_output = hidden_states_attention + hidden_states_mlp
326 # Add everything together
327 if self.tp_size > 1:
328 # do the reduction in 1 shot instead of 2 separate all reduce
329 parallel_block_output = tensor_model_parallel_all_reduce(
330 parallel_block_output
331 )
332 hidden_states = residual + parallel_block_output
333
334 return hidden_states, residual
335
336
337 @support_torch_compile
338 class CohereModel(nn.Module):
339 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
340 super().__init__()
341
342 config = vllm_config.model_config.hf_config
343 cache_config = vllm_config.cache_config
344 quant_config = vllm_config.quant_config
345 self.quant_config = quant_config
346
347 self.config = config
348
349 self.vocab_size = config.vocab_size
350
351 self.embed_tokens = VocabParallelEmbedding(
352 config.vocab_size, config.hidden_size
353 )
354 self.start_layer, self.end_layer, self.layers = make_layers(
355 config.num_hidden_layers,
356 lambda prefix: CohereDecoderLayer(
357 config, cache_config, quant_config, prefix=prefix
358 ),
359 prefix=f"{prefix}.layers",
360 )
361
362 norm_cls, norm_eps = select_norm_impl(config)
363 self.norm = norm_cls(param_shape=(config.hidden_size), eps=norm_eps)
364
365 self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
366 ["hidden_states", "residual"], config.hidden_size
367 )
368
369 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
370 return self.embed_tokens(input_ids)
371
372 def forward(
373 self,
374 input_ids: torch.Tensor | None,
375 positions: torch.Tensor,
376 intermediate_tensors: IntermediateTensors | None,
377 inputs_embeds: torch.Tensor | None = None,
378 ) -> torch.Tensor | IntermediateTensors:
379 if get_pp_group().is_first_rank:
380 if inputs_embeds is not None:
381 hidden_states = inputs_embeds
382 else:
383 hidden_states = self.embed_input_ids(input_ids)
384 residual = None
385 else:
386 assert intermediate_tensors is not None
387 hidden_states = intermediate_tensors["hidden_states"]
388 residual = intermediate_tensors["residual"]
389 for layer in islice(self.layers, self.start_layer, self.end_layer):
390 hidden_states, residual = layer(
391 positions,
392 hidden_states,
393 residual,
394 )
395 if not get_pp_group().is_last_rank:
396 return IntermediateTensors(
397 {"hidden_states": hidden_states, "residual": residual}
398 )
399 hidden_states, _ = self.norm(hidden_states, residual)
400 return hidden_states
401
402
403 class CohereForCausalLM(nn.Module, SupportsLoRA, SupportsPP, SupportsQuant):
404 hf_to_vllm_mapper = WeightsMapper(
405 orig_to_new_stacked={
406 # weight_name: (param_name, shard_id)
407 ".q_proj": (".qkv_proj", "q"),
408 ".k_proj": (".qkv_proj", "k"),
409 ".v_proj": (".qkv_proj", "v"),
410 ".gate_proj": (".gate_up_proj", 0),
411 ".up_proj": (".gate_up_proj", 1),
412 },
413 # ModelOpt NVFP4 checkpoints carry raw quantizer-module state
414 # (e.g. "*.weight_quantizer._double_scale"); drop them before loading.
415 # See #41925.
416 orig_to_new_substr={"_quantizer.": None},
417 orig_to_new_prefix={"lm_head": None},
418 )
419 packed_modules_mapping: dict[str, list[str]] = {
420 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
421 "gate_up_proj": ["gate_proj", "up_proj"],
422 }
423 # LoRA specific attributes
424 embedding_modules = {"embed_tokens": "input_embeddings"}
425
426 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
427 super().__init__()
428 config = vllm_config.model_config.hf_config
429 quant_config = vllm_config.quant_config
430
431 self.config = config
432
433 self.quant_config = quant_config
434 self.logits_processor = LogitsProcessor(
435 config.vocab_size, scale=config.logit_scale
436 )
437 self.model = CohereModel(
438 vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
439 )
440 self.make_empty_intermediate_tensors = (
441 self.model.make_empty_intermediate_tensors
442 )
443
444 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
445 return self.model.embed_input_ids(input_ids)
446
447 @torch.no_grad()
448 def forward(
449 self,
450 input_ids: torch.Tensor | None,
451 positions: torch.Tensor,
452 intermediate_tensors: IntermediateTensors | None = None,
453 inputs_embeds: torch.Tensor | None = None,
454 ) -> torch.Tensor | IntermediateTensors:
455 hidden_states = self.model(
456 input_ids, positions, intermediate_tensors, inputs_embeds
457 )
458 return hidden_states
459
460 def compute_logits(
461 self,
462 hidden_states: torch.Tensor,
463 ) -> torch.Tensor | None:
464 is_not_lora = hasattr(self.model.embed_tokens, "weight")
465 if is_not_lora:
466 logits = self.logits_processor(self.model.embed_tokens, hidden_states)
467 else:
468 logits = self.logits_processor(
469 self.model.embed_tokens.base_layer, hidden_states
470 )
471
472 return logits
473
474 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
475 loader = AutoWeightsLoader(self)
476 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)