GODELEV commited on
Commit
c8de259
Β·
verified Β·
1 Parent(s): b091cbe

Upload 9 files

Browse files
README.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language: en
3
+ tags:
4
+ - causal-lm
5
+ - gqa
6
+ - qk-norm
7
+ - rope
8
+ - swiglu
9
+ - refresh-gate
10
+ - rose-x1
11
+ license: apache-2.0
12
+ ---
13
+
14
+ # Rose-Mini
15
+
16
+ Rose X1 SLM (49.4M params).
17
+
18
+ ## Architecture
19
+ | Property | Value |
20
+ |---|---|
21
+ | Layers | 14 |
22
+ | Hidden | 512 |
23
+ | Heads | 8 (kv=2) |
24
+ | QK Norm | True |
25
+ | Refresh Gate | [4, 9] |
26
+ | Params | 49.443M |
27
+
28
+ ## Training
29
+ - Tokens: 12,206,861,568
30
+ - Val PPL: 6.14
31
+ - Optimizer: muon_adamw
config (1).json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "RoseX1ForCausalLM"
4
+ ],
5
+ "model_type": "rose_x1",
6
+ "auto_map": {
7
+ "AutoConfig": "configuration_rose_x1.RoseX1Config",
8
+ "AutoModelForCausalLM": "modeling_rose_x1.RoseX1ForCausalLM"
9
+ },
10
+ "vocab_size": 16384,
11
+ "hidden_size": 512,
12
+ "intermediate_size": 1408,
13
+ "num_hidden_layers": 14,
14
+ "num_attention_heads": 8,
15
+ "num_key_value_heads": 2,
16
+ "head_dim": 64,
17
+ "max_position_embeddings": 1024,
18
+ "hidden_act": "silu",
19
+ "rms_norm_eps": 1e-05,
20
+ "attention_bias": false,
21
+ "mlp_bias": false,
22
+ "attention_dropout": 0.0,
23
+ "tie_word_embeddings": true,
24
+ "rope_theta": 100000.0,
25
+ "rope_scaling": null,
26
+ "use_qk_norm": true,
27
+ "refresh_gate_enabled": true,
28
+ "refresh_gate_inject_layers": [
29
+ 4,
30
+ 9
31
+ ],
32
+ "refresh_gate_kernel_size": 9,
33
+ "bos_token_id": 2,
34
+ "eos_token_id": 3,
35
+ "pad_token_id": 0,
36
+ "torch_dtype": "float32",
37
+ "transformers_version": "4.40.0",
38
+ "use_cache": true,
39
+ "pretraining_tp": 1,
40
+ "initializer_range": 0.02
41
+ }
configuration_rose_x1.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HuggingFace configuration for the Rose X1 architecture."""
2
+ from transformers import PretrainedConfig
3
+
4
+
5
+ class RoseX1Config(PretrainedConfig):
6
+ model_type = "rose_x1"
7
+
8
+ def __init__(
9
+ self,
10
+ vocab_size=16384,
11
+ hidden_size=512,
12
+ intermediate_size=1408,
13
+ num_hidden_layers=14,
14
+ num_attention_heads=8,
15
+ num_key_value_heads=2,
16
+ head_dim=None,
17
+ max_position_embeddings=1024,
18
+ hidden_act="silu",
19
+ rms_norm_eps=1e-5,
20
+ attention_bias=False,
21
+ mlp_bias=False,
22
+ attention_dropout=0.0,
23
+ tie_word_embeddings=True,
24
+ rope_theta=100000.0,
25
+ rope_scaling=None,
26
+ initializer_range=0.02,
27
+ use_cache=True,
28
+ # ── Rose X1 specifics ──────────────────────────────────────────────
29
+ use_qk_norm=True,
30
+ refresh_gate_enabled=True,
31
+ refresh_gate_inject_layers=None,
32
+ refresh_gate_kernel_size=9,
33
+ **kwargs,
34
+ ):
35
+ self.vocab_size = vocab_size
36
+ self.hidden_size = hidden_size
37
+ self.intermediate_size = intermediate_size
38
+ self.num_hidden_layers = num_hidden_layers
39
+ self.num_attention_heads = num_attention_heads
40
+ self.num_key_value_heads = num_key_value_heads
41
+ self.head_dim = head_dim if head_dim is not None else hidden_size // num_attention_heads
42
+ self.max_position_embeddings = max_position_embeddings
43
+ self.hidden_act = hidden_act
44
+ self.rms_norm_eps = rms_norm_eps
45
+ self.attention_bias = attention_bias
46
+ self.mlp_bias = mlp_bias
47
+ self.attention_dropout = attention_dropout
48
+ self.tie_word_embeddings = tie_word_embeddings
49
+ self.rope_theta = rope_theta
50
+ self.rope_scaling = rope_scaling
51
+ self.initializer_range = initializer_range
52
+ self.use_cache = use_cache
53
+ self.use_qk_norm = use_qk_norm
54
+ self.refresh_gate_enabled = refresh_gate_enabled
55
+ self.refresh_gate_inject_layers = (
56
+ list(refresh_gate_inject_layers) if refresh_gate_inject_layers else []
57
+ )
58
+ self.refresh_gate_kernel_size = refresh_gate_kernel_size
59
+ super().__init__(**kwargs)
generation_config (1).json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 2,
3
+ "eos_token_id": 3
4
+ }
model (1).safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:62d976e8a2c4cc84c6d78f0392eaac1ece52be6c07fd4c4ee1c3c0d417db9c82
3
+ size 197791216
modeling_rose_x1 (3).py ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Rose X1 model implementation for Hugging Face transformers.
2
+
3
+ Architecture (T-X4 family with XSA refresh gate):
4
+ RoPE (half-split) + RMSNorm + SwiGLU + grouped-query attention with
5
+ per-head QK-norm, plus an XSA *refresh gate* that re-injects the original
6
+ token embedding through a gated depthwise-causal-conv path on a subset of
7
+ layers (``config.refresh_gate_inject_layers``).
8
+
9
+ Cache design (after the T-X4 reference implementation):
10
+ KV cache uses HF's ``DynamicCache``. The refresh gate's conv history
11
+ (last ``kernel-1`` timesteps of the normalised attention output) is stored
12
+ in a plain dict monkey-patched onto the same ``DynamicCache`` object as
13
+ ``_refresh_conv_state``, so both share one lifetime and no custom Cache
14
+ subclass is needed.
15
+ """
16
+ from typing import Optional
17
+
18
+ import torch
19
+ import torch.nn as nn
20
+ from torch.nn import functional as F
21
+ from transformers import PreTrainedModel
22
+ from transformers.cache_utils import DynamicCache
23
+ from transformers.generation.utils import GenerationMixin
24
+ from transformers.modeling_outputs import CausalLMOutputWithPast
25
+
26
+ try:
27
+ from .configuration_rose_x1 import RoseX1Config
28
+ except ImportError:
29
+ from configuration_rose_x1 import RoseX1Config
30
+
31
+
32
+ # ═══════════════════════════════════════════════════════════════════════════
33
+ # Primitives
34
+ # ═══════════════════════════════════════════════════════════════════════════
35
+
36
+ class RMSNorm(nn.Module):
37
+ """RMSNorm with fp32 internal computation, cast back to input dtype."""
38
+ def __init__(self, dim: int, eps: float = 1e-5):
39
+ super().__init__()
40
+ self.eps = eps
41
+ self.weight = nn.Parameter(torch.ones(dim))
42
+
43
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
44
+ in_dtype = x.dtype
45
+ xf = x.float()
46
+ out = xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + self.eps)
47
+ return (out * self.weight.float()).to(in_dtype)
48
+
49
+
50
+ def precompute_rope_cos_sin(head_dim: int, seq_len: int, theta: float = 100000.0):
51
+ """Precompute RoPE cos/sin tables. Returns (cos, sin) each (seq_len, head_dim//2)."""
52
+ freqs = 1.0 / (theta ** (torch.arange(0, head_dim, 2, dtype=torch.float32) / head_dim))
53
+ t = torch.arange(seq_len, dtype=torch.float32)
54
+ angles = torch.outer(t, freqs) # (seq_len, head_dim//2)
55
+ return angles.cos(), angles.sin()
56
+
57
+
58
+ def apply_rotary_emb(q: torch.Tensor, k: torch.Tensor,
59
+ cos: torch.Tensor, sin: torch.Tensor):
60
+ """Half-split RoPE (matches the trainer's ``apply_rope``).
61
+
62
+ cos / sin: (T, head_dim//2) β€” already sliced to the right positions.
63
+ q, k: (B, H, T, head_dim)
64
+ """
65
+ cos = cos.unsqueeze(0).unsqueeze(0).to(q.dtype) # (1,1,T,d//2)
66
+ sin = sin.unsqueeze(0).unsqueeze(0).to(q.dtype)
67
+ d2 = q.shape[-1] // 2
68
+
69
+ q1, q2 = q[..., :d2], q[..., d2:]
70
+ k1, k2 = k[..., :d2], k[..., d2:]
71
+
72
+ q_out = torch.cat([q1 * cos - q2 * sin, q2 * cos + q1 * sin], dim=-1)
73
+ k_out = torch.cat([k1 * cos - k2 * sin, k2 * cos + k1 * sin], dim=-1)
74
+ return q_out, k_out
75
+
76
+
77
+ # ═══════════════════════════════════════════════════════════════════════════
78
+ # Attention (GQA + QK-norm + RoPE)
79
+ # ═══════════════════════════════════════════════════════════════════════════
80
+
81
+ class RoseX1Attention(nn.Module):
82
+ def __init__(self, config: RoseX1Config, layer_idx: int):
83
+ super().__init__()
84
+ self.layer_idx = layer_idx
85
+ self.n_head = config.num_attention_heads
86
+ self.n_kv_heads = config.num_key_value_heads
87
+ self.head_dim = config.head_dim
88
+ self.n_rep = self.n_head // self.n_kv_heads
89
+
90
+ self.q_proj = nn.Linear(config.hidden_size, self.n_head * self.head_dim, bias=False)
91
+ self.k_proj = nn.Linear(config.hidden_size, self.n_kv_heads * self.head_dim, bias=False)
92
+ self.v_proj = nn.Linear(config.hidden_size, self.n_kv_heads * self.head_dim, bias=False)
93
+ self.o_proj = nn.Linear(self.n_head * self.head_dim, config.hidden_size, bias=False)
94
+
95
+ # QK-norm: per-head RMSNorm on Q & K, applied BEFORE RoPE
96
+ self.use_qk_norm = bool(getattr(config, "use_qk_norm", False))
97
+ if self.use_qk_norm:
98
+ self.q_norm = RMSNorm(self.head_dim, eps=config.rms_norm_eps)
99
+ self.k_norm = RMSNorm(self.head_dim, eps=config.rms_norm_eps)
100
+
101
+ def forward(self, x, rope_cos, rope_sin,
102
+ past_key_value: Optional[DynamicCache] = None,
103
+ use_cache: bool = False,
104
+ attention_mask: Optional[torch.Tensor] = None):
105
+ B, T, _ = x.size()
106
+
107
+ q = self.q_proj(x).view(B, T, self.n_head, self.head_dim).transpose(1, 2)
108
+ k = self.k_proj(x).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2)
109
+ v = self.v_proj(x).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2)
110
+
111
+ # ── QK-norm BEFORE RoPE (== trainer) ──────────────────────────────
112
+ if self.use_qk_norm:
113
+ q = self.q_norm(q)
114
+ k = self.k_norm(k)
115
+
116
+ # ── RoPE (half-split, cos/sin already sliced to current positions) ─
117
+ q, k = apply_rotary_emb(q, k, rope_cos, rope_sin)
118
+
119
+ # ── KV cache (DynamicCache.update handles concat internally) ──────
120
+ if past_key_value is not None:
121
+ k, v = past_key_value.update(k, v, self.layer_idx)
122
+
123
+ S = k.size(2)
124
+
125
+ # ── GQA expansion ─────────────────────────────────────────────────
126
+ k = k.unsqueeze(2).expand(B, self.n_kv_heads, self.n_rep, S, self.head_dim) \
127
+ .reshape(B, self.n_head, S, self.head_dim)
128
+ v = v.unsqueeze(2).expand(B, self.n_kv_heads, self.n_rep, S, self.head_dim) \
129
+ .reshape(B, self.n_head, S, self.head_dim)
130
+
131
+ # ── Attention mask ────────────────────────────────────────────────
132
+ # is_causal=True only for prefill (no cache) with T>1 and no padding
133
+ # mask. For decode (T=1) causal is trivially satisfied.
134
+ is_causal = (past_key_value is None
135
+ or past_key_value.get_seq_length(self.layer_idx) == T)
136
+ attn_mask = None
137
+ if attention_mask is not None:
138
+ key_pad = attention_mask.to(torch.bool)[:, None, None, :] # (B,1,1,S)
139
+ if is_causal and T > 1:
140
+ causal = torch.ones(T, S, dtype=torch.bool, device=x.device) \
141
+ .tril(diagonal=S - T)
142
+ attn_mask = key_pad & causal[None, None, :, :]
143
+ else:
144
+ attn_mask = key_pad.expand(B, 1, T, S)
145
+ is_causal = False
146
+
147
+ y = F.scaled_dot_product_attention(q, k, v,
148
+ attn_mask=attn_mask,
149
+ is_causal=is_causal)
150
+ y = y.transpose(1, 2).contiguous().view(B, T, self.n_head * self.head_dim)
151
+ return self.o_proj(y)
152
+
153
+
154
+ # ═══════════════════════════════════════════════════════════════════════════
155
+ # MLP (SwiGLU)
156
+ # ═══════════════════════════════════════════════════════════════════════════
157
+
158
+ class RoseX1MLP(nn.Module):
159
+ def __init__(self, config: RoseX1Config):
160
+ super().__init__()
161
+ self.gate_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
162
+ self.up_proj = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
163
+ self.down_proj = nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
164
+
165
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
166
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
167
+
168
+
169
+ # ═══════════════════════════════════════════════════════════════════════════
170
+ # XSA Refresh Gate
171
+ # ═══════════════════════════════════════════════════════════════════════════
172
+
173
+ class RoseX1RefreshGate(nn.Module):
174
+ """Re-injects the original token embedding (e0) into the residual stream,
175
+ gated by a causal depthwise conv over the (detached) attention output.
176
+
177
+ Conv history for cached generation is read/written via ``conv_state``
178
+ (a plain dict living on the DynamicCache object).
179
+ """
180
+ def __init__(self, config: RoseX1Config):
181
+ super().__init__()
182
+ H = config.hidden_size
183
+ self.kernel_size = int(getattr(config, "refresh_gate_kernel_size", 9))
184
+
185
+ self.attn_norm = RMSNorm(H, eps=config.rms_norm_eps)
186
+ self.emb_norm = RMSNorm(H, eps=config.rms_norm_eps)
187
+ self.gate_proj = nn.Linear(H, H, bias=False)
188
+ self.value_proj = nn.Linear(H, H, bias=False)
189
+ self.out_proj = nn.Linear(H, H, bias=False)
190
+ self.out_norm = RMSNorm(H, eps=config.rms_norm_eps)
191
+
192
+ # padding attribute documents intent; forward uses F.conv1d(padding=0)
193
+ # with manual left-pad so the same weight works for cached & non-cached.
194
+ self.causal_conv = nn.Conv1d(H, H, self.kernel_size,
195
+ groups=H, bias=False,
196
+ padding=self.kernel_size - 1)
197
+ self.alpha = nn.Parameter(torch.tensor(0.1))
198
+
199
+ def forward(self, h, attn_out, e0, conv_state=None, layer_idx=None):
200
+ a = self.attn_norm(attn_out.detach())
201
+ e = self.emb_norm(e0)
202
+
203
+ k = self.kernel_size
204
+ B, T, D = a.shape
205
+
206
+ if conv_state is not None:
207
+ # ── cached generation: prepend stored history ─────────────────
208
+ prev = conv_state.get(layer_idx)
209
+ if prev is None or prev.size(0) != B:
210
+ prev = a.new_zeros(B, k - 1, D)
211
+ a_ext = torch.cat([prev, a], dim=1) # (B, k-1+T, D)
212
+ conv_state[layer_idx] = a_ext[:, -(k - 1):, :].detach()
213
+ else:
214
+ # ── no cache (training / full recompute): left-pad zeros ──────
215
+ a_ext = F.pad(a, (0, 0, k - 1, 0)) # (B, k-1+T, D)
216
+
217
+ # Manual left-pad + padding=0 conv (== trainer's CausalDepthwiseConv1d)
218
+ c = F.conv1d(a_ext.transpose(1, 2),
219
+ self.causal_conv.weight,
220
+ bias=None, padding=0, groups=D)
221
+ c = c.transpose(1, 2) # (B, T, D)
222
+
223
+ gate = self.gate_proj(a) + c
224
+ value = self.value_proj(e)
225
+ z = self.out_norm(self.out_proj(F.silu(gate) * value))
226
+ return h + self.alpha * z
227
+
228
+
229
+ # ═══════════════════════════════════════════════════════════════════════════
230
+ # Decoder layer
231
+ # ═══════════════════════════════════════════════════════════════════════════
232
+
233
+ class RoseX1DecoderLayer(nn.Module):
234
+ def __init__(self, config: RoseX1Config, layer_idx: int):
235
+ super().__init__()
236
+ self.layer_idx = layer_idx
237
+ self.input_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
238
+ self.self_attn = RoseX1Attention(config, layer_idx)
239
+ self.post_attention_layernorm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
240
+ self.mlp = RoseX1MLP(config)
241
+
242
+ inject = list(getattr(config, "refresh_gate_inject_layers", []) or [])
243
+ self.has_refresh = (bool(getattr(config, "refresh_gate_enabled", False))
244
+ and layer_idx in inject)
245
+ if self.has_refresh:
246
+ self.refresh_gate = RoseX1RefreshGate(config)
247
+
248
+ def forward(self, x, e0, rope_cos, rope_sin,
249
+ past_key_value=None, use_cache=False,
250
+ attention_mask=None, conv_state=None):
251
+ attn_out = self.self_attn(self.input_layernorm(x), rope_cos, rope_sin,
252
+ past_key_value, use_cache, attention_mask)
253
+ x = x + attn_out
254
+ # Refresh gate fires AFTER attention residual, BEFORE FFN (== trainer)
255
+ if self.has_refresh:
256
+ x = self.refresh_gate(x, attn_out, e0,
257
+ conv_state=conv_state,
258
+ layer_idx=self.layer_idx)
259
+ x = x + self.mlp(self.post_attention_layernorm(x))
260
+ return x
261
+
262
+
263
+ # ═══════════════════════════════════════════════════════════════════════════
264
+ # Base / backbone / head
265
+ # ═══════════════════════════════════════════════════════════════════════════
266
+
267
+ class RoseX1PreTrainedModel(PreTrainedModel):
268
+ config_class = RoseX1Config
269
+ base_model_prefix = "model"
270
+ supports_gradient_checkpointing = False
271
+ _no_split_modules = ["RoseX1DecoderLayer"]
272
+ _supports_sdpa = True
273
+
274
+ def _init_weights(self, module):
275
+ std = self.config.initializer_range
276
+ if isinstance(module, nn.Linear):
277
+ nn.init.normal_(module.weight, mean=0.0, std=std)
278
+ if module.bias is not None:
279
+ nn.init.zeros_(module.bias)
280
+ elif isinstance(module, nn.Embedding):
281
+ nn.init.normal_(module.weight, mean=0.0, std=std)
282
+ elif isinstance(module, nn.Conv1d):
283
+ nn.init.normal_(module.weight, mean=0.0, std=std)
284
+ elif isinstance(module, RMSNorm):
285
+ nn.init.ones_(module.weight)
286
+
287
+
288
+ class RoseX1Model(nn.Module):
289
+ """Backbone: embed β†’ N Γ— decoder layer β†’ final norm."""
290
+ def __init__(self, config: RoseX1Config):
291
+ super().__init__()
292
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size)
293
+ self.dropout = nn.Dropout(config.attention_dropout)
294
+ self.layers = nn.ModuleList(
295
+ [RoseX1DecoderLayer(config, i) for i in range(config.num_hidden_layers)]
296
+ )
297
+ self.norm = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
298
+
299
+ def forward(self, input_ids, e0, rope_cos, rope_sin,
300
+ past_key_value=None, use_cache=False,
301
+ attention_mask=None, conv_state=None):
302
+ x = self.dropout(self.embed_tokens(input_ids))
303
+ for layer in self.layers:
304
+ x = layer(x, e0, rope_cos, rope_sin,
305
+ past_key_value, use_cache, attention_mask, conv_state)
306
+ return self.norm(x)
307
+
308
+
309
+ class RoseX1ForCausalLM(RoseX1PreTrainedModel, GenerationMixin):
310
+ # Dict format required by modern transformers' get_expanded_tied_weights_keys.
311
+ # Tells HF: "lm_head.weight is tied to model.embed_tokens.weight β€” if it's
312
+ # missing from the checkpoint, fill it from the embedding, don't warn."
313
+ _tied_weights_keys = {"lm_head.weight": "model.embed_tokens.weight"}
314
+
315
+ def __init__(self, config: RoseX1Config):
316
+ super().__init__(config)
317
+ self.model = RoseX1Model(config)
318
+
319
+ # Always create lm_head; tie it when configured (standard HF pattern).
320
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
321
+ if config.tie_word_embeddings:
322
+ self.lm_head.weight = self.model.embed_tokens.weight
323
+
324
+ self._rope_cache = None # (cos, sin) cached on device
325
+ self.post_init()
326
+
327
+ # ── Embedding accessors (used by tie_weights / resize) ────────────────
328
+ def get_input_embeddings(self):
329
+ return self.model.embed_tokens
330
+
331
+ def set_input_embeddings(self, value):
332
+ self.model.embed_tokens = value
333
+
334
+ def get_output_embeddings(self):
335
+ return self.lm_head
336
+
337
+ def set_output_embeddings(self, new_embeddings):
338
+ self.lm_head = new_embeddings
339
+
340
+ # ── RoPE cache ────────────────────────────────────────────────────────
341
+ def _get_rope(self, seq_len: int, device: torch.device):
342
+ cache = self._rope_cache
343
+ if (cache is None
344
+ or cache[0].device != device
345
+ or cache[0].size(0) < seq_len):
346
+ cos, sin = precompute_rope_cos_sin(
347
+ self.config.head_dim, seq_len, self.config.rope_theta)
348
+ cache = (cos.to(device), sin.to(device))
349
+ self._rope_cache = cache
350
+ return cache[0][:seq_len], cache[1][:seq_len]
351
+
352
+ # ── Generation plumbing ───────────────────────────────────────────────
353
+ def prepare_inputs_for_generation(self, input_ids,
354
+ past_key_values=None,
355
+ attention_mask=None, **kwargs):
356
+ # When a cache with content exists, feed only the newest token.
357
+ if past_key_values is not None and past_key_values.get_seq_length() > 0:
358
+ input_ids = input_ids[:, -1:]
359
+ return {
360
+ "input_ids": input_ids,
361
+ "attention_mask": attention_mask,
362
+ "past_key_values": past_key_values,
363
+ "use_cache": True,
364
+ }
365
+
366
+ # ── Forward ───────────────────────────────────────────────────────────
367
+ def forward(
368
+ self,
369
+ input_ids: torch.Tensor,
370
+ attention_mask: Optional[torch.Tensor] = None,
371
+ labels: Optional[torch.Tensor] = None,
372
+ past_key_values: Optional[DynamicCache] = None,
373
+ use_cache: bool = False,
374
+ **kwargs,
375
+ ) -> CausalLMOutputWithPast:
376
+ B, T = input_ids.size()
377
+
378
+ # ── Conv-state cache for the refresh gate ─────────────────────────
379
+ # Monkey-patched onto the DynamicCache so it shares the cache's
380
+ # lifetime. No custom Cache subclass needed.
381
+ conv_state = None
382
+ if use_cache:
383
+ if past_key_values is None:
384
+ past_key_values = DynamicCache()
385
+ if not hasattr(past_key_values, "_refresh_conv_state"):
386
+ past_key_values._refresh_conv_state = {}
387
+ conv_state = past_key_values._refresh_conv_state
388
+
389
+ # ── Position from cache length (no explicit position_ids needed) ──
390
+ past_len = (past_key_values.get_seq_length()
391
+ if past_key_values is not None else 0)
392
+
393
+ # ── Embeddings ────────────────────────────────────────────────────
394
+ e0 = self.model.embed_tokens(input_ids) # original embedding for refresh gate
395
+
396
+ # ── RoPE: precompute up to past_len+T, slice to current positions ─
397
+ cos, sin = self._get_rope(past_len + T, input_ids.device)
398
+ cos, sin = cos[past_len:], sin[past_len:] # (T, head_dim//2)
399
+
400
+ # ── Backbone ──────────────────────────────────────────────────────
401
+ hidden = self.model(
402
+ input_ids, e0, cos, sin,
403
+ past_key_values if use_cache else None,
404
+ use_cache, attention_mask, conv_state,
405
+ )
406
+
407
+ # ── Head ──────────────────────────────────────────────────────────
408
+ logits = self.lm_head(hidden).float() # fp32 for stable logprobs
409
+
410
+ loss = None
411
+ if labels is not None:
412
+ loss = F.cross_entropy(
413
+ logits[..., :-1, :].contiguous().view(-1, self.config.vocab_size),
414
+ labels[..., 1:].contiguous().view(-1),
415
+ ignore_index=-100,
416
+ )
417
+
418
+ return CausalLMOutputWithPast(
419
+ loss=loss,
420
+ logits=logits,
421
+ past_key_values=past_key_values if use_cache else None,
422
+ )
423
+
424
+
425
+ # ── Optional registration (lets model_type="rose_x1" resolve without auto_map) ──
426
+ try:
427
+ from transformers import AutoConfig, AutoModelForCausalLM
428
+ try:
429
+ AutoConfig.register("rose_x1", RoseX1Config)
430
+ except Exception:
431
+ pass
432
+ try:
433
+ AutoModelForCausalLM.register(RoseX1Config, RoseX1ForCausalLM)
434
+ except Exception:
435
+ pass
436
+ except Exception:
437
+ pass
tokenizer (1).json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config (1).json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|bos|>",
4
+ "clean_up_tokenization_spaces": false,
5
+ "eos_token": "<|eos|>",
6
+ "extra_special_tokens": [
7
+ "<|unk_text|>",
8
+ "<|sot|>",
9
+ "<|eot|>",
10
+ "<|system|>",
11
+ "<|user|>",
12
+ "<|assistant|>",
13
+ "<|math|>",
14
+ "<|expr|>",
15
+ "<|answer|>",
16
+ "<|code|>",
17
+ "<|think|>",
18
+ "<|end_of_think|>"
19
+ ],
20
+ "is_local": false,
21
+ "local_files_only": false,
22
+ "mask_token": "<|mask|>",
23
+ "model_max_length": 16384,
24
+ "pad_token": "<|pad|>",
25
+ "tokenizer_class": "TokenizersBackend",
26
+ "unk_token": "<|unk|>"
27
+ }
training_meta.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "step": 10358,
3
+ "val_loss": 1.8148479143190384,
4
+ "val_ppl": 6.140142278710768,
5
+ "params_M": 49.443,
6
+ "pushed_at": "2026-07-25T11:18:48.061114",
7
+ "tokens_seen": 12206861568,
8
+ "architecture": "Rose X1",
9
+ "features": [
10
+ "GQA",
11
+ "QK-Norm",
12
+ "RoPE",
13
+ "SwiGLU",
14
+ "RMSNorm",
15
+ "XSA-RefreshGate"
16
+ ],
17
+ "optimizer": "muon_adamw"
18
+ }