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 7, 05:15 UTC
[Model] Add support for OLMo Hybrid (#32550)
Yanhong Li committed
Mar 5, 2026 at 11:51 UTC
a911f4dd20d0a0fcfee362f096e9c6fd23d59590
10 files changed
+1520
-53
docs/models/supported_models.md
+1
@@ -448,6 +448,7 @@ th {
448
| `OlmoForCausalLM` | OLMo | `allenai/OLMo-1B-hf`, `allenai/OLMo-7B-hf`, etc. | ✅︎ | ✅︎ |
449
| `Olmo2ForCausalLM` | OLMo2 | `allenai/OLMo-2-0425-1B`, etc. | ✅︎ | ✅︎ |
450
| `Olmo3ForCausalLM` | OLMo3 | `allenai/Olmo-3-7B-Instruct`, `allenai/Olmo-3-32B-Think`, etc. | ✅︎ | ✅︎ |
451
+| `OlmoHybridForCausalLM` | OLMo Hybrid | `allenai/Olmo-Hybrid-7B` | ✅︎ | ✅︎ |
452
| `OlmoeForCausalLM` | OLMoE | `allenai/OLMoE-1B-7B-0924`, `allenai/OLMoE-1B-7B-0924-Instruct`, etc. | | ✅︎ |
453
| `OPTForCausalLM` | OPT, OPT-IML | `facebook/opt-66b`, `facebook/opt-iml-max-30b`, etc. | ✅︎ | ✅︎ |
454
| `OrionForCausalLM` | Orion | `OrionStarAI/Orion-14B-Base`, `OrionStarAI/Orion-14B-Chat`, etc. | | ✅︎ |
tests/models/registry.py
+1
@@ -420,6 +420,7 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
420
"OlmoForCausalLM": _HfExamplesInfo("allenai/OLMo-1B-hf"),
421
"Olmo2ForCausalLM": _HfExamplesInfo("allenai/OLMo-2-0425-1B"),
422
"Olmo3ForCausalLM": _HfExamplesInfo("allenai/Olmo-3-7B-Instruct"),
423
+ "OlmoHybridForCausalLM": _HfExamplesInfo("allenai/Olmo-Hybrid-7B"),
424
"OlmoeForCausalLM": _HfExamplesInfo("allenai/OLMoE-1B-7B-0924-Instruct"),
425
"OPTForCausalLM": _HfExamplesInfo(
426
"facebook/opt-125m", {"1b": "facebook/opt-iml-max-1.3b"}
vllm/config/compilation.py
+1
@@ -666,6 +666,7 @@ class CompilationConfig:
666
"vllm::linear_attention",
667
"vllm::plamo2_mamba_mixer",
668
"vllm::gdn_attention_core",
669
+ "vllm::olmo_hybrid_gdn_full_forward",
670
"vllm::kda_attention",
671
"vllm::sparse_attn_indexer",
672
"vllm::rocm_aiter_sparse_attn_indexer",
vllm/model_executor/layers/fla/ops/l2norm.py
+10
-5
@@ -76,16 +76,20 @@ def l2norm_fwd_kernel(
76
77
78
@triton.jit
79
-def l2norm_fwd_kernel2(X, Y, eps, M, N: tl.constexpr, MBLOCK: tl.constexpr):
79
+def l2norm_fwd_kernel2(
80
+ X, Y, eps, M, N: tl.constexpr, BD: tl.constexpr, MBLOCK: tl.constexpr
81
+):
82
xoffset = tl.program_id(0) * MBLOCK
83
row_idx = xoffset + tl.arange(0, MBLOCK)[:, None]
84
xmask = row_idx < M
83
- rindex = tl.arange(0, N)[None, :]
84
- xs = tl.load(X + (rindex + N * row_idx), xmask).to(tl.float32)
85
- square = tl.broadcast_to(xs * xs, [MBLOCK, N])
85
+ rindex = tl.arange(0, BD)[None, :]
86
+ cmask = rindex < N
87
+ mask = xmask & cmask
88
+ xs = tl.load(X + (rindex + N * row_idx), mask, other=0.0).to(tl.float32)
89
+ square = tl.broadcast_to(xs * xs, [MBLOCK, BD])
90
square_sum = tl.sum(tl.where(xmask, square, 0), 1)[:, None]
91
rsqrt = tl.rsqrt(square_sum + eps)
88
- tl.store(Y + (rindex + N * row_idx), xs * rsqrt, xmask)
92
+ tl.store(Y + (rindex + N * row_idx), xs * rsqrt, mask)
93
94
95
def l2norm_fwd(
@@ -116,6 +120,7 @@ def l2norm_fwd(
120
eps,
121
T,
122
D,
123
+ BD,
124
MBLOCK,
125
)
126
else:
vllm/model_executor/layers/fla/ops/layernorm_guard.py
+47
-48
@@ -250,57 +250,55 @@ def layer_norm_fwd(
250
return out, mean, rstd
251
252
253
-class LayerNormFn(torch.autograd.Function):
254
- @input_guard
255
- @staticmethod
256
- def forward(
257
- ctx,
253
+def _layer_norm_fn_impl(
254
+ x,
255
+ weight,
256
+ bias,
257
+ z=None,
258
+ eps=1e-6,
259
+ group_size=None,
260
+ norm_before_gate=True,
261
+ is_rms_norm=False,
262
+ activation: str = "swish",
263
+):
264
+ """Triton layer/RMS norm with optional gating.
265
+
266
+ If z is not None, computes norm(x) * silu(z) when norm_before_gate,
267
+ else norm(x * silu(z)).
268
+
269
+ This calls the triton kernel directly. The original code wrapped this
270
+ in a torch.autograd.Function (LayerNormFn) to save tensors for a
271
+ backward pass, but vLLM is inference-only so there is no backward pass.
272
+ The autograd wrapper also prevented torch.compile/dynamo from tracing
273
+ through the function due to its @staticmethod forward.
274
+ """
275
+ x_shape_og = x.shape
276
+ x = x.reshape(-1, x.shape[-1])
277
+ if x.stride(-1) != 1:
278
+ x = x.contiguous()
279
+ if z is not None:
280
+ assert z.shape == x_shape_og
281
+ z = z.reshape(-1, z.shape[-1])
282
+ if z.stride(-1) != 1:
283
+ z = z.contiguous()
284
+ weight = weight.contiguous()
285
+ if bias is not None:
286
+ bias = bias.contiguous()
287
+ y, _, _ = layer_norm_fwd(
288
x,
289
weight,
290
bias,
261
- z=None,
262
- eps=1e-6,
263
- group_size=None,
264
- norm_before_gate=True,
265
- is_rms_norm=False,
266
- activation: str = "swish",
267
- ):
268
- """If z is not None, we do norm(x) * silu(z) if norm_before_gate, else norm(x * silu(z))"""
269
-
270
- x_shape_og = x.shape
271
- # reshape input data into 2D tensor
272
- x = x.reshape(-1, x.shape[-1])
273
- if x.stride(-1) != 1:
274
- x = x.contiguous()
275
- if z is not None:
276
- assert z.shape == x_shape_og
277
- z = z.reshape(-1, z.shape[-1])
278
- if z.stride(-1) != 1:
279
- z = z.contiguous()
280
- weight = weight.contiguous()
281
- if bias is not None:
282
- bias = bias.contiguous()
283
- y, mean, rstd = layer_norm_fwd(
284
- x,
285
- weight,
286
- bias,
287
- eps,
288
- z=z,
289
- group_size=group_size,
290
- norm_before_gate=norm_before_gate,
291
- is_rms_norm=is_rms_norm,
292
- activation=activation,
293
- )
294
- ctx.save_for_backward(x, weight, bias, mean, rstd, z)
295
- ctx.x_shape_og = x_shape_og
296
- ctx.eps = eps
297
- ctx.group_size = group_size
298
- ctx.norm_before_gate = norm_before_gate
299
- ctx.is_rms_norm = is_rms_norm
300
- ctx.activation = activation
301
- return y.reshape(x_shape_og)
291
+ eps,
292
+ z=z,
293
+ group_size=group_size,
294
+ norm_before_gate=norm_before_gate,
295
+ is_rms_norm=is_rms_norm,
296
+ activation=activation,
297
+ )
298
+ return y.reshape(x_shape_og)
299
300
301
+@input_guard
302
def layernorm_fn(
303
x,
304
weight,
@@ -312,11 +310,12 @@ def layernorm_fn(
310
is_rms_norm=False,
311
activation: str = "swish",
312
):
315
- return LayerNormFn.apply(
313
+ return _layer_norm_fn_impl(
314
x, weight, bias, z, eps, group_size, norm_before_gate, is_rms_norm, activation
315
)
316
317
318
+@input_guard
319
def rmsnorm_fn(
320
x,
321
weight,
@@ -327,7 +326,7 @@ def rmsnorm_fn(
326
norm_before_gate=True,
327
activation: str = "swish",
328
):
330
- return LayerNormFn.apply(
329
+ return _layer_norm_fn_impl(
330
x, weight, bias, z, eps, group_size, norm_before_gate, True, activation
331
)
332
vllm/model_executor/models/olmo_hybrid.py
new
+1172
@@ -0,0 +1,1172 @@
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/main/src/transformers/models/olmo_hybrid/modeling_olmo_hybrid.py
6
+# Copyright 2026 The vLLM team.
7
+#
8
+# This code combines OLMo2/OLMo3 attention with Gated DeltaNet linear attention
9
+# for the OLMo Hybrid architecture.
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
+"""Inference-only OLMo Hybrid model compatible with HuggingFace weights."""
23
+
24
+from collections.abc import Iterable
25
+from functools import partial
26
+from itertools import islice
27
+
28
+import torch
29
+from einops import rearrange
30
+from torch import nn
31
+from transformers.activations import ACT2FN
32
+
33
+from vllm.compilation.decorators import support_torch_compile
34
+from vllm.config import (
35
+ CacheConfig,
36
+ ModelConfig,
37
+ SpeculativeConfig,
38
+ VllmConfig,
39
+ get_current_vllm_config,
40
+)
41
+from vllm.distributed import (
42
+ divide,
43
+ get_pp_group,
44
+ get_tensor_model_parallel_rank,
45
+ get_tensor_model_parallel_world_size,
46
+ tensor_model_parallel_all_gather,
47
+)
48
+from vllm.distributed.utils import split_tensor_along_last_dim
49
+from vllm.forward_context import ForwardContext, get_forward_context
50
+from vllm.logger import init_logger
51
+from vllm.model_executor.layers.activation import SiluAndMul
52
+from vllm.model_executor.layers.attention import Attention
53
+from vllm.model_executor.layers.fla.ops import (
54
+ chunk_gated_delta_rule,
55
+ fused_recurrent_gated_delta_rule,
56
+)
57
+from vllm.model_executor.layers.layernorm import RMSNorm, RMSNormGated
58
+from vllm.model_executor.layers.linear import (
59
+ ColumnParallelLinear,
60
+ MergedColumnParallelLinear,
61
+ QKVParallelLinear,
62
+ RowParallelLinear,
63
+)
64
+from vllm.model_executor.layers.logits_processor import LogitsProcessor
65
+from vllm.model_executor.layers.mamba.abstract import MambaBase
66
+from vllm.model_executor.layers.mamba.mamba_utils import (
67
+ MambaStateCopyFunc,
68
+ MambaStateCopyFuncCalculator,
69
+ MambaStateDtypeCalculator,
70
+ MambaStateShapeCalculator,
71
+)
72
+from vllm.model_executor.layers.mamba.ops.causal_conv1d import (
73
+ causal_conv1d_fn,
74
+ causal_conv1d_update,
75
+)
76
+from vllm.model_executor.layers.quantization import QuantizationConfig
77
+from vllm.model_executor.layers.rotary_embedding import get_rope
78
+from vllm.model_executor.layers.vocab_parallel_embedding import (
79
+ ParallelLMHead,
80
+ VocabParallelEmbedding,
81
+)
82
+from vllm.model_executor.model_loader.weight_utils import (
83
+ default_weight_loader,
84
+ sharded_weight_loader,
85
+)
86
+from vllm.model_executor.utils import set_weight_attrs
87
+from vllm.platforms import current_platform
88
+from vllm.sequence import IntermediateTensors
89
+from vllm.triton_utils import tl, triton
90
+from vllm.triton_utils.allocation import set_triton_allocator
91
+from vllm.utils.torch_utils import direct_register_custom_op
92
+from vllm.v1.attention.backend import AttentionMetadata
93
+from vllm.v1.attention.backends.gdn_attn import GDNAttentionMetadata
94
+
95
+from .interfaces import HasInnerState, IsHybrid, SupportsLoRA, SupportsPP
96
+from .utils import (
97
+ AutoWeightsLoader,
98
+ extract_layer_index,
99
+ is_pp_missing_parameter,
100
+ make_empty_intermediate_tensors_factory,
101
+ make_layers,
102
+ maybe_prefix,
103
+)
104
+
105
+logger = init_logger(__name__)
106
+
107
+
108
+def _make_fused_conv1d_weight_loader(dims, tp_size, tp_rank):
109
+ """Weight loader for loading separate HF conv weights into a fused conv1d.
110
+
111
+ dims: list of original (un-sharded) dims per section,
112
+ e.g. [key_dim, key_dim, value_dim]
113
+ """
114
+ sharded_dims = [d // tp_size for d in dims]
115
+
116
+ def weight_loader(param, loaded_weight, loaded_shard_id=None):
117
+ if loaded_weight.dim() == 2:
118
+ loaded_weight = loaded_weight.unsqueeze(1)
119
+ dim = dims[loaded_shard_id]
120
+ shard_size = dim // tp_size
121
+ tp_start = tp_rank * shard_size
122
+ sharded_weight = loaded_weight[tp_start : tp_start + shard_size]
123
+ offset = sum(sharded_dims[:loaded_shard_id])
124
+ param.data[offset : offset + shard_size].copy_(sharded_weight)
125
+
126
+ return weight_loader
127
+
128
+
129
+class OlmoHybridGatedDeltaNet(nn.Module, MambaBase):
130
+ """
131
+ Gated DeltaNet linear attention layer for OLMo Hybrid.
132
+
133
+ This implements the linear attention mechanism that replaces sliding window
134
+ attention in the hybrid architecture.
135
+ """
136
+
137
+ @property
138
+ def mamba_type(self) -> str:
139
+ return "gdn_attention"
140
+
141
+ def get_state_dtype(self) -> tuple[torch.dtype, torch.dtype]:
142
+ return MambaStateDtypeCalculator.gated_delta_net_state_dtype(
143
+ self.model_config.dtype,
144
+ self.cache_config.mamba_cache_dtype,
145
+ self.cache_config.mamba_ssm_cache_dtype,
146
+ )
147
+
148
+ def get_state_shape(self) -> tuple[tuple[int, ...], tuple[int, ...]]:
149
+ return MambaStateShapeCalculator.gated_delta_net_state_shape(
150
+ self.tp_size,
151
+ self.num_k_heads,
152
+ self.num_v_heads,
153
+ self.head_k_dim,
154
+ self.head_v_dim,
155
+ self.conv_kernel_size,
156
+ self.num_spec,
157
+ )
158
+
159
+ def __init__(
160
+ self,
161
+ config,
162
+ model_config: ModelConfig | None = None,
163
+ cache_config: CacheConfig | None = None,
164
+ quant_config: QuantizationConfig | None = None,
165
+ speculative_config: SpeculativeConfig | None = None,
166
+ prefix: str = "",
167
+ ) -> None:
168
+ super().__init__()
169
+ self.tp_size = get_tensor_model_parallel_world_size()
170
+ self.tp_rank = get_tensor_model_parallel_rank()
171
+ self.hidden_size = config.hidden_size
172
+ self.num_v_heads = config.linear_num_value_heads
173
+ self.num_k_heads = config.linear_num_key_heads
174
+ self.head_k_dim = config.linear_key_head_dim
175
+ self.head_v_dim = config.linear_value_head_dim
176
+ self.key_dim = self.head_k_dim * self.num_k_heads
177
+ self.value_dim = self.head_v_dim * self.num_v_heads
178
+
179
+ self.conv_kernel_size = config.linear_conv_kernel_dim
180
+ self.layer_idx = extract_layer_index(prefix)
181
+ self.activation = config.hidden_act
182
+ self.act = ACT2FN[config.hidden_act]
183
+ self.layer_norm_epsilon = config.rms_norm_eps
184
+ assert getattr(config, "linear_use_gate", True), (
185
+ "OlmoHybridGatedDeltaNet requires linear_use_gate=True"
186
+ )
187
+ self.allow_neg_eigval = getattr(config, "linear_allow_neg_eigval", False)
188
+ self.prefix = prefix
189
+
190
+ self.config = config
191
+ self.model_config = model_config
192
+ self.cache_config = cache_config
193
+ self.quant_config = quant_config
194
+ self.speculative_config = speculative_config
195
+ self.num_spec = (
196
+ self.speculative_config.num_speculative_tokens
197
+ if self.speculative_config
198
+ else 0
199
+ )
200
+
201
+ # Fused QKVG projection: 1 matmul instead of 4
202
+ self.in_proj_qkvg = MergedColumnParallelLinear(
203
+ input_size=self.hidden_size,
204
+ output_sizes=[self.key_dim, self.key_dim, self.value_dim, self.value_dim],
205
+ bias=False,
206
+ quant_config=quant_config,
207
+ prefix=f"{prefix}.in_proj_qkvg",
208
+ )
209
+
210
+ # Separate B and A projections to preserve numerical precision.
211
+ # Fusing these into one matmul changes FP accumulation order for the
212
+ # gating scalars, which compounds through the GDN recurrent state.
213
+ self.b_proj = ColumnParallelLinear(
214
+ input_size=self.hidden_size,
215
+ output_size=self.num_v_heads,
216
+ bias=False,
217
+ quant_config=quant_config,
218
+ prefix=f"{prefix}.b_proj",
219
+ )
220
+ self.a_proj = ColumnParallelLinear(
221
+ input_size=self.hidden_size,
222
+ output_size=self.num_v_heads,
223
+ bias=False,
224
+ quant_config=quant_config,
225
+ prefix=f"{prefix}.a_proj",
226
+ )
227
+
228
+ # Fused conv1d: single parameter instead of 3
229
+ self.conv_dim = self.key_dim * 2 + self.value_dim
230
+ self.conv1d = ColumnParallelLinear(
231
+ input_size=self.conv_kernel_size,
232
+ output_size=self.conv_dim,
233
+ bias=False,
234
+ prefix=f"{prefix}.conv1d",
235
+ )
236
+ self.conv1d.weight.data = self.conv1d.weight.data.unsqueeze(1)
237
+ delattr(self.conv1d.weight, "weight_loader")
238
+ set_weight_attrs(
239
+ self.conv1d.weight,
240
+ {
241
+ "weight_loader": _make_fused_conv1d_weight_loader(
242
+ [self.key_dim, self.key_dim, self.value_dim],
243
+ self.tp_size,
244
+ self.tp_rank,
245
+ )
246
+ },
247
+ )
248
+
249
+ self.dt_bias = nn.Parameter(
250
+ torch.ones(self.num_v_heads // self.tp_size),
251
+ )
252
+ self.A_log = nn.Parameter(
253
+ torch.empty(
254
+ divide(self.num_v_heads, self.tp_size),
255
+ )
256
+ )
257
+
258
+ set_weight_attrs(self.A_log, {"weight_loader": sharded_weight_loader(0)})
259
+ set_weight_attrs(self.dt_bias, {"weight_loader": sharded_weight_loader(0)})
260
+
261
+ # use eps=1e-5 to match FLA's FusedRMSNormGated
262
+ self.o_norm = RMSNormGated(
263
+ self.head_v_dim,
264
+ eps=1e-5,
265
+ group_size=None,
266
+ norm_before_gate=True,
267
+ device=current_platform.current_device(),
268
+ dtype=config.torch_dtype if hasattr(config, "torch_dtype") else None,
269
+ )
270
+
271
+ self.o_proj = RowParallelLinear(
272
+ self.value_dim,
273
+ self.hidden_size,
274
+ bias=False,
275
+ input_is_parallel=True,
276
+ quant_config=quant_config,
277
+ prefix=f"{prefix}.o_proj",
278
+ )
279
+
280
+ # FLA triton kernels need a PyTorch-backed allocator for scratch
281
+ # memory (required by triton >= 3.x autotuner). Set once at init.
282
+ set_triton_allocator(current_platform.current_device())
283
+
284
+ compilation_config = get_current_vllm_config().compilation_config
285
+ if prefix in compilation_config.static_forward_context:
286
+ raise ValueError(f"Duplicate layer name: {prefix}")
287
+ compilation_config.static_forward_context[prefix] = self
288
+
289
+ def rearrange_mixed_qkv(self, mixed_qkv):
290
+ if mixed_qkv is None:
291
+ return None, None, None
292
+ query, key, value = torch.split(
293
+ mixed_qkv,
294
+ [
295
+ self.key_dim // self.tp_size,
296
+ self.key_dim // self.tp_size,
297
+ self.value_dim // self.tp_size,
298
+ ],
299
+ dim=-1,
300
+ )
301
+
302
+ num_k_heads = self.num_k_heads // self.tp_size
303
+ num_v_heads = self.num_v_heads // self.tp_size
304
+
305
+ query = rearrange(query, "l (h d) -> 1 l h d", h=num_k_heads, d=self.head_k_dim)
306
+ key = rearrange(key, "l (h d) -> 1 l h d", h=num_k_heads, d=self.head_k_dim)
307
+ value = rearrange(value, "l (h d) -> 1 l h d", h=num_v_heads, d=self.head_v_dim)
308
+
309
+ # GQA expansion if needed
310
+ if num_v_heads > num_k_heads:
311
+ expand_ratio = num_v_heads // num_k_heads
312
+ query = query.unsqueeze(3).expand(-1, -1, -1, expand_ratio, -1)
313
+ query = query.reshape(1, query.shape[1], num_v_heads, self.head_k_dim)
314
+ key = key.unsqueeze(3).expand(-1, -1, -1, expand_ratio, -1)
315
+ key = key.reshape(1, key.shape[1], num_v_heads, self.head_k_dim)
316
+
317
+ return query.contiguous(), key.contiguous(), value.contiguous()
318
+
319
+ def forward(
320
+ self,
321
+ hidden_states: torch.Tensor,
322
+ output: torch.Tensor,
323
+ ):
324
+ # NOTE: We wrap the ENTIRE linear attention forward (projections +
325
+ # core recurrence + output norm + output projection) in a single
326
+ # custom op, rather than just wrapping the recurrent core like
327
+ # other GDN models (e.g. Qwen3Next) do.
328
+ #
329
+ # Why: torch.compile with inductor generates fused kernels for
330
+ # matmuls and pointwise ops. These fused kernels can differ in
331
+ # floating-point accumulation order from eager-mode cuBLAS,
332
+ # introducing small numerical differences (~1e-7 per op). For
333
+ # standard transformer attention this is harmless because each
334
+ # position is computed independently. But for the GDN recurrent
335
+ # state, these tiny input differences compound at every timestep
336
+ # across the full sequence length, causing severe logprob
337
+ # divergence (e.g. ~15% top-1 agreement with eager baseline).
338
+ #
339
+ # By making the full forward opaque to inductor, the projections
340
+ # and output norm run with eager-mode kernels (cuBLAS, triton),
341
+ # preserving numerical consistency. The tradeoff is reduced
342
+ # compilation speedup (~1.5x vs ~3x), but logprob agreement
343
+ # improves from ~15% to ~83% top-1 vs eager.
344
+ #
345
+ # The remaining ~17% divergence comes from inductor compiling
346
+ # the MLP and transformer attention layers that are NOT wrapped
347
+ # in custom ops -- their small precision differences propagate
348
+ # as inputs to the GDN layers from outside.
349
+ torch.ops.vllm.olmo_hybrid_gdn_full_forward(
350
+ hidden_states,
351
+ output,
352
+ self.prefix,
353
+ )
354
+
355
+ def _full_forward(
356
+ self,
357
+ hidden_states: torch.Tensor,
358
+ output: torch.Tensor,
359
+ ):
360
+ num_tokens = hidden_states.size(0)
361
+
362
+ # ============================================================
363
+ # Part 1: Input Projection (2 fused matmuls instead of 6)
364
+ # ============================================================
365
+ projected_qkvg, _ = self.in_proj_qkvg(hidden_states)
366
+ conv_dim_sharded = (self.key_dim * 2 + self.value_dim) // self.tp_size
367
+ mixed_qkv = projected_qkvg[..., :conv_dim_sharded]
368
+ gate = projected_qkvg[..., conv_dim_sharded:]
369
+
370
+ b, _ = self.b_proj(hidden_states)
371
+ a, _ = self.a_proj(hidden_states)
372
+
373
+ # ============================================================
374
+ # Part 2: Core Attention
375
+ # ============================================================
376
+ core_attn_out = torch.zeros(
377
+ (num_tokens, self.num_v_heads // self.tp_size, self.head_v_dim),
378
+ dtype=hidden_states.dtype,
379
+ device=hidden_states.device,
380
+ )
381
+
382
+ self._forward_core(
383
+ mixed_qkv=mixed_qkv,
384
+ b=b,
385
+ a=a,
386
+ core_attn_out=core_attn_out,
387
+ )
388
+
389
+ # ============================================================
390
+ # Part 3: Output Projection
391
+ # ============================================================
392
+ gate = gate.view(num_tokens, self.num_v_heads // self.tp_size, self.head_v_dim)
393
+ core_attn_out_flat = core_attn_out.reshape(-1, core_attn_out.shape[-1])
394
+ gate_flat = gate.reshape(-1, gate.shape[-1])
395
+ core_attn_out_normed = self.o_norm(core_attn_out_flat, gate_flat)
396
+ core_attn_out = core_attn_out_normed.view(
397
+ num_tokens, self.num_v_heads // self.tp_size, self.head_v_dim
398
+ )
399
+
400
+ core_attn_out = rearrange(core_attn_out, "l h d -> l (h d)")
401
+ output[:num_tokens], _ = self.o_proj(core_attn_out)
402
+
403
+ def _forward_core(
404
+ self,
405
+ mixed_qkv: torch.Tensor,
406
+ b: torch.Tensor,
407
+ a: torch.Tensor,
408
+ core_attn_out: torch.Tensor,
409
+ ):
410
+ """
411
+ Core attention computation (called by custom op).
412
+ """
413
+ forward_context = get_forward_context()
414
+ attn_metadata: AttentionMetadata = forward_context.attn_metadata
415
+
416
+ if attn_metadata is None:
417
+ # V1 profile run
418
+ return
419
+
420
+ assert isinstance(attn_metadata, dict)
421
+ attn_metadata = attn_metadata[self.prefix]
422
+ assert isinstance(attn_metadata, GDNAttentionMetadata)
423
+ has_initial_state = attn_metadata.has_initial_state
424
+ spec_query_start_loc = attn_metadata.spec_query_start_loc
425
+ non_spec_query_start_loc = attn_metadata.non_spec_query_start_loc
426
+ spec_sequence_masks = attn_metadata.spec_sequence_masks
427
+ spec_token_indx = attn_metadata.spec_token_indx
428
+ non_spec_token_indx = attn_metadata.non_spec_token_indx
429
+ spec_state_indices_tensor = attn_metadata.spec_state_indices_tensor
430
+ non_spec_state_indices_tensor = attn_metadata.non_spec_state_indices_tensor
431
+ self_kv_cache = self.kv_cache[forward_context.virtual_engine]
432
+ conv_state = self_kv_cache[0].transpose(-1, -2)
433
+ ssm_state = self_kv_cache[1]
434
+ num_actual_tokens = attn_metadata.num_actual_tokens
435
+ num_accepted_tokens = attn_metadata.num_accepted_tokens
436
+
437
+ mixed_qkv = mixed_qkv[:num_actual_tokens]
438
+ b = b[:num_actual_tokens]
439
+ a = a[:num_actual_tokens]
440
+
441
+ conv_weights = self.conv1d.weight.view(
442
+ self.conv1d.weight.size(0), self.conv1d.weight.size(2)
443
+ )
444
+
445
+ if spec_sequence_masks is not None:
446
+ if attn_metadata.num_prefills == 0 and attn_metadata.num_decodes == 0:
447
+ mixed_qkv_spec = mixed_qkv
448
+ mixed_qkv_non_spec = None
449
+ else:
450
+ mixed_qkv_spec = mixed_qkv.index_select(0, spec_token_indx)
451
+ mixed_qkv_non_spec = mixed_qkv.index_select(0, non_spec_token_indx)
452
+ else:
453
+ mixed_qkv_spec = None
454
+ mixed_qkv_non_spec = mixed_qkv
455
+
456
+ if spec_sequence_masks is not None:
457
+ mixed_qkv_spec = causal_conv1d_update(
458
+ mixed_qkv_spec,
459
+ conv_state,
460
+ conv_weights,
461
+ None, # no bias
462
+ self.activation,
463
+ conv_state_indices=spec_state_indices_tensor[:, 0][
464
+ : attn_metadata.num_spec_decodes
465
+ ],
466
+ num_accepted_tokens=num_accepted_tokens,
467
+ query_start_loc=spec_query_start_loc,
468
+ max_query_len=spec_state_indices_tensor.size(-1),
469
+ validate_data=False,
470
+ )
471
+
472
+ if attn_metadata.num_prefills > 0:
473
+ mixed_qkv_non_spec_T = mixed_qkv_non_spec.transpose(0, 1)
474
+ mixed_qkv_non_spec = causal_conv1d_fn(
475
+ mixed_qkv_non_spec_T,
476
+ conv_weights,
477
+ None,
478
+ activation=self.activation,
479
+ conv_states=conv_state,
480
+ has_initial_state=has_initial_state,
481
+ cache_indices=non_spec_state_indices_tensor,
482
+ query_start_loc=non_spec_query_start_loc,
483
+ metadata=attn_metadata,
484
+ ).transpose(0, 1)
485
+ elif attn_metadata.num_decodes > 0:
486
+ mixed_qkv_non_spec = causal_conv1d_update(
487
+ mixed_qkv_non_spec,
488
+ conv_state,
489
+ conv_weights,
490
+ None,
491
+ self.activation,
492
+ conv_state_indices=non_spec_state_indices_tensor[
493
+ : attn_metadata.num_decodes
494
+ ],
495
+ validate_data=True,
496
+ )
497
+ else:
498
+ mixed_qkv_non_spec = None
499
+
500
+ query_spec, key_spec, value_spec = self.rearrange_mixed_qkv(mixed_qkv_spec)
501
+ query_non_spec, key_non_spec, value_non_spec = self.rearrange_mixed_qkv(
502
+ mixed_qkv_non_spec
503
+ )
504
+
505
+ g, beta = fused_olmo_hybrid_gdn_gating(
506
+ self.A_log, a, b, self.dt_bias, self.allow_neg_eigval
507
+ )
508
+
509
+ if spec_sequence_masks is not None:
510
+ if attn_metadata.num_prefills == 0 and attn_metadata.num_decodes == 0:
511
+ g_spec = g
512
+ beta_spec = beta
513
+ g_non_spec = None
514
+ beta_non_spec = None
515
+ else:
516
+ g_spec = g.index_select(1, spec_token_indx)
517
+ beta_spec = beta.index_select(1, spec_token_indx)
518
+ g_non_spec = g.index_select(1, non_spec_token_indx)
519
+ beta_non_spec = beta.index_select(1, non_spec_token_indx)
520
+ else:
521
+ g_spec = None
522
+ beta_spec = None
523
+ g_non_spec = g
524
+ beta_non_spec = beta
525
+
526
+ if spec_sequence_masks is not None:
527
+ core_attn_out_spec, last_recurrent_state = fused_recurrent_gated_delta_rule(
528
+ q=query_spec,
529
+ k=key_spec,
530
+ v=value_spec,
531
+ g=g_spec,
532
+ beta=beta_spec,
533
+ initial_state=ssm_state,
534
+ inplace_final_state=True,
535
+ cu_seqlens=spec_query_start_loc[: attn_metadata.num_spec_decodes + 1],
536
+ ssm_state_indices=spec_state_indices_tensor,
537
+ num_accepted_tokens=num_accepted_tokens,
538
+ use_qk_l2norm_in_kernel=True,
539
+ )
540
+ else:
541
+ core_attn_out_spec, last_recurrent_state = None, None
542
+
543
+ if attn_metadata.num_prefills > 0:
544
+ initial_state = ssm_state[non_spec_state_indices_tensor].contiguous()
545
+ initial_state[~has_initial_state, ...] = 0
546
+ (
547
+ core_attn_out_non_spec,
548
+ last_recurrent_state,
549
+ ) = chunk_gated_delta_rule(
550
+ q=query_non_spec,
551
+ k=key_non_spec,
552
+ v=value_non_spec,
553
+ g=g_non_spec,
554
+ beta=beta_non_spec,
555
+ initial_state=initial_state,
556
+ output_final_state=True,
557
+ cu_seqlens=non_spec_query_start_loc,
558
+ use_qk_l2norm_in_kernel=True,
559
+ )
560
+ ssm_state[non_spec_state_indices_tensor] = last_recurrent_state.to(
561
+ ssm_state.dtype
562
+ )
563
+ elif attn_metadata.num_decodes > 0:
564
+ core_attn_out_non_spec, last_recurrent_state = (
565
+ fused_recurrent_gated_delta_rule(
566
+ q=query_non_spec,
567
+ k=key_non_spec,
568
+ v=value_non_spec,
569
+ g=g_non_spec,
570
+ beta=beta_non_spec,
571
+ initial_state=ssm_state,
572
+ inplace_final_state=True,
573
+ cu_seqlens=non_spec_query_start_loc[
574
+ : attn_metadata.num_decodes + 1
575
+ ],
576
+ ssm_state_indices=non_spec_state_indices_tensor,
577
+ use_qk_l2norm_in_kernel=True,
578
+ )
579
+ )
580
+ else:
581
+ core_attn_out_non_spec, last_recurrent_state = None, None
582
+
583
+ if spec_sequence_masks is not None and core_attn_out_non_spec is not None:
584
+ merged_out = torch.empty(
585
+ (1, num_actual_tokens, *core_attn_out_spec.shape[2:]),
586
+ dtype=core_attn_out_non_spec.dtype,
587
+ device=core_attn_out_non_spec.device,
588
+ )
589
+ merged_out.index_copy_(1, spec_token_indx, core_attn_out_spec)
590
+ merged_out.index_copy_(1, non_spec_token_indx, core_attn_out_non_spec)
591
+ core_attn_out[:num_actual_tokens] = merged_out.squeeze(0)
592
+ elif spec_sequence_masks is not None:
593
+ core_attn_out[:num_actual_tokens] = core_attn_out_spec.squeeze(0)
594
+ else:
595
+ core_attn_out[:num_actual_tokens] = core_attn_out_non_spec.squeeze(0)
596
+
597
+
598
+class OlmoHybridAttention(nn.Module):
599
+ def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
600
+ super().__init__()
601
+ self.config = vllm_config.model_config.hf_config
602
+
603
+ hidden_size = self.config.hidden_size
604
+ self.tp_size = get_tensor_model_parallel_world_size()
605
+ self.total_num_heads = self.config.num_attention_heads
606
+
607
+ assert hidden_size % self.total_num_heads == 0
608
+ assert self.total_num_heads % self.tp_size == 0
609
+
610
+ self.num_heads = self.total_num_heads // self.tp_size
611
+ self.total_num_kv_heads = (
612
+ self.config.num_key_value_heads or self.total_num_heads
613
+ )
614
+ if self.total_num_kv_heads >= self.tp_size:
615
+ assert self.total_num_kv_heads % self.tp_size == 0
616
+ else:
617
+ assert self.tp_size % self.total_num_kv_heads == 0
618
+
619
+ self.num_kv_heads = max(1, self.total_num_kv_heads // self.tp_size)
620
+ self.head_dim = hidden_size // self.total_num_heads
621
+ self.q_size = self.num_heads * self.head_dim
622
+ self.kv_size = self.num_kv_heads * self.head_dim
623
+ self.max_position_embeddings = self.config.max_position_embeddings
624
+
625
+ self.qkv_proj = QKVParallelLinear(
626
+ hidden_size,
627
+ self.head_dim,
628
+ self.total_num_heads,
629
+ self.total_num_kv_heads,
630
+ bias=False,
631
+ quant_config=vllm_config.quant_config,
632
+ prefix=f"{prefix}.qkv_proj",
633
+ )
634
+
635
+ self.tp_rank = get_tensor_model_parallel_rank()
636
+
637
+ self.k_norm = RMSNorm(
638
+ self.total_num_kv_heads * self.head_dim,
639
+ eps=self.config.rms_norm_eps,
640
+ )
641
+ self.q_norm = RMSNorm(
642
+ self.config.hidden_size,
643
+ eps=self.config.rms_norm_eps,
644
+ )
645
+
646
+ self.scaling = self.head_dim**-0.5
647
+
648
+ self.attn = Attention(
649
+ self.num_heads,
650
+ self.head_dim,
651
+ self.scaling,
652
+ num_kv_heads=self.num_kv_heads,
653
+ cache_config=vllm_config.cache_config,
654
+ quant_config=vllm_config.quant_config,
655
+ prefix=f"{prefix}.attn",
656
+ )
657
+
658
+ rope_parameters = getattr(self.config, "rope_parameters", None)
659
+ self._use_rope = (rope_parameters is not None) and (
660
+ rope_parameters["rope_theta"] is not None
661
+ )
662
+
663
+ if self._use_rope:
664
+ self.rotary_emb = get_rope(
665
+ self.head_dim,
666
+ max_position=self.max_position_embeddings,
667
+ rope_parameters=rope_parameters,
668
+ )
669
+ else:
670
+ self.rotary_emb = None
671
+
672
+ self.o_proj = RowParallelLinear(
673
+ self.total_num_heads * self.head_dim,
674
+ hidden_size,
675
+ bias=False,
676
+ quant_config=vllm_config.quant_config,
677
+ prefix=f"{prefix}.o_proj",
678
+ )
679
+
680
+ def _apply_qk_norm(
681
+ self, q: torch.Tensor, k: torch.Tensor
682
+ ) -> tuple[torch.Tensor, torch.Tensor]:
683
+ if self.tp_size > 1:
684
+ q = tensor_model_parallel_all_gather(q.contiguous())
685
+ k = tensor_model_parallel_all_gather(k.contiguous())
686
+ q = self.q_norm(q)
687
+ k = self.k_norm(k)
688
+ if self.tp_size > 1:
689
+ splitter = partial(split_tensor_along_last_dim, num_partitions=self.tp_size)
690
+ q = splitter(q)[self.tp_rank]
691
+ k = splitter(k)[self.tp_rank]
692
+ return q, k
693
+
694
+ def forward(
695
+ self,
696
+ positions: torch.Tensor,
697
+ hidden_states: torch.Tensor,
698
+ ) -> torch.Tensor:
699
+ qkv, _ = self.qkv_proj(hidden_states)
700
+ q, k, v = qkv.split([self.q_size, self.kv_size, self.kv_size], dim=-1)
701
+ q, k = self._apply_qk_norm(q, k)
702
+ if self._use_rope:
703
+ q, k = self.rotary_emb(positions, q, k)
704
+ attn_output = self.attn(q, k, v)
705
+ output, _ = self.o_proj(attn_output)
706
+ return output
707
+
708
+
709
+class OlmoHybridMLP(nn.Module):
710
+ def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
711
+ super().__init__()
712
+ config = vllm_config.model_config.hf_config
713
+ hidden_size = config.hidden_size
714
+ intermediate_size = config.intermediate_size
715
+
716
+ self.gate_up_proj = MergedColumnParallelLinear(
717
+ hidden_size,
718
+ [intermediate_size] * 2,
719
+ bias=False,
720
+ quant_config=vllm_config.quant_config,
721
+ prefix=f"{prefix}.gate_up_proj",
722
+ )
723
+
724
+ self.act_fn = SiluAndMul()
725
+
726
+ self.down_proj = RowParallelLinear(
727
+ intermediate_size,
728
+ hidden_size,
729
+ bias=False,
730
+ quant_config=vllm_config.quant_config,
731
+ prefix=f"{prefix}.down_proj",
732
+ )
733
+
734
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
735
+ gate_up, _ = self.gate_up_proj(x)
736
+ x = self.act_fn(gate_up)
737
+ x, _ = self.down_proj(x)
738
+ return x
739
+
740
+
741
+class OlmoHybridDecoderLayer(nn.Module):
742
+ def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
743
+ super().__init__()
744
+ config = vllm_config.model_config.hf_config
745
+ model_config = vllm_config.model_config
746
+ cache_config = vllm_config.cache_config
747
+ quant_config = vllm_config.quant_config
748
+ speculative_config = vllm_config.speculative_config
749
+
750
+ layer_idx = extract_layer_index(prefix)
751
+ self.layer_type = config.layer_types[layer_idx]
752
+ self.layer_idx = layer_idx
753
+
754
+ if self.layer_type == "linear_attention":
755
+ self.linear_attn = OlmoHybridGatedDeltaNet(
756
+ config,
757
+ model_config=model_config,
758
+ cache_config=cache_config,
759
+ quant_config=quant_config,
760
+ speculative_config=speculative_config,
761
+ prefix=f"{prefix}.linear_attn",
762
+ )
763
+ self.input_layernorm = RMSNorm(
764
+ config.hidden_size,
765
+ eps=config.rms_norm_eps,
766
+ )
767
+ self.post_attention_layernorm = RMSNorm(
768
+ config.hidden_size,
769
+ eps=config.rms_norm_eps,
770
+ )
771
+ else:
772
+ self.self_attn = OlmoHybridAttention(
773
+ vllm_config=vllm_config,
774
+ prefix=f"{prefix}.self_attn",
775
+ )
776
+ # Attention layers use these norm names
777
+ self.post_attention_layernorm = RMSNorm(
778
+ config.hidden_size,
779
+ eps=config.rms_norm_eps,
780
+ )
781
+ self.post_feedforward_layernorm = RMSNorm(
782
+ config.hidden_size,
783
+ eps=config.rms_norm_eps,
784
+ )
785
+
786
+ self.mlp = OlmoHybridMLP(
787
+ vllm_config=vllm_config,
788
+ prefix=f"{prefix}.mlp",
789
+ )
790
+
791
+ def forward(
792
+ self,
793
+ positions: torch.Tensor,
794
+ hidden_states: torch.Tensor,
795
+ ) -> torch.Tensor:
796
+ if self.layer_type == "linear_attention":
797
+ residual = hidden_states
798
+ hidden_states = self.input_layernorm(hidden_states)
799
+
800
+ attn_output = torch.empty_like(hidden_states)
801
+ self.linear_attn(
802
+ hidden_states=hidden_states,
803
+ output=attn_output,
804
+ )
805
+ hidden_states = residual + attn_output
806
+
807
+ residual = hidden_states
808
+ hidden_states = self.post_attention_layernorm(hidden_states)
809
+ hidden_states = self.mlp(hidden_states)
810
+ hidden_states = residual + hidden_states
811
+ else:
812
+ residual = hidden_states
813
+ hidden_states = self.self_attn(positions, hidden_states)
814
+ hidden_states = self.post_attention_layernorm(hidden_states)
815
+ hidden_states = residual + hidden_states
816
+
817
+ residual = hidden_states
818
+ hidden_states = self.mlp(hidden_states)
819
+ hidden_states = self.post_feedforward_layernorm(hidden_states)
820
+ hidden_states = residual + hidden_states
821
+ return hidden_states
822
+
823
+
824
+@support_torch_compile
825
+class OlmoHybridModel(nn.Module):
826
+ def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
827
+ super().__init__()
828
+ self.config = vllm_config.model_config.hf_config
829
+
830
+ self.embed_tokens = VocabParallelEmbedding(
831
+ self.config.vocab_size,
832
+ self.config.hidden_size,
833
+ prefix=f"{prefix}.embed_tokens",
834
+ )
835
+
836
+ self.start_layer, self.end_layer, self.layers = make_layers(
837
+ self.config.num_hidden_layers,
838
+ lambda prefix: OlmoHybridDecoderLayer(
839
+ vllm_config=vllm_config, prefix=prefix
840
+ ),
841
+ prefix=f"{prefix}.layers",
842
+ )
843
+
844
+ self.norm = RMSNorm(
845
+ self.config.hidden_size,
846
+ eps=self.config.rms_norm_eps,
847
+ )
848
+
849
+ self.make_empty_intermediate_tensors = make_empty_intermediate_tensors_factory(
850
+ ["hidden_states"], self.config.hidden_size
851
+ )
852
+
853
+ def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
854
+ return self.embed_tokens(input_ids)
855
+
856
+ def forward(
857
+ self,
858
+ input_ids: torch.Tensor,
859
+ positions: torch.Tensor,
860
+ intermediate_tensors: IntermediateTensors | None,
861
+ inputs_embeds: torch.Tensor | None = None,
862
+ ) -> torch.Tensor | IntermediateTensors:
863
+ if get_pp_group().is_first_rank:
864
+ if inputs_embeds is not None:
865
+ hidden_states = inputs_embeds
866
+ else:
867
+ hidden_states = self.embed_tokens(input_ids)
868
+ else:
869
+ assert intermediate_tensors is not None
870
+ hidden_states = intermediate_tensors["hidden_states"]
871
+ assert isinstance(hidden_states, torch.Tensor)
872
+
873
+ for layer in islice(self.layers, self.start_layer, self.end_layer):
874
+ hidden_states = layer(positions, hidden_states)
875
+
876
+ if not get_pp_group().is_last_rank:
877
+ return IntermediateTensors({"hidden_states": hidden_states})
878
+
879
+ hidden_states = self.norm(hidden_states)
880
+ return hidden_states
881
+
882
+ def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
883
+ stacked_params_mapping = [
884
+ ("qkv_proj", "q_proj", "q"),
885
+ ("qkv_proj", "k_proj", "k"),
886
+ ("qkv_proj", "v_proj", "v"),
887
+ ("gate_up_proj", "gate_proj", 0),
888
+ ("gate_up_proj", "up_proj", 1),
889
+ ]
890
+
891
+ linear_attn_stacked_params_mapping = [
892
+ ("in_proj_qkvg", "q_proj", 0),
893
+ ("in_proj_qkvg", "k_proj", 1),
894
+ ("in_proj_qkvg", "v_proj", 2),
895
+ ("in_proj_qkvg", "g_proj", 3),
896
+ ("conv1d", "q_conv1d", 0),
897
+ ("conv1d", "k_conv1d", 1),
898
+ ("conv1d", "v_conv1d", 2),
899
+ ]
900
+
901
+ params_dict = dict(self.named_parameters(remove_duplicate=False))
902
+ loaded_params: set[str] = set()
903
+
904
+ for name, loaded_weight in weights:
905
+ if is_pp_missing_parameter(name, self):
906
+ continue
907
+
908
+ handled = False
909
+
910
+ if "linear_attn" in name:
911
+ for (
912
+ param_name,
913
+ weight_name,
914
+ shard_id,
915
+ ) in linear_attn_stacked_params_mapping:
916
+ if weight_name not in name:
917
+ continue
918
+ mapped_name = name.replace(weight_name, param_name)
919
+ if mapped_name.endswith(".bias") and (
920
+ mapped_name not in params_dict
921
+ ):
922
+ continue
923
+ if mapped_name not in params_dict:
924
+ continue
925
+ param = params_dict[mapped_name]
926
+ weight_loader = param.weight_loader
927
+ weight_loader(param, loaded_weight, shard_id)
928
+ name = mapped_name
929
+ handled = True
930
+ break
931
+ else:
932
+ for param_name, weight_name, shard_id in stacked_params_mapping:
933
+ if weight_name not in name:
934
+ continue
935
+ name = name.replace(weight_name, param_name)
936
+ if name.endswith(".bias") and name not in params_dict:
937
+ continue
938
+ if name not in params_dict:
939
+ continue
940
+ param = params_dict[name]
941
+ weight_loader = param.weight_loader
942
+ weight_loader(param, loaded_weight, shard_id)
943
+ handled = True
944
+ break
945
+
946
+ if not handled:
947
+ if name.endswith(".bias") and name not in params_dict:
948
+ continue
949
+ if name not in params_dict:
950
+ continue
951
+ param = params_dict[name]
952
+ weight_loader = getattr(param, "weight_loader", default_weight_loader)
953
+ weight_loader(param, loaded_weight)
954
+ loaded_params.add(name)
955
+ return loaded_params
956
+
957
+
958
+class OlmoHybridForCausalLM(
959
+ nn.Module, HasInnerState, SupportsPP, SupportsLoRA, IsHybrid
960
+):
961
+ packed_modules_mapping = {
962
+ "qkv_proj": ["q_proj", "k_proj", "v_proj"],
963
+ "gate_up_proj": ["gate_proj", "up_proj"],
964
+ "in_proj_qkvg": ["q_proj", "k_proj", "v_proj", "g_proj"],
965
+ }
966
+
967
+ def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
968
+ super().__init__()
969
+ config = vllm_config.model_config.hf_config
970
+ self.config = config
971
+ self.vllm_config = vllm_config
972
+ self.model_config = vllm_config.model_config
973
+
974
+ self.model = OlmoHybridModel(
975
+ vllm_config=vllm_config, prefix=maybe_prefix(prefix, "model")
976
+ )
977
+
978
+ if config.tie_word_embeddings:
979
+ self.lm_head = self.model.embed_tokens
980
+ else:
981
+ self.lm_head = ParallelLMHead(
982
+ config.vocab_size,
983
+ config.hidden_size,
984
+ quant_config=vllm_config.quant_config,
985
+ prefix=maybe_prefix(prefix, "lm_head"),
986
+ )
987
+
988
+ self.logits_processor = LogitsProcessor(config.vocab_size)
989
+ self.make_empty_intermediate_tensors = (
990
+ self.model.make_empty_intermediate_tensors
991
+ )
992
+
993
+ def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
994
+ return self.model.embed_input_ids(input_ids)
995
+
996
+ def forward(
997
+ self,
998
+ input_ids: torch.Tensor,
999
+ positions: torch.Tensor,
1000
+ intermediate_tensors: IntermediateTensors | None = None,
1001
+ inputs_embeds: torch.Tensor | None = None,
1002
+ ) -> torch.Tensor | IntermediateTensors:
1003
+ hidden_states = self.model(
1004
+ input_ids=input_ids,
1005
+ positions=positions,
1006
+ intermediate_tensors=intermediate_tensors,
1007
+ inputs_embeds=inputs_embeds,
1008
+ )
1009
+ return hidden_states
1010
+
1011
+ def compute_logits(
1012
+ self,
1013
+ hidden_states: torch.Tensor,
1014
+ ) -> torch.Tensor | None:
1015
+ logits = self.logits_processor(self.lm_head, hidden_states)
1016
+ return logits
1017
+
1018
+ @classmethod
1019
+ def get_mamba_state_dtype_from_config(
1020
+ cls,
1021
+ vllm_config: "VllmConfig",
1022
+ ) -> tuple[torch.dtype, torch.dtype]:
1023
+ return MambaStateDtypeCalculator.gated_delta_net_state_dtype(
1024
+ vllm_config.model_config.dtype,
1025
+ vllm_config.cache_config.mamba_cache_dtype,
1026
+ vllm_config.cache_config.mamba_ssm_cache_dtype,
1027
+ )
1028
+
1029
+ @classmethod
1030
+ def get_mamba_state_shape_from_config(
1031
+ cls, vllm_config: "VllmConfig"
1032
+ ) -> tuple[tuple[int, int], tuple[int, int]]:
1033
+ parallel_config = vllm_config.parallel_config
1034
+ hf_config = vllm_config.model_config.hf_config
1035
+ tp_size = parallel_config.tensor_parallel_size
1036
+ num_spec = (
1037
+ vllm_config.speculative_config.num_speculative_tokens
1038
+ if vllm_config.speculative_config
1039
+ else 0
1040
+ )
1041
+ return MambaStateShapeCalculator.gated_delta_net_state_shape(
1042
+ tp_size,
1043
+ hf_config.linear_num_key_heads,
1044
+ hf_config.linear_num_value_heads,
1045
+ hf_config.linear_key_head_dim,
1046
+ hf_config.linear_value_head_dim,
1047
+ hf_config.linear_conv_kernel_dim,
1048
+ num_spec,
1049
+ )
1050
+
1051
+ @classmethod
1052
+ def get_mamba_state_copy_func(cls) -> tuple[MambaStateCopyFunc, MambaStateCopyFunc]:
1053
+ return MambaStateCopyFuncCalculator.gated_delta_net_state_copy_func()
1054
+
1055
+ def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
1056
+ loader = AutoWeightsLoader(
1057
+ self,
1058
+ skip_prefixes=(
1059
+ ["lm_head.weight"] if self.config.tie_word_embeddings else None
1060
+ ),
1061
+ )
1062
+ return loader.load_weights(weights)
1063
+
1064
+
1065
+def olmo_hybrid_gdn_full_forward(
1066
+ hidden_states: torch.Tensor,
1067
+ output: torch.Tensor,
1068
+ layer_name: str,
1069
+) -> None:
1070
+ """Full linear attention forward wrapped as a custom op.
1071
+
1072
+ Prevents inductor from compiling the projections around the GDN core,
1073
+ which would introduce numerical divergence that compounds through
1074
+ the recurrent state.
1075
+ """
1076
+ forward_context: ForwardContext = get_forward_context()
1077
+ self = forward_context.no_compile_layers[layer_name]
1078
+ self._full_forward(
1079
+ hidden_states=hidden_states,
1080
+ output=output,
1081
+ )
1082
+
1083
+
1084
+def olmo_hybrid_gdn_full_forward_fake(
1085
+ hidden_states: torch.Tensor,
1086
+ output: torch.Tensor,
1087
+ layer_name: str,
1088
+) -> None:
1089
+ """Fake implementation for torch.compile."""
1090
+ return
1091
+
1092
+
1093
+direct_register_custom_op(
1094
+ op_name="olmo_hybrid_gdn_full_forward",
1095
+ op_func=olmo_hybrid_gdn_full_forward,
1096
+ mutates_args=["output"],
1097
+ fake_impl=olmo_hybrid_gdn_full_forward_fake,
1098
+)
1099
+
1100
+
1101
+@triton.jit
1102
+def fused_olmo_hybrid_gdn_gating_kernel(
1103
+ g,
1104
+ beta_output,
1105
+ A_log,
1106
+ a,
1107
+ b,
1108
+ dt_bias,
1109
+ seq_len,
1110
+ allow_neg_eigval: tl.constexpr,
1111
+ NUM_HEADS: tl.constexpr,
1112
+ beta: tl.constexpr,
1113
+ threshold: tl.constexpr,
1114
+ BLK_HEADS: tl.constexpr,
1115
+):
1116
+ i_b, i_s, i_d = tl.program_id(0), tl.program_id(1), tl.program_id(2)
1117
+ head_off = i_d * BLK_HEADS + tl.arange(0, BLK_HEADS)
1118
+ off = i_b * seq_len * NUM_HEADS + i_s * NUM_HEADS + head_off
1119
+ mask = head_off < NUM_HEADS
1120
+ blk_A_log = tl.load(A_log + head_off, mask=mask)
1121
+ blk_a = tl.load(a + off, mask=mask)
1122
+ blk_b = tl.load(b + off, mask=mask)
1123
+ blk_bias = tl.load(dt_bias + head_off, mask=mask)
1124
+
1125
+ # g = -self.A_log.float().exp() * F.softplus(a.float() + self.dt_bias)
1126
+ x = blk_a.to(tl.float32) + blk_bias.to(tl.float32)
1127
+ softplus_x = tl.where(
1128
+ beta * x <= threshold, (1 / beta) * tl.log(1 + tl.exp(beta * x)), x
1129
+ )
1130
+ blk_g = -tl.exp(blk_A_log.to(tl.float32)) * softplus_x
1131
+ tl.store(g + off, blk_g.to(g.dtype.element_ty), mask=mask)
1132
+
1133
+ # beta = self.b_proj(hidden_states).sigmoid()
1134
+ # if self.allow_neg_eigval: beta = beta * 2.0
1135
+ blk_beta_output = tl.sigmoid(blk_b.to(tl.float32))
1136
+ if allow_neg_eigval:
1137
+ blk_beta_output = blk_beta_output * 2.0
1138
+ tl.store(
1139
+ beta_output + off, blk_beta_output.to(beta_output.dtype.element_ty), mask=mask
1140
+ )
1141
+
1142
+
1143
+def fused_olmo_hybrid_gdn_gating(
1144
+ A_log: torch.Tensor,
1145
+ a: torch.Tensor,
1146
+ b: torch.Tensor,
1147
+ dt_bias: torch.Tensor,
1148
+ allow_neg_eigval: bool = False,
1149
+ beta: float = 1.0,
1150
+ threshold: float = 20.0,
1151
+) -> tuple[torch.Tensor, torch.Tensor]:
1152
+ batch, num_heads = a.shape
1153
+ seq_len = 1
1154
+ grid = (batch, seq_len, triton.cdiv(num_heads, 8))
1155
+ g = torch.empty(1, batch, num_heads, dtype=torch.float32, device=a.device)
1156
+ beta_output = torch.empty(1, batch, num_heads, dtype=torch.float32, device=b.device)
1157
+ fused_olmo_hybrid_gdn_gating_kernel[grid](
1158
+ g,
1159
+ beta_output,
1160
+ A_log,
1161
+ a,
1162
+ b,
1163
+ dt_bias,
1164
+ seq_len,
1165
+ allow_neg_eigval,
1166
+ num_heads,
1167
+ beta,
1168
+ threshold,
1169
+ 8,
1170
+ num_warps=1,
1171
+ )
1172
+ return g, beta_output
vllm/model_executor/models/registry.py
+1
@@ -171,6 +171,7 @@ _TEXT_GENERATION_MODELS = {
171
"OlmoForCausalLM": ("olmo", "OlmoForCausalLM"),
172
"Olmo2ForCausalLM": ("olmo2", "Olmo2ForCausalLM"),
173
"Olmo3ForCausalLM": ("olmo2", "Olmo2ForCausalLM"),
174
+ "OlmoHybridForCausalLM": ("olmo_hybrid", "OlmoHybridForCausalLM"),
175
"OlmoeForCausalLM": ("olmoe", "OlmoeForCausalLM"),
176
"OPTForCausalLM": ("opt", "OPTForCausalLM"),
177
"OrionForCausalLM": ("orion", "OrionForCausalLM"),
vllm/transformers_utils/config.py
+1
@@ -97,6 +97,7 @@ _CONFIG_REGISTRY: dict[str, type[PretrainedConfig]] = LazyConfigDict(
97
speculators="SpeculatorsConfig",
98
nemotron="NemotronConfig",
99
olmo3="Olmo3Config",
100
+ olmo_hybrid="OlmoHybridConfig",
101
ovis="OvisConfig",
102
ultravox="UltravoxConfig",
103
step3_vl="Step3VLConfig",
vllm/transformers_utils/configs/__init__.py
+2
@@ -49,6 +49,7 @@ _CLASS_TO_MODULE: dict[str, str] = {
49
"NemotronConfig": "vllm.transformers_utils.configs.nemotron",
50
"NemotronHConfig": "vllm.transformers_utils.configs.nemotron_h",
51
"Olmo3Config": "vllm.transformers_utils.configs.olmo3",
52
+ "OlmoHybridConfig": "vllm.transformers_utils.configs.olmo_hybrid",
53
"OvisConfig": "vllm.transformers_utils.configs.ovis",
54
"PixelShuffleSiglip2VisionConfig": "vllm.transformers_utils.configs.isaac",
55
"RadioConfig": "vllm.transformers_utils.configs.radio",
@@ -102,6 +103,7 @@ __all__ = [
103
"NemotronConfig",
104
"NemotronHConfig",
105
"Olmo3Config",
106
+ "OlmoHybridConfig",
107
"OvisConfig",
108
"PixelShuffleSiglip2VisionConfig",
109
"RadioConfig",
vllm/transformers_utils/configs/olmo_hybrid.py
new
+284
@@ -0,0 +1,284 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+
5
+from transformers.configuration_utils import PretrainedConfig, layer_type_validation
6
+
7
+
8
+class OlmoHybridConfig(PretrainedConfig):
9
+ r"""
10
+ Configuration class for [`OlmoHybridModel`]. It is used to
11
+ instantiate an OLMo Hybrid model according to the specified
12
+ arguments, defining the model architecture. Instantiating a
13
+ configuration with the defaults will yield a similar
14
+ configuration to that of the
15
+ [allenai/Olmo-Hybrid-7B](https://huggingface.co/allenai/Olmo-Hybrid-7B)
16
+ model.
17
+
18
+ Configuration objects inherit from [`PreTrainedConfig`] and
19
+ can be used to control the model outputs. Read the
20
+ documentation from [`PreTrainedConfig`] for more information.
21
+
22
+ Args:
23
+ vocab_size (`int`, *optional*, defaults to 100352):
24
+ Vocabulary size of the OlmoHybrid model. Defines
25
+ the number of different tokens that can be
26
+ represented by the `inputs_ids` passed when
27
+ calling [`OlmoHybridModel`].
28
+ hidden_size (`int`, *optional*, defaults to 3840):
29
+ Dimension of the hidden representations.
30
+ intermediate_size (`int`, *optional*,
31
+ defaults to 11008):
32
+ Dimension of the MLP representations.
33
+ num_hidden_layers (`int`, *optional*,
34
+ defaults to 32):
35
+ Number of hidden layers in the Transformer
36
+ decoder.
37
+ num_attention_heads (`int`, *optional*,
38
+ defaults to 30):
39
+ Number of attention heads for each attention
40
+ layer in the Transformer decoder.
41
+ num_key_value_heads (`int`, *optional*):
42
+ This is the number of key_value heads that
43
+ should be used to implement Grouped Query
44
+ Attention. If
45
+ `num_key_value_heads=num_attention_heads`,
46
+ the model will use Multi Head Attention (MHA),
47
+ if `num_key_value_heads=1` the model will use
48
+ Multi Query Attention (MQA) otherwise GQA is
49
+ used. When converting a multi-head checkpoint
50
+ to a GQA checkpoint, each group key and value
51
+ head should be constructed by meanpooling all
52
+ the original heads within that group. For more
53
+ details, check out
54
+ [this paper](https://huggingface.co/papers/2305.13245).
55
+ If it is not specified, will default to
56
+ `num_attention_heads`.
57
+ hidden_act (`str` or `function`, *optional*,
58
+ defaults to `"silu"`):
59
+ The non-linear activation function (function
60
+ or string) in the decoder.
61
+ max_position_embeddings (`int`, *optional*,
62
+ defaults to 65536):
63
+ The maximum sequence length that this model
64
+ might ever be used with.
65
+ initializer_range (`float`, *optional*,
66
+ defaults to 0.02):
67
+ The standard deviation of the
68
+ truncated_normal_initializer for initializing
69
+ all weight matrices.
70
+ use_cache (`bool`, *optional*, defaults to `True`):
71
+ Whether or not the model should return the last
72
+ key/values attentions (not used by all models).
73
+ Only relevant if `config.is_decoder=True`.
74
+ pad_token_id (`int`, *optional*,
75
+ defaults to 100277):
76
+ Padding token id.
77
+ bos_token_id (`int`, *optional*):
78
+ Beginning of stream token id.
79
+ eos_token_id (`int`, *optional*,
80
+ defaults to 100257):
81
+ End of stream token id.
82
+ tie_word_embeddings (`bool`, *optional*,
83
+ defaults to `False`):
84
+ Whether to tie weight embeddings.
85
+ rope_parameters (`RopeParameters`, *optional*):
86
+ Dictionary containing the configuration
87
+ parameters for the RoPE embeddings. Can be
88
+ `None` to disable RoPE.
89
+ attention_bias (`bool`, *optional*,
90
+ defaults to `False`):
91
+ Whether to use a bias in the query, key, value
92
+ and output projection layers during
93
+ self-attention.
94
+ attention_dropout (`float`, *optional*,
95
+ defaults to 0.0):
96
+ The dropout ratio for the attention
97
+ probabilities.
98
+ rms_norm_eps (`float`, *optional*,
99
+ defaults to 1e-06):
100
+ The epsilon used by the rms normalization
101
+ layers.
102
+ layer_types (`list`, *optional*):
103
+ Attention pattern for each layer. Can contain
104
+ `"full_attention"` or `"linear_attention"`.
105
+ Defaults to linear attention for most layers
106
+ with full attention for every 4th layer.
107
+ linear_num_key_heads (`int`, *optional*):
108
+ Number of key heads for the linear attention
109
+ layers. Defaults to `num_attention_heads`.
110
+ linear_num_value_heads (`int`, *optional*):
111
+ Number of value heads for the linear attention
112
+ layers. Defaults to `num_attention_heads`.
113
+ linear_key_head_dim (`int`, *optional*):
114
+ Dimension of each key head in linear attention
115
+ layers. Defaults to
116
+ `0.75 * hidden_size / linear_num_key_heads`.
117
+ linear_value_head_dim (`int`, *optional*):
118
+ Dimension of each value head in linear
119
+ attention layers. Defaults to
120
+ `2 * linear_key_head_dim`.
121
+ linear_a_log_min (`float`, *optional*,
122
+ defaults to 0.0):
123
+ Minimum value for uniform initialization of
124
+ A_log in GatedDeltaNet layers.
125
+ linear_a_log_max (`float`, *optional*,
126
+ defaults to 16.0):
127
+ Maximum value for uniform initialization of
128
+ A_log in GatedDeltaNet layers.
129
+ linear_dt_min (`float`, *optional*,
130
+ defaults to 0.001):
131
+ Minimum value for dt initialization in
132
+ GatedDeltaNet layers.
133
+ linear_dt_max (`float`, *optional*,
134
+ defaults to 0.1):
135
+ Maximum value for dt initialization in
136
+ GatedDeltaNet layers.
137
+ linear_dt_init_floor (`float`, *optional*,
138
+ defaults to 0.0001):
139
+ Floor value for clamping dt during
140
+ initialization in GatedDeltaNet layers.
141
+ linear_conv_kernel_dim (`int`, *optional*,
142
+ defaults to 4):
143
+ Kernel size for the short convolution applied
144
+ to queries, keys, and values in linear
145
+ attention layers.
146
+ linear_allow_neg_eigval (`bool`, *optional*,
147
+ defaults to `True`):
148
+ Whether to allow negative eigenvalues in the
149
+ GatedDeltaNet recurrence. When `True`, the
150
+ beta parameter is scaled by 2.0 to allow
151
+ values in range [0, 2] instead of [0, 1].
152
+ ```python
153
+ >>> from transformers import (
154
+ ... OlmoHybridModel,
155
+ ... OlmoHybridConfig,
156
+ ... )
157
+
158
+ >>> configuration = OlmoHybridConfig()
159
+ >>> model = OlmoHybridModel(configuration)
160
+ >>> configuration = model.config
161
+ ```
162
+ """
163
+
164
+ model_type = "olmo_hybrid"
165
+ keys_to_ignore_at_inference = ["past_key_values"]
166
+ base_model_tp_plan = {
167
+ "layers.*.self_attn.q_proj": "colwise_gather_output",
168
+ "layers.*.self_attn.k_proj": "colwise_gather_output",
169
+ "layers.*.self_attn.v_proj": "colwise_gather_output",
170
+ "layers.*.self_attn.o_proj": "rowwise_split_input",
171
+ "layers.*.mlp.gate_proj": "colwise",
172
+ "layers.*.mlp.up_proj": "colwise",
173
+ "layers.*.mlp.down_proj": "rowwise",
174
+ }
175
+ base_model_pp_plan = {
176
+ "embed_tokens": (["input_ids"], ["inputs_embeds"]),
177
+ "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
178
+ "norm": (["hidden_states"], ["hidden_states"]),
179
+ }
180
+
181
+ def __init__(
182
+ self,
183
+ vocab_size: int | None = 100352,
184
+ hidden_size: int | None = 3840,
185
+ intermediate_size: int | None = 11008,
186
+ num_hidden_layers: int | None = 32,
187
+ num_attention_heads: int | None = 30,
188
+ num_key_value_heads: int | None = None,
189
+ hidden_act: str | None = "silu",
190
+ max_position_embeddings: int | None = 65536,
191
+ initializer_range: float | None = 0.02,
192
+ use_cache: bool | None = True,
193
+ pad_token_id: int | None = 100277,
194
+ bos_token_id: int | None = None,
195
+ eos_token_id: int | None = 100257,
196
+ tie_word_embeddings: bool | None = False,
197
+ rope_parameters=None,
198
+ attention_bias: bool | None = False,
199
+ attention_dropout: float | None = 0.0,
200
+ rms_norm_eps: float | None = 1e-06,
201
+ layer_types: list[str] | None = None,
202
+ linear_num_key_heads: int | None = None,
203
+ linear_num_value_heads: int | None = None,
204
+ linear_key_head_dim: int | None = None,
205
+ linear_value_head_dim: int | None = None,
206
+ linear_a_log_min: float = 0.0,
207
+ linear_a_log_max: float = 16.0,
208
+ linear_dt_min: float = 0.001,
209
+ linear_dt_max: float = 0.1,
210
+ linear_dt_init_floor: float = 1e-4,
211
+ linear_conv_kernel_dim: int = 4,
212
+ linear_allow_neg_eigval: bool = True,
213
+ **kwargs,
214
+ ):
215
+ super().__init__(**kwargs)
216
+
217
+ assert num_hidden_layers is not None
218
+ assert hidden_size is not None
219
+ assert num_attention_heads is not None
220
+
221
+ if layer_types is None:
222
+ # Default: linear attention for most layers, full attention every 4th layer
223
+ layer_types = ["linear_attention"] * int(num_hidden_layers)
224
+ for i in range(int(num_hidden_layers)):
225
+ if i % 4 == 3:
226
+ layer_types[i] = "full_attention"
227
+ # Ensure at least one full attention layer for small num_hidden_layers
228
+ if "full_attention" not in layer_types:
229
+ layer_types[-1] = "full_attention"
230
+
231
+ layer_type_validation(layer_types, num_hidden_layers)
232
+ if "linear_attention" not in layer_types:
233
+ raise ValueError(
234
+ "OLMoHybrid expects at least one 'linear_attention' layer."
235
+ )
236
+ if all(t == "linear_attention" for t in layer_types):
237
+ raise ValueError("OLMoHybrid expects at least one attention layer.")
238
+
239
+ self.layer_types = layer_types
240
+
241
+ if linear_num_key_heads is None:
242
+ linear_num_key_heads = num_attention_heads
243
+ if linear_num_value_heads is None:
244
+ linear_num_value_heads = num_attention_heads
245
+ if linear_key_head_dim is None:
246
+ linear_key_head_dim = int(0.75 * hidden_size / linear_num_key_heads)
247
+ if linear_value_head_dim is None:
248
+ linear_value_head_dim = 2 * linear_key_head_dim
249
+
250
+ self.linear_num_key_heads = linear_num_key_heads
251
+ self.linear_num_value_heads = linear_num_value_heads
252
+ self.linear_key_head_dim = linear_key_head_dim
253
+ self.linear_value_head_dim = linear_value_head_dim
254
+ self.linear_a_log_min = linear_a_log_min
255
+ self.linear_a_log_max = linear_a_log_max
256
+ self.linear_dt_min = linear_dt_min
257
+ self.linear_dt_max = linear_dt_max
258
+ self.linear_dt_init_floor = linear_dt_init_floor
259
+ self.linear_conv_kernel_dim = linear_conv_kernel_dim
260
+ self.linear_allow_neg_eigval = linear_allow_neg_eigval
261
+ self.vocab_size = vocab_size
262
+ self.max_position_embeddings = max_position_embeddings
263
+ self.hidden_size = hidden_size
264
+ self.intermediate_size = intermediate_size
265
+ self.num_hidden_layers = num_hidden_layers
266
+ self.num_attention_heads = num_attention_heads
267
+
268
+ # for backward compatibility
269
+ if num_key_value_heads is None:
270
+ num_key_value_heads = num_attention_heads
271
+
272
+ self.num_key_value_heads = num_key_value_heads
273
+ self.hidden_act = hidden_act
274
+ self.initializer_range = initializer_range
275
+ self.rms_norm_eps = rms_norm_eps
276
+ self.use_cache = use_cache
277
+ self.attention_bias = attention_bias
278
+ self.attention_dropout = attention_dropout
279
+ self.rope_parameters = rope_parameters
280
+
281
+ self.tie_word_embeddings = tie_word_embeddings
282
+ self.pad_token_id = pad_token_id
283
+ self.bos_token_id = bos_token_id
284
+ self.eos_token_id = eos_token_id