Banaxi-Tech commited on
Commit
bd0ade7
·
verified ·
1 Parent(s): 5c6eb2b

Publish sequence-routed SLMoE architecture

Browse files
Files changed (2) hide show
  1. configuration_slmoe.py +126 -0
  2. modeling_slmoe.py +506 -0
configuration_slmoe.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Configuration for the sequence-routed SLMoE causal language model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+
7
+ from transformers import PretrainedConfig
8
+
9
+
10
+ class SLMoEConfig(PretrainedConfig):
11
+ model_type = "slmoe"
12
+ keys_to_ignore_at_inference = ["router_aux_loss", "router_z_loss"]
13
+
14
+ def __init__(
15
+ self,
16
+ vocab_size: int = 8192,
17
+ hidden_size: int = 256,
18
+ num_hidden_layers: int = 8,
19
+ num_attention_heads: int = 8,
20
+ num_key_value_heads: int = 2,
21
+ head_dim: int = 32,
22
+ num_experts: int = 64,
23
+ num_experts_per_sequence: int = 13,
24
+ expert_intermediate_size: int = 56,
25
+ router_prefix_length: int = 32,
26
+ router_jitter_noise: float = 0.01,
27
+ router_aux_loss_coeff: float = 0.01,
28
+ router_z_loss_coeff: float = 1e-3,
29
+ expert_output_scale: float | None = None,
30
+ max_position_embeddings: int = 4096,
31
+ rope_theta: float = 100000.0,
32
+ rms_norm_eps: float = 1e-6,
33
+ initializer_range: float = 0.02,
34
+ tie_word_embeddings: bool = True,
35
+ use_cache: bool = True,
36
+ bos_token_id: int = 1,
37
+ eos_token_id: int = 2,
38
+ pad_token_id: int = 0,
39
+ unk_token_id: int = 3,
40
+ **kwargs,
41
+ ):
42
+ if hidden_size != num_attention_heads * head_dim:
43
+ raise ValueError("hidden_size must equal num_attention_heads * head_dim")
44
+ if num_attention_heads % num_key_value_heads:
45
+ raise ValueError("num_attention_heads must be divisible by num_key_value_heads")
46
+ if not 0 < num_experts_per_sequence <= num_experts:
47
+ raise ValueError("num_experts_per_sequence must be in [1, num_experts]")
48
+ if router_prefix_length < 1:
49
+ raise ValueError("router_prefix_length must be positive")
50
+
51
+ self.vocab_size = vocab_size
52
+ self.hidden_size = hidden_size
53
+ self.num_hidden_layers = num_hidden_layers
54
+ self.num_attention_heads = num_attention_heads
55
+ self.num_key_value_heads = num_key_value_heads
56
+ self.head_dim = head_dim
57
+ self.num_experts = num_experts
58
+ self.num_experts_per_sequence = num_experts_per_sequence
59
+ self.expert_intermediate_size = expert_intermediate_size
60
+ self.router_prefix_length = router_prefix_length
61
+ self.router_jitter_noise = router_jitter_noise
62
+ self.router_aux_loss_coeff = router_aux_loss_coeff
63
+ self.router_z_loss_coeff = router_z_loss_coeff
64
+ self.expert_output_scale = (
65
+ math.sqrt(num_experts_per_sequence)
66
+ if expert_output_scale is None
67
+ else expert_output_scale
68
+ )
69
+ self.max_position_embeddings = max_position_embeddings
70
+ self.rope_theta = rope_theta
71
+ self.rms_norm_eps = rms_norm_eps
72
+ self.initializer_range = initializer_range
73
+ self.use_cache = use_cache
74
+ super().__init__(
75
+ tie_word_embeddings=tie_word_embeddings,
76
+ bos_token_id=bos_token_id,
77
+ eos_token_id=eos_token_id,
78
+ pad_token_id=pad_token_id,
79
+ unk_token_id=unk_token_id,
80
+ **kwargs,
81
+ )
82
+
83
+ def parameter_counts(self) -> dict[str, int]:
84
+ """Return analytical total and single-sequence active parameter counts."""
85
+ hidden = self.hidden_size
86
+ query_width = self.num_attention_heads * self.head_dim
87
+ kv_width = self.num_key_value_heads * self.head_dim
88
+ embeddings = self.vocab_size * hidden
89
+ attention = (
90
+ hidden * query_width
91
+ + 2 * hidden * kv_width
92
+ + query_width * hidden
93
+ )
94
+ attention_norms = 2 * self.head_dim
95
+ block_norms = 2 * hidden
96
+ one_expert = 3 * hidden * self.expert_intermediate_size
97
+ all_experts = self.num_experts * one_expert
98
+ active_experts = self.num_experts_per_sequence * one_expert
99
+ router = hidden + hidden * self.num_experts
100
+ final_norm = hidden
101
+ output_head = 0 if self.tie_word_embeddings else embeddings
102
+ shared_per_layer = attention + attention_norms + block_norms
103
+ total = (
104
+ embeddings
105
+ + self.num_hidden_layers * (shared_per_layer + all_experts)
106
+ + router
107
+ + final_norm
108
+ + output_head
109
+ )
110
+ active = (
111
+ embeddings
112
+ + self.num_hidden_layers * (shared_per_layer + active_experts)
113
+ + router
114
+ + final_norm
115
+ + output_head
116
+ )
117
+ return {
118
+ "total": total,
119
+ "active_per_sequence": active,
120
+ "one_expert_path": self.num_hidden_layers * one_expert,
121
+ }
122
+
123
+
124
+ SLMoEConfig.register_for_auto_class("AutoConfig")
125
+
126
+ __all__ = ["SLMoEConfig"]
modeling_slmoe.py ADDED
@@ -0,0 +1,506 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Sequence-routed mixture-of-experts causal language model."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ from dataclasses import dataclass
7
+ from typing import Optional
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from transformers import PreTrainedModel
13
+ from transformers.cache_utils import Cache, DynamicCache
14
+ from transformers.generation.utils import GenerationMixin
15
+ from transformers.utils import ModelOutput
16
+
17
+ try:
18
+ from .configuration_slmoe import SLMoEConfig
19
+ except ImportError: # Allows the standalone training script to import local code.
20
+ from configuration_slmoe import SLMoEConfig
21
+
22
+
23
+ @dataclass
24
+ class SLMoECausalLMOutputWithPast(ModelOutput):
25
+ loss: Optional[torch.Tensor] = None
26
+ logits: Optional[torch.Tensor] = None
27
+ past_key_values: Optional[Cache] = None
28
+ router_aux_loss: Optional[torch.Tensor] = None
29
+ router_z_loss: Optional[torch.Tensor] = None
30
+ expert_indices: Optional[torch.LongTensor] = None
31
+ expert_weights: Optional[torch.Tensor] = None
32
+
33
+
34
+ class SLMoERMSNorm(nn.Module):
35
+ def __init__(self, dim: int, eps: float = 1e-6):
36
+ super().__init__()
37
+ self.eps = eps
38
+ self.weight = nn.Parameter(torch.ones(dim))
39
+
40
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
41
+ states = hidden_states.float()
42
+ states = states * torch.rsqrt(states.square().mean(-1, keepdim=True) + self.eps)
43
+ return (states * self.weight.float()).to(hidden_states.dtype)
44
+
45
+
46
+ def _rope_cos_sin(
47
+ head_dim: int,
48
+ positions: torch.Tensor,
49
+ theta: float,
50
+ ) -> tuple[torch.Tensor, torch.Tensor]:
51
+ inv_freq = 1.0 / (
52
+ theta
53
+ ** (
54
+ torch.arange(0, head_dim, 2, dtype=torch.float32, device=positions.device)
55
+ / head_dim
56
+ )
57
+ )
58
+ frequencies = torch.outer(positions.float(), inv_freq)
59
+ return frequencies.cos(), frequencies.sin()
60
+
61
+
62
+ def _apply_rope(
63
+ query: torch.Tensor,
64
+ key: torch.Tensor,
65
+ cosine: torch.Tensor,
66
+ sine: torch.Tensor,
67
+ ) -> tuple[torch.Tensor, torch.Tensor]:
68
+ query_dtype = query.dtype
69
+ key_dtype = key.dtype
70
+ cosine = cosine[None, None, :, :]
71
+ sine = sine[None, None, :, :]
72
+ query_pairs = query.float().reshape(*query.shape[:-1], -1, 2)
73
+ key_pairs = key.float().reshape(*key.shape[:-1], -1, 2)
74
+ query_even, query_odd = query_pairs.unbind(-1)
75
+ key_even, key_odd = key_pairs.unbind(-1)
76
+ query = torch.stack(
77
+ (query_even * cosine - query_odd * sine, query_even * sine + query_odd * cosine),
78
+ dim=-1,
79
+ ).flatten(-2)
80
+ key = torch.stack(
81
+ (key_even * cosine - key_odd * sine, key_even * sine + key_odd * cosine),
82
+ dim=-1,
83
+ ).flatten(-2)
84
+ return query.to(query_dtype), key.to(key_dtype)
85
+
86
+
87
+ class SLMoECache(DynamicCache):
88
+ """K/V cache carrying the one routing decision for the whole response."""
89
+
90
+ def __init__(self, config: SLMoEConfig):
91
+ try:
92
+ super().__init__(config=config)
93
+ except TypeError:
94
+ super().__init__()
95
+ self.expert_indices: torch.LongTensor | None = None
96
+ self.expert_weights: torch.Tensor | None = None
97
+
98
+ def set_routing(
99
+ self,
100
+ expert_indices: torch.LongTensor,
101
+ expert_weights: torch.Tensor,
102
+ ) -> None:
103
+ if self.expert_indices is not None:
104
+ raise RuntimeError("The sequence routing plan may only be set once")
105
+ self.expert_indices = expert_indices
106
+ self.expert_weights = expert_weights
107
+
108
+ def reorder_cache(self, beam_idx: torch.LongTensor):
109
+ super().reorder_cache(beam_idx)
110
+ if self.expert_indices is not None:
111
+ beam_idx = beam_idx.to(self.expert_indices.device)
112
+ self.expert_indices = self.expert_indices.index_select(0, beam_idx)
113
+ self.expert_weights = self.expert_weights.index_select(0, beam_idx)
114
+
115
+ def batch_repeat_interleave(self, repeats: int):
116
+ super().batch_repeat_interleave(repeats)
117
+ if self.expert_indices is not None:
118
+ self.expert_indices = self.expert_indices.repeat_interleave(repeats, dim=0)
119
+ self.expert_weights = self.expert_weights.repeat_interleave(repeats, dim=0)
120
+
121
+ def batch_select_indices(self, indices: torch.Tensor):
122
+ super().batch_select_indices(indices)
123
+ if self.expert_indices is not None:
124
+ indices = indices.to(self.expert_indices.device)
125
+ self.expert_indices = self.expert_indices.index_select(0, indices)
126
+ self.expert_weights = self.expert_weights.index_select(0, indices)
127
+
128
+
129
+ class SLMoEAttention(nn.Module):
130
+ def __init__(self, config: SLMoEConfig, layer_idx: int):
131
+ super().__init__()
132
+ self.layer_idx = layer_idx
133
+ self.num_heads = config.num_attention_heads
134
+ self.num_kv_heads = config.num_key_value_heads
135
+ self.head_dim = config.head_dim
136
+ self.num_kv_groups = self.num_heads // self.num_kv_heads
137
+ self.q_proj = nn.Linear(config.hidden_size, self.num_heads * self.head_dim, bias=False)
138
+ self.k_proj = nn.Linear(config.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
139
+ self.v_proj = nn.Linear(config.hidden_size, self.num_kv_heads * self.head_dim, bias=False)
140
+ self.o_proj = nn.Linear(self.num_heads * self.head_dim, config.hidden_size, bias=False)
141
+ self.o_proj.SLMOE_SCALE_INIT = True
142
+ self.q_norm = SLMoERMSNorm(self.head_dim, config.rms_norm_eps)
143
+ self.k_norm = SLMoERMSNorm(self.head_dim, config.rms_norm_eps)
144
+
145
+ def forward(
146
+ self,
147
+ hidden_states: torch.Tensor,
148
+ cosine: torch.Tensor,
149
+ sine: torch.Tensor,
150
+ attention_mask: torch.Tensor | None = None,
151
+ past_key_values: Cache | None = None,
152
+ ) -> torch.Tensor:
153
+ batch_size, query_length, _ = hidden_states.shape
154
+ query = self.q_proj(hidden_states).view(
155
+ batch_size, query_length, self.num_heads, self.head_dim
156
+ ).transpose(1, 2)
157
+ key = self.k_proj(hidden_states).view(
158
+ batch_size, query_length, self.num_kv_heads, self.head_dim
159
+ ).transpose(1, 2)
160
+ value = self.v_proj(hidden_states).view(
161
+ batch_size, query_length, self.num_kv_heads, self.head_dim
162
+ ).transpose(1, 2)
163
+ query = self.q_norm(query)
164
+ key = self.k_norm(key)
165
+ query, key = _apply_rope(query, key, cosine, sine)
166
+
167
+ past_length = 0
168
+ if past_key_values is not None:
169
+ past_length = past_key_values.get_seq_length(self.layer_idx)
170
+ key, value = past_key_values.update(key, value, self.layer_idx)
171
+
172
+ key_length = key.size(-2)
173
+ key = key.repeat_interleave(self.num_kv_groups, dim=1)
174
+ value = value.repeat_interleave(self.num_kv_groups, dim=1)
175
+ is_causal = query_length > 1 and past_length == 0 and attention_mask is None
176
+ sdpa_mask = None
177
+ if not is_causal and query_length > 1:
178
+ query_positions = past_length + torch.arange(query_length, device=query.device)
179
+ key_positions = torch.arange(key_length, device=query.device)
180
+ sdpa_mask = (key_positions[None, :] <= query_positions[:, None])[None, None]
181
+ if attention_mask is not None:
182
+ key_padding = attention_mask.to(torch.bool)
183
+ if key_padding.size(-1) < key_length:
184
+ key_padding = F.pad(key_padding, (key_length - key_padding.size(-1), 0), value=True)
185
+ else:
186
+ key_padding = key_padding[:, -key_length:]
187
+ key_padding = key_padding[:, None, None, :]
188
+ sdpa_mask = key_padding if sdpa_mask is None else sdpa_mask & key_padding
189
+ is_causal = False
190
+
191
+ output = F.scaled_dot_product_attention(
192
+ query,
193
+ key,
194
+ value,
195
+ attn_mask=sdpa_mask,
196
+ is_causal=is_causal,
197
+ )
198
+ output = output.transpose(1, 2).contiguous().view(
199
+ batch_size, query_length, self.num_heads * self.head_dim
200
+ )
201
+ return self.o_proj(output)
202
+
203
+
204
+ class SLMoESequenceRouter(nn.Module):
205
+ """Choose one fixed expert set from a causal prefix of each sequence."""
206
+
207
+ def __init__(self, config: SLMoEConfig):
208
+ super().__init__()
209
+ self.num_experts = config.num_experts
210
+ self.top_k = config.num_experts_per_sequence
211
+ self.prefix_length = config.router_prefix_length
212
+ self.jitter_noise = config.router_jitter_noise
213
+ self.norm = SLMoERMSNorm(config.hidden_size, config.rms_norm_eps)
214
+ self.proj = nn.Linear(config.hidden_size, config.num_experts, bias=False)
215
+
216
+ def prefix_mask(
217
+ self,
218
+ token_embeddings: torch.Tensor,
219
+ attention_mask: torch.Tensor | None,
220
+ ) -> torch.Tensor:
221
+ batch_size, sequence_length, _ = token_embeddings.shape
222
+ if attention_mask is None:
223
+ positions = torch.arange(sequence_length, device=token_embeddings.device)
224
+ return (positions < self.prefix_length).expand(batch_size, -1)
225
+ valid = attention_mask[:, -sequence_length:].to(torch.bool)
226
+ valid_order = valid.long().cumsum(dim=-1)
227
+ return valid & (valid_order <= self.prefix_length)
228
+
229
+ def forward(
230
+ self,
231
+ token_embeddings: torch.Tensor,
232
+ attention_mask: torch.Tensor | None,
233
+ ) -> tuple[torch.LongTensor, torch.Tensor, torch.Tensor, torch.Tensor]:
234
+ prefix_mask = self.prefix_mask(token_embeddings, attention_mask)
235
+ normalized = self.norm(token_embeddings)
236
+ mask = prefix_mask.unsqueeze(-1).to(normalized.dtype)
237
+ pooled = (normalized * mask).sum(dim=1) / mask.sum(dim=1).clamp_min(1.0)
238
+ if self.training and self.jitter_noise > 0:
239
+ pooled = pooled * torch.empty_like(pooled).uniform_(
240
+ 1.0 - self.jitter_noise,
241
+ 1.0 + self.jitter_noise,
242
+ )
243
+ router_logits = self.proj(pooled).float()
244
+ router_probs = F.softmax(router_logits, dim=-1, dtype=torch.float32)
245
+ top_probs, expert_indices = torch.topk(
246
+ router_probs,
247
+ k=self.top_k,
248
+ dim=-1,
249
+ sorted=True,
250
+ )
251
+ expert_weights = top_probs / top_probs.sum(dim=-1, keepdim=True).clamp_min(1e-9)
252
+
253
+ selected_fraction = F.one_hot(
254
+ expert_indices,
255
+ num_classes=self.num_experts,
256
+ ).float().mean(dim=(0, 1))
257
+ probability_fraction = router_probs.mean(dim=0)
258
+ auxiliary_loss = self.num_experts * torch.sum(
259
+ selected_fraction * probability_fraction
260
+ )
261
+ router_z_loss = torch.logsumexp(router_logits, dim=-1).square().mean()
262
+ return expert_indices, expert_weights, auxiliary_loss, router_z_loss
263
+
264
+
265
+ class SLMoEExpertBank(nn.Module):
266
+ """Batched expert weights; only the sequence-selected slices are evaluated."""
267
+
268
+ def __init__(self, config: SLMoEConfig):
269
+ super().__init__()
270
+ experts = config.num_experts
271
+ hidden = config.hidden_size
272
+ intermediate = config.expert_intermediate_size
273
+ self.output_scale = config.expert_output_scale
274
+ self.gate_weight = nn.Parameter(torch.empty(experts, intermediate, hidden))
275
+ self.up_weight = nn.Parameter(torch.empty(experts, intermediate, hidden))
276
+ self.down_weight = nn.Parameter(torch.empty(experts, hidden, intermediate))
277
+ nn.init.normal_(self.gate_weight, mean=0.0, std=config.initializer_range)
278
+ nn.init.normal_(self.up_weight, mean=0.0, std=config.initializer_range)
279
+ down_std = config.initializer_range * (2 * config.num_hidden_layers) ** -0.5
280
+ nn.init.normal_(self.down_weight, mean=0.0, std=down_std)
281
+
282
+ def forward(
283
+ self,
284
+ hidden_states: torch.Tensor,
285
+ expert_indices: torch.LongTensor,
286
+ expert_weights: torch.Tensor,
287
+ ) -> torch.Tensor:
288
+ gate_weight = self.gate_weight[expert_indices]
289
+ up_weight = self.up_weight[expert_indices]
290
+ down_weight = self.down_weight[expert_indices]
291
+ gate = torch.einsum("bsh,bkih->bski", hidden_states, gate_weight)
292
+ up = torch.einsum("bsh,bkih->bski", hidden_states, up_weight)
293
+ activated = F.silu(gate) * up
294
+ activated = activated * expert_weights[:, None, :, None].to(activated.dtype)
295
+ output = torch.einsum("bski,bkhi->bsh", activated, down_weight)
296
+ return output * self.output_scale
297
+
298
+
299
+ class SLMoEBlock(nn.Module):
300
+ def __init__(self, config: SLMoEConfig, layer_idx: int):
301
+ super().__init__()
302
+ self.input_norm = SLMoERMSNorm(config.hidden_size, config.rms_norm_eps)
303
+ self.attention = SLMoEAttention(config, layer_idx)
304
+ self.post_attention_norm = SLMoERMSNorm(config.hidden_size, config.rms_norm_eps)
305
+ self.experts = SLMoEExpertBank(config)
306
+
307
+ def forward(
308
+ self,
309
+ hidden_states: torch.Tensor,
310
+ cosine: torch.Tensor,
311
+ sine: torch.Tensor,
312
+ expert_indices: torch.LongTensor,
313
+ expert_weights: torch.Tensor,
314
+ attention_mask: torch.Tensor | None,
315
+ past_key_values: Cache | None,
316
+ ) -> torch.Tensor:
317
+ hidden_states = hidden_states + self.attention(
318
+ self.input_norm(hidden_states),
319
+ cosine,
320
+ sine,
321
+ attention_mask=attention_mask,
322
+ past_key_values=past_key_values,
323
+ )
324
+ return hidden_states + self.experts(
325
+ self.post_attention_norm(hidden_states),
326
+ expert_indices,
327
+ expert_weights,
328
+ )
329
+
330
+
331
+ class SLMoEPreTrainedModel(PreTrainedModel):
332
+ config_class = SLMoEConfig
333
+ base_model_prefix = "transformer"
334
+ supports_gradient_checkpointing = False
335
+ _no_split_modules = ["SLMoEBlock"]
336
+ _supports_sdpa = True
337
+ _supports_cache_class = True
338
+
339
+ def _init_weights(self, module: nn.Module):
340
+ std = self.config.initializer_range
341
+ if hasattr(module, "SLMOE_SCALE_INIT"):
342
+ std *= (2 * self.config.num_hidden_layers) ** -0.5
343
+ if isinstance(module, nn.Linear):
344
+ nn.init.normal_(module.weight, mean=0.0, std=std)
345
+ elif isinstance(module, nn.Embedding):
346
+ nn.init.normal_(module.weight, mean=0.0, std=std)
347
+
348
+
349
+ class SLMoEForCausalLM(SLMoEPreTrainedModel, GenerationMixin):
350
+ _tied_weights_keys = {"lm_head.weight": "transformer.wte.weight"}
351
+
352
+ @classmethod
353
+ def _supports_default_dynamic_cache(cls) -> bool:
354
+ return False
355
+
356
+ def __init__(self, config: SLMoEConfig):
357
+ super().__init__(config)
358
+ self.router = SLMoESequenceRouter(config)
359
+ self.transformer = nn.ModuleDict(
360
+ {
361
+ "wte": nn.Embedding(config.vocab_size, config.hidden_size),
362
+ "h": nn.ModuleList(
363
+ [SLMoEBlock(config, index) for index in range(config.num_hidden_layers)]
364
+ ),
365
+ "ln_f": SLMoERMSNorm(config.hidden_size, config.rms_norm_eps),
366
+ }
367
+ )
368
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
369
+ self.embedding_scale = math.sqrt(config.hidden_size)
370
+ self.post_init()
371
+ if config.tie_word_embeddings:
372
+ self.tie_weights()
373
+
374
+ def get_input_embeddings(self):
375
+ return self.transformer["wte"]
376
+
377
+ def set_input_embeddings(self, value):
378
+ self.transformer["wte"] = value
379
+
380
+ def get_output_embeddings(self):
381
+ return self.lm_head
382
+
383
+ def set_output_embeddings(self, value):
384
+ self.lm_head = value
385
+
386
+ def _route(
387
+ self,
388
+ token_embeddings: torch.Tensor,
389
+ attention_mask: torch.Tensor | None,
390
+ past_key_values: SLMoECache | None,
391
+ ) -> tuple[torch.LongTensor, torch.Tensor, torch.Tensor, torch.Tensor]:
392
+ if past_key_values is not None and past_key_values.expert_indices is not None:
393
+ zero = token_embeddings.new_zeros((), dtype=torch.float32)
394
+ return (
395
+ past_key_values.expert_indices,
396
+ past_key_values.expert_weights,
397
+ zero,
398
+ zero,
399
+ )
400
+ expert_indices, expert_weights, auxiliary_loss, router_z_loss = self.router(
401
+ token_embeddings,
402
+ attention_mask,
403
+ )
404
+ if past_key_values is not None:
405
+ past_key_values.set_routing(expert_indices, expert_weights)
406
+ return expert_indices, expert_weights, auxiliary_loss, router_z_loss
407
+
408
+ def forward(
409
+ self,
410
+ input_ids: torch.LongTensor,
411
+ attention_mask: Optional[torch.Tensor] = None,
412
+ labels: Optional[torch.LongTensor] = None,
413
+ past_key_values: Optional[Cache] = None,
414
+ use_cache: Optional[bool] = None,
415
+ **kwargs,
416
+ ) -> SLMoECausalLMOutputWithPast:
417
+ if use_cache is None:
418
+ use_cache = self.config.use_cache and labels is None
419
+ if use_cache and past_key_values is None:
420
+ past_key_values = SLMoECache(self.config)
421
+ if use_cache and not isinstance(past_key_values, SLMoECache):
422
+ raise TypeError("SLMoE requires SLMoECache to preserve sequence routing")
423
+ if not use_cache:
424
+ past_key_values = None
425
+
426
+ past_length = past_key_values.get_seq_length() if past_key_values is not None else 0
427
+ sequence_length = input_ids.size(1)
428
+ total_length = past_length + sequence_length
429
+ if total_length > self.config.max_position_embeddings:
430
+ raise ValueError(
431
+ f"Sequence length {total_length} exceeds {self.config.max_position_embeddings}"
432
+ )
433
+
434
+ token_embeddings = self.transformer["wte"](input_ids)
435
+ expert_indices, expert_weights, router_aux_loss, router_z_loss = self._route(
436
+ token_embeddings,
437
+ attention_mask,
438
+ past_key_values,
439
+ )
440
+ hidden_states = token_embeddings * self.embedding_scale
441
+ positions = torch.arange(
442
+ past_length,
443
+ total_length,
444
+ dtype=torch.float32,
445
+ device=input_ids.device,
446
+ )
447
+ cosine, sine = _rope_cos_sin(
448
+ self.config.head_dim,
449
+ positions,
450
+ self.config.rope_theta,
451
+ )
452
+ for block in self.transformer["h"]:
453
+ hidden_states = block(
454
+ hidden_states,
455
+ cosine,
456
+ sine,
457
+ expert_indices,
458
+ expert_weights,
459
+ attention_mask,
460
+ past_key_values,
461
+ )
462
+ hidden_states = self.transformer["ln_f"](hidden_states)
463
+ logits = self.lm_head(hidden_states)
464
+
465
+ loss = None
466
+ if labels is not None:
467
+ shift_logits = logits[..., :-1, :].float().contiguous()
468
+ shift_labels = labels[..., 1:].clone().contiguous()
469
+ prefix_mask = self.router.prefix_mask(token_embeddings, attention_mask)
470
+ sequence_positions = torch.arange(sequence_length, device=input_ids.device)
471
+ last_prefix_position = torch.where(
472
+ prefix_mask,
473
+ sequence_positions[None, :],
474
+ -1,
475
+ ).amax(dim=-1)
476
+ prediction_positions = sequence_positions[:-1][None, :]
477
+ shift_labels[prediction_positions < last_prefix_position[:, None]] = -100
478
+ ce_loss = F.cross_entropy(
479
+ shift_logits.reshape(-1, shift_logits.size(-1)),
480
+ shift_labels.reshape(-1),
481
+ ignore_index=-100,
482
+ )
483
+ loss = (
484
+ ce_loss
485
+ + self.config.router_aux_loss_coeff * router_aux_loss
486
+ + self.config.router_z_loss_coeff * router_z_loss
487
+ )
488
+ return SLMoECausalLMOutputWithPast(
489
+ loss=loss,
490
+ logits=logits,
491
+ past_key_values=past_key_values,
492
+ router_aux_loss=router_aux_loss,
493
+ router_z_loss=router_z_loss,
494
+ expert_indices=expert_indices,
495
+ expert_weights=expert_weights,
496
+ )
497
+
498
+
499
+ SLMoEForCausalLM.register_for_auto_class("AutoModelForCausalLM")
500
+
501
+ __all__ = [
502
+ "SLMoECache",
503
+ "SLMoECausalLMOutputWithPast",
504
+ "SLMoEForCausalLM",
505
+ "SLMoEPreTrainedModel",
506
+ ]