@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / eca18691d2
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 15, 09:45 UTC

[MODEL] FalconH1 (#18406)

Signed-off-by: dhia.rhaiem <dhia.rhaiem@tii.ae> Co-authored-by: younesbelkada <younesbelkada@gmail.com> Co-authored-by: Ilyas Chahed <ilyas.chahed@tii.ae> Co-authored-by: Jingwei Zuo <jingwei.zuo@tii.ae>

Dhia Eddine Rhaiem committed May 21, 2025 at 15:59 UTC eca18691d2fe29c4f6c1b466709eda9f123116ea
5 files changed +798 -59
docs/source/models/supported_models.md
+5
@@ -392,6 +392,11 @@ Specified using `--task generate`.
392 * `tiiuae/falcon-mamba-7b`, `tiiuae/falcon-mamba-7b-instruct`, etc.
393 * ✅︎
394 * ✅︎
395 +- * `FalconH1ForCausalLM`
396 + * Falcon-H1
397 + * `tiiuae/Falcon-H1-34B-Base`, `tiiuae/Falcon-H1-34B-Instruct`, etc.
398 + * ✅︎
399 + * ✅︎
400 - * `GemmaForCausalLM`
401 * Gemma
402 * `google/gemma-2b`, `google/gemma-1.1-2b-it`, etc.
tests/models/registry.py
+3
@@ -147,6 +147,9 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
147 "ExaoneForCausalLM": _HfExamplesInfo("LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct"), # noqa: E501
148 "Fairseq2LlamaForCausalLM": _HfExamplesInfo("mgleize/fairseq2-dummy-Llama-3.2-1B"), # noqa: E501
149 "FalconForCausalLM": _HfExamplesInfo("tiiuae/falcon-7b"),
150 + "FalconH1ForCausalLM":_HfExamplesInfo("tiiuae/Falcon-H1-1.5B-Instruct",
151 + is_available_online=False,
152 + min_transformers_version="4.52.2"),
153 "GemmaForCausalLM": _HfExamplesInfo("google/gemma-1.1-2b-it"),
154 "Gemma2ForCausalLM": _HfExamplesInfo("google/gemma-2-9b"),
155 "Gemma3ForCausalLM": _HfExamplesInfo("google/gemma-3-1b-it"),
vllm/model_executor/layers/mamba/mamba_mixer2.py
+104 -59
@@ -34,7 +34,11 @@ from vllm.model_executor.utils import set_weight_attrs
34 @CustomOp.register("mixer2_gated_rms_norm")
35 class Mixer2RMSNormGated(CustomOp):
36
37 - def __init__(self, full_hidden_size, full_n_groups, eps=1e-6):
37 + def __init__(self,
38 + full_hidden_size: int,
39 + full_n_groups: int,
40 + use_rms_norm: bool = True,
41 + eps: float = 1e-6):
42 super().__init__()
43 self.tp_size = get_tensor_model_parallel_world_size()
44 self.tp_rank = get_tensor_model_parallel_rank()
@@ -44,11 +48,17 @@ class Mixer2RMSNormGated(CustomOp):
48 self.n_groups = full_hidden_size // self.group_size
49
50 self.variance_epsilon = eps
47 - self.weight = nn.Parameter(torch.ones(self.per_rank_hidden_size))
48 - set_weight_attrs(self.weight,
49 - {"weight_loader": sharded_weight_loader(0)})
50 - assert self.full_hidden_size % self.tp_size== 0,\
51 - "Tensor parallel world size must divide hidden size."
51 + self.use_rms_norm = use_rms_norm
52 + if self.use_rms_norm:
53 + # Register norm weight only if we're actually applying RMSNorm
54 + self.weight = nn.Parameter(torch.ones(self.per_rank_hidden_size))
55 + set_weight_attrs(self.weight,
56 + {"weight_loader": sharded_weight_loader(0)})
57 + else:
58 + # Avoid checkpoint mismatch by skipping unused parameter
59 + self.register_parameter("weight", None)
60 + assert (self.full_hidden_size % self.tp_size == 0
61 + ), "Tensor parallel world size must divide hidden size."
62
63 def forward_native(
64 self,
@@ -66,6 +76,8 @@ class Mixer2RMSNormGated(CustomOp):
76 # the input and then redundantly compute the RMSNorm.
77 input_dtype = x.dtype
78 x = x * nn.functional.silu(gate.to(torch.float32))
79 + if not self.use_rms_norm:
80 + return x
81
82 if self.n_groups == 1:
83 if self.tp_size > 1:
@@ -74,7 +86,7 @@ class Mixer2RMSNormGated(CustomOp):
86 global_sums = tensor_model_parallel_all_reduce(local_sums)
87 # Calculate the variance
88 count = self.tp_size * x.shape[-1]
77 - variance = (global_sums / count)
89 + variance = global_sums / count
90
91 else:
92 variance = x.pow(2).mean(-1, keepdim=True)
@@ -106,6 +118,9 @@ class Mixer2RMSNormGated(CustomOp):
118 gate: torch.Tensor,
119 ) -> Union[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
120
121 + if not self.use_rms_norm:
122 + return x * nn.functional.silu(gate.to(torch.float32))
123 +
124 if self.tp_size > 1 or self.n_groups != 1:
125 return self.forward_native(x, gate)
126
@@ -124,7 +139,7 @@ class Mixer2RMSNormGated(CustomOp):
139
140
141 def extra_groups_for_head_shards(ngroups: int, tp_size: int):
127 - """Compute the increase in group numbers to account for
142 + """Compute the increase in group numbers to account for
143 replication in order to accompany the head shards."""
144
145 # in the case ngoups % tp_size == 0, this will be zero
@@ -182,13 +197,15 @@ def mamba_v2_sharded_weight_loader(
197 # seem to handle slices well.
198 # https://github.com/python/mypy/issues/2410
199 param.data[
185 - boundary:(boundary + take), # type: ignore[misc]
186 - ...] = loaded_weight[loaded_start_idx:( # type: ignore[misc]
187 - loaded_start_idx + take)] # type: ignore[misc]
200 + boundary:(boundary + take),
201 + ... # type: ignore[misc]
202 + ] = loaded_weight[loaded_start_idx:(loaded_start_idx +
203 + take) # type: ignore[misc]
204 + ] # type: ignore[misc]
205
206 # move indexing boundaries
207 boundary += shard_size
191 - loaded_boundary += (full_dim - extra)
208 + loaded_boundary += full_dim - extra
209
210 return loader
211
@@ -206,19 +223,22 @@ class MambaMixer2(CustomOp):
223 **selective** state spaces)
224 """
225
209 - def __init__(self,
210 - hidden_size: int,
211 - ssm_state_size: int,
212 - conv_kernel_size: int,
213 - intermediate_size: int,
214 - use_conv_bias: bool,
215 - use_bias: bool,
216 - n_groups: int = 1,
217 - num_heads: int = 128,
218 - head_dim: int = 64,
219 - rms_norm_eps: float = 1e-5,
220 - activation="silu",
221 - quant_config: Optional[QuantizationConfig] = None):
226 + def __init__(
227 + self,
228 + hidden_size: int,
229 + ssm_state_size: int,
230 + conv_kernel_size: int,
231 + intermediate_size: int,
232 + use_conv_bias: bool,
233 + use_bias: bool,
234 + n_groups: int = 1,
235 + num_heads: int = 128,
236 + head_dim: int = 64,
237 + rms_norm_eps: float = 1e-5,
238 + activation: str = "silu",
239 + use_rms_norm: bool = True,
240 + quant_config: Optional[QuantizationConfig] = None,
241 + ):
242 super().__init__()
243
244 # For TP, the sharding plan is as follows:
@@ -238,17 +258,16 @@ class MambaMixer2(CustomOp):
258 self.tp_size = get_tensor_model_parallel_world_size()
259 tp_rank = get_tensor_model_parallel_rank()
260
241 - assert num_heads % self.tp_size == 0, \
242 - "Tensor parallel world size must divide num heads."
261 + assert (num_heads % self.tp_size == 0
262 + ), "Tensor parallel world size must divide num heads."
263
244 - assert (n_groups % self.tp_size) == 0 or n_groups == 1, \
245 - (
246 - "If tensor parallel world size does not divide num_heads, "
247 - "then num_groups must equal 1."
248 - )
264 + assert (n_groups % self.tp_size) == 0 or n_groups == 1, (
265 + "If tensor parallel world size does not divide num_heads, "
266 + "then num_groups must equal 1.")
267
250 - assert self.tp_size == 1 or quant_config is None, \
251 - "Tensor parallel currently not supported for quantized models."
268 + assert (
269 + self.tp_size == 1 or quant_config is None
270 + ), "Tensor parallel currently not supported for quantized models."
271
272 self.ssm_state_size = ssm_state_size
273 self.activation = activation
@@ -265,8 +284,7 @@ class MambaMixer2(CustomOp):
284 self.n_groups = n_groups + extra_groups_for_head_shards(
285 n_groups, self.tp_size)
286
268 - self.conv_dim = (intermediate_size +
269 - 2 * self.n_groups * ssm_state_size)
287 + self.conv_dim = intermediate_size + 2 * self.n_groups * ssm_state_size
288 self.conv1d = ColumnParallelLinear(
289 input_size=conv_kernel_size,
290 output_size=self.conv_dim,
@@ -279,11 +297,12 @@ class MambaMixer2(CustomOp):
297 # doesn't allow to override it
298 self.conv1d.weight.data = self.conv1d.weight.data.unsqueeze(1)
299
282 - self.in_proj = ColumnParallelLinear(input_size=hidden_size,
283 - output_size=intermediate_size +
284 - self.conv_dim + self.num_heads,
285 - bias=use_bias,
286 - quant_config=quant_config)
300 + self.in_proj = ColumnParallelLinear(
301 + input_size=hidden_size,
302 + output_size=intermediate_size + self.conv_dim + self.num_heads,
303 + bias=use_bias,
304 + quant_config=quant_config,
305 + )
306
307 # - because in_proj is a concatenation of 3 weights, we
308 # need to interleave them before sharding
@@ -305,7 +324,8 @@ class MambaMixer2(CustomOp):
324 # - ditto for the otther two weights below
325 delattr(self.conv1d.bias, "weight_loader")
326 set_weight_attrs(
308 - self.conv1d.bias, {
327 + self.conv1d.bias,
328 + {
329 "weight_loader":
330 mamba_v2_sharded_weight_loader(
331 [
@@ -316,18 +336,25 @@ class MambaMixer2(CustomOp):
336 self.tp_size,
337 tp_rank,
338 )
319 - })
339 + },
340 + )
341
342 delattr(self.conv1d.weight, "weight_loader")
343 set_weight_attrs(
323 - self.conv1d.weight, {
344 + self.conv1d.weight,
345 + {
346 "weight_loader":
325 - mamba_v2_sharded_weight_loader([
326 - intermediate_settings,
327 - group_shard_settings,
328 - group_shard_settings,
329 - ], self.tp_size, tp_rank)
330 - })
347 + mamba_v2_sharded_weight_loader(
348 + [
349 + intermediate_settings,
350 + group_shard_settings,
351 + group_shard_settings,
352 + ],
353 + self.tp_size,
354 + tp_rank,
355 + )
356 + },
357 + )
358
359 if quant_config is None:
360 # - quant layers do not have a weight loader
@@ -345,8 +372,10 @@ class MambaMixer2(CustomOp):
372 head_setings, # for dt
373 ],
374 self.tp_size,
348 - tp_rank)
349 - })
375 + tp_rank,
376 + )
377 + },
378 + )
379
380 # - these are TPed by heads to reduce the size of the
381 # temporal shape
@@ -357,6 +386,7 @@ class MambaMixer2(CustomOp):
386 ))
387 self.D = nn.Parameter(torch.ones(num_heads // self.tp_size))
388 self.dt_bias = nn.Parameter(torch.ones(num_heads // self.tp_size))
389 + self.use_rms_norm = use_rms_norm
390
391 set_weight_attrs(self.D, {"weight_loader": sharded_weight_loader(0)})
392 a_weight_loader = composed_weight_loader(
@@ -365,18 +395,25 @@ class MambaMixer2(CustomOp):
395 set_weight_attrs(self.dt_bias,
396 {"weight_loader": sharded_weight_loader(0)})
397
368 - self.out_proj = RowParallelLinear(intermediate_size,
369 - hidden_size,
370 - bias=use_bias,
371 - input_is_parallel=True,
372 - quant_config=quant_config)
398 + self.out_proj = RowParallelLinear(
399 + intermediate_size,
400 + hidden_size,
401 + bias=use_bias,
402 + input_is_parallel=True,
403 + quant_config=quant_config,
404 + )
405
406 self.norm = Mixer2RMSNormGated(intermediate_size,
407 n_groups,
408 + self.use_rms_norm,
409 eps=rms_norm_eps)
410
378 - def forward_native(self, hidden_states: torch.Tensor,
379 - conv_state: torch.Tensor, ssm_state: torch.Tensor):
411 + def forward_native(
412 + self,
413 + hidden_states: torch.Tensor,
414 + conv_state: torch.Tensor,
415 + ssm_state: torch.Tensor,
416 + ):
417 pass
418
419 def forward_cuda(
@@ -384,6 +421,7 @@ class MambaMixer2(CustomOp):
421 hidden_states: torch.Tensor,
422 mamba_cache_params: MambaCacheParams,
423 mamba2_metadata: Mamba2Metadata,
424 + mup_vector: Optional[torch.Tensor] = None,
425 ):
426 # mamba2_metadata contains metadata necessary for the mamba2 triton
427 # kernels to operate in continuous batching and in chunked prefill
@@ -401,6 +439,10 @@ class MambaMixer2(CustomOp):
439
440 # 1. Gated MLP's linear projection
441 projected_states, _ = self.in_proj(hidden_states)
442 +
443 + if mup_vector is not None:
444 + projected_states = projected_states * mup_vector
445 +
446 gate, hidden_states_B_C, dt = torch.split(
447 projected_states,
448 [
@@ -561,6 +603,9 @@ class MambaMixer2(CustomOp):
603 hidden_states = torch.vstack(ssd_output_list)
604
605 # 4. gated MLP
606 + # GatedRMSNorm internally applying SiLU to the gate
607 + # SiLU is applied internally before normalization, unlike standard
608 + # norm usage
609 hidden_states = self.norm(hidden_states, gate)
610
611 # 5. Final linear projection
vllm/model_executor/models/falcon_h1.py new
+685
@@ -0,0 +1,685 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +"""Inference-only FalconH1 model."""
3 +from collections.abc import Iterable
4 +from typing import Optional
5 +
6 +import torch
7 +from torch import nn
8 +from transformers import FalconH1Config
9 +
10 +from vllm.attention.layer import Attention
11 +from vllm.config import CacheConfig, VllmConfig
12 +from vllm.distributed import divide, get_tensor_model_parallel_world_size
13 +from vllm.distributed.parallel_state import get_pp_group
14 +from vllm.forward_context import get_forward_context
15 +from vllm.model_executor.layers.activation import SiluAndMul
16 +from vllm.model_executor.layers.layernorm import RMSNorm
17 +from vllm.model_executor.layers.linear import (MergedColumnParallelLinear,
18 + QKVParallelLinear,
19 + RowParallelLinear)
20 +from vllm.model_executor.layers.logits_processor import LogitsProcessor
21 +from vllm.model_executor.layers.mamba.mamba2_metadata import (
22 + Mamba2Metadata, prepare_mamba2_metadata)
23 +from vllm.model_executor.layers.mamba.mamba_mixer2 import (
24 + MambaMixer2, extra_groups_for_head_shards)
25 +from vllm.model_executor.layers.quantization import QuantizationConfig
26 +from vllm.model_executor.layers.rotary_embedding import get_rope
27 +from vllm.model_executor.layers.vocab_parallel_embedding import (
28 + DEFAULT_VOCAB_PADDING_SIZE, ParallelLMHead, VocabParallelEmbedding)
29 +from vllm.model_executor.model_loader.weight_utils import default_weight_loader
30 +from vllm.model_executor.models.mamba_cache import (MambaCacheManager,
31 + MambaCacheParams)
32 +from vllm.model_executor.sampling_metadata import SamplingMetadata
33 +from vllm.sequence import IntermediateTensors
34 +
35 +from .interfaces import (HasInnerState, IsHybrid, SupportsLoRA, SupportsPP,
36 + SupportsV0Only)
37 +from .utils import (PPMissingLayer, is_pp_missing_parameter,
38 + make_empty_intermediate_tensors_factory, make_layers,
39 + maybe_prefix)
40 +
41 +
42 +class FalconH1MLP(nn.Module):
43 +
44 + def __init__(
45 + self,
46 + config: FalconH1Config,
47 + quant_config: Optional[QuantizationConfig] = None,
48 + bias: bool = False,
49 + ) -> None:
50 + super().__init__()
51 + self.gate_up_proj = MergedColumnParallelLinear(
52 + input_size=config.hidden_size,
53 + output_sizes=[config.intermediate_size] * 2,
54 + bias=bias,
55 + quant_config=quant_config,
56 + )
57 + self.down_proj = RowParallelLinear(
58 + input_size=config.intermediate_size,
59 + output_size=config.hidden_size,
60 + bias=bias,
61 + quant_config=quant_config,
62 + )
63 + self.tp_size = get_tensor_model_parallel_world_size()
64 + self.intermediate_size = config.intermediate_size
65 + self.gate_multiplier, self.down_multiplier = config.mlp_multipliers
66 + if config.hidden_act != "silu":
67 + raise ValueError(f"Unsupported activation: {config.hidden_act}. "
68 + "Only silu is supported for now.")
69 + self.act_fn = SiluAndMul()
70 +
71 + def forward(self, x):
72 + x, _ = self.gate_up_proj(x)
73 + x[:, :self.intermediate_size // self.tp_size] *= self.gate_multiplier
74 + x = self.act_fn(x)
75 + x, _ = self.down_proj(x)
76 + x = x * self.down_multiplier
77 + return x
78 +
79 +
80 +class FalconH1SSMDecoderLayer(nn.Module):
81 +
82 + def __init__(
83 + self,
84 + config: FalconH1Config,
85 + cache_config: Optional[CacheConfig] = None,
86 + quant_config: Optional[QuantizationConfig] = None,
87 + ) -> None:
88 + super().__init__()
89 + self.config = config
90 + self.tp_size = get_tensor_model_parallel_world_size()
91 +
92 + self.d_ssm = (int(config.mamba_expand * config.hidden_size)
93 + if config.mamba_d_ssm is None else config.mamba_d_ssm)
94 +
95 + self.mamba = MambaMixer2(
96 + hidden_size=config.hidden_size,
97 + ssm_state_size=config.mamba_d_state,
98 + conv_kernel_size=config.mamba_d_conv,
99 + intermediate_size=self.d_ssm,
100 + use_conv_bias=config.mamba_conv_bias,
101 + use_bias=config.mamba_proj_bias,
102 + n_groups=config.mamba_n_groups,
103 + num_heads=config.mamba_n_heads,
104 + head_dim=config.mamba_d_head,
105 + rms_norm_eps=config.rms_norm_eps,
106 + activation=config.hidden_act,
107 + quant_config=quant_config,
108 + use_rms_norm=config.mamba_rms_norm,
109 + )
110 + # n_groups is overridden later by `MambaMixer2`
111 + self.groups_time_state_size = self.mamba.n_groups * config.mamba_d_state
112 + self.zxbcdt_multipliers = config.ssm_multipliers
113 + self._init_mup_vector()
114 +
115 + def _init_mup_vector(self):
116 + """
117 + Non learnable per-block scaling vector composed of element-wise
118 + multipliersapplied to each separate contiguous block of the output
119 + of the linear projection (in_proj) before further processing
120 + (gating, convolution, SSM):
121 +
122 + - Z block: [0 : d_ssm] → zxbcdt_multipliers[0]
123 + - X block: [d_ssm : 2 * d_ssm] → zxbcdt_multipliers[1]
124 + - B block: [2 * d_ssm : 2 * d_ssm + G * S] → zxbcdt_multipliers[2]
125 + - C block: [2 * d_ssm + G * S : 2 * d_ssm + 2 * G * S]
126 + → zxbcdt_multipliers[3]
127 + - dt block: [2 * d_ssm + 2 * G * S : end] → zxbcdt_multipliers[4]
128 +
129 + where:
130 + - d_ssm: Dimension of state-space model latent
131 + - G: Number of groups (n_groups)
132 + - S: SSM state size per group
133 + - All indices are divided by tp_size to support tensor parallelism
134 + """
135 + vector_shape = (2 * self.d_ssm + 2 * self.groups_time_state_size +
136 + self.config.mamba_n_heads) // self.tp_size
137 + mup_vector = torch.ones(1, vector_shape)
138 + # Z vector 0 -> d_ssm
139 + mup_vector[:, :self.d_ssm //
140 + self.tp_size] *= self.zxbcdt_multipliers[0]
141 + # X vector d_ssm -> 2 * d_ssm
142 + mup_vector[:,
143 + (self.d_ssm //
144 + self.tp_size):(2 * self.d_ssm //
145 + self.tp_size)] *= self.zxbcdt_multipliers[1]
146 + # B vector 2 * d_ssm -> 2 * d_ssm + (n_group * d_state)
147 + mup_vector[
148 + :,
149 + (2 * self.d_ssm) //
150 + self.tp_size:(2 * self.d_ssm + self.groups_time_state_size) //
151 + self.tp_size,
152 + ] *= self.zxbcdt_multipliers[2]
153 + # C vector 2 * d_ssm + (n_group * d_state)
154 + # -> 2 * d_ssm + 2 * (n_group * d_state)
155 + mup_vector[
156 + :,
157 + (2 * self.d_ssm + self.groups_time_state_size) //
158 + self.tp_size:(2 * self.d_ssm + 2 * self.groups_time_state_size) //
159 + self.tp_size,
160 + ] *= self.zxbcdt_multipliers[3]
161 + # dt vector 2 * d_ssm + 2 * (n_group * d_state)
162 + # -> 2 * d_ssm + 2 * (n_group * d_state) + n_heads
163 + mup_vector[
164 + :,
165 + (2 * self.d_ssm + 2 * self.groups_time_state_size) //
166 + self.tp_size:,
167 + ] *= self.zxbcdt_multipliers[4]
168 +
169 + self.register_buffer("mup_vector", mup_vector, persistent=False)
170 +
171 + def forward(
172 + self,
173 + hidden_states: torch.Tensor,
174 + residual: Optional[torch.Tensor],
175 + mamba_cache_params: MambaCacheParams,
176 + mamba2_metadata: Mamba2Metadata,
177 + **kwargs,
178 + ):
179 + hidden_states = self.mamba(
180 + hidden_states,
181 + mamba_cache_params,
182 + mamba2_metadata=mamba2_metadata,
183 + mup_vector=self.mup_vector,
184 + )
185 + return hidden_states, residual
186 +
187 +
188 +class FalconH1AttentionDecoderLayer(nn.Module):
189 +
190 + def __init__(
191 + self,
192 + config: FalconH1Config,
193 + cache_config: Optional[CacheConfig] = None,
194 + quant_config: Optional[QuantizationConfig] = None,
195 + prefix: str = "",
196 + ) -> None:
197 + super().__init__()
198 + rope_theta = getattr(config, "rope_theta", 1e11)
199 + rope_scaling = getattr(config, "rope_scaling", None)
200 + max_position_embeddings = getattr(config, "max_position_embeddings",
201 + 8192)
202 + self.hidden_size = config.hidden_size
203 + tp_size = get_tensor_model_parallel_world_size()
204 + self.total_num_heads = config.num_attention_heads
205 + assert self.total_num_heads % tp_size == 0
206 + self.num_heads = self.total_num_heads // tp_size
207 + self.total_num_kv_heads = config.num_key_value_heads
208 + if self.total_num_kv_heads >= tp_size:
209 + # Number of KV heads is greater than TP size, so we partition
210 + # the KV heads across multiple tensor parallel GPUs.
211 + assert self.total_num_kv_heads % tp_size == 0
212 + else:
213 + # Number of KV heads is less than TP size, so we replicate
214 + # the KV heads across multiple tensor parallel GPUs.
215 + assert tp_size % self.total_num_kv_heads == 0
216 + self.num_kv_heads = max(1, self.total_num_kv_heads // tp_size)
217 + self.head_dim = (config.hidden_size // self.total_num_heads if getattr(
218 + config, "head_dim", None) is None else config.head_dim)
219 + self.q_size = self.num_heads * self.head_dim
220 + self.kv_size = self.num_kv_heads * self.head_dim
221 + self.scaling = self.head_dim**-0.5
222 + self.rope_theta = rope_theta
223 + self.max_position_embeddings = max_position_embeddings
224 +
225 + if hasattr(config, "partial_rotary_factor"):
226 + rotary_dim = self.head_dim * config.partial_rotary_factor
227 + elif hasattr(config, "attn_rotary_emb"):
228 + rotary_dim = config.attn_rotary_emb # for backward compatibility
229 + else:
230 + rotary_dim = self.head_dim # default
231 +
232 + self.rotary_emb = get_rope(
233 + head_size=self.head_dim,
234 + rotary_dim=rotary_dim,
235 + max_position=max_position_embeddings,
236 + rope_scaling=rope_scaling,
237 + base=rope_theta,
238 + is_neox_style=True,
239 + dtype=None, # see impl of get_rope
240 + )
241 +
242 + self.qkv_proj = QKVParallelLinear(
243 + config.hidden_size,
244 + self.head_dim,
245 + self.total_num_heads,
246 + self.total_num_kv_heads,
247 + bias=False,
248 + quant_config=quant_config,
249 + prefix=f"{prefix}.qkv_proj",
250 + )
251 + self.o_proj = RowParallelLinear(
252 + self.total_num_heads * self.head_dim,
253 + config.hidden_size,
254 + bias=False,
255 + quant_config=quant_config,
256 + prefix=f"{prefix}.o_proj",
257 + )
258 +
259 + self.attn = Attention(
260 + self.num_heads,
261 + self.head_dim,
262 + self.scaling,
263 + num_kv_heads=self.num_kv_heads,
264 + cache_config=cache_config,
265 + prefix=f"{prefix}.attn",
266 + )
267 + self.key_multiplier = config.key_multiplier
268 +
269 + def self_attention(
270 + self,
271 + positions: torch.Tensor,
272 + hidden_states: torch.Tensor,
273 + **kwargs,
274 + ) -> torch.Tensor:
275 + qkv, _ = self.qkv_proj(hidden_states)
276 + q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
277 + k = k * self.key_multiplier
278 +
279 + q, k = self.rotary_emb(positions, q, k)
280 + attn_output = self.attn(q, k, v)
281 + output, _ = self.o_proj(attn_output)
282 + return output
283 +
284 + def forward(
285 + self,
286 + positions: torch.Tensor,
287 + hidden_states: torch.Tensor,
288 + residual: Optional[torch.Tensor],
289 + **kwargs,
290 + ):
291 + hidden_states = self.self_attention(
292 + positions=positions,
293 + hidden_states=hidden_states,
294 + )
295 + return hidden_states, residual
296 +
297 +
298 +class FalconH1ParallelHybrid(nn.Module):
299 + """
300 + A hybrid decoder layer for FalconH1 where the input is processed
301 + in parallel through both the self-attention branch and the SSM (Mamba)
302 + branch. Their outputs are then summed to produce the final hidden state.
303 +
304 + This layer uses:
305 + - FalconH1AttentionDecoderLayer for the multi-head self-attention branch.
306 + - FalconH1SSMDecoderLayer for the state-space (Mamba) branch.
307 + """
308 +
309 + def __init__(
310 + self,
311 + config: FalconH1Config,
312 + layer_idx: int,
313 + cache_config: Optional[CacheConfig] = None,
314 + quant_config: Optional[QuantizationConfig] = None,
315 + prefix: str = "",
316 + ) -> None:
317 + super().__init__()
318 + # Instantiate the attention branch
319 + self.self_attn = FalconH1AttentionDecoderLayer(
320 + config=config,
321 + cache_config=cache_config,
322 + quant_config=quant_config,
323 + prefix=prefix,
324 + )
325 + # Instantiate the SSM branch
326 + self.mamba = FalconH1SSMDecoderLayer(
327 + config=config,
328 + cache_config=cache_config,
329 + quant_config=quant_config,
330 + )
331 + self.ssm_out_multiplier = config.ssm_out_multiplier
332 + self.ssm_in_multiplier = config.ssm_in_multiplier
333 +
334 + self.attention_in_multiplier = config.attention_in_multiplier
335 + self.attn_out_multiplier = config.attention_out_multiplier
336 +
337 + self.feed_forward = FalconH1MLP(config)
338 +
339 + self.input_layernorm = RMSNorm(config.hidden_size,
340 + eps=config.rms_norm_eps)
341 + self.pre_ff_layernorm = RMSNorm(config.hidden_size,
342 + eps=config.rms_norm_eps)
343 +
344 + def forward(
345 + self,
346 + positions: torch.Tensor,
347 + hidden_states: torch.Tensor,
348 + mamba_cache_params: MambaCacheParams,
349 + mamba2_metadata: Mamba2Metadata,
350 + **kwargs,
351 + ):
352 + residual = hidden_states
353 + hidden_states = self.input_layernorm(hidden_states)
354 + # Process input through the attention branch.
355 + # FalconH1AttentionDecoderLayer expects positions, hidden_states,
356 + # kv_cache, attn_metadata, and residual.
357 + attn_hidden, _ = self.self_attn(
358 + positions=positions,
359 + hidden_states=hidden_states * self.attention_in_multiplier,
360 + residual=residual,
361 + **kwargs,
362 + )
363 +
364 + # Process input through the SSM branch.
365 + # FalconH1SSMDecoderLayer expects hidden_states, attn_metadata,
366 + # residual, mamba_cache_params, and sequence_idx.
367 + ssm_hidden, _ = self.mamba(
368 + hidden_states=hidden_states * self.ssm_in_multiplier,
369 + residual=residual,
370 + mamba_cache_params=mamba_cache_params,
371 + mamba2_metadata=mamba2_metadata,
372 + **kwargs,
373 + )
374 + # Sum the outputs from both branches.
375 + # We assume both branches produce outputs of the same
376 + # dimensionality (config.hidden_size).
377 + hidden_states = (attn_hidden * self.attn_out_multiplier) + (
378 + ssm_hidden * self.ssm_out_multiplier)
379 + hidden_states = hidden_states + residual
380 +
381 + # feed-forward
382 + residual = hidden_states
383 + hidden_states = self.pre_ff_layernorm(hidden_states)
384 + hidden_states = self.feed_forward(hidden_states)
385 + hidden_states = residual + hidden_states
386 +
387 + return hidden_states
388 +
389 +
390 +class FalconH1Model(nn.Module):
391 +
392 + def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
393 + super().__init__()
394 + config: FalconH1Config = vllm_config.model_config.hf_config
395 + cache_config = vllm_config.cache_config
396 + quant_config = vllm_config.quant_config
397 + lora_config = vllm_config.lora_config
398 +
399 + self.config = config
400 + lora_vocab = ((lora_config.lora_extra_vocab_size *
401 + (lora_config.max_loras or 1)) if lora_config else 0)
402 + self.vocab_size = config.vocab_size + lora_vocab
403 + self.org_vocab_size = config.vocab_size
404 + if get_pp_group().is_first_rank:
405 +
406 + self.embed_tokens = VocabParallelEmbedding(
407 + self.vocab_size,
408 + config.hidden_size,
409 + org_num_embeddings=config.vocab_size,
410 + )
411 + self.embedding_multiplier = config.embedding_multiplier
412 + else:
413 + self.embed_tokens = PPMissingLayer()
414 + self.embedding_multiplier = 1.0
415 +
416 + def get_layer(prefix: str):
417 + layer_idx = int(prefix.rsplit(".", 1)[1])
418 + layer_class = FalconH1ParallelHybrid
419 + return layer_class(
420 + config,
421 + layer_idx,
422 + cache_config,
423 + quant_config=quant_config,
424 + prefix=prefix,
425 + )
426 +
427 + self.start_layer, self.end_layer, self.layers = make_layers(
428 + config.num_hidden_layers, get_layer, prefix=f"{prefix}.layers")
429 + self.make_empty_intermediate_tensors = (
430 + make_empty_intermediate_tensors_factory(
431 + ["hidden_states", "residual"], config.hidden_size))
432 + if get_pp_group().is_last_rank:
433 + self.final_layernorm = RMSNorm(config.hidden_size,
434 + eps=config.rms_norm_eps)
435 + else:
436 + self.final_layernorm = PPMissingLayer()
437 +
438 + def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
439 + return self.embed_tokens(input_ids)
440 +
441 + def forward(
442 + self,
443 + input_ids: torch.Tensor,
444 + positions: torch.Tensor,
445 + mamba_cache_params: MambaCacheParams,
446 + intermediate_tensors: Optional[IntermediateTensors] = None,
447 + inputs_embeds: Optional[torch.Tensor] = None,
448 + ) -> torch.Tensor:
449 +
450 + # pass a sequence index tensor, that is required for
451 + # proper continuous batching computation including
452 + # chunked prefill
453 + attn_metadata = get_forward_context().attn_metadata
454 + mamba2_metadata = prepare_mamba2_metadata(
455 + chunk_size=self.config.mamba_chunk_size,
456 + input_ids=input_ids,
457 + attn_metadata=attn_metadata,
458 + )
459 + if get_pp_group().is_first_rank:
460 + if inputs_embeds is not None:
461 + hidden_states = inputs_embeds * self.embedding_multiplier
462 + else:
463 + hidden_states = (self.get_input_embeddings(input_ids) *
464 + self.embedding_multiplier)
465 + else:
466 + assert intermediate_tensors is not None
467 + hidden_states = intermediate_tensors["hidden_states"]
468 +
469 + for i in range(self.start_layer, self.end_layer):
470 + layer = self.layers[i]
471 + layer_mamba_cache_params = mamba_cache_params.at_layer_idx(i)
472 + hidden_states = layer(
473 + positions=positions,
474 + hidden_states=hidden_states,
475 + mamba_cache_params=layer_mamba_cache_params,
476 + mamba2_metadata=mamba2_metadata,
477 + )
478 + if not get_pp_group().is_last_rank:
479 + return IntermediateTensors({
480 + "hidden_states": hidden_states,
481 + })
482 + hidden_states = self.final_layernorm(hidden_states)
483 + return hidden_states
484 +
485 +
486 +class FalconH1ForCausalLM(nn.Module, HasInnerState, SupportsLoRA, SupportsPP,
487 + IsHybrid, SupportsV0Only):
488 + packed_modules_mapping = {
489 + "qkv_proj": ["q_proj", "k_proj", "v_proj"],
490 + "gate_up_proj": ["gate_proj", "up_proj"],
491 + }
492 +
493 + embedding_modules = {
494 + "embed_tokens": "input_embeddings",
495 + "lm_head": "output_embeddings",
496 + }
497 + embedding_padding_modules = ["lm_head"]
498 +
499 + def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
500 + config = vllm_config.model_config.hf_config
501 + self.vllm_config = vllm_config
502 + self.model_config = vllm_config.model_config
503 + cache_config = vllm_config.cache_config
504 + lora_config = vllm_config.lora_config
505 + scheduler_config = vllm_config.scheduler_config
506 + assert (not cache_config.enable_prefix_caching
507 + ), "FalconH1 currently does not support prefix caching"
508 +
509 + self.quant_config = vllm_config.quant_config
510 +
511 + super().__init__()
512 + self.config = config
513 + self.scheduler_config = scheduler_config
514 + self.model = FalconH1Model(vllm_config=vllm_config,
515 + prefix=maybe_prefix(prefix, "model"))
516 + self.tie_word_embeddings = config.tie_word_embeddings
517 + self.unpadded_vocab_size = config.vocab_size
518 + self.mamba_cache: Optional[MambaCacheManager] = None
519 + if lora_config:
520 + self.unpadded_vocab_size += lora_config.lora_extra_vocab_size
521 + if get_pp_group().is_last_rank:
522 + self.lm_head = ParallelLMHead(
523 + self.unpadded_vocab_size,
524 + config.hidden_size,
525 + org_num_embeddings=config.vocab_size,
526 + padding_size=(
527 + DEFAULT_VOCAB_PADDING_SIZE
528 + # We need bigger padding if using lora for kernel
529 + # compatibility
530 + if not lora_config else
531 + lora_config.lora_vocab_padding_size),
532 + )
533 + self.lm_head_multiplier = config.lm_head_multiplier
534 + if self.tie_word_embeddings:
535 + self.lm_head = self.lm_head.tie_weights(
536 + self.model.embed_tokens)
537 + # Used to track and store by the Mamba cache between steps.
538 +
539 + self.logits_processor = LogitsProcessor(
540 + self.unpadded_vocab_size,
541 + config.vocab_size,
542 + scale=config.lm_head_multiplier,
543 + )
544 + else:
545 + self.lm_head = PPMissingLayer()
546 +
547 + self.make_empty_intermediate_tensors = (
548 + self.model.make_empty_intermediate_tensors)
549 +
550 + def get_input_embeddings(self, input_ids: torch.Tensor) -> torch.Tensor:
551 + return self.model.get_input_embeddings(input_ids)
552 +
553 + def forward(
554 + self,
555 + input_ids: torch.Tensor,
556 + positions: torch.Tensor,
557 + intermediate_tensors: Optional[IntermediateTensors] = None,
558 + inputs_embeds: Optional[torch.Tensor] = None,
559 + **kwargs,
560 + ):
561 + if self.mamba_cache is None:
562 + self.mamba_cache = MambaCacheManager(
563 + self.vllm_config,
564 + self.lm_head.weight.dtype
565 + if hasattr(self.lm_head, 'weight') else torch.bfloat16,
566 + self.config.num_hidden_layers,
567 + *self._get_mamba_cache_shape(),
568 + )
569 + mamba_cache_params = self.mamba_cache.current_run_tensors(**kwargs)
570 + hidden_states = self.model(
571 + input_ids,
572 + positions,
573 + mamba_cache_params,
574 + intermediate_tensors,
575 + inputs_embeds,
576 + )
577 +
578 + return hidden_states
579 +
580 + def copy_inputs_before_cuda_graphs(self, input_buffers, **kwargs):
581 + return self.mamba_cache.copy_inputs_before_cuda_graphs(
582 + input_buffers, **kwargs)
583 +
584 + def get_seqlen_agnostic_capture_inputs(self, batch_size: int):
585 + return self.mamba_cache.get_seqlen_agnostic_capture_inputs(batch_size)
586 +
587 + def _get_mamba_cache_shape(
588 + self) -> tuple[tuple[int, int], tuple[int, int]]:
589 + world_size = get_tensor_model_parallel_world_size()
590 + hidden_size = self.config.hidden_size
591 +
592 + conv_state_shape, temporal_state_shape = None, None
593 +
594 + intermediate_size = (int(self.config.mamba_expand *
595 + hidden_size) if self.config.mamba_d_ssm
596 + is None else self.config.mamba_d_ssm)
597 +
598 + # if n_groups is not divisible by world_size, need to extend the shards
599 + # to ensure all groups needed by a head is sharded along with it
600 + n_groups = self.config.mamba_n_groups + extra_groups_for_head_shards(
601 + self.config.mamba_n_groups, world_size)
602 +
603 + # - heads and n_groups are TP-ed
604 + conv_dim = intermediate_size + 2 * n_groups * self.config.mamba_d_state
605 + conv_state_shape = (
606 + divide(conv_dim, world_size),
607 + self.config.mamba_d_conv - 1,
608 + )
609 +
610 + # These are not TP-ed as they depend on A, dt_bias, D
611 + # - they are typically small
612 + # e.g., (h_heads, d_head, d_state) = (128, 64, 128)
613 + temporal_state_shape = (
614 + divide(self.config.mamba_n_heads, world_size),
615 + self.config.mamba_d_head,
616 + self.config.mamba_d_state,
617 + )
618 + return conv_state_shape, temporal_state_shape
619 +
620 + def compute_logits(
621 + self,
622 + hidden_states: torch.Tensor,
623 + sampling_metadata: SamplingMetadata,
624 + ) -> Optional[torch.Tensor]:
625 + logits = self.logits_processor(self.lm_head, hidden_states,
626 + sampling_metadata)
627 +
628 + return logits
629 +
630 + def load_weights(self, weights: Iterable[tuple[str,
631 + torch.Tensor]]) -> set[str]:
632 + stacked_params_mapping = [
633 + # (param_name, shard_name, shard_id)
634 + ("qkv_proj", "q_proj", "q"),
635 + ("qkv_proj", "k_proj", "k"),
636 + ("qkv_proj", "v_proj", "v"),
637 + ("gate_up_proj", "gate_proj", 0),
638 + ("gate_up_proj", "up_proj", 1),
639 + ]
640 +
641 + params_dict = dict(self.named_parameters())
642 + loaded_params: set[str] = set()
643 + for name, loaded_weight in weights:
644 + if "rotary_emb.inv_freq" in name:
645 + continue
646 +
647 + if "A_log" in name:
648 + name = name.replace("A_log", "A")
649 +
650 + if "mamba" in name:
651 + name = name.replace("mamba", "mamba.mamba")
652 +
653 + for param_name, weight_name, shard_id in stacked_params_mapping:
654 + if weight_name not in name:
655 + continue
656 +
657 + name = name.replace(weight_name, param_name)
658 + # Skip loading extra bias for GPTQ models.
659 + if name.endswith(".bias") and name not in params_dict:
660 + continue
661 + # Skip layers on other devices.
662 + if is_pp_missing_parameter(name, self):
663 + continue
664 + param = params_dict[name]
665 + weight_loader = param.weight_loader
666 + weight_loader(param, loaded_weight, shard_id)
667 + break
668 + else:
669 + # Skip loading extra bias for GPTQ models.
670 + if name.endswith(".bias") and name not in params_dict:
671 + continue
672 + if is_pp_missing_parameter(name, self):
673 + continue
674 + if self.tie_word_embeddings and "lm_head" in name:
675 + continue
676 +
677 + param = params_dict[name]
678 + weight_loader = getattr(param, "weight_loader",
679 + default_weight_loader)
680 + weight_loader(param, loaded_weight)
681 + loaded_params.add(name)
682 +
683 + if self.tie_word_embeddings:
684 + loaded_params.add("lm_head.weight")
685 + return loaded_params
vllm/model_executor/models/registry.py
+1
@@ -79,6 +79,7 @@ _TEXT_GENERATION_MODELS = {
79 "LLaMAForCausalLM": ("llama", "LlamaForCausalLM"),
80 "MambaForCausalLM": ("mamba", "MambaForCausalLM"),
81 "FalconMambaForCausalLM": ("mamba", "MambaForCausalLM"),
82 + "FalconH1ForCausalLM":("falcon_h1", "FalconH1ForCausalLM"),
83 "Mamba2ForCausalLM": ("mamba2", "Mamba2ForCausalLM"),
84 "MiniCPMForCausalLM": ("minicpm", "MiniCPMForCausalLM"),
85 "MiniCPM3ForCausalLM": ("minicpm3", "MiniCPM3ForCausalLM"),