leejunhyeok commited on
Commit
33ac2f6
·
verified ·
1 Parent(s): 4811a84

Upload 2 files

Browse files
Files changed (2) hide show
  1. configuration_motif.py +300 -0
  2. modeling_motif.py +1690 -0
configuration_motif.py ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from transformers.configuration_utils import PretrainedConfig
3
+ from transformers.utils import logging
4
+
5
+ logger = logging.get_logger(__name__)
6
+
7
+
8
+ class MotifConfig(PretrainedConfig):
9
+ r"""
10
+ This is the configuration class to store the configuration of a [`MotifModel`]. It is used to instantiate a
11
+ Motif model according to the specified arguments, defining the model architecture.
12
+ Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
13
+ documentation from [`PretrainedConfig`] for more information.
14
+ Args:
15
+ vocab_size (`int`, *optional*, defaults to 151936):
16
+ Vocabulary size of the Motif model. Defines the number of different tokens that can be represented by the
17
+ `inputs_ids` passed when calling [`MotifModel`]
18
+ hidden_size (`int`, *optional*, defaults to 4096):
19
+ Dimension of the hidden representations.
20
+ intermediate_size (`int`, *optional*, defaults to 22016):
21
+ Dimension of the MLP representations.
22
+ num_hidden_layers (`int`, *optional*, defaults to 32):
23
+ Number of hidden layers in the Transformer encoder.
24
+ num_attention_heads (`int`, *optional*, defaults to 32):
25
+ Number of attention heads for each attention layer in the Transformer encoder.
26
+ num_key_value_heads (`int`, *optional*, defaults to 32):
27
+ This is the number of key_value heads that should be used to implement Grouped Query Attention. If
28
+ `num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
29
+ `num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
30
+ converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
31
+ by meanpooling all the original heads within that group. For more details checkout [this
32
+ paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to `32`.
33
+ hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
34
+ The non-linear activation function (function or string) in the decoder.
35
+ max_position_embeddings (`int`, *optional*, defaults to 32768):
36
+ The maximum sequence length that this model might ever be used with.
37
+ initializer_range (`float`, *optional*, defaults to 0.02):
38
+ The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
39
+ rms_norm_eps (`float`, *optional*, defaults to 1e-06):
40
+ The epsilon used by the rms normalization layers.
41
+ use_cache (`bool`, *optional*, defaults to `True`):
42
+ Whether or not the model should return the last key/values attentions (not used by all models). Only
43
+ relevant if `config.is_decoder=True`.
44
+ tie_word_embeddings (`bool`, *optional*, defaults to `False`):
45
+ Whether the model's input and output word embeddings should be tied.
46
+ rope_theta (`float`, *optional*, defaults to 1000000.0):
47
+ The base period of the RoPE embeddings.
48
+ rope_scaling (`Dict`, *optional*):
49
+ Dictionary containing the scaling configuration for the RoPE embeddings. NOTE: if you apply new rope type
50
+ and you expect the model to work on longer `max_position_embeddings`, we recommend you to update this value
51
+ accordingly.
52
+ Expected contents:
53
+ `rope_type` (`str`):
54
+ The sub-variant of RoPE to use. Can be one of ['default', 'linear', 'dynamic', 'yarn', 'longrope',
55
+ 'llama3'], with 'default' being the original RoPE implementation.
56
+ `factor` (`float`, *optional*):
57
+ Used with all rope types except 'default'. The scaling factor to apply to the RoPE embeddings. In
58
+ most scaling types, a `factor` of x will enable the model to handle sequences of length x *
59
+ original maximum pre-trained length.
60
+ `original_max_position_embeddings` (`int`, *optional*):
61
+ Used with 'dynamic', 'longrope' and 'llama3'. The original max position embeddings used during
62
+ pretraining.
63
+ `attention_factor` (`float`, *optional*):
64
+ Used with 'yarn' and 'longrope'. The scaling factor to be applied on the attention
65
+ computation. If unspecified, it defaults to value recommended by the implementation, using the
66
+ `factor` field to infer the suggested value.
67
+ `beta_fast` (`float`, *optional*):
68
+ Only used with 'yarn'. Parameter to set the boundary for extrapolation (only) in the linear
69
+ ramp function. If unspecified, it defaults to 32.
70
+ `beta_slow` (`float`, *optional*):
71
+ Only used with 'yarn'. Parameter to set the boundary for interpolation (only) in the linear
72
+ ramp function. If unspecified, it defaults to 1.
73
+ `short_factor` (`List[float]`, *optional*):
74
+ Only used with 'longrope'. The scaling factor to be applied to short contexts (<
75
+ `original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
76
+ size divided by the number of attention heads divided by 2
77
+ `long_factor` (`List[float]`, *optional*):
78
+ Only used with 'longrope'. The scaling factor to be applied to long contexts (<
79
+ `original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
80
+ size divided by the number of attention heads divided by 2
81
+ `low_freq_factor` (`float`, *optional*):
82
+ Only used with 'llama3'. Scaling factor applied to low frequency components of the RoPE
83
+ `high_freq_factor` (`float`, *optional*):
84
+ Only used with 'llama3'. Scaling factor applied to high frequency components of the RoPE
85
+ use_sliding_window (`bool`, *optional*, defaults to `False`):
86
+ Whether to use sliding window attention.
87
+ sliding_window (`int`, *optional*, defaults to 4096):
88
+ Sliding window attention (SWA) window size. If not specified, will default to `4096`.
89
+ max_window_layers (`int`, *optional*, defaults to 28):
90
+ The number of layers that use SWA (Sliding Window Attention). The bottom layers use SWA while the top use full attention.
91
+ attention_dropout (`float`, *optional*, defaults to 0.0):
92
+ The dropout ratio for the attention probabilities.
93
+ ```python
94
+ >>> from transformers import MotifModel, MotifConfig
95
+ >>> # Initializing a Motif style configuration
96
+ >>> configuration = MotifConfig()
97
+ >>> # Initializing a model from the Motif-102B style configuration
98
+ >>> model = MotifModel(configuration)
99
+ >>> # Accessing the model configuration
100
+ >>> configuration = model.config
101
+ ```"""
102
+
103
+ model_type = "Motif"
104
+ keys_to_ignore_at_inference = ["past_key_values"]
105
+
106
+ base_model_tp_plan = {
107
+ # Attention
108
+ "layers.*.self_attn.q_proj": "colwise",
109
+ "layers.*.self_attn.k_proj": "colwise",
110
+ "layers.*.self_attn.v_proj": "colwise",
111
+ "layers.*.self_attn.o_proj": "rowwise",
112
+ # Dense MLP
113
+ "layers.*.mlp.gate_proj": "colwise",
114
+ "layers.*.mlp.up_proj": "colwise",
115
+ "layers.*.mlp.down_proj": "rowwise",
116
+ # MoE experts (fused gate+up)
117
+ "layers.*.moe.experts.gate_up_proj": "packed_colwise",
118
+ "layers.*.moe.experts.down_proj": "rowwise",
119
+ # Shared experts
120
+ "layers.*.moe.shared_experts.gate_proj": "colwise",
121
+ "layers.*.moe.shared_experts.up_proj": "colwise",
122
+ "layers.*.moe.shared_experts.down_proj": "rowwise",
123
+ }
124
+
125
+ base_model_pp_plan = {
126
+ "embed_tokens": (["input_ids"], ["inputs_embeds"]),
127
+ "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
128
+ "norm": (["hidden_states"], ["hidden_states"]),
129
+ }
130
+
131
+ def __init__(
132
+ self,
133
+ vocab_size=151936,
134
+ hidden_size=4096,
135
+ intermediate_size=22016,
136
+ num_hidden_layers=32,
137
+ num_attention_heads=32,
138
+ num_key_value_heads=32,
139
+ hidden_act="silu",
140
+ max_position_embeddings=32768,
141
+ initializer_range=0.02,
142
+ rms_norm_eps=1e-6,
143
+ use_cache=True,
144
+ tie_word_embeddings=False,
145
+ rope_theta=1000000.0,
146
+ rope_scaling=None,
147
+ use_sliding_window=False,
148
+ sliding_window=4096,
149
+ max_window_layers=28,
150
+ sliding_window_pattern="interleave",
151
+ sliding_window_period=2,
152
+ attention_dropout=0.0,
153
+ # Differential Attention parameters
154
+ head_dim=None,
155
+ num_noise_heads=0,
156
+ k_ratio=1,
157
+ # MoE parameters
158
+ num_experts=0,
159
+ experts_top_k=2,
160
+ num_shared_experts=0,
161
+ interleave_moe_layer_step=0,
162
+ moe_intermediate_size=None,
163
+ score_func="softmax",
164
+ route_norm=False,
165
+ route_scale=1.0,
166
+ load_balance_coeff=None,
167
+ score_before_experts=False,
168
+ _debug_force_load_balance=False,
169
+ output_router_logits=False,
170
+ router_aux_loss_coef=0.0,
171
+ # MHC (Manifold-constrained Hyper-Connections) parameters
172
+ mhc_enabled=False,
173
+ mhc_expansion_rate=4,
174
+ mhc_identity_init=False,
175
+ mhc_sinkhorn_iters=20,
176
+ # DiffAttention V2 / Attention class
177
+ diff_v2=False,
178
+ attention_cls="basic",
179
+ # GDLA (Grouped Differential Latent Attention) parameters
180
+ q_lora_rank=0,
181
+ kv_lora_rank=0,
182
+ qk_rope_head_dim=None,
183
+ v_head_dim=None,
184
+ original_seq_len=32768,
185
+ rope_factor=1.0,
186
+ mscale=1.0,
187
+ swa_rope_theta=None,
188
+ # Attention output gating
189
+ headwise_attn_output_gate=False,
190
+ elementwise_attn_output_gate=False,
191
+ # MoE: first N layers always dense (no MoE), regardless of interleave schedule
192
+ n_dense_first_layers=0,
193
+ # MTP (Multi-Token Prediction) speculative decoding
194
+ num_nextn_predict_layers=0,
195
+ **kwargs,
196
+ ):
197
+ self.vocab_size = vocab_size
198
+ self.max_position_embeddings = max_position_embeddings
199
+ self.hidden_size = hidden_size
200
+ self.intermediate_size = intermediate_size
201
+ self.num_hidden_layers = num_hidden_layers
202
+ self.num_attention_heads = num_attention_heads
203
+ self.use_sliding_window = use_sliding_window
204
+ self.sliding_window = sliding_window if use_sliding_window else None
205
+ self.max_window_layers = max_window_layers
206
+ self.sliding_window_pattern = sliding_window_pattern
207
+ self.sliding_window_period = sliding_window_period
208
+
209
+ # for backward compatibility
210
+ if num_key_value_heads is None:
211
+ num_key_value_heads = num_attention_heads
212
+
213
+ self.num_key_value_heads = num_key_value_heads
214
+ self.hidden_act = hidden_act
215
+ self.initializer_range = initializer_range
216
+ self.rms_norm_eps = rms_norm_eps
217
+ self.use_cache = use_cache
218
+ self.rope_theta = rope_theta
219
+ self.rope_scaling = rope_scaling
220
+ self.attention_dropout = attention_dropout
221
+
222
+ # Differential Attention configuration
223
+ self.head_dim = head_dim
224
+ self.num_noise_heads = num_noise_heads
225
+ self.k_ratio = k_ratio
226
+
227
+ # MoE configuration
228
+ self.num_experts = num_experts
229
+ self.experts_top_k = experts_top_k
230
+ self.num_shared_experts = num_shared_experts
231
+ self.interleave_moe_layer_step = interleave_moe_layer_step
232
+ self.moe_intermediate_size = moe_intermediate_size if moe_intermediate_size is not None else intermediate_size
233
+ self.score_func = score_func
234
+ self.route_norm = route_norm
235
+ self.route_scale = route_scale
236
+ self.load_balance_coeff = load_balance_coeff
237
+ self.score_before_experts = score_before_experts
238
+ self._debug_force_load_balance = _debug_force_load_balance
239
+ self.output_router_logits = output_router_logits
240
+ self.router_aux_loss_coef = router_aux_loss_coef
241
+
242
+ # MHC configuration
243
+ self.mhc_enabled = mhc_enabled
244
+ self.mhc_expansion_rate = mhc_expansion_rate
245
+ self.mhc_identity_init = mhc_identity_init
246
+ self.mhc_sinkhorn_iters = mhc_sinkhorn_iters
247
+
248
+ # DiffAttention V2 / Attention class
249
+ self.diff_v2 = diff_v2
250
+ self.attention_cls = attention_cls
251
+
252
+ # GDLA parameters
253
+ self.q_lora_rank = q_lora_rank
254
+ self.kv_lora_rank = kv_lora_rank
255
+ self.qk_rope_head_dim = qk_rope_head_dim
256
+ self.v_head_dim = v_head_dim
257
+ self.original_seq_len = original_seq_len
258
+ self.rope_factor = rope_factor
259
+ self.mscale = mscale
260
+ self.swa_rope_theta = swa_rope_theta
261
+
262
+ # Attention output gating
263
+ self.headwise_attn_output_gate = headwise_attn_output_gate
264
+ self.elementwise_attn_output_gate = elementwise_attn_output_gate
265
+
266
+ # MoE dense-first layers
267
+ self.n_dense_first_layers = n_dense_first_layers
268
+
269
+ # MTP speculative decoding
270
+ self.num_nextn_predict_layers = num_nextn_predict_layers
271
+
272
+ # Validate the correctness of rotary position embeddings parameters
273
+ # BC: if there is a 'type' field, move it to 'rope_type'.
274
+ if self.rope_scaling is not None and "type" in self.rope_scaling:
275
+ self.rope_scaling["rope_type"] = self.rope_scaling["type"]
276
+ # Motif applies the YaRN mscale on the attention softmax scale
277
+ # (DeepSeek-style, full-attention layers only), never on the cos/sin table.
278
+ # Default attention_factor=1.0 so transformers' YaRN rope init does not ALSO
279
+ # scale cos/sin (which would double-apply mscale); apply_yarn_scaling=False
280
+ # makes that intent explicit for the modeling code (MotifRotaryEmbedding).
281
+ if self.rope_scaling is not None and self.rope_scaling.get("rope_type") == "yarn":
282
+ self.rope_scaling.setdefault("attention_factor", 1.0)
283
+ self.rope_scaling.setdefault("apply_yarn_scaling", False)
284
+ if callable(getattr(type(self), "validate_rope", None)):
285
+ self.validate_rope()
286
+
287
+ # The per-expert PolyNorm activation (GroupedPolyNorm) is only correct via
288
+ # the EAGER experts loop: the grouped_mm / batched_mm interfaces call
289
+ # _apply_gate once over all expert-sorted tokens with no per-expert index,
290
+ # so they cannot apply per-expert coefficients. Force eager dispatch for
291
+ # MoE Motif models unless the caller explicitly overrides it. (This also
292
+ # covers ROCm, where torch._grouped_mm has no runtime kernel.)
293
+ if self.num_experts > 0 and "experts_implementation" not in kwargs:
294
+ kwargs["experts_implementation"] = "eager"
295
+
296
+ super().__init__(
297
+ tie_word_embeddings=tie_word_embeddings,
298
+ **kwargs,
299
+ )
300
+ logger.info(f" kwargs : {kwargs}")
modeling_motif.py ADDED
@@ -0,0 +1,1690 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import math
3
+ from typing import Callable, Literal, Optional, Tuple
4
+
5
+ import einops
6
+ import torch
7
+ import torch.nn.functional as F
8
+ import torch.utils.checkpoint
9
+ from torch import nn
10
+ from torch.nn import CrossEntropyLoss
11
+ from transformers.activations import ACT2CLS as _ACT2CLS
12
+ from transformers.activations import ClassInstantier
13
+ from transformers.cache_utils import Cache, DynamicCache, StaticCache
14
+ from transformers.generation import GenerationMixin
15
+ from transformers.modeling_attn_mask_utils import AttentionMaskConverter
16
+ from transformers.modeling_layers import GradientCheckpointingLayer
17
+ from transformers.modeling_outputs import MoeCausalLMOutputWithPast, MoeModelOutputWithPast
18
+ from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS
19
+ from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
20
+ from transformers.utils import auto_docstring, can_return_tuple, logging
21
+
22
+ from .configuration_motif import MotifConfig
23
+
24
+ logger = logging.get_logger(__name__)
25
+
26
+ if hasattr(torch.version, "hip") and torch.version.hip is not None:
27
+ activation = None
28
+ logger.warning_once("Using HIP")
29
+ logger.warning_once("Due to the HIP, we do not utilize the kernel ops for precision.")
30
+ logger.warning_once("Using torch ops")
31
+ kernelRMSNorm = None
32
+ PolyNormKernel = None
33
+ else:
34
+ logger.warning_once("Using CUDA")
35
+ try:
36
+ import kernels
37
+
38
+ activation = kernels.get_kernel("Motif-Technologies/activation")
39
+ kernelRMSNorm = activation.layers.RMSNorm
40
+ PolyNormKernel = activation.layers.PolyNorm
41
+ except Exception as e:
42
+ activation = None
43
+ kernelRMSNorm = None
44
+ PolyNormKernel = None
45
+ logger.warning_once(f"Failed to import kernel ops: {e}")
46
+ logger.warning_once("Using torch ops")
47
+
48
+
49
+ class PolyNormTorch(torch.nn.Module):
50
+ """
51
+ A trainable activation function introduced in https://arxiv.org/html/2411.03884v1.
52
+ The code is copied from https://github.com/BryceZhuo/PolyCom?tab=readme-ov-file/README.md,
53
+ with the change `* torch.rsqrt` => `/ torch.sqrt`.
54
+ """
55
+
56
+ def __init__(self, eps=1e-6, sigmoid_weight: bool = True):
57
+ super(PolyNormTorch, self).__init__()
58
+ self.weight = torch.nn.Parameter(torch.ones(3) / 3)
59
+ self.bias = torch.nn.Parameter(torch.zeros(1))
60
+ self.eps = eps
61
+ self.sigmoid_weight = sigmoid_weight
62
+
63
+ def _norm(self, x):
64
+ return x / torch.sqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
65
+
66
+ def _coeffs(self):
67
+ w = self.weight.float()
68
+ return torch.sigmoid(w) if self.sigmoid_weight else w
69
+
70
+ def _poly(self, x):
71
+ w = self._coeffs()
72
+ return w[0] * self._norm(x**3) + w[1] * self._norm(x**2) + w[2] * self._norm(x) + self.bias.float()
73
+
74
+ def forward(self, x):
75
+ orig_dtype = x.dtype
76
+ return self._poly(x.float()).to(orig_dtype)
77
+
78
+ def forward_mul(self, x, mul):
79
+ orig_dtype = x.dtype
80
+ return (self._poly(x.float()) * mul.float()).to(orig_dtype)
81
+
82
+
83
+ PolyNorm = PolyNormKernel if PolyNormKernel is not None else PolyNormTorch
84
+ CUSTOM_ACT2CLS = {"poly_norm": PolyNorm}
85
+ ACT2CLS = {**_ACT2CLS, **CUSTOM_ACT2CLS}
86
+ ACT2FN = ClassInstantier(ACT2CLS)
87
+
88
+
89
+ class GroupedPolyNorm(nn.Module):
90
+ """Per-expert PolyNorm: weight [num_experts, 3], bias [num_experts, 1].
91
+
92
+ Mirrors titan's GroupedExpertsPolyNorm — each expert has independent
93
+ polynomial normalization coefficients.
94
+ """
95
+
96
+ def __init__(
97
+ self,
98
+ num_experts: int,
99
+ eps: float = 1e-6,
100
+ sigmoid_weight: bool = True,
101
+ bias_clamp: Optional[float] = None,
102
+ output_scale: float = 1.0,
103
+ hidden_clamp: Optional[float] = None,
104
+ ):
105
+ super().__init__()
106
+ self.num_experts = num_experts
107
+ self.eps = eps
108
+ self.sigmoid_weight = sigmoid_weight
109
+ self.bias_clamp = bias_clamp
110
+ self.output_scale = output_scale
111
+ self.hidden_clamp = hidden_clamp
112
+ self.weight = nn.Parameter(torch.ones(num_experts, 3) / 3)
113
+ self.bias = nn.Parameter(torch.zeros(num_experts, 1))
114
+
115
+ def _norm(self, x: torch.Tensor) -> torch.Tensor:
116
+ return x / torch.sqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
117
+
118
+ def forward_single(self, x: torch.Tensor, mul: torch.Tensor, expert_idx: int) -> torch.Tensor:
119
+ orig_dtype = x.dtype
120
+ w = self.weight[expert_idx].float()
121
+ if self.sigmoid_weight:
122
+ w = torch.sigmoid(w)
123
+ b = self.bias[expert_idx].float()
124
+ if self.bias_clamp is not None:
125
+ b = b.clamp(-self.bias_clamp, self.bias_clamp)
126
+ xf = x.float()
127
+ mf = mul.float()
128
+ if self.hidden_clamp is not None:
129
+ xf = xf.clamp(-self.hidden_clamp, self.hidden_clamp)
130
+ mf = mf.clamp(-self.hidden_clamp, self.hidden_clamp)
131
+ poly = w[0] * self._norm(xf**3) + w[1] * self._norm(xf**2) + w[2] * self._norm(xf) + b
132
+ result = poly * mf
133
+ if self.hidden_clamp is not None:
134
+ result = result.clamp(-self.hidden_clamp, self.hidden_clamp)
135
+ result = result * self.output_scale
136
+ return result.to(orig_dtype)
137
+
138
+
139
+ class MotifRMSNorm(nn.Module):
140
+ def __init__(self, hidden_size, eps=1e-6):
141
+ """
142
+ MotifRMSNorm is equivalent to T5LayerNorm
143
+ """
144
+ super().__init__()
145
+ self.weight = nn.Parameter(torch.ones(hidden_size))
146
+ self.variance_epsilon = eps
147
+
148
+ def forward(self, hidden_states):
149
+ input_dtype = hidden_states.dtype
150
+ hidden_states = hidden_states.to(torch.float32)
151
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
152
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
153
+ return self.weight * hidden_states.to(input_dtype)
154
+
155
+ def extra_repr(self):
156
+ return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
157
+
158
+
159
+ class MHCLayer(nn.Module):
160
+ """Manifold-constrained Hyper-Connections (MHC) layer.
161
+
162
+ Written inline in the HF model (no llm_training.layers.mhc dependency).
163
+ apply_h_res uses a pure-PyTorch einsum instead of the Triton kernel.
164
+
165
+ Reference: https://arxiv.org/abs/2512.24880
166
+ """
167
+
168
+ def __init__(
169
+ self,
170
+ expansion_rate: int,
171
+ num_dim: int,
172
+ identity_init: bool = False,
173
+ sinkhorn_iters: int = 20,
174
+ h_post_coeff: float = 2.0,
175
+ ):
176
+ super().__init__()
177
+ self.expansion_rate = expansion_rate
178
+ self.num_dim = num_dim
179
+ self.sinkhorn_iters = sinkhorn_iters
180
+ self.h_post_coeff = float(h_post_coeff)
181
+
182
+ E, D = expansion_rate, num_dim
183
+ self.proj_pre = nn.Linear(E * D, E, bias=False)
184
+ self.proj_post = nn.Linear(E * D, E, bias=False)
185
+ self.proj_res = nn.Linear(E * D, E * E, bias=False)
186
+
187
+ RMSNorm = kernelRMSNorm if kernelRMSNorm is not None else MotifRMSNorm
188
+ self.rms_norm = RMSNorm(E * D, eps=1e-6)
189
+
190
+ self.bias_pre = nn.Parameter(torch.empty(E))
191
+ self.bias_post = nn.Parameter(torch.empty(E))
192
+ self.bias_res = nn.Parameter(torch.empty(E, E))
193
+ self.alpha_pre = nn.Parameter(torch.empty(1))
194
+ self.alpha_post = nn.Parameter(torch.empty(1))
195
+ self.alpha_res = nn.Parameter(torch.empty(1))
196
+
197
+ self._init_weights(identity_init)
198
+
199
+ def _init_weights(self, identity_init: bool) -> None:
200
+ if hasattr(self.rms_norm, "reset_parameters"):
201
+ self.rms_norm.reset_parameters()
202
+ if identity_init:
203
+ nn.init.zeros_(self.alpha_pre)
204
+ nn.init.zeros_(self.alpha_post)
205
+ nn.init.zeros_(self.alpha_res)
206
+ nn.init.xavier_uniform_(self.proj_pre.weight)
207
+ nn.init.xavier_uniform_(self.proj_post.weight)
208
+ nn.init.xavier_uniform_(self.proj_res.weight)
209
+ uniform_weight = 1.0 / self.expansion_rate
210
+ bias_pre_value = math.log(uniform_weight / (1 - uniform_weight)) if 0 < uniform_weight < 1 else 0.0
211
+ nn.init.constant_(self.bias_pre, bias_pre_value)
212
+ nn.init.zeros_(self.bias_post)
213
+ nn.init.constant_(self.bias_res, -10.0)
214
+ self.bias_res.data.fill_diagonal_(0.0)
215
+ else:
216
+ nn.init.normal_(self.alpha_pre, mean=0.0, std=0.1)
217
+ nn.init.normal_(self.alpha_post, mean=0.0, std=0.1)
218
+ nn.init.normal_(self.alpha_res, mean=0.0, std=0.1)
219
+ nn.init.xavier_uniform_(self.proj_pre.weight)
220
+ nn.init.xavier_uniform_(self.proj_post.weight)
221
+ nn.init.xavier_uniform_(self.proj_res.weight)
222
+ nn.init.zeros_(self.bias_pre)
223
+ nn.init.zeros_(self.bias_post)
224
+ nn.init.normal_(self.bias_res, mean=0.0, std=0.1)
225
+
226
+ def _sinkhorn_knopp_batch(self, matrix: torch.Tensor) -> torch.Tensor:
227
+ orig_dtype = matrix.dtype
228
+ # Run Sinkhorn-Knopp in float32 (bf16/fp16 exp() is numerically unstable)
229
+ m = matrix.float().clamp(-20.0, 20.0).exp()
230
+ for _ in range(self.sinkhorn_iters):
231
+ m = m / m.sum(dim=-1, keepdim=True).clamp(min=1e-8)
232
+ m = m / m.sum(dim=-2, keepdim=True).clamp(min=1e-8)
233
+ return m.to(orig_dtype)
234
+
235
+ def forward(self, x: torch.Tensor):
236
+ batch_size, seq_len, expansion_rate, dim = x.shape
237
+ x_reshaped = x.reshape(batch_size, seq_len, expansion_rate * dim)
238
+ x_norm = self.rms_norm(x_reshaped)
239
+
240
+ # Cast projection outputs to float32 (paper §4.3.1)
241
+ proj_pre_out = self.proj_pre(x_norm).float()
242
+ proj_post_out = self.proj_post(x_norm).float()
243
+ proj_res_out = self.proj_res(x_norm).float().reshape(batch_size, seq_len, expansion_rate, expansion_rate)
244
+
245
+ h_pre = torch.sigmoid((self.alpha_pre * proj_pre_out + self.bias_pre).clamp(-10.0, 10.0))
246
+ h_post = self.h_post_coeff * torch.sigmoid((self.alpha_post * proj_post_out + self.bias_post).clamp(-10.0, 10.0))
247
+ h_res = self._sinkhorn_knopp_batch(self.alpha_res * proj_res_out + self.bias_res)
248
+
249
+ return h_pre, h_post, h_res
250
+
251
+ @classmethod
252
+ def apply_h_res(cls, x: torch.Tensor, h_res: torch.Tensor) -> torch.Tensor:
253
+ """h_res: (B, S, E, E), x: (B, S, E, D) -> (B, S, E, D)."""
254
+ return torch.einsum("bsij,bsjd->bsid", h_res, x.float()).to(x.dtype)
255
+
256
+ @classmethod
257
+ def apply_h_pre(cls, x: torch.Tensor, h_pre: torch.Tensor) -> torch.Tensor:
258
+ """Weighted sum over expansion dim: (B, S, E, D) -> (B, S, D)."""
259
+ return (x * h_pre.unsqueeze(-1)).sum(dim=2).to(x.dtype)
260
+
261
+ @classmethod
262
+ def apply_h_post(cls, x: torch.Tensor, h_post: torch.Tensor) -> torch.Tensor:
263
+ """Expand: (B, S, D) -> (B, S, E, D)."""
264
+ return (h_post.unsqueeze(-1) * x.unsqueeze(2)).to(x.dtype)
265
+
266
+ def extra_repr(self) -> str:
267
+ return f"expansion_rate={self.expansion_rate}, sinkhorn_iters={self.sinkhorn_iters}"
268
+
269
+
270
+ def _compute_yarn_inv_freq(
271
+ dim: int,
272
+ end: int,
273
+ theta: float,
274
+ original_seq_len: int,
275
+ rope_factor: float,
276
+ beta_fast: float = 32.0,
277
+ beta_slow: float = 1.0,
278
+ device=None,
279
+ ) -> torch.Tensor:
280
+ """YaRN frequency interpolation, matching llm-training's
281
+ ``precompute_freqs_cis_yarn`` (model.py) exactly. Returns ``inv_freq`` of
282
+ shape ``[dim // 2]`` (the per-position freqs table is built from it in
283
+ ``MotifRotaryEmbedding.forward``). Only the frequencies are interpolated —
284
+ the cos/sin table is never scaled by mscale (Motif folds mscale into the
285
+ attention softmax scale of full-attention layers instead)."""
286
+
287
+ def find_correction_dim(num_rotations, d, base, max_seq_len):
288
+ return d * math.log(max_seq_len / (num_rotations * 2 * math.pi)) / (2 * math.log(base))
289
+
290
+ def find_correction_range(low_rot, high_rot, d, base, max_seq_len):
291
+ low = math.floor(find_correction_dim(low_rot, d, base, max_seq_len))
292
+ high = math.ceil(find_correction_dim(high_rot, d, base, max_seq_len))
293
+ return max(low, 0), min(high, d - 1)
294
+
295
+ def linear_ramp_factor(lo, hi, d):
296
+ if lo == hi:
297
+ hi += 0.001
298
+ ramp = (torch.arange(d, dtype=torch.float32, device=device) - lo) / (hi - lo)
299
+ return torch.clamp(ramp, 0, 1)
300
+
301
+ freqs = 1.0 / (theta ** (torch.arange(0, dim, 2, dtype=torch.float32, device=device) / dim))
302
+ if end > original_seq_len:
303
+ low, high = find_correction_range(beta_fast, beta_slow, dim, theta, original_seq_len)
304
+ smooth = 1 - linear_ramp_factor(low, high, dim // 2)
305
+ freqs = freqs / rope_factor * (1 - smooth) + freqs * smooth
306
+ return freqs
307
+
308
+
309
+ class MotifRotaryEmbedding(nn.Module):
310
+ inv_freq: torch.Tensor
311
+
312
+ def __init__(self, config: MotifConfig, device=None, rope_head_dim: Optional[int] = None):
313
+ super().__init__()
314
+ # BC: "rope_type" was originally "type"
315
+ if hasattr(config, "rope_scaling") and isinstance(config.rope_scaling, dict):
316
+ self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type"))
317
+ else:
318
+ self.rope_type = "default"
319
+ self.max_seq_len_cached = config.max_position_embeddings
320
+ self.original_max_seq_len = config.max_position_embeddings
321
+
322
+ self.config = config
323
+ # Use rope_head_dim if provided (e.g. for GDLA which only applies RoPE to qk_rope_head_dim dims)
324
+ effective_head_dim = (
325
+ rope_head_dim
326
+ if rope_head_dim is not None
327
+ else (config.head_dim if config.head_dim is not None else config.hidden_size // config.num_attention_heads)
328
+ )
329
+ if self.rope_type == "default":
330
+ self.rope_init_fn = None
331
+ inv_freq = 1.0 / (
332
+ config.rope_theta
333
+ ** (torch.arange(0, effective_head_dim, 2, dtype=torch.int64).float().to(device) / effective_head_dim)
334
+ )
335
+ self.attention_scaling = 1.0
336
+
337
+ elif self.rope_type == "yarn":
338
+ self.rope_init_fn = None
339
+ rope_scaling = config.rope_scaling if isinstance(config.rope_scaling, dict) else {}
340
+ factor = float(rope_scaling.get("factor", getattr(config, "rope_factor", 1.0)))
341
+ original_seq_len = int(
342
+ rope_scaling.get(
343
+ "original_max_position_embeddings",
344
+ getattr(config, "original_seq_len", config.max_position_embeddings),
345
+ )
346
+ )
347
+ beta_fast = float(rope_scaling.get("beta_fast", 32))
348
+ beta_slow = float(rope_scaling.get("beta_slow", 1))
349
+ theta = float(rope_scaling.get("rope_theta", config.rope_theta))
350
+ inv_freq = _compute_yarn_inv_freq(
351
+ effective_head_dim,
352
+ config.max_position_embeddings,
353
+ theta,
354
+ original_seq_len,
355
+ factor,
356
+ beta_fast,
357
+ beta_slow,
358
+ device,
359
+ )
360
+ self.attention_scaling = 1.0
361
+
362
+ else:
363
+ self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
364
+ inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device)
365
+ rope_scaling = config.rope_scaling if isinstance(config.rope_scaling, dict) else {}
366
+ if not rope_scaling.get("apply_yarn_scaling", False):
367
+ self.attention_scaling = 1.0
368
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
369
+ self.original_inv_freq = self.inv_freq
370
+
371
+ def _dynamic_frequency_update(self, position_ids, device):
372
+ seq_len = torch.max(position_ids) + 1
373
+ if seq_len > self.max_seq_len_cached:
374
+ if self.rope_init_fn is not None:
375
+ inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device, seq_len=seq_len)
376
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
377
+ self.max_seq_len_cached = seq_len
378
+
379
+ if seq_len < self.original_max_seq_len and self.max_seq_len_cached > self.original_max_seq_len:
380
+ self.register_buffer("inv_freq", self.original_inv_freq, persistent=False)
381
+ self.max_seq_len_cached = self.original_max_seq_len
382
+
383
+ @torch.no_grad()
384
+ def forward(self, x, position_ids):
385
+ if "dynamic" in self.rope_type:
386
+ self._dynamic_frequency_update(position_ids, device=x.device)
387
+
388
+ if (not getattr(self, "_inv_ready", False)) or self.inv_freq.is_meta \
389
+ or float(self.inv_freq.detach().abs().sum()) == 0.0:
390
+ _rhd = self.inv_freq.shape[0] * 2
391
+ if self.rope_type == "yarn":
392
+ _rs = self.config.rope_scaling if isinstance(self.config.rope_scaling, dict) else {}
393
+ _iv = _compute_yarn_inv_freq(
394
+ _rhd, self.config.max_position_embeddings,
395
+ float(_rs.get("rope_theta", self.config.rope_theta)),
396
+ int(_rs.get("original_max_position_embeddings",
397
+ getattr(self.config, "original_seq_len", self.config.max_position_embeddings))),
398
+ float(_rs.get("factor", getattr(self.config, "rope_factor", 1.0))),
399
+ float(_rs.get("beta_fast", 32)), float(_rs.get("beta_slow", 1)), x.device)
400
+ else: # plain RoPE (SWA layers: rope_theta=swa_rope_theta, no YaRN)
401
+ _iv = 1.0 / (self.config.rope_theta ** (
402
+ torch.arange(0, _rhd, 2, dtype=torch.int64).float().to(x.device) / _rhd))
403
+ self.register_buffer("inv_freq", _iv.to(device=x.device, dtype=torch.float32), persistent=False)
404
+ self.original_inv_freq = self.inv_freq
405
+ self._inv_ready = True
406
+ inv_freq_expanded = self.inv_freq[None, :, None].to(device=x.device, dtype=torch.float32).expand(position_ids.shape[0], -1, 1)
407
+ position_ids_expanded = position_ids[:, None, :].float()
408
+
409
+ device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
410
+ with torch.autocast(device_type=device_type, enabled=False):
411
+ freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
412
+ emb = torch.cat((freqs, freqs), dim=-1)
413
+ cos = emb.cos() * self.attention_scaling
414
+ sin = emb.sin() * self.attention_scaling
415
+
416
+ return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
417
+
418
+
419
+ def rotate_half(x):
420
+ """
421
+ Rotates half of the dimensions of the input tensor using torch.roll and in-place negation.
422
+
423
+ Args:
424
+ x (torch.Tensor): The input tensor.
425
+
426
+ Returns:
427
+ torch.Tensor: A tensor where the latter half of the dimensions are negated
428
+ and moved before the first half.
429
+ """
430
+ half_size = x.shape[-1] // 2
431
+ rotated_tensor = torch.roll(x, shifts=-half_size, dims=-1)
432
+ rotated_tensor[..., :half_size] *= -1
433
+
434
+ return rotated_tensor
435
+
436
+
437
+ def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
438
+ """
439
+ Applies rotary position embeddings to the input tensors.
440
+ Args:
441
+ q (torch.Tensor): Query tensor of shape (B, NH, S, D_KV).
442
+ k (torch.Tensor): Key tensor of shape (B, NH, S, D_KV).
443
+ cos (torch.Tensor): Cosine values for rotary embedding, shape (B, S, D) from MotifRotaryEmbedding.
444
+ sin (torch.Tensor): Sine values for rotary embedding, shape (B, S, D) from MotifRotaryEmbedding.
445
+ position_ids: Unused, kept for API compatibility.
446
+ unsqueeze_dim (int, optional): Dimension along which `cos` and `sin` are unsqueezed.
447
+ Defaults to 1 (head dimension).
448
+ Returns:
449
+ Tuple[torch.Tensor, torch.Tensor]: Transformed query and key tensors.
450
+ """
451
+ cos = cos.unsqueeze(unsqueeze_dim)
452
+ sin = sin.unsqueeze(unsqueeze_dim)
453
+ q_embed = (q * cos) + (rotate_half(q) * sin)
454
+ k_embed = (k * cos) + (rotate_half(k) * sin)
455
+ return q_embed, k_embed
456
+
457
+
458
+ def apply_rotary_pos_emb_single(
459
+ x: torch.Tensor,
460
+ cos: torch.Tensor,
461
+ sin: torch.Tensor,
462
+ ) -> torch.Tensor:
463
+ """Apply RoPE to a single tensor in (B, S, NH, D) format.
464
+
465
+ Used by GDLA to apply positional encoding only to the rope portion of Q/K.
466
+ cos/sin shape: (B, S, D) — broadcast over NH dimension.
467
+ """
468
+ cos = cos.unsqueeze(2) # (B, S, 1, D)
469
+ sin = sin.unsqueeze(2) # (B, S, 1, D)
470
+ return x * cos + rotate_half(x) * sin
471
+
472
+
473
+ class MotifMLP(nn.Module):
474
+ def __init__(self, config, intermediate_size: int | None = None):
475
+ super().__init__()
476
+ self.hidden_size = config.hidden_size
477
+ self.intermediate_size = intermediate_size if intermediate_size is not None else config.intermediate_size
478
+
479
+ self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
480
+ self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
481
+ self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
482
+ if config.hidden_act == "poly_norm":
483
+ self.act_fn = PolyNormTorch(sigmoid_weight=getattr(config, "polynorm_sigmoid_weight", True))
484
+ else:
485
+ self.act_fn = ACT2FN[config.hidden_act]
486
+ self.hidden_clamp = getattr(config, "hidden_clamp", None)
487
+ self.polynorm_output_scale = float(getattr(config, "polynorm_output_scale", 1.0))
488
+
489
+ def forward(self, hidden_state):
490
+ gate = self.gate_proj(hidden_state)
491
+ up = self.up_proj(hidden_state)
492
+ if isinstance(self.act_fn, PolyNormTorch):
493
+ if self.hidden_clamp is not None:
494
+ gate = gate.clamp(-self.hidden_clamp, self.hidden_clamp)
495
+ up = up.clamp(-self.hidden_clamp, self.hidden_clamp)
496
+ hidden_state = self.act_fn.forward_mul(gate, up)
497
+ if self.polynorm_output_scale != 1.0:
498
+ hidden_state = hidden_state * self.polynorm_output_scale
499
+ else:
500
+ hidden_state = self.act_fn(gate) * up
501
+ return self.down_proj(hidden_state)
502
+
503
+
504
+ def repeat_kv(hidden_states: torch.Tensor, dim: int, n_rep: int) -> torch.Tensor:
505
+ return torch.repeat_interleave(hidden_states, dim=dim, repeats=n_rep)
506
+
507
+
508
+ def eager_attention_forward(
509
+ module: nn.Module,
510
+ query: torch.Tensor,
511
+ key: torch.Tensor,
512
+ value: torch.Tensor,
513
+ attention_mask: Optional[torch.Tensor],
514
+ scaling: float,
515
+ dropout: float = 0.0,
516
+ **kwargs,
517
+ ):
518
+ """Eager attention forward compatible with ALL_ATTENTION_FUNCTIONS interface.
519
+ Expects query/key/value in [batch, num_heads, seq_len, head_dim] format.
520
+ """
521
+ attn_weights = torch.matmul(query, key.transpose(2, 3)) * scaling
522
+ if attention_mask is not None:
523
+ causal_mask = attention_mask[:, :, :, : key.shape[-2]]
524
+ attn_weights = attn_weights + causal_mask
525
+
526
+ attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
527
+ attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
528
+ attn_output = torch.matmul(attn_weights, value)
529
+ attn_output = attn_output.transpose(1, 2).contiguous()
530
+
531
+ return attn_output, attn_weights
532
+
533
+
534
+ class MotifGDLAttention(nn.Module):
535
+ """Grouped Differential Latent Attention (GDLA) for HF Transformers.
536
+
537
+ Ports GDLAttention from torchtitan. Uses low-rank Q and KV projections
538
+ (MLA-style) with RoPE applied only to the qk_rope_head_dim dimensions.
539
+ Only diff_v2=True is fully supported (the motif3 configuration).
540
+ """
541
+
542
+ def __init__(self, config: MotifConfig, layer_idx: Optional[int] = None):
543
+ super().__init__()
544
+ self.config = config
545
+ self.layer_idx = layer_idx
546
+
547
+ self.hidden_size = config.hidden_size
548
+ self.num_heads = config.num_attention_heads
549
+ self.num_key_value_heads = config.num_key_value_heads
550
+ self.head_dim = config.head_dim if config.head_dim is not None else self.hidden_size // self.num_heads
551
+ self.is_causal = True
552
+ self.attention_dropout = config.attention_dropout
553
+
554
+ # Head split
555
+ self.num_noise_heads = config.num_noise_heads
556
+ self.grouped_ratio = (self.num_heads - self.num_noise_heads) // self.num_noise_heads
557
+ self.n_signal_heads = self.grouped_ratio * self.num_noise_heads
558
+
559
+ # GDLA dimensions
560
+ self.q_lora_rank = config.q_lora_rank
561
+ self.kv_lora_rank = config.kv_lora_rank
562
+ self.qk_rope_head_dim = config.qk_rope_head_dim if config.qk_rope_head_dim is not None else self.head_dim // 2
563
+ self.qk_nope_head_dim = self.head_dim - self.qk_rope_head_dim
564
+ self.v_head_dim = config.v_head_dim if config.v_head_dim is not None else self.head_dim
565
+ self.diff_v2 = getattr(config, "diff_v2", True)
566
+ self.sliding_window = None
567
+ is_swa_layer = False
568
+ if config.use_sliding_window and getattr(config, "sliding_window", None) is not None:
569
+ pattern = getattr(config, "sliding_window_pattern", "interleave")
570
+ period = getattr(config, "sliding_window_period", 2)
571
+ effective_window = config.sliding_window + 1
572
+ if pattern == "all":
573
+ self.sliding_window = effective_window
574
+ is_swa_layer = True
575
+ elif pattern == "interleave" and layer_idx % period != 0:
576
+ self.sliding_window = effective_window
577
+ is_swa_layer = True
578
+ self.is_swa_layer = is_swa_layer
579
+ self.scaling = self.head_dim**-0.5
580
+ original_seq_len = getattr(config, "original_seq_len", 32768)
581
+ rope_factor = getattr(config, "rope_factor", 1.0)
582
+ mscale = getattr(config, "mscale", 1.0)
583
+ if (not is_swa_layer) and config.max_position_embeddings > original_seq_len:
584
+ mscale_val = 0.1 * mscale * math.log(rope_factor) + 1.0
585
+ self.scaling = self.scaling * mscale_val * mscale_val
586
+
587
+ # Output gating
588
+ self.elementwise_attn_output_gate = getattr(config, "elementwise_attn_output_gate", False)
589
+ self.headwise_attn_output_gate = getattr(config, "headwise_attn_output_gate", False)
590
+
591
+ # Required by transformers SDPA interface for GQA repeat_kv dispatch
592
+ self.num_key_value_groups = self.num_heads // self.num_key_value_heads
593
+
594
+ RMSNorm = kernelRMSNorm if kernelRMSNorm is not None else MotifRMSNorm
595
+
596
+ # Query LoRA
597
+ self.wq_a = nn.Linear(self.hidden_size, self.q_lora_rank, bias=False)
598
+ self.q_norm = RMSNorm(self.q_lora_rank, eps=config.rms_norm_eps)
599
+
600
+ if self.elementwise_attn_output_gate:
601
+ # Separate gate projection; for V2: n_signal_heads gates; for V1: n_signal_heads*2
602
+ gate_extra = self.n_signal_heads if self.diff_v2 else self.n_signal_heads * 2
603
+ self.wq_b = nn.Linear(self.q_lora_rank, self.num_heads * self.head_dim, bias=False)
604
+ self.wq_b_gate = nn.Linear(self.q_lora_rank, gate_extra * self.v_head_dim, bias=False)
605
+ else:
606
+ self.wq_b = nn.Linear(self.q_lora_rank, self.num_heads * self.head_dim, bias=False)
607
+ self.wq_b_gate = None
608
+
609
+ # KV LoRA: output kv_lora_rank + qk_rope_head_dim
610
+ self.wkv_a = nn.Linear(self.hidden_size, self.kv_lora_rank + self.qk_rope_head_dim, bias=False)
611
+
612
+ if self.diff_v2:
613
+ self.kv_norm = RMSNorm(self.kv_lora_rank, eps=config.rms_norm_eps)
614
+ self.wkv_b = nn.Linear(
615
+ self.kv_lora_rank,
616
+ self.num_key_value_heads * (self.qk_nope_head_dim + self.v_head_dim),
617
+ bias=False,
618
+ )
619
+ self.lambda_proj = nn.Linear(self.hidden_size, self.n_signal_heads, bias=False)
620
+ self.wo = nn.Linear(self.n_signal_heads * self.v_head_dim, self.hidden_size, bias=False)
621
+ else:
622
+ raise NotImplementedError(
623
+ "GDLA V1 (diff_v2=False) is not yet implemented in HF. Use attention_cls='gdla' only with diff_v2=True."
624
+ )
625
+
626
+ self.swa_rotary_emb = None
627
+ swa_rope_theta = getattr(config, "swa_rope_theta", None)
628
+ if self.is_swa_layer and swa_rope_theta is not None:
629
+ swa_config = copy.copy(config)
630
+ swa_config.rope_scaling = None
631
+ swa_config.rope_theta = swa_rope_theta
632
+ self.swa_rotary_emb = MotifRotaryEmbedding(swa_config, rope_head_dim=self.qk_rope_head_dim)
633
+
634
+ def forward(
635
+ self,
636
+ hidden_states: torch.Tensor,
637
+ attention_mask: Optional[torch.Tensor] = None,
638
+ position_ids: Optional[torch.LongTensor] = None,
639
+ past_key_value: Optional[Cache] = None,
640
+ output_attentions: bool = False,
641
+ use_cache: bool = False,
642
+ cache_position: Optional[torch.LongTensor] = None,
643
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
644
+ **kwargs,
645
+ ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
646
+ bsz, q_len, _ = hidden_states.size()
647
+ _wqa = F.linear(hidden_states.float(), self.wq_a.weight.float())
648
+ q_latent = self.q_norm(_wqa) # fp32
649
+ q = F.linear(q_latent, self.wq_b.weight.float()).view(
650
+ bsz, q_len, self.num_heads, self.head_dim).to(hidden_states.dtype)
651
+ q_latent = q_latent.to(hidden_states.dtype) # bf16 for the gate below
652
+
653
+ # Gate score (elementwise)
654
+ gate_score = None
655
+ if self.elementwise_attn_output_gate and self.wq_b_gate is not None:
656
+ gate_score = self.wq_b_gate(q_latent).view(bsz, q_len, -1, self.v_head_dim)
657
+
658
+ # Split Q into nope (no-positional) and rope parts
659
+ q_nope, q_pe = torch.split(q, [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1)
660
+
661
+ # KV path: project to kv_lora_rank + qk_rope_head_dim, then split
662
+ kv_raw = self.wkv_a(hidden_states) # (bsz, q_len, kv_lora_rank + qk_rope_head_dim)
663
+ kv_latent, k_pe = torch.split(kv_raw, [self.kv_lora_rank, self.qk_rope_head_dim], dim=-1)
664
+
665
+ if self.swa_rotary_emb is not None:
666
+ cos, sin = self.swa_rotary_emb(hidden_states, position_ids)
667
+ else:
668
+ cos, sin = position_embeddings
669
+ _rope_dtype = q_pe.dtype
670
+ cos_f, sin_f = cos.float(), sin.float()
671
+ q_pe = apply_rotary_pos_emb_single(q_pe.float(), cos_f, sin_f).to(_rope_dtype)
672
+ k_pe = apply_rotary_pos_emb_single(k_pe.unsqueeze(2).float(), cos_f, sin_f).to(_rope_dtype)
673
+
674
+ # Reconstruct full Q with nope + rope
675
+ q_total = torch.cat([q_nope, q_pe], dim=-1)
676
+
677
+ # KV projection: norm -> project -> split k_nope and v
678
+ kv_latent = kv_latent.contiguous()
679
+ kv_proj = self.wkv_b(self.kv_norm(kv_latent))
680
+ kv_proj = kv_proj.view(bsz, q_len, self.num_key_value_heads, self.qk_nope_head_dim + self.v_head_dim)
681
+ k_nope, v = torch.split(kv_proj, [self.qk_nope_head_dim, self.v_head_dim], dim=-1)
682
+
683
+ # Assemble full K: k_nope + k_pe (broadcast shared rope over all kv heads)
684
+ k_full = torch.cat([k_nope, k_pe.expand(-1, -1, self.num_key_value_heads, -1)], dim=-1)
685
+
686
+ # Lambda (input-dependent for V2)
687
+ lambda_full = self.lambda_proj(hidden_states) # (bsz, q_len, n_signal_heads)
688
+
689
+ # Transpose to (B, H, S, D) before cache (DynamicCache expects this format)
690
+ k_full = k_full.transpose(1, 2) # (bsz, n_kv_heads, q_len, head_dim)
691
+ v = v.transpose(1, 2) # (bsz, n_kv_heads, q_len, v_head_dim)
692
+
693
+ # KV cache
694
+ if past_key_value is not None:
695
+ cache_kwargs = {"cache_position": cache_position}
696
+ k_full, v = past_key_value.update(k_full, v, self.layer_idx, cache_kwargs)
697
+
698
+ dropout_rate = 0.0 if not self.training else self.attention_dropout
699
+
700
+ # Cast dtype if needed
701
+ input_dtype = q_total.dtype
702
+ if input_dtype == torch.float32:
703
+ if torch.is_autocast_enabled():
704
+ target_dtype = torch.get_autocast_gpu_dtype()
705
+ elif hasattr(self.config, "_pre_quantization_dtype"):
706
+ target_dtype = self.config._pre_quantization_dtype
707
+ else:
708
+ target_dtype = self.wq_b.weight.dtype
709
+ q_total = q_total.to(target_dtype)
710
+ k_full = k_full.to(target_dtype)
711
+ v = v.to(target_dtype)
712
+
713
+ # Attention: pad v to head_dim if v_head_dim != head_dim (flash_attn compatibility)
714
+ need_v_pad = self.v_head_dim != self.head_dim
715
+
716
+ attention_interface: Callable = ALL_ATTENTION_FUNCTIONS.get_interface(
717
+ self.config._attn_implementation, eager_attention_forward
718
+ )
719
+
720
+ # k_full and v are already (B, H, S, D); transpose q for interface
721
+ q_t = q_total.transpose(1, 2) # (bsz, n_heads, q_len, head_dim)
722
+ k_t = k_full # (bsz, n_kv_heads, kv_seq_len, head_dim)
723
+ v_t = v # (bsz, n_kv_heads, kv_seq_len, v_head_dim)
724
+
725
+ if need_v_pad:
726
+ v_t = F.pad(v_t, [0, self.head_dim - self.v_head_dim])
727
+
728
+ # Truncate mask to actual kv length (sliding window cache may return fewer tokens than target_length)
729
+ if attention_mask is not None:
730
+ attention_mask = attention_mask[:, -k_t.shape[-2] :]
731
+
732
+ attn_out, _ = attention_interface(
733
+ self,
734
+ q_t,
735
+ k_t,
736
+ v_t,
737
+ attention_mask,
738
+ dropout=dropout_rate,
739
+ scaling=self.scaling,
740
+ sliding_window=self.sliding_window,
741
+ is_causal=self.is_causal,
742
+ **kwargs,
743
+ )
744
+
745
+ # Normalize to (B, S, H, D)
746
+ if attn_out.shape[1] == self.num_heads: # (B, H, S, D) from SDPA
747
+ attn_out = attn_out.transpose(1, 2)
748
+ # Now (B, S, H, D)
749
+
750
+ if need_v_pad:
751
+ attn_out = attn_out[..., : self.v_head_dim].contiguous()
752
+
753
+ # Split heads into signal and noise groups
754
+ num_groups = self.num_noise_heads # n_heads // (grouped_ratio + 1)
755
+ attn_reshaped = einops.rearrange(
756
+ attn_out,
757
+ "b s (g gs) d -> b s g gs d",
758
+ g=num_groups,
759
+ gs=self.grouped_ratio + 1,
760
+ )
761
+ attn1 = attn_reshaped[:, :, :, : self.grouped_ratio, :].reshape(bsz, q_len, -1, self.v_head_dim)
762
+ attn2_group = attn_reshaped[:, :, :, self.grouped_ratio :, :].reshape(bsz, q_len, num_groups, self.v_head_dim)
763
+ attn2 = repeat_kv(attn2_group, 2, self.grouped_ratio) # (bsz, q_len, n_signal_heads, v_head_dim)
764
+
765
+ lambda_scale = torch.sigmoid(lambda_full.float()).to(attn1.dtype).unsqueeze(-1)
766
+ attn_output = attn1 - lambda_scale * attn2
767
+
768
+ if gate_score is not None:
769
+ attn_output = attn_output * torch.sigmoid(gate_score)
770
+
771
+ # Output projection
772
+ attn_output = attn_output.reshape(bsz, q_len, -1)
773
+ attn_output = self.wo(attn_output)
774
+
775
+ return attn_output, None, past_key_value
776
+
777
+
778
+ class TokenChoiceTopKRouter(nn.Module):
779
+ """This class implements token-choice routing. In token-choice top-K routing, each token is
780
+ routed to top K experts based on the router scores.
781
+
782
+ Args:
783
+ dim (int): Dimension of input tokens.
784
+ num_experts (int): Number of experts in each moe layer.
785
+ experts_top_k (int): Number of experts each token will be routed to in token-choice routing.
786
+ score_func (Literal["softmax", "sigmoid"]): Whether to use sigmoid or softmax for router scores.
787
+ route_norm (bool): Whether to normalize the routing scores when using sigmoid.
788
+ route_scale (float): Scaling factor applied to the routing scores.
789
+ """
790
+
791
+ def __init__(
792
+ self,
793
+ hidden_size: int,
794
+ num_experts: int,
795
+ experts_top_k: int,
796
+ score_func: Literal["softmax", "sigmoid"],
797
+ route_norm: bool,
798
+ route_scale: float,
799
+ _debug_force_load_balance: bool = False,
800
+ ):
801
+ super().__init__()
802
+ self.gate = nn.Linear(hidden_size, num_experts, bias=False)
803
+ self.num_experts = num_experts
804
+ self.experts_top_k = experts_top_k
805
+ self.score_func = score_func
806
+ self.route_norm = route_norm
807
+ self.route_scale = route_scale
808
+ self._debug_force_load_balance = _debug_force_load_balance
809
+
810
+ def _debug_force_load_balance_routing(self, scores: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
811
+ """Balanced round-robin expert assignment.
812
+ Returns (selected_experts_indices [N, K] LongTensor, top_scores [N, K] FloatTensor).
813
+ """
814
+ n_tokens = scores.size(0)
815
+ # Round-robin indices with exact balance
816
+ selected_experts_indices = (
817
+ torch.arange(n_tokens * self.experts_top_k, device=scores.device, dtype=torch.int64).reshape(
818
+ n_tokens, self.experts_top_k
819
+ )
820
+ % self.num_experts
821
+ )
822
+ top_scores = scores.gather(dim=1, index=selected_experts_indices) # [N,K]
823
+ return selected_experts_indices, top_scores
824
+
825
+ def forward(
826
+ self, x: torch.Tensor, expert_bias: torch.Tensor | None = None
827
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
828
+ """
829
+ Args:
830
+ x (torch.Tensor): Input tensor with shape ``(bs*slen, dim)``.
831
+ expert_bias (torch.Tensor | None, optional): Optional bias tensor for experts with shape ``(num_experts,)``.
832
+ Used for load balancing. Defaults to None.
833
+
834
+ Returns:
835
+ tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
836
+ - top_scores (torch.Tensor):
837
+ Routing scores for selected experts with shape ``(bs*slen, experts_top_k)``.
838
+ - selected_experts_indices (torch.Tensor):
839
+ Expert indices selected for each token with shape ``(bs*slen, experts_top_k)``.
840
+ - num_tokens_per_expert (torch.Tensor):
841
+ Number of tokens assigned to each expert with shape ``(num_experts,)``.
842
+ """
843
+ scores = F.linear(x.to(torch.float32), self.gate.weight.to(torch.float32))
844
+
845
+ # By default, sigmoid or softmax is performed in float32 to avoid loss explosion
846
+ if self.score_func == "sigmoid":
847
+ scores = torch.sigmoid(scores.to(torch.float32))
848
+ elif self.score_func == "softmax":
849
+ scores = F.softmax(scores.to(torch.float32), dim=1)
850
+ else:
851
+ raise NotImplementedError(f"Unknown score function {self.score_func}")
852
+
853
+
854
+ if expert_bias is not None:
855
+ _, selected_experts_indices = torch.topk(scores + expert_bias, k=self.experts_top_k, dim=1)
856
+ top_scores = scores.gather(dim=1, index=selected_experts_indices)
857
+ else:
858
+ top_scores, selected_experts_indices = torch.topk(scores, k=self.experts_top_k, dim=1)
859
+
860
+ # debug override: balanced round-robin routing
861
+ if self._debug_force_load_balance:
862
+ (
863
+ selected_experts_indices,
864
+ top_scores,
865
+ ) = self._debug_force_load_balance_routing(scores)
866
+
867
+ if self.route_norm:
868
+ denominator = top_scores.sum(dim=-1, keepdim=True) + 1e-20
869
+ top_scores = top_scores / denominator
870
+ top_scores = top_scores * self.route_scale
871
+
872
+ num_tokens_per_expert = torch.bincount(selected_experts_indices.view(-1).long(), minlength=self.num_experts).to(
873
+ dtype=torch.float32
874
+ )
875
+
876
+ return top_scores, selected_experts_indices, num_tokens_per_expert
877
+
878
+ def init_weights(self, init_std: float):
879
+ nn.init.trunc_normal_(self.gate.weight, mean=0.0, std=init_std)
880
+
881
+
882
+ class MotifExperts(nn.Module):
883
+ """Collection of expert weights stored as fused 3D tensors.
884
+
885
+ NOTE: the @use_experts_implementation decorator was intentionally removed.
886
+ That decorator dispatches forward() through config._experts_implementation,
887
+ whose default (grouped_mm) calls _apply_gate once over all expert-sorted
888
+ tokens with no per-expert index — incompatible with per-expert PolyNorm. We
889
+ use the explicit eager per-expert loop below directly, with no dispatch."""
890
+
891
+ def __init__(self, config):
892
+ super().__init__()
893
+ self.num_experts = config.num_experts
894
+ self.hidden_size = config.hidden_size
895
+ moe_intermediate = getattr(config, "moe_intermediate_size", config.intermediate_size)
896
+ self.intermediate_dim = moe_intermediate
897
+
898
+ # Fused gate+up: [num_experts, 2*intermediate, hidden_size]
899
+ self.gate_up_proj = nn.Parameter(torch.empty(self.num_experts, 2 * self.intermediate_dim, self.hidden_size))
900
+ # Down projection: [num_experts, hidden_size, intermediate]
901
+ self.down_proj = nn.Parameter(torch.empty(self.num_experts, self.hidden_size, self.intermediate_dim))
902
+ if config.hidden_act == "poly_norm":
903
+ self.act_fn = GroupedPolyNorm(
904
+ self.num_experts,
905
+ sigmoid_weight=getattr(config, "polynorm_sigmoid_weight", True),
906
+ bias_clamp=getattr(config, "polynorm_bias_clamp", None),
907
+ output_scale=float(getattr(config, "polynorm_output_scale", 1.0)),
908
+ hidden_clamp=getattr(config, "hidden_clamp", None),
909
+ )
910
+ else:
911
+ self.act_fn = ACT2FN[config.hidden_act]
912
+
913
+ def forward(
914
+ self,
915
+ hidden_states: torch.Tensor,
916
+ top_k_index: torch.Tensor,
917
+ top_k_weights: torch.Tensor,
918
+ ) -> torch.Tensor:
919
+ """Eager expert dispatch (loops over experts).
920
+
921
+ Args:
922
+ hidden_states: [total_tokens, hidden_size]
923
+ top_k_index: [total_tokens, top_k] expert indices
924
+ top_k_weights: [total_tokens, top_k] routing weights
925
+
926
+ Returns:
927
+ [total_tokens, hidden_size]
928
+ """
929
+ final_hidden_states = torch.zeros_like(hidden_states, dtype=torch.float32)
930
+ expert_mask = F.one_hot(top_k_index, num_classes=self.num_experts).permute(2, 1, 0)
931
+
932
+ for expert_idx in range(self.num_experts):
933
+ top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
934
+ if token_idx.shape[0] == 0:
935
+ continue
936
+
937
+ current_state = hidden_states[token_idx]
938
+ gate_up = current_state @ self.gate_up_proj[expert_idx].T # [T, 2*I]
939
+ current_hidden = self._apply_gate(gate_up, expert_idx) @ self.down_proj[expert_idx].T # [T, H]
940
+
941
+ current_hidden = current_hidden.float() * top_k_weights[token_idx, top_k_pos, None].float()
942
+ final_hidden_states.index_add_(0, token_idx, current_hidden)
943
+
944
+ return final_hidden_states # fp32; MoE.forward downcasts after adding shared
945
+
946
+ def _apply_gate(self, gate_up_output: torch.Tensor, expert_idx: int = 0) -> torch.Tensor:
947
+ gate, up = gate_up_output.chunk(2, dim=-1)
948
+ gate = gate.contiguous()
949
+ if isinstance(self.act_fn, GroupedPolyNorm):
950
+ return self.act_fn.forward_single(gate, up, expert_idx)
951
+ return self.act_fn(gate) * up
952
+
953
+
954
+ class MoE(nn.Module):
955
+ def __init__(self, config):
956
+ super().__init__()
957
+
958
+ self.num_experts = config.num_experts
959
+ self.experts_top_k = config.experts_top_k
960
+
961
+ self.experts = MotifExperts(config)
962
+
963
+ self.router = TokenChoiceTopKRouter(
964
+ hidden_size=config.hidden_size,
965
+ num_experts=config.num_experts,
966
+ experts_top_k=config.experts_top_k,
967
+ score_func=config.score_func,
968
+ route_norm=config.route_norm,
969
+ route_scale=config.route_scale,
970
+ _debug_force_load_balance=config._debug_force_load_balance,
971
+ )
972
+
973
+ moe_intermediate = getattr(config, "moe_intermediate_size", config.intermediate_size)
974
+ self.shared_experts = (
975
+ MotifMLP(config, intermediate_size=moe_intermediate) if config.num_shared_experts > 0 else None
976
+ )
977
+ self.score_before_experts = config.score_before_experts
978
+ self.load_balance_coeff = config.load_balance_coeff
979
+ if self.load_balance_coeff is not None:
980
+ assert self.load_balance_coeff > 0.0
981
+ self.expert_bias = nn.Parameter(torch.zeros(config.num_experts, dtype=torch.float32), requires_grad=False)
982
+ else:
983
+ self.expert_bias = None
984
+
985
+ def forward(self, x: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
986
+ """
987
+ Args:
988
+ x (torch.Tensor): Input tensor with shape ``(bs, slen, dim)``.
989
+
990
+ Returns:
991
+ tuple: (output tensor (bs, slen, dim), router_logits (bs*slen, num_experts))
992
+ """
993
+ bs, slen, dim = x.shape
994
+ x = x.view(-1, dim)
995
+
996
+ # Route tokens
997
+ top_scores, selected_experts_indices, num_tokens_per_expert = self.router(x, self.expert_bias)
998
+ if self.score_before_experts:
999
+ final_hidden_states = self._score_before_forward(x, selected_experts_indices, top_scores)
1000
+ else:
1001
+ final_hidden_states = self.experts(x, selected_experts_indices, top_scores)
1002
+
1003
+ if self.shared_experts is not None:
1004
+ final_hidden_states = final_hidden_states + self.shared_experts(x).float()
1005
+
1006
+ router_logits = self.router.gate(x.view(-1, dim)) if hasattr(self.router, "gate") else None
1007
+
1008
+ return final_hidden_states.reshape(bs, slen, dim).to(x.dtype), router_logits
1009
+
1010
+ def _score_before_forward(
1011
+ self,
1012
+ hidden_states: torch.Tensor,
1013
+ top_k_index: torch.Tensor,
1014
+ top_k_weights: torch.Tensor,
1015
+ ) -> torch.Tensor:
1016
+ """Custom dispatch for score_before_experts mode.
1017
+
1018
+ Pre-weights inputs by routing scores before expert computation,
1019
+ rather than weighting expert outputs (the standard approach).
1020
+ """
1021
+ final_hidden_states = torch.zeros_like(hidden_states)
1022
+ expert_mask = F.one_hot(top_k_index, num_classes=self.num_experts).permute(2, 1, 0)
1023
+
1024
+ for expert_idx in range(self.num_experts):
1025
+ top_k_pos, token_idx = torch.where(expert_mask[expert_idx])
1026
+ if token_idx.shape[0] == 0:
1027
+ continue
1028
+
1029
+ current_state = hidden_states[token_idx]
1030
+ weights = top_k_weights[token_idx, top_k_pos, None]
1031
+ # Pre-weight input
1032
+ current_state = (current_state.to(torch.float32) * weights).to(hidden_states.dtype)
1033
+
1034
+ gate_up = current_state @ self.experts.gate_up_proj[expert_idx].T # [T, 2*I]
1035
+ current_hidden = self.experts._apply_gate(gate_up, expert_idx) @ self.experts.down_proj[expert_idx].T # [T, H]
1036
+
1037
+ final_hidden_states.index_add_(0, token_idx, current_hidden.to(final_hidden_states.dtype))
1038
+
1039
+ return final_hidden_states
1040
+
1041
+ def init_weights(self, init_std: float, buffer_device: torch.device):
1042
+ nn.init.trunc_normal_(self.experts.gate_up_proj, mean=0.0, std=0.02)
1043
+ nn.init.trunc_normal_(self.experts.down_proj, mean=0.0, std=init_std)
1044
+ self.router.init_weights(init_std)
1045
+ if self.shared_experts is not None:
1046
+ nn.init.trunc_normal_(self.shared_experts.gate_proj.weight, mean=0.0, std=0.02)
1047
+ nn.init.trunc_normal_(self.shared_experts.up_proj.weight, mean=0.0, std=init_std)
1048
+ nn.init.trunc_normal_(self.shared_experts.down_proj.weight, mean=0.0, std=init_std)
1049
+ nn.init.zeros_(self.expert_bias)
1050
+
1051
+
1052
+ class MotifDecoderLayer(GradientCheckpointingLayer):
1053
+ _ATTN_CLS = {
1054
+ "gdla": MotifGDLAttention,
1055
+ }
1056
+
1057
+ def __init__(self, config: MotifConfig, layer_idx: int):
1058
+ super().__init__()
1059
+ self.hidden_size = config.hidden_size
1060
+
1061
+ attention_cls_name = getattr(config, "attention_cls", "basic")
1062
+ attn_cls = self._ATTN_CLS.get(attention_cls_name)
1063
+ if attn_cls is None:
1064
+ raise ValueError(f"Unknown attention_cls={attention_cls_name!r}, expected one of {list(self._ATTN_CLS)}")
1065
+ self.self_attn = attn_cls(config, layer_idx)
1066
+
1067
+ # n_dense_first_layers: first N layers always dense (no MoE)
1068
+ n_dense_first = getattr(config, "n_dense_first_layers", 0)
1069
+ self.moe_enabled = (
1070
+ layer_idx >= n_dense_first and (layer_idx + 1) % config.interleave_moe_layer_step == 0
1071
+ if config.interleave_moe_layer_step != 0
1072
+ else False
1073
+ )
1074
+
1075
+ if self.moe_enabled:
1076
+ self.moe = MoE(config)
1077
+ self.moe.layer_idx = layer_idx
1078
+ else:
1079
+ self.mlp = MotifMLP(config)
1080
+
1081
+ RMSNorm = kernelRMSNorm if kernelRMSNorm is not None else MotifRMSNorm
1082
+ self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1083
+ self.post_attention_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1084
+
1085
+ # MHC (Manifold-constrained Hyper-Connections) layers
1086
+ self.mhc_enabled = getattr(config, "mhc_enabled", False)
1087
+ if self.mhc_enabled:
1088
+ mhc_expansion_rate = config.mhc_expansion_rate
1089
+ # h_post = (1 + mhc_h_post_alpha_end) * sigmoid(...); motif3 alpha_end=0 -> 1.0.
1090
+ mhc_h_post_coeff = 1.0 + float(getattr(config, "mhc_h_post_alpha_end", 0.0))
1091
+ self.mhc_attn = MHCLayer(
1092
+ expansion_rate=mhc_expansion_rate,
1093
+ num_dim=config.hidden_size,
1094
+ identity_init=getattr(config, "mhc_identity_init", False),
1095
+ sinkhorn_iters=getattr(config, "mhc_sinkhorn_iters", 20),
1096
+ h_post_coeff=mhc_h_post_coeff,
1097
+ )
1098
+ self.mhc_ffn = MHCLayer(
1099
+ expansion_rate=mhc_expansion_rate,
1100
+ num_dim=config.hidden_size,
1101
+ identity_init=getattr(config, "mhc_identity_init", False),
1102
+ sinkhorn_iters=getattr(config, "mhc_sinkhorn_iters", 20),
1103
+ h_post_coeff=mhc_h_post_coeff,
1104
+ )
1105
+
1106
+ def forward(
1107
+ self,
1108
+ hidden_states: torch.Tensor,
1109
+ attention_mask: Optional[torch.Tensor] = None,
1110
+ position_ids: Optional[torch.LongTensor] = None,
1111
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
1112
+ output_attentions: Optional[bool] = False,
1113
+ use_cache: Optional[bool] = False,
1114
+ cache_position: Optional[torch.LongTensor] = None,
1115
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, # will become mandatory in v4.46
1116
+ **kwargs,
1117
+ ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
1118
+ """
1119
+ Args:
1120
+ hidden_states (`torch.FloatTensor`): input to the layer of shape `(batch, seq_len, embed_dim)`
1121
+ attention_mask (`torch.FloatTensor`, *optional*): attention mask of size
1122
+ `(batch, sequence_length)` where padding elements are indicated by 0.
1123
+ output_attentions (`bool`, *optional*):
1124
+ Whether or not to return the attentions tensors of all attention layers. See `attentions` under
1125
+ returned tensors for more detail.
1126
+ use_cache (`bool`, *optional*):
1127
+ If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
1128
+ (see `past_key_values`).
1129
+ past_key_value (`Tuple(torch.FloatTensor)`, *optional*): cached past key and value projection states
1130
+ cache_position (`torch.LongTensor` of shape `(sequence_length)`, *optional*):
1131
+ Indices depicting the position of the input sequence tokens in the sequence.
1132
+ position_embeddings (`Tuple[torch.FloatTensor, torch.FloatTensor]`, *optional*):
1133
+ Tuple containing the cosine and sine positional embeddings of shape `(batch_size, seq_len, head_dim)`,
1134
+ with `head_dim` being the embedding dimension of each attention head.
1135
+ kwargs (`dict`, *optional*):
1136
+ Arbitrary kwargs to be ignored, used for FSDP and other methods that injects code
1137
+ into the model
1138
+ """
1139
+
1140
+ if self.mhc_enabled:
1141
+ return self._forward_with_mhc(
1142
+ hidden_states,
1143
+ attention_mask=attention_mask,
1144
+ position_ids=position_ids,
1145
+ past_key_value=past_key_value,
1146
+ output_attentions=output_attentions,
1147
+ use_cache=use_cache,
1148
+ cache_position=cache_position,
1149
+ position_embeddings=position_embeddings,
1150
+ )
1151
+
1152
+ residual = hidden_states
1153
+
1154
+ hidden_states = self.input_layernorm(hidden_states)
1155
+
1156
+ # Self Attention
1157
+ hidden_states, self_attn_weights, present_key_value = self.self_attn(
1158
+ hidden_states=hidden_states,
1159
+ attention_mask=attention_mask,
1160
+ position_ids=position_ids,
1161
+ past_key_value=past_key_value,
1162
+ output_attentions=output_attentions,
1163
+ use_cache=use_cache,
1164
+ cache_position=cache_position,
1165
+ position_embeddings=position_embeddings,
1166
+ )
1167
+ hidden_states = residual + hidden_states
1168
+
1169
+ # Fully Connected
1170
+ residual = hidden_states
1171
+ hidden_states = self.post_attention_layernorm(hidden_states)
1172
+
1173
+ router_logits = None
1174
+ if self.moe_enabled:
1175
+ hidden_states, router_logits = self.moe(hidden_states)
1176
+ else:
1177
+ hidden_states = self.mlp(hidden_states)
1178
+ hidden_states = residual + hidden_states
1179
+
1180
+ outputs = (hidden_states,)
1181
+
1182
+ if output_attentions:
1183
+ outputs += (self_attn_weights,)
1184
+
1185
+ if use_cache:
1186
+ outputs += (present_key_value,)
1187
+
1188
+ outputs += (router_logits,)
1189
+
1190
+ return outputs
1191
+
1192
+ def _forward_with_mhc(
1193
+ self,
1194
+ hidden_states: torch.Tensor,
1195
+ attention_mask: Optional[torch.Tensor] = None,
1196
+ position_ids: Optional[torch.LongTensor] = None,
1197
+ past_key_value: Optional[Tuple[torch.Tensor]] = None,
1198
+ output_attentions: Optional[bool] = False,
1199
+ use_cache: Optional[bool] = False,
1200
+ cache_position: Optional[torch.LongTensor] = None,
1201
+ position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
1202
+ ) -> Tuple:
1203
+ """MHC residual path. hidden_states: (batch, seq_len, expansion_rate, dim)."""
1204
+ x = hidden_states
1205
+
1206
+ # === Attention sublayer with MHC ===
1207
+ h_pre_attn, h_post_attn, h_res_attn = self.mhc_attn(x)
1208
+
1209
+ # Reduce for attention input: (B, S, E, D) -> (B, S, D)
1210
+ x_reduced = MHCLayer.apply_h_pre(x, h_pre_attn)
1211
+
1212
+ attn_in = self.input_layernorm(x_reduced)
1213
+ attn_out, self_attn_weights, present_key_value = self.self_attn(
1214
+ hidden_states=attn_in,
1215
+ attention_mask=attention_mask,
1216
+ position_ids=position_ids,
1217
+ past_key_value=past_key_value,
1218
+ output_attentions=output_attentions,
1219
+ use_cache=use_cache,
1220
+ cache_position=cache_position,
1221
+ position_embeddings=position_embeddings,
1222
+ )
1223
+
1224
+ _res_attn = torch.einsum("bsij,bsjd->bsid", h_res_attn, x.float())
1225
+ _post_attn = h_post_attn.unsqueeze(-1) * attn_out.float().unsqueeze(2)
1226
+ h = (_res_attn + _post_attn).to(x.dtype)
1227
+
1228
+ # === FFN sublayer with MHC ===
1229
+ h_pre_ffn, h_post_ffn, h_res_ffn = self.mhc_ffn(h)
1230
+
1231
+ # Reduce for FFN input: (B, S, E, D) -> (B, S, D)
1232
+ h_reduced = MHCLayer.apply_h_pre(h, h_pre_ffn)
1233
+ n_out = self.post_attention_layernorm(h_reduced)
1234
+
1235
+ router_logits = None
1236
+ if self.moe_enabled:
1237
+ ffn_out, router_logits = self.moe(n_out)
1238
+ else:
1239
+ ffn_out = self.mlp(n_out)
1240
+
1241
+ # MHC FFN combine: out = H_res @ h + H_post * ffn_out, fp32 + single downcast.
1242
+ _res_ffn = torch.einsum("bsij,bsjd->bsid", h_res_ffn, h.float())
1243
+ _post_ffn = h_post_ffn.unsqueeze(-1) * ffn_out.float().unsqueeze(2)
1244
+ out = (_res_ffn + _post_ffn).to(h.dtype)
1245
+
1246
+ outputs = (out,)
1247
+
1248
+ if output_attentions:
1249
+ outputs += (self_attn_weights,)
1250
+
1251
+ if use_cache:
1252
+ outputs += (present_key_value,)
1253
+
1254
+ outputs += (router_logits,)
1255
+
1256
+ return outputs
1257
+
1258
+
1259
+ @auto_docstring
1260
+ class MotifPreTrainedModel(PreTrainedModel):
1261
+ config_class = MotifConfig
1262
+ base_model_prefix = "model"
1263
+ supports_gradient_checkpointing = True
1264
+ _no_split_modules = ["MotifDecoderLayer"]
1265
+ _skip_keys_device_placement = "past_key_values"
1266
+ _supports_flash_attn = True
1267
+ _supports_sdpa = True
1268
+ _supports_flex_attn = True
1269
+ _supports_attention_backend = True
1270
+ _supports_cache_class = True
1271
+ _supports_quantized_cache = True
1272
+ _supports_static_cache = True
1273
+
1274
+ def _init_weights(self, module):
1275
+ std = self.config.initializer_range
1276
+ if isinstance(module, nn.Linear):
1277
+ module.weight.data = torch.where(abs(module.weight.data) > 3 * std, 0, module.weight.data)
1278
+ if module.bias is not None:
1279
+ module.bias.data.zero_()
1280
+ elif isinstance(module, nn.Embedding):
1281
+ module.weight.data = torch.where(abs(module.weight.data) > 3 * std, 0, module.weight.data)
1282
+ if module.padding_idx is not None:
1283
+ module.weight.data[module.padding_idx].zero_()
1284
+ elif isinstance(module, MoE):
1285
+ module.init_weights(std, buffer_device=torch.device("cpu"))
1286
+
1287
+
1288
+ @auto_docstring
1289
+ class MotifModel(MotifPreTrainedModel):
1290
+ """
1291
+ Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`MotifDecoderLayer`]
1292
+
1293
+ Args:
1294
+ config: MotifConfig
1295
+ """
1296
+
1297
+ def __init__(self, config: MotifConfig):
1298
+ super().__init__(config)
1299
+ # Only flash_attention_2 supports GDLA's GQA + per-layer sliding window (see error).
1300
+ if getattr(config, "_attn_implementation", None) != "flash_attention_2":
1301
+ raise ValueError(
1302
+ "Motif requires attn_implementation='flash_attention_2' (got "
1303
+ f"{getattr(config, '_attn_implementation', None)!r}). The GDLA attention uses GQA "
1304
+ "and per-layer sliding-window attention, which the eager backend (no GQA KV repeat) "
1305
+ "and the sdpa backend (sliding-window mask mismatch past `sliding_window` tokens "
1306
+ "during decode) do not handle correctly yet. Please load with "
1307
+ "attn_implementation='flash_attention_2'."
1308
+ )
1309
+ self.padding_idx = getattr(config, "pad_token_id", None)
1310
+ self.vocab_size = config.vocab_size
1311
+
1312
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
1313
+ self.layers = nn.ModuleList(
1314
+ [MotifDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
1315
+ )
1316
+ self._attn_implementation = config._attn_implementation
1317
+ RMSNorm = kernelRMSNorm if kernelRMSNorm is not None else MotifRMSNorm
1318
+ self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1319
+ # GDLA applies RoPE only to qk_rope_head_dim dimensions
1320
+ rope_head_dim = (
1321
+ getattr(config, "qk_rope_head_dim", None) if getattr(config, "attention_cls", "basic") == "gdla" else None
1322
+ )
1323
+ self.rotary_emb = MotifRotaryEmbedding(config=config, rope_head_dim=rope_head_dim)
1324
+
1325
+ self.mhc_enabled = getattr(config, "mhc_enabled", False)
1326
+ self.mhc_expansion_rate = getattr(config, "mhc_expansion_rate", 4)
1327
+
1328
+ self.gradient_checkpointing = False
1329
+ # Initialize weights and apply final processing
1330
+ self.post_init()
1331
+
1332
+ def get_input_embeddings(self):
1333
+ return self.embed_tokens
1334
+
1335
+ def set_input_embeddings(self, value):
1336
+ self.embed_tokens = value
1337
+
1338
+ @can_return_tuple
1339
+ @auto_docstring
1340
+ def forward(
1341
+ self,
1342
+ input_ids: torch.LongTensor = None,
1343
+ attention_mask: Optional[torch.Tensor] = None,
1344
+ position_ids: Optional[torch.LongTensor] = None,
1345
+ past_key_values: Optional[Cache] = None,
1346
+ inputs_embeds: Optional[torch.FloatTensor] = None,
1347
+ use_cache: Optional[bool] = None,
1348
+ output_attentions: Optional[bool] = None,
1349
+ output_hidden_states: Optional[bool] = None,
1350
+ output_router_logits: Optional[bool] = None,
1351
+ return_dict: Optional[bool] = None,
1352
+ cache_position: Optional[torch.LongTensor] = None,
1353
+ ) -> MoeModelOutputWithPast:
1354
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1355
+ output_hidden_states = (
1356
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1357
+ )
1358
+ output_router_logits = (
1359
+ output_router_logits
1360
+ if output_router_logits is not None
1361
+ else getattr(self.config, "output_router_logits", False)
1362
+ )
1363
+ use_cache = use_cache if use_cache is not None else self.config.use_cache
1364
+
1365
+ if (input_ids is None) ^ (inputs_embeds is not None):
1366
+ raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
1367
+
1368
+ if self.gradient_checkpointing and self.training:
1369
+ if use_cache:
1370
+ logger.warning_once(
1371
+ "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`..."
1372
+ )
1373
+ use_cache = False
1374
+
1375
+ if use_cache and past_key_values is None:
1376
+ past_key_values = DynamicCache()
1377
+
1378
+ if inputs_embeds is None:
1379
+ inputs_embeds = self.embed_tokens(input_ids)
1380
+
1381
+ if cache_position is None:
1382
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
1383
+ cache_position = torch.arange(
1384
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
1385
+ )
1386
+ if position_ids is None:
1387
+ position_ids = cache_position.unsqueeze(0)
1388
+
1389
+ causal_mask = self._update_causal_mask(
1390
+ attention_mask, inputs_embeds, cache_position, past_key_values, output_attentions
1391
+ )
1392
+
1393
+ hidden_states = inputs_embeds
1394
+
1395
+ # Create position embeddings BEFORE MHC expansion (uses (B, S, D) for dtype/device)
1396
+ position_embeddings = self.rotary_emb(hidden_states, position_ids)
1397
+
1398
+ # Expand to (B, S, E, D) for MHC
1399
+ if self.mhc_enabled:
1400
+ hidden_states = hidden_states.unsqueeze(2).expand(-1, -1, self.mhc_expansion_rate, -1).contiguous()
1401
+
1402
+ # Decoder layers
1403
+ all_hidden_states = () if output_hidden_states else None
1404
+ all_self_attns = () if output_attentions else None
1405
+ all_router_logits = () if output_router_logits else None
1406
+ next_decoder_cache = None
1407
+
1408
+ for decoder_layer in self.layers:
1409
+ if output_hidden_states:
1410
+ all_hidden_states += (hidden_states,)
1411
+
1412
+ layer_outputs = decoder_layer(
1413
+ hidden_states,
1414
+ attention_mask=causal_mask,
1415
+ position_ids=position_ids,
1416
+ past_key_value=past_key_values,
1417
+ output_attentions=output_attentions,
1418
+ use_cache=use_cache,
1419
+ cache_position=cache_position,
1420
+ position_embeddings=position_embeddings,
1421
+ )
1422
+
1423
+ hidden_states = layer_outputs[0]
1424
+
1425
+ if use_cache:
1426
+ next_decoder_cache = layer_outputs[2 if output_attentions else 1]
1427
+
1428
+ if output_attentions:
1429
+ all_self_attns += (layer_outputs[1],)
1430
+
1431
+ # Router logits are always the last element
1432
+ if output_router_logits:
1433
+ all_router_logits += (layer_outputs[-1],)
1434
+
1435
+ # Reduce from (B, S, E, D) back to (B, S, D) for MHC
1436
+ if self.mhc_enabled:
1437
+ hidden_states = hidden_states.mean(dim=2)
1438
+
1439
+ hidden_states = self.norm(hidden_states)
1440
+
1441
+ # Add hidden states from the last decoder layer
1442
+ if output_hidden_states:
1443
+ all_hidden_states += (hidden_states,)
1444
+
1445
+ next_cache = next_decoder_cache if use_cache else None
1446
+
1447
+ return MoeModelOutputWithPast(
1448
+ last_hidden_state=hidden_states,
1449
+ past_key_values=next_cache,
1450
+ hidden_states=all_hidden_states,
1451
+ attentions=all_self_attns,
1452
+ router_logits=all_router_logits,
1453
+ )
1454
+
1455
+ def _update_causal_mask(
1456
+ self,
1457
+ attention_mask: torch.Tensor,
1458
+ input_tensor: torch.Tensor,
1459
+ cache_position: torch.Tensor,
1460
+ past_key_values: Cache,
1461
+ output_attentions: bool,
1462
+ ):
1463
+ if self.config._attn_implementation == "flash_attention_2":
1464
+ if attention_mask is not None and 0.0 in attention_mask:
1465
+ return attention_mask
1466
+ return None
1467
+
1468
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
1469
+ using_static_cache = isinstance(past_key_values, StaticCache)
1470
+
1471
+ # When output attentions is True, sdpa implementation's forward method calls the eager implementation's forward
1472
+ if self.config._attn_implementation == "sdpa" and not using_static_cache and not output_attentions:
1473
+ if AttentionMaskConverter._ignore_causal_mask_sdpa(
1474
+ attention_mask,
1475
+ inputs_embeds=input_tensor,
1476
+ past_key_values_length=past_seen_tokens,
1477
+ sliding_window=self.config.sliding_window,
1478
+ is_training=self.training,
1479
+ ):
1480
+ return None
1481
+
1482
+ dtype, device = input_tensor.dtype, input_tensor.device
1483
+ min_dtype = torch.finfo(dtype).min
1484
+ sequence_length = input_tensor.shape[1]
1485
+ # StaticCache
1486
+ if using_static_cache:
1487
+ target_length = past_key_values.get_max_cache_shape()
1488
+ # DynamicCache or no cache
1489
+ else:
1490
+ target_length = (
1491
+ attention_mask.shape[-1]
1492
+ if isinstance(attention_mask, torch.Tensor)
1493
+ else past_seen_tokens + sequence_length
1494
+ )
1495
+
1496
+ # In case the provided `attention` mask is 2D, we generate a causal mask here (4D).
1497
+ causal_mask = self._prepare_4d_causal_attention_mask_with_cache_position(
1498
+ attention_mask,
1499
+ sequence_length=sequence_length,
1500
+ target_length=target_length,
1501
+ dtype=dtype,
1502
+ device=device,
1503
+ cache_position=cache_position,
1504
+ batch_size=input_tensor.shape[0],
1505
+ config=self.config,
1506
+ past_key_values=past_key_values,
1507
+ )
1508
+
1509
+ if (
1510
+ self.config._attn_implementation == "sdpa"
1511
+ and attention_mask is not None
1512
+ and attention_mask.device.type == "cuda"
1513
+ and not output_attentions
1514
+ ):
1515
+ causal_mask = AttentionMaskConverter._unmask_unattended(causal_mask, min_dtype)
1516
+
1517
+ return causal_mask
1518
+
1519
+ @staticmethod
1520
+ def _prepare_4d_causal_attention_mask_with_cache_position(
1521
+ attention_mask: torch.Tensor,
1522
+ sequence_length: int,
1523
+ target_length: int,
1524
+ dtype: torch.dtype,
1525
+ device: torch.device,
1526
+ cache_position: torch.Tensor,
1527
+ batch_size: int,
1528
+ config: MotifConfig,
1529
+ past_key_values: Cache,
1530
+ ):
1531
+ """
1532
+ Creates a causal 4D mask of shape `(batch_size, 1, query_length, key_value_length)` from a 2D mask of shape
1533
+ `(batch_size, key_value_length)`, or if the input `attention_mask` is already 4D, do nothing.
1534
+
1535
+ Args:
1536
+ attention_mask (`torch.Tensor`):
1537
+ A 2D attention mask of shape `(batch_size, key_value_length)` or a 4D attention mask of shape `(batch_size, 1, query_length, key_value_length)`.
1538
+ sequence_length (`int`):
1539
+ The sequence length being processed.
1540
+ target_length (`int`):
1541
+ The target length: when generating with static cache, the mask should be as long as the static cache, to account for the 0 padding, the part of the cache that is not filled yet.
1542
+ dtype (`torch.dtype`):
1543
+ The dtype to use for the 4D attention mask.
1544
+ device (`torch.device`):
1545
+ The device to plcae the 4D attention mask on.
1546
+ cache_position (`torch.Tensor`):
1547
+ Indices depicting the position of the input sequence tokens in the sequence.
1548
+ batch_size (`torch.Tensor`):
1549
+ Batch size.
1550
+ config (`MotifConfig`):
1551
+ The model's configuration class
1552
+ past_key_values (`Cache`):
1553
+ The cache class that is being used currently to generate
1554
+ """
1555
+ if attention_mask is not None and attention_mask.dim() == 4:
1556
+ # In this case we assume that the mask comes already in inverted form and requires no inversion or slicing.
1557
+ causal_mask = attention_mask
1558
+ else:
1559
+ min_dtype = torch.finfo(dtype).min
1560
+ causal_mask = torch.full(
1561
+ (sequence_length, target_length), fill_value=min_dtype, dtype=dtype, device=cache_position.device
1562
+ )
1563
+ diagonal_attend_mask = torch.arange(target_length, device=cache_position.device) > cache_position.reshape(
1564
+ -1, 1
1565
+ )
1566
+ if config.sliding_window is not None:
1567
+ if sequence_length > target_length:
1568
+ sliding_attend_mask = torch.arange(target_length, device=device) <= (
1569
+ cache_position.reshape(-1, 1) - config.sliding_window
1570
+ )
1571
+ diagonal_attend_mask.bitwise_or_(sliding_attend_mask)
1572
+ causal_mask *= diagonal_attend_mask
1573
+ causal_mask = causal_mask[None, None, :, :].expand(batch_size, 1, -1, -1)
1574
+ if attention_mask is not None:
1575
+ causal_mask = causal_mask.clone() # copy to contiguous memory for in-place edit
1576
+ if attention_mask.shape[-1] > target_length:
1577
+ attention_mask = attention_mask[:, :target_length]
1578
+ mask_length = attention_mask.shape[-1]
1579
+ padding_mask = causal_mask[:, :, :, :mask_length] + attention_mask[:, None, None, :]
1580
+ padding_mask = padding_mask == 0
1581
+ causal_mask[:, :, :, :mask_length] = causal_mask[:, :, :, :mask_length].masked_fill(
1582
+ padding_mask, min_dtype
1583
+ )
1584
+ return causal_mask
1585
+
1586
+
1587
+ class MotifForCausalLM(MotifPreTrainedModel, GenerationMixin):
1588
+ _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
1589
+ _tp_plan = {"lm_head": "colwise_gather_output"}
1590
+ _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
1591
+
1592
+ def __init__(self, config):
1593
+ super().__init__(config)
1594
+ self.model = MotifModel(config)
1595
+ self.vocab_size = config.vocab_size
1596
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
1597
+
1598
+ # Initialize weights and apply final processing
1599
+ self.post_init()
1600
+
1601
+ if config.tie_word_embeddings:
1602
+ self.tie_weights()
1603
+
1604
+ def get_input_embeddings(self):
1605
+ return self.model.embed_tokens
1606
+
1607
+ def set_input_embeddings(self, value):
1608
+ self.model.embed_tokens = value
1609
+
1610
+ def get_output_embeddings(self):
1611
+ return self.lm_head
1612
+
1613
+ def set_output_embeddings(self, new_embeddings):
1614
+ self.lm_head = new_embeddings
1615
+
1616
+ def set_decoder(self, decoder):
1617
+ self.model = decoder
1618
+
1619
+ def get_decoder(self):
1620
+ return self.model
1621
+
1622
+ @can_return_tuple
1623
+ @auto_docstring
1624
+ def forward(
1625
+ self,
1626
+ input_ids: torch.LongTensor = None,
1627
+ attention_mask: Optional[torch.Tensor] = None,
1628
+ position_ids: Optional[torch.LongTensor] = None,
1629
+ past_key_values: Optional[Cache] = None,
1630
+ inputs_embeds: Optional[torch.FloatTensor] = None,
1631
+ labels: Optional[torch.LongTensor] = None,
1632
+ use_cache: Optional[bool] = None,
1633
+ output_attentions: Optional[bool] = None,
1634
+ output_hidden_states: Optional[bool] = None,
1635
+ output_router_logits: Optional[bool] = None,
1636
+ return_dict: Optional[bool] = None,
1637
+ cache_position: Optional[torch.LongTensor] = None,
1638
+ logits_to_keep: int = 0,
1639
+ **kwargs,
1640
+ ) -> MoeCausalLMOutputWithPast:
1641
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
1642
+ output_hidden_states = (
1643
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
1644
+ )
1645
+ output_router_logits = (
1646
+ output_router_logits
1647
+ if output_router_logits is not None
1648
+ else getattr(self.config, "output_router_logits", False)
1649
+ )
1650
+
1651
+ # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
1652
+ outputs = self.model(
1653
+ input_ids=input_ids,
1654
+ attention_mask=attention_mask,
1655
+ position_ids=position_ids,
1656
+ past_key_values=past_key_values,
1657
+ inputs_embeds=inputs_embeds,
1658
+ use_cache=use_cache,
1659
+ output_attentions=output_attentions,
1660
+ output_hidden_states=output_hidden_states,
1661
+ output_router_logits=output_router_logits,
1662
+ cache_position=cache_position,
1663
+ )
1664
+
1665
+ hidden_states = outputs[0]
1666
+ # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
1667
+ logits = self.lm_head(hidden_states[:, -logits_to_keep:, :])
1668
+ logits = logits.float()
1669
+
1670
+ loss = None
1671
+ if labels is not None:
1672
+ # Shift so that tokens < n predict n
1673
+ shift_logits = logits[..., :-1, :].contiguous()
1674
+ shift_labels = labels[..., 1:].contiguous()
1675
+ # Flatten the tokens
1676
+ loss_fct = CrossEntropyLoss()
1677
+ shift_logits = shift_logits.view(-1, self.config.vocab_size)
1678
+ shift_labels = shift_labels.view(-1)
1679
+ # Enable model parallelism
1680
+ shift_labels = shift_labels.to(shift_logits.device)
1681
+ loss = loss_fct(shift_logits, shift_labels)
1682
+
1683
+ return MoeCausalLMOutputWithPast(
1684
+ loss=loss,
1685
+ logits=logits,
1686
+ past_key_values=outputs.past_key_values,
1687
+ hidden_states=outputs.hidden_states,
1688
+ attentions=outputs.attentions,
1689
+ router_logits=outputs.router_logits,
1690
+ )