kokolamba commited on
Commit
f640da0
·
1 Parent(s): f633391

Update model files

Browse files
README.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ ---
2
+ license: mit
3
+ ---
checkpoint-2700/config.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "SharedSpaceDecoderForCausalLM"
4
+ ],
5
+ "attention_backend": "flash_attention_2",
6
+ "attention_bias": false,
7
+ "attention_dropout_prob": 0.1,
8
+ "bos_token_id": 50256,
9
+ "classifier_dropout": null,
10
+ "dtype": "float32",
11
+ "eos_token_id": 50256,
12
+ "ffn_decompose": false,
13
+ "ffn_rank": null,
14
+ "hidden_dropout_prob": 0.1,
15
+ "hidden_size": 768,
16
+ "initializer_range": 0.02,
17
+ "intermediate_size": 2048,
18
+ "kv_shared_dim": null,
19
+ "layer_norm_eps": 1e-12,
20
+ "max_position_embeddings": 1024,
21
+ "model_type": "shared_subspace_decoder",
22
+ "nope_dims": 32,
23
+ "norm_type": "rmsnorm",
24
+ "num_attention_heads": 12,
25
+ "num_dense_layers": 0,
26
+ "num_hidden_layers": 12,
27
+ "o_shared_dim": null,
28
+ "pad_token_id": 50256,
29
+ "q_shared_dim": null,
30
+ "qk_private_dim": 64,
31
+ "rms_norm_eps": 1e-06,
32
+ "rope_dims": 32,
33
+ "rope_scaling": {
34
+ "factor": 2.0,
35
+ "type": "linear"
36
+ },
37
+ "rope_theta": 10000.0,
38
+ "transformers_version": "4.56.0",
39
+ "vo_private_dim": 64,
40
+ "vocab_rank": null,
41
+ "vocab_size": 50257,
42
+ "vocab_subspace": false
43
+ }
checkpoint-2700/feedforward.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
2
+
3
+ # `feedforward.py`
4
+
5
+ Regarding dropout:
6
+
7
+ - I don't see it applied to the MoE in DeepSeek-V3, [here](https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py).
8
+
9
+ - I don't see it applied in [modeling_llama.py](https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py#L140)
10
+
11
+ Norms:
12
+
13
+ * nn.RMSNorm [here](https://docs.pytorch.org/docs/stable/generated/torch.nn.RMSNorm.html)
14
+
15
+ ## FFN
16
+ """
17
+
18
+ import torch
19
+ import torch.nn as nn
20
+ import torch.nn.functional as F
21
+ from .shared_space_config import SharedSpaceDecoderConfig
22
+
23
+
24
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
25
+ """
26
+ Create a normalization layer based on the config norm_type.
27
+
28
+ Args:
29
+ hidden_size: The dimension to normalize over
30
+ config: Configuration containing norm_type and epsilon values
31
+
32
+ Returns:
33
+ Either a LayerNorm or RMSNorm layer
34
+ """
35
+ if config.norm_type == "layernorm":
36
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
37
+ elif config.norm_type == "rmsnorm":
38
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
39
+ else:
40
+ # This should be caught by config validation, but being defensive
41
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
42
+
43
+
44
+ # TODO - Find a shared place to put this.
45
+ class DeepseekV3RMSNorm(nn.Module):
46
+ def __init__(self, hidden_size, eps=1e-6):
47
+ """
48
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
49
+ """
50
+ super().__init__()
51
+ self.weight = nn.Parameter(torch.ones(hidden_size))
52
+ self.variance_epsilon = eps
53
+
54
+ def forward(self, hidden_states):
55
+ input_dtype = hidden_states.dtype
56
+ hidden_states = hidden_states.to(torch.float32)
57
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
58
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
59
+ return self.weight * hidden_states.to(input_dtype)
60
+
61
+ class SubspaceFeedForward(nn.Module):
62
+ """
63
+ Feed-forward block for SharedSpaceDecoder.
64
+
65
+ Implements SwiGLU:
66
+ FFN(x) = W_out( Swish(W_in(x)) ⊙ W_gate(x) ) + residual
67
+
68
+ Supports both dense and decomposed MLP variants.
69
+
70
+ Dense:
71
+ - W_in: Linear(hidden_dim → intermediate_dim)
72
+ - W_gate: Linear(hidden_dim → intermediate_dim)
73
+ - W_out: Linear(intermediate_dim → hidden_dim)
74
+
75
+ Decomposed:
76
+ - W_in_shared: Linear(hidden_dim → rank, bias=False)
77
+ - W_in_shared_norm: RMSNorm
78
+ - W_in: Linear(rank → intermediate_dim)
79
+ - W_gate_shared: Linear(hidden_dim → rank, bias=False)
80
+ - W_gate_shared_norm: RMSNorm
81
+ - W_gate: Linear(rank → intermediate_dim)
82
+ - W_out: Linear(intermediate_dim → rank, bias=False)
83
+ - W_out_shared: Linear(rank → hidden_dim)
84
+
85
+ Residual, dropout, and post-norm are handled inside the block.
86
+ """
87
+
88
+ def __init__(self, config, layer_idx):
89
+ super().__init__()
90
+
91
+
92
+ #dropout_prob = config.hidden_dropout_prob # TODO - Style -- don't define variables if only used once.
93
+
94
+ # Determine whether this is a dense or decomposed layer.
95
+ # It's dense if either:
96
+ # - ffn_decompose is disabled (no dense layers at all)
97
+ # - ffn_decompose is enabled, but this is one of the early dense layers.
98
+ self.is_dense = (not config.ffn_decompose) or (layer_idx < config.num_dense_layers)
99
+
100
+ hidden_dim = config.hidden_size
101
+ intermediate_dim = config.intermediate_size # TODO - Find something shorter, and use the same name.
102
+
103
+ # If it's one of the dense layers,
104
+ if self.is_dense:
105
+ # === Dense FFN Projections ===
106
+ self.W_in = nn.Linear(hidden_dim, intermediate_dim)
107
+ self.W_gate = nn.Linear(hidden_dim, intermediate_dim)
108
+ self.W_out = nn.Linear(intermediate_dim, hidden_dim)
109
+
110
+ # Define weights for the decomposed version.
111
+ else:
112
+ rank = config.ffn_rank
113
+
114
+ print("hidden_dim:", hidden_dim)
115
+ print("rank:", rank)
116
+
117
+ # === Input Projections ===
118
+ self.W_in_shared = nn.Linear(hidden_dim, rank, bias=False)
119
+ self.W_in_shared_norm = create_norm_layer(rank, config)
120
+ self.W_in = nn.Linear(rank, intermediate_dim, bias=True)
121
+
122
+ # === Gate Projections ===
123
+ self.W_gate_shared = nn.Linear(hidden_dim, rank, bias=False)
124
+ self.W_gate_shared_norm = create_norm_layer(rank, config)
125
+ self.W_gate = nn.Linear(rank, intermediate_dim, bias=True)
126
+
127
+ # === Output Projection ===
128
+ self.W_out = nn.Linear(intermediate_dim, rank, bias=False)
129
+ # TODO - Could experiment with this.
130
+ #self.W_out_shared_layernorm = DeepseekV3RMSNorm(rank, eps=config.eps)
131
+ self.W_out_shared = nn.Linear(rank, hidden_dim, bias=True)
132
+
133
+ # See notes no dropout
134
+ #self.dropout = nn.Dropout(config.hidden_dropout_prob)
135
+
136
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
137
+ # === Tensor Dimension Symbols ===
138
+ # B: batch_size — number of samples in the batch
139
+ # T: seq_len — number of tokens per sample
140
+ # D: hidden_dim — model embedding size
141
+ # R: ffn_rank — latent shared subspace dimension
142
+ # D_ff: intermediate_size — FFN hidden dimension
143
+
144
+ # =========================
145
+ # Gated Feedforward
146
+ # =========================
147
+
148
+ if self.is_dense:
149
+ # =============
150
+ # Dense
151
+ # =============
152
+
153
+ # Input: x [B, T, D]
154
+ # Output: x_proj [B, T, D_ff]
155
+ x_proj = self.W_in(x)
156
+
157
+ # Output: gate [B, T, D_ff]
158
+ gate = self.W_gate(x)
159
+
160
+ # SwiGLU nonlinearity
161
+ x = F.silu(x_proj) * gate # [B, T, D_ff]
162
+
163
+ # See notes on dropout
164
+ #x = self.dropout(x)
165
+
166
+ # Output: x [B, T, D]
167
+ x = self.W_out(x)
168
+
169
+ else:
170
+ # ==================
171
+ # Decomposed
172
+ # ==================
173
+
174
+ # Input: x [B, T, D]
175
+ # Output: x_proj [B, T, D_ff]
176
+ x_proj = self.W_in(self.W_in_shared_norm(self.W_in_shared(x)))
177
+
178
+ # Input: x [B, T, D]
179
+ # Output: gate [B, T, D_ff]
180
+ gate = self.W_gate(self.W_gate_shared_norm(self.W_gate_shared(x)))
181
+
182
+ # SwiGLU nonlinearity
183
+ x = F.silu(x_proj) * gate # [B, T, D_ff]
184
+
185
+ # See notes on dropout
186
+ #x = self.dropout(x)
187
+
188
+ # Output: x [B, T, D]
189
+ x = self.W_out_shared(self.W_out(x))
190
+
191
+
192
+ return x
193
+
194
+
195
+
196
+
checkpoint-2700/gla.py ADDED
@@ -0,0 +1,721 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
2
+
3
+ # `gla.py`
4
+
5
+ Based on: https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py
6
+
7
+ """
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from typing import Optional
13
+ import math
14
+
15
+ from .shared_space_config import SharedSpaceDecoderConfig
16
+
17
+
18
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
19
+ """
20
+ Create a normalization layer based on the config norm_type.
21
+
22
+ If `hidden_size` is `None`, this returns an identity layer.
23
+
24
+ Args:
25
+ hidden_size: The dimension to normalize over
26
+ config: Configuration containing norm_type and epsilon values
27
+
28
+ Returns:
29
+ Either a LayerNorm or RMSNorm layer
30
+ """
31
+ if hidden_size is None:
32
+ return nn.Identity()
33
+ elif config.norm_type == "layernorm":
34
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
35
+ elif config.norm_type == "rmsnorm":
36
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
37
+ else:
38
+ # This should be caught by config validation, but being defensive
39
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
40
+
41
+
42
+ # TODO - Find a shared place to put this.
43
+ class DeepseekV3RMSNorm(nn.Module):
44
+ def __init__(self, hidden_size, eps=1e-6):
45
+ """
46
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
47
+ """
48
+ super().__init__()
49
+ self.weight = nn.Parameter(torch.ones(hidden_size))
50
+ self.variance_epsilon = eps
51
+
52
+ def forward(self, hidden_states):
53
+ input_dtype = hidden_states.dtype
54
+ hidden_states = hidden_states.to(torch.float32)
55
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
56
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
57
+ return self.weight * hidden_states.to(input_dtype)
58
+
59
+
60
+ # Helper function needed because it's called twice during RoPE,
61
+ # but I dumped it in the comments there.
62
+ # TODO - Nah, screw it, just write it twice! At least then you get
63
+ # to use the word 'query' instead of 'x'.
64
+ def rotate_half(x):
65
+ """Rotates half the hidden dims of the input."""
66
+ x1 = x[..., : x.shape[-1] // 2]
67
+ x2 = x[..., x.shape[-1] // 2 :]
68
+ return torch.cat((-x2, x1), dim=-1)
69
+
70
+ class RotaryEmbedding(nn.Module):
71
+ """Precompute RoPE embeddings and store them as buffers."""
72
+
73
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
74
+ super().__init__()
75
+
76
+ dim = config.rope_dims
77
+ seq_len = config.max_position_embeddings
78
+
79
+ # ------------------------------
80
+ # Compute inverse frequencies
81
+ # ------------------------------
82
+ # Shape: [dim // 2]
83
+ # inv_freq[i] = 1 / (theta^(i / dim))
84
+ inv_freq = 1.0 / (
85
+ config.rope_theta
86
+ ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim)
87
+ )
88
+
89
+ # ------------------------------
90
+ # Apply RoPE scaling if configured
91
+ # ------------------------------
92
+ if config.rope_scaling is not None:
93
+ scaling_type = config.rope_scaling.get("type", "linear")
94
+ scaling_factor = config.rope_scaling.get("factor", 1.0)
95
+
96
+ if scaling_type == "linear":
97
+ # Linear scaling: divide frequencies by scaling factor
98
+ inv_freq = inv_freq / scaling_factor
99
+ elif scaling_type == "dynamic":
100
+ # Dynamic scaling: adjust based on sequence length
101
+ # This is a simplified implementation
102
+ inv_freq = inv_freq / scaling_factor
103
+ else:
104
+ print(f"Warning: Unknown RoPE scaling type '{scaling_type}', using linear scaling")
105
+ inv_freq = inv_freq / scaling_factor
106
+
107
+ # ------------------------------
108
+ # Compute position indices
109
+ # ------------------------------
110
+ # Shape: [seq_len]
111
+ t = torch.arange(seq_len, dtype=torch.float32)
112
+
113
+ # ------------------------------
114
+ # Outer product: [seq_len, dim // 2]
115
+ # Each row i contains: t[i] * inv_freq
116
+ # ------------------------------
117
+ freqs = torch.outer(t, inv_freq)
118
+
119
+ # ------------------------------
120
+ # Duplicate for interleaved sin/cos: [seq_len, dim]
121
+ # This matches the common format: [sin_0, cos_0, sin_1, cos_1, ...]
122
+ # ------------------------------
123
+ emb = torch.cat((freqs, freqs), dim=-1)
124
+
125
+ # ------------------------------
126
+ # Register cos/sin as buffers
127
+ # - Stored in float32
128
+ # - Will be moved to correct device/dtype via model.to(...)
129
+ # - Not saved with state_dict (persistent=False)
130
+ # ------------------------------
131
+ self.register_buffer("cos", emb.cos(), persistent=False)
132
+ self.register_buffer("sin", emb.sin(), persistent=False)
133
+
134
+ def forward(self, position_ids: torch.LongTensor) -> tuple[torch.Tensor, torch.Tensor]:
135
+ """ """
136
+ return None # This function is not necessary.
137
+
138
+ """## GLA"""
139
+
140
+ class GroupedLatentAttention(nn.Module):
141
+ """
142
+ This version of Multihead Latent Attention applies the re-ordering trick from DeepSeekV3.
143
+ Instead of comparing the queries and keys in the query-key space, we compare them in the
144
+ kv-shared space.
145
+
146
+ For clarity, I've re-interpreted the naming of the heads, and am framing it as MQA.
147
+ What were previously labeled the query and key heads are now treated as a low-rank decomposition
148
+ of the query heads.
149
+ What we considered the "shared key/value space" is now a single key head that is also used as the
150
+ value head.
151
+ Finally, what we previously labeled the value and output heads are now treated as a low-rank
152
+ decomposition of the output heads.
153
+
154
+ This interpretation / implementation is designed to leverage the performance benefits of GQA.
155
+ The trade-off is that the query-key matching space is now larger--it will require a greater
156
+ number of calculations to match the queries to the keys. The hope is that the memory bandwidth
157
+ savings will outweigh the increased computational cost.
158
+
159
+ The same applies to the value-output space.
160
+
161
+ Note that, although the query-key and value-output spaces are now large, the low-rank
162
+ decomposition of the query heads and output heads ensures that the heads are still effectively
163
+ low rank / not over-parameterized.
164
+
165
+ Finally, note that this implementation also supports the optional use of shared spaces on
166
+ the query and output sides.
167
+
168
+ I've named the class "GroupedLatentAttention" because I may expand it to support multiple
169
+ key/value heads (i.e., multiple groups of query heads) in the future.
170
+
171
+ ==== Adding RoPE to VO ====
172
+
173
+ ### **Attempt**
174
+
175
+ We're extending Rotary Position Embeddings (RoPE) beyond the query-key interaction to the **value-output path** in Multihead Latent Attention (MLA).
176
+
177
+ * In DeepSeek-V3's MLA framing, the same **full-rank key/value head** provides both the keys (for patterns) and the values (for messages).
178
+ * Queries and output heads are low-rank bottlenecks, effectively serving as vocabularies of **pattern directions** (Q) and **message directions** (O).
179
+ * Standard RoPE only modulates the Q–K dot product. Our attempt is to also apply RoPE phases consistently in the V–O pathway, so that **positional dependence is preserved in both the matching (QK) and messaging (VO) sides**.
180
+
181
+ --
182
+
183
+ ### **Hypothesis**
184
+
185
+ If we rotate value vectors by their **source position phase** and then apply the **inverse rotation at the destination** before output projection, the model gains a clean **relative-position equivariance** in the message path, mirroring the property RoPE provides for queries and keys.
186
+
187
+ This should:
188
+
189
+ 1. Make the 1-to-1 correspondence between "pattern templates" (Q) and "message templates" (O) more consistent.
190
+ 2. Reduce the burden on output heads to learn ad-hoc positional compensation.
191
+ 3. Improve long-context generalization, since both attention matching *and* message passing would share the same relative-position geometry.
192
+
193
+
194
+ """
195
+
196
+ def __init__(self, config: SharedSpaceDecoderConfig, layer_idx: int):
197
+ super().__init__()
198
+
199
+ self.config = config
200
+
201
+ # Used to determine if this layer is dense or uses latents.
202
+ self.layer_idx = layer_idx
203
+ self.attention_dropout_prob = config.attention_dropout_prob
204
+
205
+ self.num_heads = config.num_attention_heads
206
+
207
+ self.rope_theta = config.rope_theta
208
+ self.rope_dims = config.rope_dims
209
+ self.nope_dims = config.nope_dims
210
+
211
+ self.q_shared_dim = config.q_shared_dim
212
+ # What was previously considered the key/value shared dimension is now the
213
+ # size of the MQA style single key/value head.
214
+ self.kv_head_dim = config.kv_shared_dim
215
+ self.o_shared_dim = config.o_shared_dim
216
+
217
+ # What was previously the query/key head size is now the size of
218
+ # the query head decomposition.
219
+ self.q_inner_dim = config.qk_private_dim
220
+
221
+ # What was previously the value/output head size is now the size of
222
+ # the output head decomposition.
223
+ self.o_inner_dim = config.vo_private_dim
224
+
225
+ self.hidden_size = config.hidden_size
226
+
227
+ # =========================
228
+ # Input Projections
229
+ # =========================
230
+
231
+ # If this is one of the dense layers,
232
+ if self.layer_idx < config.num_dense_layers:
233
+
234
+ # =========================
235
+ # Dense Attention
236
+ # =========================
237
+
238
+ # No latent projections.
239
+ self.latent_spaces = False
240
+
241
+ # Define the standard QKV projection
242
+ self.qkv_proj = nn.Linear(
243
+ config.hidden_size,
244
+ self.num_heads * (self.qk_private_dim * 2 + self.vo_private_dim),
245
+ bias=config.attention_bias,
246
+ )
247
+
248
+ # Dense output projection
249
+ self.o_proj = nn.Linear(
250
+ self.num_heads * self.vo_private_dim,
251
+ config.hidden_size,
252
+ bias=config.attention_bias,
253
+ )
254
+
255
+ # If we're past the dense layers,
256
+ else:
257
+
258
+ # =========================
259
+ # Latent Attention
260
+ # =========================
261
+
262
+ # Use latent projections.
263
+ self.latent_spaces = True
264
+
265
+ # Input latent projections
266
+
267
+ print("config.q_shared_dim", config.q_shared_dim)
268
+
269
+ # ==========================
270
+ # Shared Query Space
271
+ # ==========================
272
+
273
+ # If we're using a shared query subspace,
274
+ if config.q_shared_dim is not None:
275
+ # Set a flag that we'll check in `forward`.
276
+ self.query_shared = True
277
+
278
+ self.q_shared_proj = nn.Linear(
279
+ config.hidden_size,
280
+ self.q_shared_dim,
281
+ bias=config.attention_bias,
282
+ )
283
+
284
+ self.q_shared_norm = create_norm_layer(self.q_shared_dim, config)
285
+
286
+ else:
287
+ print("Using identity for shared projection.")
288
+ # Set a flag that we'll check in `forward`.
289
+ self.query_shared = False
290
+
291
+ self.q_shared_dim = config.hidden_size
292
+
293
+ #print("Updated self.q_shared_dim to", self.q_shared_dim)
294
+
295
+ # Use identity.
296
+ self.q_shared_proj = nn.Identity()
297
+ self.q_shared_norm = nn.Identity()
298
+
299
+ # ==========================
300
+ # Shared Output Space
301
+ # ==========================
302
+
303
+ # If we're using a shared output space,
304
+ if config.o_shared_dim is not None:
305
+ # Set a flag that we'll check in `forward`.
306
+ self.output_shared = True
307
+
308
+ # Shared output projection
309
+ # The head outputs from `o_private_proj` are first summed together (across
310
+ # heads) in the latent space.
311
+ # Then we project their combined outputs (a single vector per token)
312
+ # back to model space via `o_shared_proj`.
313
+ self.o_shared_proj = nn.Linear(
314
+ self.o_shared_dim,
315
+ self.hidden_size,
316
+ bias=config.attention_bias
317
+ )
318
+
319
+ self.o_shared_norm = create_norm_layer(self.o_shared_dim, config)
320
+
321
+ else:
322
+ # Set a flag that we'll check in `forward`.
323
+ self.output_shared = False
324
+ self.o_shared_dim = config.hidden_size
325
+
326
+ # Use identity.
327
+ self.o_shared_proj = nn.Identity()
328
+ self.o_shared_norm = nn.Identity()
329
+
330
+ # ================================
331
+ # Decomposed Query Heads
332
+ # ================================
333
+
334
+ # Query down projections.
335
+ # The query head inner dimension makes the head low rank, as usual.
336
+ self.q_priv_a_proj = nn.Linear(
337
+ self.q_shared_dim,
338
+ self.num_heads * self.q_inner_dim,
339
+ bias=False
340
+ )
341
+
342
+ # Query up projections.
343
+ # We project back to the larger key/value space.
344
+ # Rather than create a linear and break it apart, we can create our
345
+ # desired shapes.
346
+ # per-head Dq_c -> Dkv (store as [H, Dq_c, Dkv])
347
+ self.q_priv_b_weight = nn.Parameter(
348
+ torch.empty(self.num_heads, self.q_inner_dim, self.kv_head_dim)
349
+ )
350
+ nn.init.kaiming_uniform_(self.q_priv_b_weight, a=math.sqrt(5))
351
+
352
+ # ====================================
353
+ # Single Joint Key/Value Head
354
+ # ====================================
355
+
356
+ # The single joint key/value head.
357
+ self.kv_priv_proj = nn.Linear(
358
+ self.hidden_size,
359
+ self.kv_head_dim,
360
+ bias=False,
361
+ )
362
+
363
+ self.kv_priv_norm = create_norm_layer(self.kv_head_dim, config)
364
+
365
+ # ================================
366
+ # Decomposed Output Heads
367
+ # ================================
368
+
369
+ # Down: values [B,H,T,Dkv] -> per-head Do_c using weights [H, Dkv, Do_c]
370
+ self.o_priv_a_weight = nn.Parameter(
371
+ torch.empty(self.num_heads, self.kv_head_dim, self.o_inner_dim)
372
+ )
373
+ nn.init.kaiming_uniform_(self.o_priv_a_weight, a=math.sqrt(5))
374
+
375
+ # Output up projections.
376
+
377
+ # We project back to the larger output subspace (or the model space,
378
+ # if no subspace is used).
379
+ self.o_priv_b_proj = nn.Linear(
380
+ self.num_heads * self.o_inner_dim,
381
+ self.o_shared_dim,
382
+ bias=False
383
+ )
384
+
385
+ # Let SDPA choose 1/sqrt(E). If you want explicit: self.kv_head_dim ** -0.5
386
+ self.softmax_scale = None
387
+
388
+
389
+ def forward(
390
+ self,
391
+ hidden_states: torch.Tensor,
392
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
393
+ attention_mask: Optional[torch.Tensor],
394
+ #past_key_value: Optional[Cache] = None, # TODO - Can I remove this?
395
+ #cache_position: Optional[torch.LongTensor] = None, # TODO - Can I remove this?
396
+ **kwargs,
397
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor], Optional[tuple[torch.Tensor]]]:
398
+ # === Tensor Dimension Symbols ===
399
+ # B: batch_size — number of samples in the batch
400
+ # T: seq_len — number of tokens per sample
401
+ # H: n_heads — number of attention heads
402
+ # D: hidden_dim — model embedding size
403
+ # Dq_c: q_inner_dim - per-head decomposition dim for Q
404
+ Dq_c = self.q_inner_dim # per-head inner dim for Q
405
+ # Do_c: o_inner_dim - per-head decomposition dim for O
406
+ Do_c = self.o_inner_dim # per-head inner dim for O
407
+ # Dkv: kv_head_dim - Head size of the joint key/value head
408
+ Dkv = self.kv_head_dim # Head size of the joint key/value head
409
+ # Dr: rope_dims - The first Dr dimensions receive rope.
410
+ # Dq_s: q_shared_dim - query shared subspace size
411
+ Dq_s = self.q_shared_dim
412
+ # Do_s: o_shared_dim - output shared subspace size
413
+ Do_s = self.o_shared_dim
414
+
415
+ # Input token embeddings
416
+ # hidden_states: [B, T, D]
417
+ B, T = hidden_states.shape[:2]
418
+ H = self.num_heads
419
+
420
+
421
+
422
+ # =============================
423
+ # Shared Query Space
424
+ # =============================
425
+ # These are set to identity if no shared query space is used.
426
+
427
+ # Project token embeddings into shared latents
428
+ # Input:
429
+ # hidden_states [B, T, D]
430
+ # q_shared_proj [D, Dq_s]
431
+ # kv_shared_proj [D, Dkv]
432
+ # Output:
433
+ # q_shared [B, T, Dq_s]
434
+ # kv_shared [B, T, Dkv]
435
+ q_shared = self.q_shared_proj(hidden_states)
436
+
437
+ # Normalize latent vectors, shapes unchanged.
438
+ q_shared = self.q_shared_norm(q_shared)
439
+
440
+ # ================================
441
+ # Decomposed Query Heads
442
+ # ================================
443
+
444
+
445
+ # Project query latents onto decomposed query heads.
446
+ #
447
+ # Down projection ('a')
448
+ # Input:
449
+ # q_shared [B, T, Dq_s]
450
+ # q_priv_a_proj [Dq_s, H*Dq_c]
451
+ # Output:
452
+ # queries_c [B, T, H*Dq_c]
453
+ queries_c = self.q_priv_a_proj(q_shared)
454
+
455
+ # Split the vectors by head
456
+ # Input:
457
+ # queries_c [B, T, H*Dq_c]
458
+ # Output:
459
+ # queries_c [B, T, H, Dq_c]
460
+ queries_c = queries_c.view(B, T, H, Dq_c)
461
+
462
+ # Up projection ('b')
463
+ # Input:
464
+ # queries_c [B, T, H, Dq_c]
465
+ # q_priv_b_weight [H, Dq_c, Dkv]
466
+ # Output:
467
+ # queries [B, H, T, Dkv]
468
+ queries = torch.einsum("bthd,hdc->bhtc", queries_c, self.q_priv_b_weight)
469
+
470
+ # ===================================
471
+ # Single Joint Key/Value Head
472
+ # ===================================
473
+
474
+ # Project token embeddings into single joint key/value head.
475
+ # Input:
476
+ # hidden_states [B, T, D]
477
+ # kv_priv_proj [D, Dkv]
478
+ # Output:
479
+ # keyvalue [B, T, Dkv]
480
+ keyvalue = self.kv_priv_proj(hidden_states)
481
+
482
+ # Apply QK normalization.
483
+ keyvalue = self.kv_priv_norm(keyvalue)
484
+
485
+ # Prepare the queries and keyvalue vectors for RoPE and flash attention.
486
+ # We have multiple query heads, and the queries are in `queries`.
487
+ # We have a single key head, and the keyvector is in `keyvalue`.
488
+
489
+ # Move the head dimension to the front, so for each head, we have
490
+ # a series of vectors for each token in the sequence.
491
+ #
492
+ # Inputs:
493
+ # keyvalue [B, T, Dkv]
494
+ # Output:
495
+ # keyvalue [B, 1, T, Dkv]
496
+ keyvalue = keyvalue.unsqueeze(1)
497
+
498
+ # ==================
499
+ # RoPE
500
+ # ==================
501
+ # Apply rotary position embeddings to the first `self.rope_dims` of
502
+ # each head.
503
+ # The slice operations are free, but the concatenation is
504
+ # not, because the outputs of the rotation operation are new data
505
+ # occupying different memory. Still considered the best option,
506
+ # though.
507
+
508
+ # 1. Unpack the precomputed cosine and sine embeddings
509
+ # Position embeddings is a tuple of
510
+ # (cos [seq_len, rope_dims],
511
+ # sin [seq_len, rope_dims])
512
+ cos, sin = position_embeddings
513
+
514
+ # 2. Split the query and key heads into the part to rotate and the part
515
+ # to pass through (early columns get position info, later ones don't)
516
+ #
517
+ # (Using queries as example)
518
+ # Inputs:
519
+ # queries [B, H, T, Dkv] Dkv = rope_dims + not_rope_dims
520
+ # Outputs:
521
+ # q_rope [B, H, T, Dr]
522
+ # q_pass [B, H, T, Dkv-Dr]
523
+ q_rope, q_pass = queries[..., :self.rope_dims], queries[..., self.rope_dims:]
524
+ k_rope, k_pass = keyvalue[..., :self.rope_dims], keyvalue[..., self.rope_dims:]
525
+
526
+ # 3. Apply the rotary embedding to the designated slice
527
+ #
528
+ # To broadcast cos and sin across the batch and head dimensions, we unsqueeze them.
529
+ # Shape change: [T, Dr] -> [1, 1, T, Dr]
530
+ cos = cos.unsqueeze(0).unsqueeze(0)
531
+ sin = sin.unsqueeze(0).unsqueeze(0)
532
+
533
+ #print("q_rope.shape[-1] // 2:", (q_rope.shape[-1] // 2))
534
+ #print("x1 = x[..., :x.shape[-1] // 2 ].shape:", q_rope[..., :q_rope.shape[-1] // 2 ].shape)
535
+ #print("sin/cos.shape:", cos.shape)
536
+ #print("q_rope.shape:", q_rope.shape)
537
+ #print("(q_rope * cos).shape:", (q_rope * cos).shape)
538
+ #print("rotate_half(q_rope).shape:", rotate_half(q_rope).shape)
539
+ #print("(rotate_half(q_rope) * sin).shape:", (rotate_half(q_rope) * sin).shape)
540
+ """
541
+ In this example batch_size = 2, hum_heads = 8, seq_len = 65, rope_dims = 16
542
+
543
+ q_rope.shape[-1] // 2: 8
544
+ x1 = x[..., :x.shape[-1] // 2 ].shape: torch.Size([2, 8, 65, 8])
545
+
546
+ sin/cos.shape: torch.Size([1, 1, 65, 16]) # After double unsqueeze.
547
+ vq_rope.shape: torch.Size([2, 8, 65, 16])
548
+
549
+ (q_rope * cos).shape: torch.Size([2, 8, 65, 16])
550
+
551
+ rotate_half(q_rope).shape: torch.Size([2, 8, 65, 16])
552
+ (rotate_half(q_rope) * sin).shape: torch.Size([2, 8, 65, 16])
553
+ """
554
+
555
+
556
+ # Let's walk through the queries as the example.
557
+ # What does rotate half do?
558
+ # dim -1 is the row vectors, the queries
559
+ #
560
+ # Step 1: Split the vector in half.
561
+ # "q_rope.shape[-1] // 2" <- How much to select. Half the length of the q_rope vector
562
+ # x1 = x[..., :x.shape[-1] // 2 ] # Select the first half of the vector.
563
+ # x2 = x[..., x.shape[-1] // 2:] # Select the second half.
564
+ #
565
+ # Step 2:
566
+ # - Apply negative to the values in the second half.
567
+ # - Reverse the order of the halves.
568
+ # return torch.cat((-x2, x1), dim=-1)
569
+ #
570
+ # ---- (q_rope * cos) ----
571
+ # Element-wise multiply the values in each `cos` vector with the
572
+ # corresponding (i.e., same sequence position) `q_rope` vector.
573
+ #
574
+ # Inputs:
575
+ # q_rope [B, H, T, Dr]
576
+ # cos [1, 1, T, Dr]
577
+ #
578
+ # Outputs:
579
+ # x [B, H, T, Dr]
580
+ #
581
+ # ---- (rotate_half(q_rope)) ----
582
+ # TODO
583
+ #
584
+ # Inputs:
585
+ # q_rope [B, T, Dr]
586
+ #
587
+ # Outputs:
588
+ # rot_q_rope [B, T, Dr]
589
+ #
590
+ # ---- rotated * sin ----
591
+ # TODO
592
+ q_rotated = (q_rope * cos) + (rotate_half(q_rope) * sin)
593
+ k_rotated = (k_rope * cos) + (rotate_half(k_rope) * sin)
594
+
595
+ # 4. Concatenate the rotated and pass-through parts back together
596
+ # Input (each): [B, H, T, Dr] and [B, H, T, Dkv-Dr]
597
+ # Output (each): [B, H, T, Dkv]
598
+ # (Where h = 1 for the key head and h = num_heads for the query heads)
599
+ queries = torch.cat((q_rotated, q_pass), dim=-1)
600
+ keyvalue = torch.cat((k_rotated, k_pass), dim=-1)
601
+
602
+ # ====================
603
+ # GQA / MQA
604
+ # ====================
605
+ # GPT says that flash attention will infer the broadcasting, so `expand` is not needed.
606
+ #
607
+ # We need to use the `expand` operation to broadcast the keyvalue vector
608
+ # across the query heads.
609
+ # Input:
610
+ # keyvalue [B, 1, T, Dkv]
611
+ # Output:
612
+ # keyvalue [B, H, T, Dkv]
613
+ #keyvalue = keyvalue.expand(-1, H, -1, -1)
614
+
615
+ # ===================
616
+ # Attention
617
+ # ===================
618
+ # We're ready for the attention score calculation.
619
+
620
+ # Only apply dropout during training.
621
+ # self.training is a pytorch flag.
622
+ if self.training:
623
+ dropout_p = self.attention_dropout_prob
624
+ else:
625
+ dropout_p = 0.0
626
+
627
+ # Call SDPA / Flash Attention
628
+ # https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html
629
+ # Apply MQA / GQA. In this case, we have a single key head, and multiple query heads.
630
+ values = F.scaled_dot_product_attention(
631
+ queries,
632
+ keyvalue, # Single key vector (joint with value) for GQA / MQA.
633
+ keyvalue, # Single value vector (joint with key) for GQA / MQA.
634
+ attn_mask=None, # attention_mask,
635
+ dropout_p=dropout_p,
636
+ scale=self.softmax_scale,
637
+ is_causal=True, # This is a decoder - apply causal masking
638
+ )
639
+
640
+ # Attention outputs:
641
+ # values [B, H, T, Dkv]
642
+
643
+ # The final Dr dims of the value vectors carry RoPE information.
644
+ # We can either (1) add position dependence to the value-output process,
645
+ # or (2) we can strip off the RoPE information and only use the non-RoPE parts.
646
+
647
+ # Let's try option 1!
648
+
649
+ # Split the values into the RoPE and non-RoPE parts.
650
+ # Input:
651
+ # values [B, H, T, Dkv]
652
+ # Output:
653
+ # values_rope [B, H, T, Dr]
654
+ # values_pass [B, H, T, Dkv-Dr]
655
+ values_rope, values_pass = values[..., :self.rope_dims], values[..., self.rope_dims:]
656
+
657
+ # Fold the query RoPE information into the value vectors.
658
+ # Inverse rotation: R_{-θ} x = (x * cos) - (rotate_half(x) * sin)
659
+ # Input:
660
+ # values_rope [B, H, T, Dr]
661
+ # cos [1, 1, T, Dr]
662
+ # sin [1, 1, T, Dr]
663
+ # Output:
664
+ # values_unrot [B, H, T, Dr]
665
+ values_unrot = (values_rope * cos) - (rotate_half(values_rope) * sin)
666
+
667
+ # Now the values have the offset information in their rope dimensions,
668
+ # and the output heads can learn to use it.
669
+ values = torch.cat((values_unrot, values_pass), dim=-1) # [B,H,T,Dkv]
670
+
671
+ # =========================
672
+ # Output Projection
673
+ # =========================
674
+
675
+
676
+ # Project the values onto the decomposed output heads.
677
+ # Output down projection heads.
678
+ # Input:
679
+ # values [B, H, T, Dkv]
680
+ # o_priv_a_weight [H, Dkv, Do_c]
681
+ # Output:
682
+ # outputs_c [B, H, T, Do_c]
683
+ outputs_c = torch.einsum("bhtd,hdc->bhtc", values, self.o_priv_a_weight)
684
+
685
+ # For the up projection, we can concatenate the 'outputs_c' vectors by head,
686
+ # (in the same way we would usually concatenate the value vectors)
687
+ # Input:
688
+ # outputs_c [B, H, T, Do_c]
689
+ # Output:
690
+ # outputs_c [B, T, H*Do_c]
691
+
692
+ outputs_c = outputs_c.permute(0, 2, 1, 3).contiguous().view(B, T, H * Do_c)
693
+
694
+ # Project up to the shared output space and sum across the output heads.
695
+ # Input:
696
+ # outputs_c [B, T, H*Do_c]
697
+ # o_priv_b_proj [H*Do_c, Do_s]
698
+ # Output:
699
+ # output_s [B, T, Do_s]
700
+ output_s = self.o_priv_b_proj(outputs_c)
701
+
702
+ # Apply normalization to the output latents
703
+ output_s = self.o_shared_norm(output_s)
704
+
705
+ # Re-project the output latent representation back to model space.
706
+ # Input:
707
+ # output_s [B, T, Do_s]
708
+ # o_shared_proj [Do_s, D]
709
+ # Output:
710
+ # attn_output [B, T, D]
711
+ attn_output = self.o_shared_proj(output_s)
712
+
713
+ # TODO - Not currently supported.
714
+ # If this is a dense layer,
715
+ # Project the values back into model space.
716
+ # attn_output = self.o_proj(attn_output)
717
+
718
+ # -----------------------------------------
719
+
720
+ return attn_output
721
+
checkpoint-2700/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
checkpoint-2700/mla.py ADDED
@@ -0,0 +1,619 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
2
+
3
+ # `mla.py`
4
+
5
+ Based on: https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py
6
+
7
+ ## RotaryEmbedding
8
+ """
9
+
10
+ import torch
11
+ import torch.nn as nn
12
+ import torch.nn.functional as F
13
+ from typing import Optional
14
+
15
+ from .shared_space_config import SharedSpaceDecoderConfig
16
+
17
+
18
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
19
+ """
20
+ Create a normalization layer based on the config norm_type.
21
+
22
+ If `hidden_size` is `None`, this returns an identity layer.
23
+
24
+ Args:
25
+ hidden_size: The dimension to normalize over
26
+ config: Configuration containing norm_type and epsilon values
27
+
28
+ Returns:
29
+ Either a LayerNorm or RMSNorm layer
30
+ """
31
+ if hidden_size is None:
32
+ return nn.Identity()
33
+ elif config.norm_type == "layernorm":
34
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
35
+ elif config.norm_type == "rmsnorm":
36
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
37
+ else:
38
+ # This should be caught by config validation, but being defensive
39
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
40
+
41
+
42
+ # TODO - Find a shared place to put this.
43
+ class DeepseekV3RMSNorm(nn.Module):
44
+ def __init__(self, hidden_size, eps=1e-6):
45
+ """
46
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
47
+ """
48
+ super().__init__()
49
+ self.weight = nn.Parameter(torch.ones(hidden_size))
50
+ self.variance_epsilon = eps
51
+
52
+ def forward(self, hidden_states):
53
+ input_dtype = hidden_states.dtype
54
+ hidden_states = hidden_states.to(torch.float32)
55
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
56
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
57
+ return self.weight * hidden_states.to(input_dtype)
58
+
59
+
60
+ # Helper function needed because it's called twice during RoPE,
61
+ # but I dumped it in the comments there.
62
+ # TODO - Nah, screw it, just write it twice! At least then you get
63
+ # to use the word 'query' instead of 'x'.
64
+ def rotate_half(x):
65
+ """Rotates half the hidden dims of the input."""
66
+ x1 = x[..., : x.shape[-1] // 2]
67
+ x2 = x[..., x.shape[-1] // 2 :]
68
+ return torch.cat((-x2, x1), dim=-1)
69
+
70
+ class RotaryEmbedding(nn.Module):
71
+ """Precompute RoPE embeddings and store them as buffers."""
72
+
73
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
74
+ super().__init__()
75
+
76
+ dim = config.rope_dims
77
+ seq_len = config.max_position_embeddings
78
+
79
+ # ------------------------------
80
+ # Compute inverse frequencies
81
+ # ------------------------------
82
+ # Shape: [dim // 2]
83
+ # inv_freq[i] = 1 / (theta^(i / dim))
84
+ inv_freq = 1.0 / (
85
+ config.rope_theta
86
+ ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim)
87
+ )
88
+
89
+ # ------------------------------
90
+ # Apply RoPE scaling if configured
91
+ # ------------------------------
92
+ if config.rope_scaling is not None:
93
+ scaling_type = config.rope_scaling.get("type", "linear")
94
+ scaling_factor = config.rope_scaling.get("factor", 1.0)
95
+
96
+ if scaling_type == "linear":
97
+ # Linear scaling: divide frequencies by scaling factor
98
+ inv_freq = inv_freq / scaling_factor
99
+ elif scaling_type == "dynamic":
100
+ # Dynamic scaling: adjust based on sequence length
101
+ # This is a simplified implementation
102
+ inv_freq = inv_freq / scaling_factor
103
+ else:
104
+ print(f"Warning: Unknown RoPE scaling type '{scaling_type}', using linear scaling")
105
+ inv_freq = inv_freq / scaling_factor
106
+
107
+ # ------------------------------
108
+ # Compute position indices
109
+ # ------------------------------
110
+ # Shape: [seq_len]
111
+ t = torch.arange(seq_len, dtype=torch.float32)
112
+
113
+ # ------------------------------
114
+ # Outer product: [seq_len, dim // 2]
115
+ # Each row i contains: t[i] * inv_freq
116
+ # ------------------------------
117
+ freqs = torch.outer(t, inv_freq)
118
+
119
+ # ------------------------------
120
+ # Duplicate for interleaved sin/cos: [seq_len, dim]
121
+ # This matches the common format: [sin_0, cos_0, sin_1, cos_1, ...]
122
+ # ------------------------------
123
+ emb = torch.cat((freqs, freqs), dim=-1)
124
+
125
+ # ------------------------------
126
+ # Register cos/sin as buffers
127
+ # - Stored in float32
128
+ # - Will be moved to correct device/dtype via model.to(...)
129
+ # - Not saved with state_dict (persistent=False)
130
+ # ------------------------------
131
+ self.register_buffer("cos", emb.cos(), persistent=False)
132
+ self.register_buffer("sin", emb.sin(), persistent=False)
133
+
134
+ def forward(self, position_ids: torch.LongTensor) -> tuple[torch.Tensor, torch.Tensor]:
135
+ """ """
136
+ return None # This function is not necessary.
137
+
138
+ """## MLA"""
139
+
140
+ class MultiheadLatentAttention(nn.Module):
141
+ """
142
+ A variant of MLA with:
143
+ - Simplified RoPE handling:
144
+ - A portion of the head dimensions are used for position information.
145
+ - Same number of queries as keys. (no MQA)
146
+ - Optional output subspace
147
+ """
148
+
149
+ def __init__(self, config: SharedSpaceDecoderConfig, layer_idx: int):
150
+ super().__init__()
151
+
152
+ self.config = config
153
+
154
+ # Used to determine if this layer is dense or uses latents.
155
+ self.layer_idx = layer_idx
156
+ self.attention_dropout_prob = config.attention_dropout_prob
157
+
158
+ self.num_heads = config.num_attention_heads
159
+
160
+ self.rope_theta = config.rope_theta
161
+ self.rope_dims = config.rope_dims
162
+ self.nope_dims = config.nope_dims
163
+
164
+ self.q_shared_dim = config.q_shared_dim
165
+ self.kv_shared_dim = config.kv_shared_dim
166
+ self.o_shared_dim = config.o_shared_dim
167
+
168
+ self.qk_private_dim = config.qk_private_dim
169
+ self.vo_private_dim = config.vo_private_dim
170
+
171
+ self.hidden_size = config.hidden_size
172
+
173
+ # =========================
174
+ # Input Projections
175
+ # =========================
176
+
177
+ # If this is one of the dense layers,
178
+ if self.layer_idx < config.num_dense_layers:
179
+
180
+ # =========================
181
+ # Dense Attention
182
+ # =========================
183
+
184
+ # No latent projections.
185
+ self.latent_spaces = False
186
+
187
+ # Define the standard QKV projection
188
+ self.qkv_proj = nn.Linear(
189
+ config.hidden_size,
190
+ self.num_heads * (self.qk_private_dim * 2 + self.vo_private_dim),
191
+ bias=config.attention_bias,
192
+ )
193
+
194
+ # Dense output projection
195
+ self.o_proj = nn.Linear(
196
+ self.num_heads * self.vo_private_dim,
197
+ config.hidden_size,
198
+ bias=config.attention_bias,
199
+ )
200
+
201
+ # If we're past the dense layers,
202
+ else:
203
+
204
+ # =========================
205
+ # Latent Attention
206
+ # =========================
207
+
208
+ # Use latent projections.
209
+ self.latent_spaces = True
210
+
211
+ # Input latent projections
212
+
213
+ print("config.q_shared_dim", config.q_shared_dim)
214
+
215
+ # If we're using a shared query subspace,
216
+ if config.q_shared_dim is not None:
217
+ # Set a flag that we'll check in `forward`.
218
+ self.query_shared = True
219
+
220
+ self.q_shared_proj = nn.Linear(
221
+ config.hidden_size,
222
+ self.q_shared_dim,
223
+ bias=config.attention_bias,
224
+ )
225
+
226
+ self.q_shared_norm = create_norm_layer(self.q_shared_dim, config)
227
+
228
+ else:
229
+ print("Using identity for shared projection.")
230
+ # Set a flag that we'll check in `forward`.
231
+ self.query_shared = False
232
+
233
+ self.q_shared_dim = config.hidden_size
234
+
235
+ #print("Updated self.q_shared_dim to", self.q_shared_dim)
236
+
237
+ # Use identity.
238
+ self.q_shared_proj = nn.Identity()
239
+ self.q_shared_norm = nn.Identity()
240
+
241
+ # If we're using a shared key/value subspace,
242
+ if config.kv_shared_dim is not None:
243
+ # Set a flag that we'll check in `forward`.
244
+ self.keyvalue_shared = True
245
+
246
+ self.kv_shared_proj = nn.Linear(
247
+ config.hidden_size,
248
+ self.kv_shared_dim,
249
+ bias=config.attention_bias,
250
+ )
251
+
252
+ self.kv_shared_norm = create_norm_layer(self.kv_shared_dim, config)
253
+
254
+ else:
255
+ # Set a flag that we'll check in `forward`.
256
+ self.keyvalue_shared = False
257
+
258
+ self.kv_shared_dim = config.hidden_size
259
+
260
+ # Use identity.
261
+ self.kv_shared_proj = nn.Identity()
262
+ self.kv_shared_norm = nn.Identity()
263
+
264
+ #print("config.q_shared_dim", config.q_shared_dim)
265
+ #print("self.qk_private_dim", self.qk_private_dim)
266
+
267
+ # Query heads
268
+ self.q_private_proj = nn.Linear(
269
+ self.q_shared_dim,
270
+ self.num_heads * self.qk_private_dim,
271
+ bias=False # TODO
272
+ )
273
+
274
+ # Key and Value heads, concatenated
275
+ self.kv_private_proj = nn.Linear(
276
+ self.kv_shared_dim,
277
+ self.num_heads * (self.qk_private_dim + self.vo_private_dim),
278
+ bias=False,
279
+ )
280
+
281
+ # Use output subspace if o_shared_dim is specified
282
+ self.output_subspace = config.o_shared_dim is not None
283
+
284
+ # If we're using an output subspace,
285
+ if self.output_subspace:
286
+
287
+ # ==========================
288
+ # Output Subspace
289
+ # ==========================
290
+
291
+ self.o_shared_dim = config.o_shared_dim
292
+
293
+ # Per-head output projections
294
+ # (Similar to original W^O, but projects the scored value vectors
295
+ # into a latent space instead of back to the model)
296
+ self.o_private_proj = nn.Linear(
297
+ self.num_heads * self.vo_private_dim,
298
+ self.o_shared_dim,
299
+ bias=False
300
+ )
301
+
302
+ # Norm layer between o_private_proj and o_shared_proj
303
+ # Note: In previous ViT experiments, this norm step hurt performance, but was beneficial
304
+ # in the DeepSeekV3 experiments.
305
+ # However, we're making it configurable so it can be tested in different contexts.
306
+ self.o_private_norm = create_norm_layer(self.o_shared_dim, config)
307
+
308
+ # Shared output projection
309
+ # The head outputs from `o_private_proj` are first summed together (across
310
+ # heads) in the latent space.
311
+ # Then we project their combined outputs (a single vector per token)
312
+ # back to model space via `o_shared_proj`.
313
+ self.o_shared_proj = nn.Linear(
314
+ self.o_shared_dim,
315
+ self.hidden_size,
316
+ bias=config.attention_bias
317
+ )
318
+ else:
319
+ # Dense output projection
320
+ self.o_proj = nn.Linear(
321
+ self.num_heads * self.vo_private_dim,
322
+ config.hidden_size,
323
+ bias=config.attention_bias,
324
+ )
325
+
326
+ # Softmax scaling factor.
327
+ self.softmax_scale = self.qk_private_dim ** (-0.5)
328
+
329
+
330
+ def forward(
331
+ self,
332
+ hidden_states: torch.Tensor,
333
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
334
+ attention_mask: Optional[torch.Tensor],
335
+ #past_key_value: Optional[Cache] = None, # TODO - Can I remove this?
336
+ #cache_position: Optional[torch.LongTensor] = None, # TODO - Can I remove this?
337
+ **kwargs,
338
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor], Optional[tuple[torch.Tensor]]]:
339
+ # === Tensor Dimension Symbols ===
340
+ # B: batch_size — number of samples in the batch
341
+ # T: seq_len — number of tokens per sample
342
+ # H: n_heads — number of attention heads
343
+ # D: hidden_dim — model embedding size
344
+ # Dv: vo_private_dim - per-head value/output projection dimension
345
+ # Dr: rope_dims - The first Dr dimensions receive rope.
346
+ # Cq: q_shared_dim - query shared subspace size
347
+ # Ckv: kv_shared_dim - key-value shared subspace size
348
+ # Co: o_shared_dim - output shared subspace size
349
+
350
+ # Input token embeddings
351
+ # hidden_states: [B, T, D]
352
+ B, T = hidden_states.shape[:2]
353
+ H = self.num_heads
354
+ Dq = self.qk_private_dim # per-head dim for Q and K
355
+ Dv = self.vo_private_dim # per-head dim for V/O
356
+
357
+ Dc_q, Dc_kv = self.q_shared_dim, self.kv_shared_dim
358
+
359
+ # ==============================
360
+ # QKV Head Projections
361
+ # ==============================
362
+ # Project tokens into per-head query, key, and value vectors
363
+
364
+ # If this layer uses latent projections,
365
+ if self.latent_spaces:
366
+
367
+ # ================================
368
+ # Shared Space Projections
369
+ # ================================
370
+
371
+ # Project token embeddings into shared latents
372
+ # Input:
373
+ # hidden_states [B, T, D]
374
+ # q_shared_proj [D, Cq]
375
+ # kv_shared_proj [D, Ckv]
376
+ # Output:
377
+ # q_shared [B, T, Cq]
378
+ # kv_shared [B, T, Ckv]
379
+
380
+ # If we're using a shared query subspace,
381
+ if self.q_shared_dim is not None:
382
+ q_shared = self.q_shared_proj(hidden_states)
383
+
384
+ # Normalize latent vectors, shapes unchanged.
385
+ q_shared = self.q_shared_norm(q_shared)
386
+ # Otherwise,
387
+ else:
388
+ # Use the hidden states
389
+ q_shared = hidden_states
390
+
391
+ # If we're using a shared key/value subspace,
392
+ if self.kv_shared_dim is not None:
393
+
394
+ # Project token embeddings into shared subspace.
395
+ kv_shared = self.kv_shared_proj(hidden_states)
396
+
397
+ # Normalize latent vectors, shapes unchanged.
398
+ kv_shared = self.kv_shared_norm(kv_shared)
399
+ # Otherwise,
400
+ else:
401
+ # Use the hidden states
402
+ kv_shared = hidden_states
403
+
404
+ # ======================================
405
+ # Per-Head (Private) Projections
406
+ # ======================================
407
+
408
+ # Project query latents onto query heads.
409
+ # Input:
410
+ # q_shared [B, T, Cq]
411
+ # q_private_proj [Cq, H*Dh]
412
+ # Output:
413
+ # queries [B, T, H*Dh]
414
+ queries = self.q_private_proj(q_shared)
415
+
416
+ # Project key/value latents onto key and value heads.
417
+ # The key and value heads are all concatenated, each head occupies
418
+ # Dh columns of the kv_private_proj. This yields the key and value
419
+ # vectors concatenated in the same way.
420
+ #
421
+ # Input:
422
+ # kv_shared [B, T, Ckv]
423
+ # kv_private_proj [Ckv, 2*H*Dh]
424
+ # Output:
425
+ # keysvalues [B, T, 2*H*Dh]
426
+ keysvalues = self.kv_private_proj(kv_shared)
427
+
428
+ # Split into key and value tensors
429
+ # Each: [B, T, H * Dh]
430
+ keys, values = keysvalues.chunk(2, dim=-1)
431
+
432
+ # If this is a dense attention layer (no latent projections),
433
+ else:
434
+
435
+ # ====================
436
+ # Standard MHA
437
+ # ====================
438
+
439
+ # Standard QKV projection
440
+ # Input:
441
+ # hidden_states [B, T, D]
442
+ # qkv_proj [D, 3*H*Dh]
443
+ # Output:
444
+ # querieskeysvalues [B, T, 3*H*Dh]
445
+ querieskeysvalues = self.qkv_proj(hidden_states)
446
+
447
+ # Separate query, key, and value vectors
448
+ # Each: [B, T, H * Dh]
449
+ queries, keys, values = querieskeysvalues.chunk(3, dim=-1)
450
+
451
+ # Split up queries so that there's just one per row.
452
+ # Same for keys and values.
453
+ #
454
+ # Inputs:
455
+ # Each [B, T, H*Dh]
456
+ # Output:
457
+ # Each [B, H, T, Dh]
458
+ queries = queries.view(B, T, H, Dq).transpose(1, 2)
459
+ keys = keys.view(B, T, H, Dq).transpose(1, 2)
460
+ values = values.view(B, T, H, Dv).transpose(1, 2)
461
+
462
+ # ==================
463
+ # RoPE
464
+ # ==================
465
+ # Apply rotary position embeddings to the first `self.rope_dims` of
466
+ # each head.
467
+ # The slice operations are free, but the concatenation is
468
+ # not, because the outputs of the rotation operation are new data
469
+ # occupying different memory. Still considered the best option,
470
+ # though.
471
+
472
+ # 1. Unpack the precomputed cosine and sine embeddings
473
+ # Position embeddings is a tuple of
474
+ # (cos [seq_len, rope_dims],
475
+ # sin [seq_len, rope_dims])
476
+ cos, sin = position_embeddings
477
+
478
+ # 2. Split the query and key heads into the part to rotate and the part
479
+ # to pass through (early columns get position info, later ones don't)
480
+ #
481
+ # (Using queries as example)
482
+ # Inputs:
483
+ # queries [B, H, T, Dh] Dh = rope_dims + not_rope_dims
484
+ # Outputs:
485
+ # q_rope [B, H, T, Dr]
486
+ # q_pass [B, H, T, Dh-Dr]
487
+ q_rope, q_pass = queries[..., :self.rope_dims], queries[..., self.rope_dims:]
488
+ k_rope, k_pass = keys[..., :self.rope_dims], keys[..., self.rope_dims:]
489
+
490
+ # 3. Apply the rotary embedding to the designated slice
491
+ #
492
+ # To broadcast cos and sin across the batch and head dimensions, we unsqueeze them.
493
+ # Shape change: [T, Dr] -> [1, 1, T, Dr]
494
+ cos = cos.unsqueeze(0).unsqueeze(0)
495
+ sin = sin.unsqueeze(0).unsqueeze(0)
496
+
497
+ #print("q_rope.shape[-1] // 2:", (q_rope.shape[-1] // 2))
498
+ #print("x1 = x[..., :x.shape[-1] // 2 ].shape:", q_rope[..., :q_rope.shape[-1] // 2 ].shape)
499
+ #print("sin/cos.shape:", cos.shape)
500
+ #print("q_rope.shape:", q_rope.shape)
501
+ #print("(q_rope * cos).shape:", (q_rope * cos).shape)
502
+ #print("rotate_half(q_rope).shape:", rotate_half(q_rope).shape)
503
+ #print("(rotate_half(q_rope) * sin).shape:", (rotate_half(q_rope) * sin).shape)
504
+ """
505
+ In this example batch_size = 2, hum_heads = 8, seq_len = 65, rope_dims = 16
506
+
507
+ q_rope.shape[-1] // 2: 8
508
+ x1 = x[..., :x.shape[-1] // 2 ].shape: torch.Size([2, 8, 65, 8])
509
+
510
+ sin/cos.shape: torch.Size([1, 1, 65, 16]) # After double unsqueeze.
511
+ vq_rope.shape: torch.Size([2, 8, 65, 16])
512
+
513
+ (q_rope * cos).shape: torch.Size([2, 8, 65, 16])
514
+
515
+ rotate_half(q_rope).shape: torch.Size([2, 8, 65, 16])
516
+ (rotate_half(q_rope) * sin).shape: torch.Size([2, 8, 65, 16])
517
+ """
518
+
519
+
520
+ # Let's walk through the queries as the example.
521
+ # What does rotate half do?
522
+ # dim -1 is the row vectors, the queries
523
+ #
524
+ # Step 1: Split the vector in half.
525
+ # "q_rope.shape[-1] // 2" <- How much to select. Half the length of the q_rope vector
526
+ # x1 = x[..., :x.shape[-1] // 2 ] # Select the first half of the vector.
527
+ # x2 = x[..., x.shape[-1] // 2:] # Select the second half.
528
+ #
529
+ # Step 2:
530
+ # - Apply negative to the values in the second half.
531
+ # - Reverse the order of the halves.
532
+ # return torch.cat((-x2, x1), dim=-1)
533
+ #
534
+ # ---- (q_rope * cos) ----
535
+ # Element-wise multiply the values in each `cos` vector with the
536
+ # corresponding (i.e., same sequence position) `q_rope` vector.
537
+ #
538
+ # Inputs:
539
+ # q_rope [B, H, T, Dr]
540
+ # cos [1, 1, T, Dr]
541
+ #
542
+ # Outputs:
543
+ # x [B, H, T, Dr]
544
+ #
545
+ # ---- (rotate_half(q_rope)) ----
546
+ # TODO
547
+ #
548
+ # Inputs:
549
+ # q_rope [B, T, Dr]
550
+ #
551
+ # Outputs:
552
+ # rot_q_rope [B, T, Dr]
553
+ #
554
+ # ---- rotated * sin ----
555
+ # TODO
556
+ q_rotated = (q_rope * cos) + (rotate_half(q_rope) * sin)
557
+ k_rotated = (k_rope * cos) + (rotate_half(k_rope) * sin)
558
+
559
+ # 4. Concatenate the rotated and pass-through parts back together
560
+ # Input (each): [B, H, T, Dr] and [B, H, T, Dq-Dr]
561
+ # Output (each): [B, H, T, Dq]
562
+ queries = torch.cat((q_rotated, q_pass), dim=-1)
563
+ keys = torch.cat((k_rotated, k_pass), dim=-1)
564
+
565
+ # ===================
566
+ # Attention
567
+ # ===================
568
+ # The tensors (queries, keys, values) now have shape [B, H, T, Dq]
569
+ # and are ready for the attention score calculation.
570
+
571
+ # Only apply dropout during training.
572
+ # self.training is a pytorch flag.
573
+ if self.training:
574
+ dropout_p = self.attention_dropout_prob
575
+ else:
576
+ dropout_p = 0.0
577
+
578
+ # Call SDPA / Flash Attention
579
+ # https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html
580
+ attn_output = F.scaled_dot_product_attention(
581
+ queries,
582
+ keys,
583
+ values,
584
+ attn_mask=None, # attention_mask,
585
+ dropout_p=dropout_p,
586
+ scale=self.softmax_scale,
587
+ is_causal=True, # This is a decoder - apply causal masking
588
+ )
589
+
590
+ # Reshape output back to [B, T, H * Dv] from [B, H, T, Dv]
591
+ attn_output = attn_output.transpose(1, 2).contiguous().view(B, T, H * Dv)
592
+
593
+ # =========================
594
+ # Output Projection
595
+ # =========================
596
+
597
+ # If we are using an output latent projection,
598
+ if self.latent_spaces and self.output_subspace:
599
+
600
+ # Project the attention output into the output latent space.
601
+ # This is analogous to the W^O matrix in standard attention but
602
+ # projects to an intermediate latent dimension.
603
+ attn_output = self.o_private_proj(attn_output)
604
+
605
+ # Apply normalization to the output latents
606
+ attn_output = self.o_private_norm(attn_output)
607
+
608
+ # Re-project the output latent representation back to model space.
609
+ attn_output = self.o_shared_proj(attn_output)
610
+
611
+ # If this is a dense layer,
612
+ else:
613
+ # Project the values back into model space.
614
+ attn_output = self.o_proj(attn_output)
615
+
616
+ # -----------------------------------------
617
+
618
+ return attn_output
619
+
checkpoint-2700/optimizer.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5f7a1430fc97b046dd29e562728ef516f253dba0862a4e8159c3b0f62449c3ba
3
+ size 988989899
checkpoint-2700/pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bb5ec96e21b65268860c6e701fc4420d405a47a2a6ccf3b86e30f1c05dcca018
3
+ size 494483579
checkpoint-2700/rng_state.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3c35fc70182e7ca9c2fecd3307516287efe33bd69963aae42900e793d8582f9b
3
+ size 14645
checkpoint-2700/scheduler.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3c42329fe9ce60834aecb564501f655ead9473db295ff06d83d914a3e71fedd4
3
+ size 1465
checkpoint-2700/shared_space_config.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# `shared_space_config.py`
2
+
3
+ #### `*Config`
4
+ """
5
+
6
+ from typing import Optional
7
+
8
+ import torch
9
+ from torch import nn
10
+
11
+ from transformers.configuration_utils import PretrainedConfig
12
+ from transformers.modeling_utils import PreTrainedModel
13
+
14
+ """`def make_shorthand`"""
15
+
16
+ def make_shorthand(model_cfg):
17
+ """
18
+ Takes an instance subencoder `*Config` and constructs a shorthand
19
+ name for the model based on settings.
20
+ """
21
+
22
+ dense_str = str(model_cfg.num_dense_layers) + "mha + "
23
+
24
+ if model_cfg.o_shared_dim is not None:
25
+ o_str = "." + str(model_cfg.o_shared_dim)
26
+ else:
27
+ o_str = ""
28
+
29
+ # If no output subspace is used, the dimension will show as -1.
30
+ attn_str = (
31
+ dense_str
32
+ + "mla."
33
+ + str(model_cfg.q_shared_dim)
34
+ + "."
35
+ + str(model_cfg.kv_shared_dim)
36
+ + o_str
37
+ )
38
+
39
+ # MLP Configuration
40
+ if model_cfg.ffn_decompose:
41
+ dense_str = (
42
+ str(model_cfg.num_dense_layers)
43
+ + "mlp."
44
+ + str(model_cfg.intermediate_size)
45
+ + " + "
46
+ )
47
+
48
+ mlp_str = (
49
+ dense_str
50
+ + str(model_cfg.num_hidden_layers - model_cfg.num_dense_layers)
51
+ + "dcmp."
52
+ + "x"
53
+ + str(model_cfg.intermediate_size)
54
+ + "."
55
+ + str(model_cfg.ffn_rank)
56
+ )
57
+ else:
58
+ mlp_str = "mlp." + str(model_cfg.intermediate_size)
59
+
60
+ # Assemble string
61
+ shorthand = (
62
+ f"{attn_str} - {mlp_str} - "
63
+ f"h{model_cfg.hidden_size} - l{model_cfg.num_hidden_layers}"
64
+ )
65
+
66
+ """
67
+ The run name includes training settings
68
+
69
+ run_name = (
70
+ f"{config['stats']['total_elements']} - "
71
+ f"{attn_str} - {mlp_str} - "
72
+ f"h{model_cfg.hidden_size} - l{model_cfg.num_hidden_layers} - "
73
+ f"bs{ptrain_cfg['train_batch_size']} - lr{lr_str} - "
74
+ f"seq{ptrain_cfg['max_seq_length']}"
75
+ )
76
+ """
77
+
78
+ return shorthand
79
+
80
+
81
+ class SharedSpaceDecoderConfig(PretrainedConfig):
82
+ r"""
83
+ Configuration class for SharedSpaceDecoderConfig.
84
+
85
+ Extends the HuggingFace `PretrainedConfig` to support architectural
86
+ variations including:
87
+ - Multi-Head Latent Attention (MLA)
88
+ - Decomposed MLPs (low-rank FFNs)
89
+ - Flexible attention backends (eager, flash, sdpa)
90
+ - Explicit shared subspaces for Q, K, V, and O projections
91
+
92
+ This config does not infer any defaults based on `hidden_size`. All
93
+ dimensions and ranks must be explicitly specified. If required values are
94
+ missing, a `ValueError` is raised during initialization.
95
+
96
+ ----------------------
97
+ Core Model Parameters:
98
+ ----------------------
99
+ - vocab_size (`int`) — Vocabulary size.
100
+ - hidden_size (`int`) — Model hidden dimension.
101
+ - num_hidden_layers (`int`) — Number of transformer blocks.
102
+ - intermediate_size (`int`) — Feed-forward hidden dimension.
103
+ - hidden_act (`str`) — Activation function.
104
+ - hidden_dropout_prob (`float`) — Dropout after projections and FFNs.
105
+ - attention_dropout_prob (`float`) — Dropout applied to attention scores.
106
+ - max_position_embeddings (`int`) — Max sequence length.
107
+ - initializer_range (`float`) — Stddev of weight init.
108
+
109
+ - layer_norm_eps (`float`) — Epsilon for LayerNorm.
110
+ - rms_norm_ps (`float`) — Epsilon for RMSNorm
111
+
112
+ - classifier_dropout (`float` or None) — Dropout for final classifier.
113
+
114
+ - vocab_subspace
115
+ - vocab_rank
116
+
117
+ ----------------------------------
118
+ Multi-Head Latent Attention (MLA):
119
+ ----------------------------------
120
+ - num_attention_heads (`int`) — Number of attention heads.
121
+
122
+ - q_shared_dim (`int`) — Rank of the shared query subspace.
123
+ - kv_shared_dim (`int`) — Rank of the shared key/value subspace.
124
+
125
+ - output_subspace (`bool`) — Whether to use a shared latent subspace for output projections.
126
+ - o_shared_dim (`int`) — Rank of the shared output subspace (required if `output_subspace=True`).
127
+ - qk_private_dim (`int`) — Query/key private dimension per head.
128
+ - vo_private_dim (`int`) — Value/output private dimension per head.
129
+
130
+ - rope_dims (`int`) — Number of head dimensions carrying RoPE.
131
+ - nope_dims (`int`) — Non-positional encoding dimensions.
132
+ - rope_theta (`float`) — Base frequency used for RoPE.
133
+ - rope_scaling (`dict` or None) — HF-style scaling dict for RoPE.
134
+ - attention_bias (`bool`) — Whether to include bias terms in Q/K/V projections.
135
+ - num_dense_layers (`int`) — Number of leading layers that do not use
136
+ subspaces for attention or FFNs.
137
+ - attention_backend (`str`) — Must be one of `"eager"`, `"flash_attention_2"`, or `"sdpa"`.
138
+
139
+ ----------------------
140
+ Decomposed MLP (Low-Rank FFN):
141
+ ----------------------
142
+ - ffn_decompose (`bool`) — Whether to enable low-rank FFNs.
143
+ - ffn_rank (`int`) — Rank of the shared FFN latent space (required if `ffn_decompose=True`).
144
+
145
+ ----------------------
146
+ Validation Behavior:
147
+ ----------------------
148
+ Raises `ValueError` at init time if:
149
+ - FFN decomposition is enabled without specifying `ffn_rank`.
150
+ - An unknown `attention_backend` is provided.
151
+ """
152
+
153
+ model_type = "shared_subspace_decoder"
154
+
155
+ def __init__(
156
+ self,
157
+
158
+ # === Core Model ===
159
+ vocab_size: int = 30522,
160
+ hidden_size: int = 512,
161
+ num_hidden_layers: int = 12,
162
+
163
+ intermediate_size: int = 3072,
164
+
165
+ hidden_dropout_prob=0.1,
166
+ attention_dropout_prob=0.1,
167
+ max_position_embeddings: int = 2048,
168
+ initializer_range=0.02,
169
+ layer_norm_eps=1e-12,
170
+ rms_norm_eps=1e-6, # Their default, but confirm in config.
171
+ norm_type="layernorm", # Choice between "layernorm" and "rmsnorm"
172
+ classifier_dropout=None,
173
+
174
+ vocab_subspace=False,
175
+ vocab_rank=None,
176
+ tie_word_embeddings=True,
177
+
178
+ # === Multi-Head Latent Attention ===
179
+ num_attention_heads: int = 16,
180
+ rope_dims: int = 16,
181
+
182
+ q_shared_dim: int = None,
183
+ kv_shared_dim: int = None,
184
+
185
+ o_shared_dim=None, # If None, no output subspace is used
186
+
187
+ # Private head dimensions
188
+ qk_private_dim: int = None, # Query/key private dimension per head
189
+ vo_private_dim: int = None, # Value/output private dimension per head
190
+ nope_dims: int = None, # Non-positional encoding dimensions
191
+
192
+ attention_backend="eager",
193
+ rope_theta=10000.0,
194
+ rope_scaling=None,
195
+ attention_bias=False,
196
+
197
+ # === MLA Composition ===
198
+ num_dense_layers=12, # dense MHA layers before MLA starts
199
+
200
+ # === Decomposed MLP ===
201
+ ffn_decompose=False,
202
+ ffn_rank=None,
203
+ **kwargs
204
+ ) -> None:
205
+ super().__init__(**kwargs)
206
+
207
+
208
+
209
+ # === Core Model ===
210
+ self.vocab_size = vocab_size
211
+ self.hidden_size = hidden_size
212
+ self.num_hidden_layers = num_hidden_layers
213
+ self.intermediate_size = intermediate_size
214
+ self.hidden_dropout_prob = hidden_dropout_prob
215
+ self.attention_dropout_prob = attention_dropout_prob
216
+ self.max_position_embeddings = max_position_embeddings
217
+ self.initializer_range = initializer_range
218
+ self.layer_norm_eps = layer_norm_eps
219
+ self.rms_norm_eps = rms_norm_eps
220
+ self.norm_type = norm_type
221
+ self.classifier_dropout = classifier_dropout
222
+
223
+ self.vocab_subspace = vocab_subspace
224
+ self.vocab_rank = vocab_rank
225
+ self.tie_word_embeddings = tie_word_embeddings
226
+
227
+ # === MLA ===
228
+ self.num_attention_heads = num_attention_heads
229
+ self.rope_dims = rope_dims
230
+
231
+ self.q_shared_dim = q_shared_dim
232
+ self.kv_shared_dim = kv_shared_dim
233
+ self.o_shared_dim = o_shared_dim
234
+
235
+ # Private head dimensions
236
+ self.qk_private_dim = qk_private_dim
237
+ self.vo_private_dim = vo_private_dim
238
+ self.nope_dims = nope_dims
239
+ self.rope_theta = rope_theta
240
+ self.rope_scaling = rope_scaling
241
+ self.attention_bias = attention_bias
242
+ self.num_dense_layers = num_dense_layers
243
+
244
+ # === Decomposed FFN ===
245
+ self.ffn_decompose = ffn_decompose
246
+ self.ffn_rank = ffn_rank
247
+
248
+ # === Attention backend ===
249
+ self.attention_backend = attention_backend
250
+
251
+ # === Validation ===
252
+ # TODO - Somewhere during training these get instantiated with bad
253
+ # values...
254
+ #self._validate()
255
+
256
+ #print(f" > SubEnc *Config.init: {make_shorthand(self)}\n")
257
+
258
+
259
+ def _validate(self):
260
+ # === Model ===
261
+ if self.num_dense_layers > self.num_hidden_layers:
262
+ raise ValueError("`num_dense_layers` must be <= `num_hidden_layers`")
263
+ if self.vocab_subspace and self.vocab_rank is None:
264
+ raise ValueError("`vocab_rank` must be set when `vocab_subspace=True`")
265
+
266
+ # === MLA Validation ===
267
+ # At least one of q_shared_dim or kv_shared_dim must be set if we have subspace layers
268
+ if self.num_dense_layers < self.num_hidden_layers and self.q_shared_dim is None and self.kv_shared_dim is None:
269
+ raise ValueError("At least one of q_shared_dim or kv_shared_dim must be set when there are subspace layers")
270
+
271
+ # Validate that private dimensions are set
272
+ if self.qk_private_dim is None or self.vo_private_dim is None:
273
+ raise ValueError("Must set qk_private_dim and vo_private_dim")
274
+ if self.nope_dims is None:
275
+ raise ValueError("Must set nope_dims")
276
+
277
+ # === Decomposed FFN ===
278
+ if self.ffn_decompose and self.ffn_rank is None:
279
+ raise ValueError("`ffn_rank` must be set when `ffn_decompose=True`")
280
+ if self.ffn_decompose and self.num_dense_layers >= self.num_hidden_layers:
281
+ raise ValueError("`ffn_decompose` was set but `num_dense` is >= number of layers")
282
+
283
+ # === Attention Backend ===
284
+ valid_backends = ["eager", "flash_attention_2", "sdpa"]
285
+ if self.attention_backend not in valid_backends:
286
+ raise ValueError(f"Unknown attention backend: {self.attention_backend}, options are {valid_backends}")
287
+
288
+ # === Norm Type ===
289
+ valid_norm_types = ["layernorm", "rmsnorm"]
290
+ if self.norm_type not in valid_norm_types:
291
+ raise ValueError(f"Unknown norm type: {self.norm_type}, options are {valid_norm_types}")
292
+
293
+ #### `get_config`
294
+
295
+ import json
296
+
297
+ def get_config(filename):
298
+
299
+ # Load the config file.
300
+ with open(filename) as f:
301
+ full_cfg = json.load(f)
302
+
303
+ # Strict key check on the model configuration.
304
+
305
+ # Get the list of keys allowed / required by `*Config`
306
+ valid_keys = SharedSpaceDecoderConfig.__init__.__code__.co_varnames
307
+ # Remove `self` and `kwargs`
308
+ valid_keys = set(valid_keys) - {"self", "kwargs"}
309
+
310
+ # Compare the set of keys in the json file vs `*Config`
311
+ extra_keys = set(full_cfg["model"]) - valid_keys
312
+ missing_keys = valid_keys - set(full_cfg["model"])
313
+
314
+ # If there any in the `json` that aren't in `*Config`,
315
+ if extra_keys:
316
+ # List them for the user.
317
+ raise ValueError(f"Unknown keys in config: {sorted(extra_keys)}")
318
+
319
+ # If the json config is missing required keys,
320
+ if missing_keys:
321
+ # List them for the user.
322
+ raise ValueError(f"config json is missing: {sorted(missing_keys)}")
323
+
324
+ # Will raise TypeError, by design, if required args are missing
325
+ # The asterisks unpack the dictionary into a list of keywords as though
326
+ # all of the settings were writting out individually.
327
+ model_cfg = SharedSpaceDecoderConfig(**full_cfg["model"])
328
+
329
+ return full_cfg, model_cfg
checkpoint-2700/shared_space_decoder.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """# shared_subspace_encoder.py"""
4
+
5
+ from typing import Optional
6
+
7
+ import torch
8
+ from torch import nn
9
+
10
+ from transformers.configuration_utils import PretrainedConfig
11
+ from transformers.modeling_utils import PreTrainedModel
12
+ from transformers.modeling_attn_mask_utils import _prepare_4d_attention_mask_for_sdpa
13
+
14
+ from .mla import MultiheadLatentAttention, RotaryEmbedding
15
+ from .feedforward import SubspaceFeedForward
16
+ from .shared_space_config import SharedSpaceDecoderConfig
17
+
18
+ """`RMSNorm`
19
+
20
+ From:
21
+ https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py
22
+
23
+ TODO - May not need?
24
+ """
25
+
26
+ class DeepseekV3RMSNorm(nn.Module):
27
+ def __init__(self, hidden_size, eps=1e-6):
28
+ """
29
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
30
+ """
31
+ super().__init__()
32
+ self.weight = nn.Parameter(torch.ones(hidden_size))
33
+ self.variance_epsilon = eps
34
+
35
+ def forward(self, hidden_states):
36
+ input_dtype = hidden_states.dtype
37
+ hidden_states = hidden_states.to(torch.float32)
38
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
39
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
40
+ return self.weight * hidden_states.to(input_dtype)
41
+
42
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
43
+ """
44
+ Create a normalization layer based on the config norm_type.
45
+
46
+ Args:
47
+ hidden_size: The dimension to normalize over
48
+ config: Configuration containing norm_type and epsilon values
49
+
50
+ Returns:
51
+ Either a LayerNorm or RMSNorm layer
52
+ """
53
+ if config.norm_type == "layernorm":
54
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
55
+ elif config.norm_type == "rmsnorm":
56
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
57
+ else:
58
+ # This should be caught by config validation, but being defensive
59
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
60
+
61
+ """#### *PreTrainedModel"""
62
+
63
+ class SharedSpaceDecoderPreTrainedModel(PreTrainedModel):
64
+ """
65
+ The **PreTrainedModel object:
66
+ - Is instantiated when TODO
67
+ - Initializes:
68
+ - TODO
69
+ - Provides access to TODO
70
+ - Executes TODO
71
+ """
72
+
73
+ config_class = SharedSpaceDecoderConfig
74
+ base_model_prefix = "model"
75
+
76
+ def _init_weights(self, module: nn.Module) -> None:
77
+ """Weight initialization hook used by :class:`PreTrainedModel`.
78
+
79
+ ``PreTrainedModel.post_init`` will recursively apply this function to
80
+ every submodule right after construction. HuggingFace models override
81
+ it so that creating a model from scratch yields the same initialization
82
+ as ``from_pretrained`` when no checkpoint is supplied.
83
+
84
+ This decoder-specific initialization strategy includes:
85
+ - Proper handling of configurable normalization layers (LayerNorm or RMSNorm)
86
+ - Special initialization for language modeling heads
87
+ - Considerations for causal attention and autoregressive modeling
88
+ - Support for both dense and decomposed vocabulary embeddings
89
+ """
90
+
91
+ if isinstance(module, nn.Linear):
92
+ # Standard linear layer initialization
93
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
94
+ if module.bias is not None:
95
+ module.bias.data.zero_()
96
+
97
+ elif isinstance(module, nn.Embedding):
98
+ # Initialize embeddings with normal distribution
99
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
100
+ if module.padding_idx is not None:
101
+ module.weight.data[module.padding_idx].zero_()
102
+
103
+ elif isinstance(module, DeepseekV3RMSNorm):
104
+ # RMSNorm initialization: weight to 1.0, no bias term
105
+ module.weight.data.fill_(1.0)
106
+
107
+ elif isinstance(module, nn.LayerNorm):
108
+ # LayerNorm initialization: bias to 0, weight to 1.0
109
+ module.bias.data.zero_()
110
+ module.weight.data.fill_(1.0)
111
+
112
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
113
+
114
+ # Classes
115
+ """
116
+
117
+ """#### `*Layer`"""
118
+
119
+ class SharedSpaceDecoderLayer(nn.Module):
120
+ """
121
+ The **Layer object:
122
+ - Is instantiated by :class:`SharedSpaceDecoderModel` for each
123
+ Transformer block in the decoder.
124
+ - Initializes:
125
+ - ``self_attn`` – multi-head latent attention implementing either
126
+ dense or latent projections depending on the configuration.
127
+ - ``ffn`` – a :class:`SubspaceFeedForward` block.
128
+ - RMSNorm layers for pre-attention and pre-FFN normalization.
129
+ - Provides access to the attention and feed-forward submodules via the
130
+ attributes ``self_attn`` and ``ffn``.
131
+ - Executes a single decoder block in :meth:`forward`.
132
+ """
133
+
134
+ def __init__(self, config: SharedSpaceDecoderConfig, layer_idx: int) -> None:
135
+
136
+ super().__init__()
137
+
138
+ # Norm applied prior to attention.
139
+ self.attn_input_norm = create_norm_layer(config.hidden_size, config)
140
+
141
+ # Attention block
142
+ self.self_attn = MultiheadLatentAttention(config, layer_idx)
143
+
144
+ # Norm applied prior to FFN
145
+ self.ffn_input_norm = create_norm_layer(config.hidden_size, config)
146
+
147
+ # Feed-forward network used after attention
148
+ self.ffn = SubspaceFeedForward(config, layer_idx)
149
+
150
+ def forward(
151
+ self,
152
+ hidden_states: torch.Tensor,
153
+ position_embeddings: tuple[torch.Tensor, torch.Tensor], # RoPE embeddings
154
+ attention_mask: Optional[torch.Tensor],
155
+ ) -> torch.Tensor:
156
+
157
+ # ========================
158
+ # Self Attention
159
+ # ========================
160
+ residual_strm = hidden_states
161
+
162
+ # Normalize the hidden states to create the input to attention.
163
+ attn_input = self.attn_input_norm(hidden_states)
164
+
165
+ # Evaluate
166
+ attn_output = self.self_attn(
167
+ attn_input,
168
+ position_embeddings,
169
+ attention_mask,
170
+ )
171
+
172
+ # Add the attention output (the residual) back to the non-normalized
173
+ # hidden_states.
174
+ hidden_states = residual_strm + attn_output
175
+
176
+ # ===========================
177
+ # Feed-Forward Network
178
+ # ===========================
179
+ residual_strm = hidden_states
180
+
181
+ # Normalize the updated hidden states prior to the FFN
182
+ ffn_input = self.ffn_input_norm(hidden_states)
183
+
184
+ # Evaluate
185
+ ffn_output = self.ffn(ffn_input)
186
+
187
+ # Add the output the un-normalized hidden states.
188
+ hidden_states = residual_strm + ffn_output
189
+
190
+ return hidden_states
191
+
192
+ """#### *Model"""
193
+
194
+ class SharedSpaceDecoderModel(SharedSpaceDecoderPreTrainedModel):
195
+ """
196
+ The **Model object:
197
+ - Initializes:
198
+ - The vocabulary embeddings (and optional decomposition)
199
+ - Position embeddings (calculated in RotaryEmbedding)
200
+ - All of the **Layer objects.
201
+ - Provides interface to vocab embeddings.
202
+ - Executes the whole decoder model in `forward` with causal attention.
203
+
204
+ This is the base decoder without the language modeling head.
205
+ Use SubspaceDecoderForCausalLM for language modeling tasks.
206
+ """
207
+
208
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
209
+ super().__init__(config)
210
+
211
+ # ============================
212
+ # Vocabulary Embeddings
213
+ # ============================
214
+ # Decomposing the vocabulary (if enabled) defines a shared projection
215
+ # which constrains the model to store semantic information (and
216
+ # whatever other static token knowledge) into a limited set of
217
+ # feature directions.
218
+
219
+ # If we're decomposing the token embeddings,
220
+ # TODO - Rename to vocab_subspace.
221
+ if config.vocab_subspace:
222
+
223
+ # Create the embedding table. Vocabulary embeddings are learned
224
+ # in a lower dimensional latent space.
225
+ self.vocab_embed = nn.Embedding(
226
+ config.vocab_size, # Number of tokens
227
+ config.vocab_rank # Subspace dimension
228
+ )
229
+
230
+ # Create a
231
+ # Selected token latents will be projected up to model size.
232
+ # vocab_proj has shape [vocab_rank x model_size]
233
+ self.vocab_proj = nn.Linear(
234
+ config.vocab_rank, # Size of latents
235
+ config.hidden_size, # Model size
236
+ bias=False
237
+ )
238
+
239
+ # Otherwise, for a dense vocabulary,
240
+ else:
241
+ # Create the dense embedding table in model space.
242
+ self.vocab_embed = nn.Embedding(
243
+ config.vocab_size, # Number of tokens
244
+ config.hidden_size # Model size
245
+ )
246
+
247
+ self.vocab_proj = None
248
+
249
+ # =====================
250
+ # RoPE Embeddings
251
+ # =====================
252
+
253
+ # Pre-computes the table of RoPE embeddings, leaving them in
254
+ # GPU memory.
255
+ self.rope = RotaryEmbedding(config)
256
+
257
+ # ===================
258
+ # Create Layers
259
+ # ===================
260
+
261
+ layers = []
262
+
263
+ # For each layer,
264
+ for i in range(config.num_hidden_layers):
265
+ # Create a **Layer, providing the config and indicating its number.
266
+ layers.append(
267
+ SharedSpaceDecoderLayer(
268
+ config,
269
+ layer_idx = i
270
+ )
271
+ )
272
+
273
+ # Wrap in torch ModuleList
274
+ self.layers = nn.ModuleList(layers)
275
+
276
+ # Whatever huggingface does behind the scenes...
277
+ self.post_init()
278
+
279
+ # Agents: Do not define boilerplate helpers, e.g., get/set_input_embeddings
280
+
281
+
282
+ def embed(self, input_ids: torch.LongTensor) -> torch.Tensor:
283
+ """
284
+ Return token embeddings for input ids.
285
+ This will perform the up projection to model space if the vocabulary is
286
+ decomposed.
287
+
288
+ input_ids have shape [batch_size, seq_len]
289
+ """
290
+
291
+ # If the vocabulary is decomposed,
292
+ if self.vocab_proj is not None:
293
+
294
+ # Retrieve the latents
295
+ # input_ids: [batch_size, seq_len]
296
+ # x: [batch_size, seq_len, latent_dim]
297
+ x = self.vocab_embed(input_ids)
298
+
299
+ # Project the latents back to model space and return.
300
+ return(self.vocab_proj(x))
301
+
302
+ # If the vocabulary is dense,
303
+ else:
304
+ # Just return the embeddings.
305
+ return self.vocab_embed(input_ids)
306
+
307
+ def forward(
308
+ self,
309
+ input_ids: torch.LongTensor,
310
+ attention_mask: Optional[torch.Tensor] = None,
311
+ **kwargs,
312
+ ) -> torch.Tensor:
313
+ """
314
+ Run the full decoder stack with causal attention.
315
+
316
+ Inputs:
317
+ input_ids [batch_size, seq_len]
318
+ attention_mask [batch_size, seq_len] - 1 for real tokens, 0 for padding
319
+
320
+ Returns:
321
+ Final decoder layer output [batch_size, seq_len, model_size]
322
+ """
323
+
324
+ # Retrieve the token embeddings for this sequence.
325
+ # These are model_size, regardless of whether the vocab is decompd.
326
+ hidden_states = self.embed(input_ids)
327
+
328
+ # Retrieve the rotary position embeddings for all of the positions in
329
+ # our current input sequence.
330
+
331
+ seq_len = hidden_states.size(1)
332
+
333
+ # Retrieves just the ones necessary for the sequence length of the
334
+ # input. These are vectors, two per token. Their length is the
335
+ # number of head dimensions we're applying RoPE to.
336
+ # Input
337
+ # cos: [max_seq_len, rope_dims]
338
+ # sin: [max_seq_len, rope_dims]
339
+ # Outputs:
340
+ # R_cos [seq_len, rope_dims]
341
+ # R_sin [seq_len, rope_dims]
342
+ R_cos = self.rope.cos[:seq_len]
343
+ R_sin = self.rope.sin[:seq_len]
344
+
345
+
346
+ # ===============================
347
+ # Attention Mask Conversion
348
+ # ===============================
349
+
350
+ """
351
+ use_sdpa_attention_masks = (
352
+ self.attn_implementation == "sdpa"
353
+ and self.position_embedding_type == "absolute"
354
+ and head_mask is None
355
+ and not output_attentions
356
+ )
357
+ """
358
+
359
+ # Expand the attention mask
360
+ #if use_sdpa_attention_masks and attention_mask.dim() == 2:
361
+ if True:
362
+ # Expand the attention mask for SDPA.
363
+ # [bsz, seq_len] -> [bsz, 1, seq_len, seq_len]
364
+ extended_attention_mask = _prepare_4d_attention_mask_for_sdpa(
365
+ attention_mask,
366
+ hidden_states.dtype,
367
+ tgt_len = seq_len
368
+ )
369
+ attention_mask = extended_attention_mask
370
+
371
+
372
+ # Run the model!
373
+
374
+ # For each decoder layer,
375
+ for layer_i, layer in enumerate(self.layers):
376
+
377
+ # Evaluate the layer
378
+ hidden_states = layer(
379
+ hidden_states, # Token embeddings
380
+ (R_cos, R_sin), # Rope embeddings, passed as a tuple.
381
+ attention_mask, # Attn mask
382
+ )
383
+
384
+ # Return the final output of the decoder stack.
385
+ return hidden_states
386
+
checkpoint-2700/special_tokens_map.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": "<|endoftext|>",
3
+ "eos_token": "<|endoftext|>",
4
+ "pad_token": "<|endoftext|>",
5
+ "unk_token": "<|endoftext|>"
6
+ }
checkpoint-2700/task_heads.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ from typing import Optional, Union
6
+
7
+ from transformers.modeling_outputs import CausalLMOutputWithPast
8
+
9
+ from .shared_space_config import SharedSpaceDecoderConfig
10
+ from .shared_space_decoder import (
11
+ SharedSpaceDecoderPreTrainedModel,
12
+ SharedSpaceDecoderModel,
13
+ DeepseekV3RMSNorm
14
+ )
15
+
16
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
17
+ """
18
+ Create a normalization layer based on the config norm_type.
19
+
20
+ Args:
21
+ hidden_size: The dimension to normalize over
22
+ config: Configuration containing norm_type and epsilon values
23
+
24
+ Returns:
25
+ Either a LayerNorm or RMSNorm layer
26
+ """
27
+ if config.norm_type == "layernorm":
28
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
29
+ elif config.norm_type == "rmsnorm":
30
+ from .shared_space_decoder import DeepseekV3RMSNorm
31
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
32
+ else:
33
+ # This should be caught by config validation, but being defensive
34
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
35
+
36
+
37
+ class SharedSpaceDecoderForCausalLM(SharedSpaceDecoderPreTrainedModel):
38
+ """
39
+ Subspace Decoder model with a causal language modeling head.
40
+
41
+ This model extends the SharedSpaceDecoderModel with:
42
+ - A language modeling head that projects hidden states to vocabulary logits
43
+ - Support for computing cross-entropy loss for language modeling
44
+ - Proper HuggingFace compatibility for causal language modeling tasks
45
+ - Decoder-specific initialization strategies
46
+
47
+ The model can be used for:
48
+ - Text generation
49
+ - Language modeling pretraining
50
+ - Fine-tuning on downstream tasks
51
+ """
52
+
53
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
54
+ super().__init__(config)
55
+
56
+ # Initialize the base decoder model
57
+ self.model = SharedSpaceDecoderModel(config)
58
+
59
+ # Final layer norm before the language modeling head
60
+ self.norm = create_norm_layer(config.hidden_size, config)
61
+
62
+ # Language modeling head
63
+ # Projects from hidden_size to vocab_size to get logits for each token
64
+ self.lm_head = nn.Linear(
65
+ config.hidden_size,
66
+ config.vocab_size,
67
+ bias=False # Following common practice in modern LMs
68
+ )
69
+
70
+ # Initialize weights with decoder-specific strategy
71
+ # Note: tie_weights() will be called automatically by post_init() if config.tie_word_embeddings=True
72
+ self.post_init()
73
+
74
+ def _init_weights(self, module: nn.Module) -> None:
75
+ """
76
+ Decoder-specific weight initialization with special handling for language modeling head.
77
+
78
+ Key differences from encoder initialization:
79
+ - Language modeling head gets specialized initialization for stability
80
+ - Configurable normalization layers (LayerNorm or RMSNorm) are properly handled
81
+ - Weight tying considerations for embedding/lm_head relationship
82
+ """
83
+
84
+ # Use the base class initialization for most modules
85
+ super()._init_weights(module)
86
+
87
+ # Special handling for language modeling head
88
+ if module is self.lm_head:
89
+ # Use smaller initialization for the language modeling head
90
+ # This helps with training stability in autoregressive generation
91
+ # Common practice is to use std=initializer_range or smaller
92
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
93
+
94
+ # If weight tying is not used, we might want even smaller init
95
+ if self.model.vocab_proj is not None:
96
+ # For vocab subspace models where weights aren't tied,
97
+ # use a smaller scale to prevent initial logits from being too large
98
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range * 0.5)
99
+
100
+ def get_input_embeddings(self):
101
+ """Return the input embedding layer for compatibility with HuggingFace."""
102
+ return self.model.vocab_embed
103
+
104
+ def set_input_embeddings(self, value):
105
+ """Set the input embedding layer for compatibility with HuggingFace."""
106
+ self.model.vocab_embed = value
107
+
108
+ def get_output_embeddings(self):
109
+ """Return the output embedding layer (lm_head) for compatibility."""
110
+ return self.lm_head
111
+
112
+ def set_output_embeddings(self, new_embeddings):
113
+ """Set the output embedding layer for compatibility."""
114
+ self.lm_head = new_embeddings
115
+
116
+ def tie_weights(self):
117
+ """
118
+ Tie the input and output embedding weights.
119
+
120
+ This method sets the language modeling head's weight to be the same as
121
+ the input embedding weight. This reduces the number of parameters and
122
+ is a common practice in modern language models.
123
+
124
+ Note: For vocab subspace models, we need to handle the case where
125
+ input embeddings go through a projection layer.
126
+ """
127
+ # Only tie when embeddings live in model space (no vocab_proj)
128
+ if getattr(self.model, "vocab_proj", None) is None:
129
+ # Use HF utility for correct tying/cloning semantics
130
+ self._tie_or_clone_weights(self.lm_head, self.model.vocab_embed)
131
+ # else: leave untied for subspace case
132
+
133
+
134
+ def forward(
135
+ self,
136
+ input_ids: torch.LongTensor,
137
+ attention_mask: Optional[torch.Tensor] = None,
138
+ labels: Optional[torch.LongTensor] = None,
139
+ **kwargs,
140
+ ) -> Union[CausalLMOutputWithPast, tuple]:
141
+ """
142
+ Forward pass for causal language modeling.
143
+
144
+ Args:
145
+ input_ids: Token ids of shape [batch_size, seq_len]
146
+ attention_mask: Attention mask of shape [batch_size, seq_len]
147
+ (1 for real tokens, 0 for padding)
148
+ labels: Ground truth token ids for computing loss. Same shape as input_ids.
149
+ If provided, loss will be computed. Typically input_ids shifted by 1.
150
+
151
+ Returns:
152
+ CausalLMOutputWithPast containing:
153
+ - logits: Prediction logits of shape [batch_size, seq_len, vocab_size]
154
+ - loss: Cross-entropy loss if labels provided, else None
155
+ - hidden_states: Final layer hidden states [batch_size, seq_len, hidden_size]
156
+ """
157
+
158
+ # Run the base decoder model
159
+ # This applies all the transformer layers with causal attention
160
+ hidden_states = self.model(
161
+ input_ids=input_ids,
162
+ attention_mask=attention_mask,
163
+ **kwargs
164
+ )
165
+
166
+ # Apply final layer normalization
167
+ # This normalizes the final hidden states before the language modeling head
168
+ hidden_states = self.norm(hidden_states)
169
+
170
+ # Project to vocabulary logits
171
+ # Shape: [batch_size, seq_len, vocab_size]
172
+ logits = self.lm_head(hidden_states)
173
+
174
+ # Compute loss if labels are provided
175
+ # Previously, we had custom loss computation here, but now we use the
176
+ # standard HuggingFace loss function.
177
+ loss = None
178
+ if labels is not None:
179
+ # Flatten the tokens
180
+ loss = self.loss_function(
181
+ logits,
182
+ labels,
183
+ vocab_size=self.config.vocab_size,
184
+ **kwargs,
185
+ )
186
+
187
+ # Return in HuggingFace format
188
+ return CausalLMOutputWithPast(
189
+ loss=loss,
190
+ logits=logits,
191
+ past_key_values=None, # Not implementing KV cache yet
192
+ #hidden_states=hidden_states,
193
+ hidden_states=hidden_states if kwargs.get("output_hidden_states", False) else None,
194
+ attentions=None,
195
+ )
196
+
checkpoint-2700/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
checkpoint-2700/tokenizer_config.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "50256": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": true,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ }
12
+ },
13
+ "bos_token": "<|endoftext|>",
14
+ "clean_up_tokenization_spaces": false,
15
+ "eos_token": "<|endoftext|>",
16
+ "extra_special_tokens": {},
17
+ "model_max_length": 1024,
18
+ "pad_token": "<|endoftext|>",
19
+ "tokenizer_class": "GPT2Tokenizer",
20
+ "unk_token": "<|endoftext|>"
21
+ }
checkpoint-2700/trainer_state.json ADDED
@@ -0,0 +1,1060 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "best_global_step": 2700,
3
+ "best_metric": 3.600645640400387,
4
+ "best_model_checkpoint": "checkpoints/gpt-2_seq1024_mla0-0-0/checkpoint-2700",
5
+ "epoch": 0.8138045362067666,
6
+ "eval_steps": 300,
7
+ "global_step": 2700,
8
+ "is_hyper_param_search": false,
9
+ "is_local_process_zero": true,
10
+ "is_world_process_zero": true,
11
+ "log_history": [
12
+ {
13
+ "epoch": 0.006028181749679753,
14
+ "grad_norm": 2.0441031455993652,
15
+ "learning_rate": 3.166666666666667e-05,
16
+ "loss": 10.3921,
17
+ "step": 20
18
+ },
19
+ {
20
+ "epoch": 0.012056363499359506,
21
+ "grad_norm": 1.7166392803192139,
22
+ "learning_rate": 6.500000000000001e-05,
23
+ "loss": 9.241,
24
+ "step": 40
25
+ },
26
+ {
27
+ "epoch": 0.01808454524903926,
28
+ "grad_norm": 0.7614754438400269,
29
+ "learning_rate": 9.833333333333333e-05,
30
+ "loss": 8.2219,
31
+ "step": 60
32
+ },
33
+ {
34
+ "epoch": 0.02411272699871901,
35
+ "grad_norm": 0.46116286516189575,
36
+ "learning_rate": 0.00013166666666666665,
37
+ "loss": 7.5368,
38
+ "step": 80
39
+ },
40
+ {
41
+ "epoch": 0.030140908748398764,
42
+ "grad_norm": 1.6069883108139038,
43
+ "learning_rate": 0.000165,
44
+ "loss": 7.21,
45
+ "step": 100
46
+ },
47
+ {
48
+ "epoch": 0.03616909049807852,
49
+ "grad_norm": 1.2077178955078125,
50
+ "learning_rate": 0.00019833333333333335,
51
+ "loss": 6.8976,
52
+ "step": 120
53
+ },
54
+ {
55
+ "epoch": 0.04219727224775827,
56
+ "grad_norm": 0.642643928527832,
57
+ "learning_rate": 0.00023166666666666667,
58
+ "loss": 6.641,
59
+ "step": 140
60
+ },
61
+ {
62
+ "epoch": 0.04822545399743802,
63
+ "grad_norm": 0.7632517218589783,
64
+ "learning_rate": 0.00026500000000000004,
65
+ "loss": 6.4194,
66
+ "step": 160
67
+ },
68
+ {
69
+ "epoch": 0.05425363574711778,
70
+ "grad_norm": 1.2542935609817505,
71
+ "learning_rate": 0.00029833333333333334,
72
+ "loss": 6.2428,
73
+ "step": 180
74
+ },
75
+ {
76
+ "epoch": 0.06028181749679753,
77
+ "grad_norm": 1.1738799810409546,
78
+ "learning_rate": 0.0003316666666666667,
79
+ "loss": 6.1026,
80
+ "step": 200
81
+ },
82
+ {
83
+ "epoch": 0.06630999924647728,
84
+ "grad_norm": 0.46843603253364563,
85
+ "learning_rate": 0.000365,
86
+ "loss": 5.9586,
87
+ "step": 220
88
+ },
89
+ {
90
+ "epoch": 0.07233818099615703,
91
+ "grad_norm": 0.3949953019618988,
92
+ "learning_rate": 0.00039833333333333333,
93
+ "loss": 5.8304,
94
+ "step": 240
95
+ },
96
+ {
97
+ "epoch": 0.07836636274583679,
98
+ "grad_norm": 1.0866719484329224,
99
+ "learning_rate": 0.0004316666666666667,
100
+ "loss": 5.7185,
101
+ "step": 260
102
+ },
103
+ {
104
+ "epoch": 0.08439454449551655,
105
+ "grad_norm": 0.34839189052581787,
106
+ "learning_rate": 0.000465,
107
+ "loss": 5.6037,
108
+ "step": 280
109
+ },
110
+ {
111
+ "epoch": 0.09042272624519629,
112
+ "grad_norm": 0.5791395902633667,
113
+ "learning_rate": 0.0004983333333333334,
114
+ "loss": 5.5003,
115
+ "step": 300
116
+ },
117
+ {
118
+ "epoch": 0.09042272624519629,
119
+ "eval_loss": 5.428642945231348,
120
+ "eval_perplexity": 227.839844387096,
121
+ "eval_runtime": 113.1707,
122
+ "eval_samples_per_second": 14.659,
123
+ "eval_steps_per_second": 0.23,
124
+ "step": 300
125
+ },
126
+ {
127
+ "epoch": 0.09645090799487605,
128
+ "grad_norm": 0.532134473323822,
129
+ "learning_rate": 0.0004964814814814814,
130
+ "loss": 5.3805,
131
+ "step": 320
132
+ },
133
+ {
134
+ "epoch": 0.1024790897445558,
135
+ "grad_norm": 0.5876124501228333,
136
+ "learning_rate": 0.0004927777777777777,
137
+ "loss": 5.2775,
138
+ "step": 340
139
+ },
140
+ {
141
+ "epoch": 0.10850727149423556,
142
+ "grad_norm": 0.4140375256538391,
143
+ "learning_rate": 0.0004890740740740741,
144
+ "loss": 5.193,
145
+ "step": 360
146
+ },
147
+ {
148
+ "epoch": 0.1145354532439153,
149
+ "grad_norm": 0.5529780387878418,
150
+ "learning_rate": 0.0004853703703703704,
151
+ "loss": 5.0912,
152
+ "step": 380
153
+ },
154
+ {
155
+ "epoch": 0.12056363499359506,
156
+ "grad_norm": 0.3331276774406433,
157
+ "learning_rate": 0.0004816666666666667,
158
+ "loss": 5.0266,
159
+ "step": 400
160
+ },
161
+ {
162
+ "epoch": 0.1265918167432748,
163
+ "grad_norm": 0.6916081309318542,
164
+ "learning_rate": 0.00047796296296296297,
165
+ "loss": 4.9375,
166
+ "step": 420
167
+ },
168
+ {
169
+ "epoch": 0.13261999849295456,
170
+ "grad_norm": 0.31799590587615967,
171
+ "learning_rate": 0.0004742592592592593,
172
+ "loss": 4.9026,
173
+ "step": 440
174
+ },
175
+ {
176
+ "epoch": 0.1386481802426343,
177
+ "grad_norm": 0.5735257267951965,
178
+ "learning_rate": 0.00047055555555555555,
179
+ "loss": 4.8075,
180
+ "step": 460
181
+ },
182
+ {
183
+ "epoch": 0.14467636199231407,
184
+ "grad_norm": 0.5078163146972656,
185
+ "learning_rate": 0.00046685185185185187,
186
+ "loss": 4.759,
187
+ "step": 480
188
+ },
189
+ {
190
+ "epoch": 0.15070454374199382,
191
+ "grad_norm": 0.3884360194206238,
192
+ "learning_rate": 0.00046314814814814813,
193
+ "loss": 4.6706,
194
+ "step": 500
195
+ },
196
+ {
197
+ "epoch": 0.15673272549167358,
198
+ "grad_norm": 0.5591968297958374,
199
+ "learning_rate": 0.00045944444444444445,
200
+ "loss": 4.627,
201
+ "step": 520
202
+ },
203
+ {
204
+ "epoch": 0.16276090724135334,
205
+ "grad_norm": 0.29390859603881836,
206
+ "learning_rate": 0.0004557407407407407,
207
+ "loss": 4.5691,
208
+ "step": 540
209
+ },
210
+ {
211
+ "epoch": 0.1687890889910331,
212
+ "grad_norm": 0.3524036407470703,
213
+ "learning_rate": 0.00045203703703703703,
214
+ "loss": 4.5066,
215
+ "step": 560
216
+ },
217
+ {
218
+ "epoch": 0.17481727074071282,
219
+ "grad_norm": 0.4607946574687958,
220
+ "learning_rate": 0.0004483333333333333,
221
+ "loss": 4.4661,
222
+ "step": 580
223
+ },
224
+ {
225
+ "epoch": 0.18084545249039258,
226
+ "grad_norm": 0.2523379623889923,
227
+ "learning_rate": 0.00044462962962962967,
228
+ "loss": 4.4331,
229
+ "step": 600
230
+ },
231
+ {
232
+ "epoch": 0.18084545249039258,
233
+ "eval_loss": 4.357323692651888,
234
+ "eval_perplexity": 78.04797429242741,
235
+ "eval_runtime": 112.5783,
236
+ "eval_samples_per_second": 14.736,
237
+ "eval_steps_per_second": 0.231,
238
+ "step": 600
239
+ },
240
+ {
241
+ "epoch": 0.18687363424007233,
242
+ "grad_norm": 0.3953287601470947,
243
+ "learning_rate": 0.00044092592592592594,
244
+ "loss": 4.3877,
245
+ "step": 620
246
+ },
247
+ {
248
+ "epoch": 0.1929018159897521,
249
+ "grad_norm": 0.38012024760246277,
250
+ "learning_rate": 0.00043722222222222225,
251
+ "loss": 4.3619,
252
+ "step": 640
253
+ },
254
+ {
255
+ "epoch": 0.19892999773943185,
256
+ "grad_norm": 0.3135126233100891,
257
+ "learning_rate": 0.0004335185185185185,
258
+ "loss": 4.3442,
259
+ "step": 660
260
+ },
261
+ {
262
+ "epoch": 0.2049581794891116,
263
+ "grad_norm": 0.49422895908355713,
264
+ "learning_rate": 0.00042981481481481484,
265
+ "loss": 4.3045,
266
+ "step": 680
267
+ },
268
+ {
269
+ "epoch": 0.21098636123879136,
270
+ "grad_norm": 0.27019643783569336,
271
+ "learning_rate": 0.0004261111111111111,
272
+ "loss": 4.2808,
273
+ "step": 700
274
+ },
275
+ {
276
+ "epoch": 0.21701454298847112,
277
+ "grad_norm": 0.3935423791408539,
278
+ "learning_rate": 0.0004224074074074074,
279
+ "loss": 4.2467,
280
+ "step": 720
281
+ },
282
+ {
283
+ "epoch": 0.22304272473815084,
284
+ "grad_norm": 0.28830042481422424,
285
+ "learning_rate": 0.0004187037037037037,
286
+ "loss": 4.2274,
287
+ "step": 740
288
+ },
289
+ {
290
+ "epoch": 0.2290709064878306,
291
+ "grad_norm": 0.2877708673477173,
292
+ "learning_rate": 0.000415,
293
+ "loss": 4.2075,
294
+ "step": 760
295
+ },
296
+ {
297
+ "epoch": 0.23509908823751036,
298
+ "grad_norm": 0.3449930250644684,
299
+ "learning_rate": 0.00041129629629629627,
300
+ "loss": 4.1909,
301
+ "step": 780
302
+ },
303
+ {
304
+ "epoch": 0.2411272699871901,
305
+ "grad_norm": 0.326265424489975,
306
+ "learning_rate": 0.00040759259259259264,
307
+ "loss": 4.1684,
308
+ "step": 800
309
+ },
310
+ {
311
+ "epoch": 0.24715545173686987,
312
+ "grad_norm": 0.3821180760860443,
313
+ "learning_rate": 0.0004038888888888889,
314
+ "loss": 4.1513,
315
+ "step": 820
316
+ },
317
+ {
318
+ "epoch": 0.2531836334865496,
319
+ "grad_norm": 0.2768200635910034,
320
+ "learning_rate": 0.0004001851851851852,
321
+ "loss": 4.1317,
322
+ "step": 840
323
+ },
324
+ {
325
+ "epoch": 0.2592118152362294,
326
+ "grad_norm": 0.29724735021591187,
327
+ "learning_rate": 0.0003964814814814815,
328
+ "loss": 4.1171,
329
+ "step": 860
330
+ },
331
+ {
332
+ "epoch": 0.2652399969859091,
333
+ "grad_norm": 0.2814749479293823,
334
+ "learning_rate": 0.0003927777777777778,
335
+ "loss": 4.1049,
336
+ "step": 880
337
+ },
338
+ {
339
+ "epoch": 0.2712681787355889,
340
+ "grad_norm": 0.26310989260673523,
341
+ "learning_rate": 0.00038907407407407407,
342
+ "loss": 4.0858,
343
+ "step": 900
344
+ },
345
+ {
346
+ "epoch": 0.2712681787355889,
347
+ "eval_loss": 4.030442206068737,
348
+ "eval_perplexity": 56.285795665128816,
349
+ "eval_runtime": 112.6912,
350
+ "eval_samples_per_second": 14.722,
351
+ "eval_steps_per_second": 0.231,
352
+ "step": 900
353
+ },
354
+ {
355
+ "epoch": 0.2772963604852686,
356
+ "grad_norm": 0.3063352108001709,
357
+ "learning_rate": 0.0003853703703703704,
358
+ "loss": 4.0813,
359
+ "step": 920
360
+ },
361
+ {
362
+ "epoch": 0.2833245422349484,
363
+ "grad_norm": 0.4063352346420288,
364
+ "learning_rate": 0.00038166666666666666,
365
+ "loss": 4.0647,
366
+ "step": 940
367
+ },
368
+ {
369
+ "epoch": 0.28935272398462814,
370
+ "grad_norm": 0.2601182758808136,
371
+ "learning_rate": 0.000377962962962963,
372
+ "loss": 4.0447,
373
+ "step": 960
374
+ },
375
+ {
376
+ "epoch": 0.29538090573430786,
377
+ "grad_norm": 0.3153649568557739,
378
+ "learning_rate": 0.00037425925925925924,
379
+ "loss": 4.0417,
380
+ "step": 980
381
+ },
382
+ {
383
+ "epoch": 0.30140908748398765,
384
+ "grad_norm": 0.26004716753959656,
385
+ "learning_rate": 0.0003705555555555556,
386
+ "loss": 4.0279,
387
+ "step": 1000
388
+ },
389
+ {
390
+ "epoch": 0.3074372692336674,
391
+ "grad_norm": 0.43524181842803955,
392
+ "learning_rate": 0.0003668518518518519,
393
+ "loss": 4.0152,
394
+ "step": 1020
395
+ },
396
+ {
397
+ "epoch": 0.31346545098334716,
398
+ "grad_norm": 0.2601913511753082,
399
+ "learning_rate": 0.0003631481481481482,
400
+ "loss": 4.0026,
401
+ "step": 1040
402
+ },
403
+ {
404
+ "epoch": 0.3194936327330269,
405
+ "grad_norm": 0.25712424516677856,
406
+ "learning_rate": 0.00035944444444444446,
407
+ "loss": 3.9933,
408
+ "step": 1060
409
+ },
410
+ {
411
+ "epoch": 0.3255218144827067,
412
+ "grad_norm": 0.3313097357749939,
413
+ "learning_rate": 0.0003557407407407408,
414
+ "loss": 3.9842,
415
+ "step": 1080
416
+ },
417
+ {
418
+ "epoch": 0.3315499962323864,
419
+ "grad_norm": 0.238124281167984,
420
+ "learning_rate": 0.00035203703703703704,
421
+ "loss": 3.9745,
422
+ "step": 1100
423
+ },
424
+ {
425
+ "epoch": 0.3375781779820662,
426
+ "grad_norm": 0.28039032220840454,
427
+ "learning_rate": 0.00034833333333333336,
428
+ "loss": 3.9588,
429
+ "step": 1120
430
+ },
431
+ {
432
+ "epoch": 0.3436063597317459,
433
+ "grad_norm": 0.3661600649356842,
434
+ "learning_rate": 0.0003446296296296296,
435
+ "loss": 3.9532,
436
+ "step": 1140
437
+ },
438
+ {
439
+ "epoch": 0.34963454148142564,
440
+ "grad_norm": 0.22854666411876678,
441
+ "learning_rate": 0.0003409259259259259,
442
+ "loss": 3.9392,
443
+ "step": 1160
444
+ },
445
+ {
446
+ "epoch": 0.3556627232311054,
447
+ "grad_norm": 0.2930833697319031,
448
+ "learning_rate": 0.0003372222222222222,
449
+ "loss": 3.9312,
450
+ "step": 1180
451
+ },
452
+ {
453
+ "epoch": 0.36169090498078516,
454
+ "grad_norm": 0.25500425696372986,
455
+ "learning_rate": 0.0003335185185185185,
456
+ "loss": 3.9295,
457
+ "step": 1200
458
+ },
459
+ {
460
+ "epoch": 0.36169090498078516,
461
+ "eval_loss": 3.874079793811062,
462
+ "eval_perplexity": 48.13838066773452,
463
+ "eval_runtime": 112.5895,
464
+ "eval_samples_per_second": 14.735,
465
+ "eval_steps_per_second": 0.231,
466
+ "step": 1200
467
+ },
468
+ {
469
+ "epoch": 0.36771908673046494,
470
+ "grad_norm": 0.27924397587776184,
471
+ "learning_rate": 0.00032981481481481485,
472
+ "loss": 3.9157,
473
+ "step": 1220
474
+ },
475
+ {
476
+ "epoch": 0.37374726848014467,
477
+ "grad_norm": 0.2649654448032379,
478
+ "learning_rate": 0.0003261111111111111,
479
+ "loss": 3.9136,
480
+ "step": 1240
481
+ },
482
+ {
483
+ "epoch": 0.37977545022982445,
484
+ "grad_norm": 0.27920904755592346,
485
+ "learning_rate": 0.00032240740740740743,
486
+ "loss": 3.899,
487
+ "step": 1260
488
+ },
489
+ {
490
+ "epoch": 0.3858036319795042,
491
+ "grad_norm": 0.238219752907753,
492
+ "learning_rate": 0.0003187037037037037,
493
+ "loss": 3.8965,
494
+ "step": 1280
495
+ },
496
+ {
497
+ "epoch": 0.3918318137291839,
498
+ "grad_norm": 0.2615567743778229,
499
+ "learning_rate": 0.000315,
500
+ "loss": 3.8877,
501
+ "step": 1300
502
+ },
503
+ {
504
+ "epoch": 0.3978599954788637,
505
+ "grad_norm": 0.266513466835022,
506
+ "learning_rate": 0.0003112962962962963,
507
+ "loss": 3.8806,
508
+ "step": 1320
509
+ },
510
+ {
511
+ "epoch": 0.4038881772285434,
512
+ "grad_norm": 0.3212108314037323,
513
+ "learning_rate": 0.0003075925925925926,
514
+ "loss": 3.8774,
515
+ "step": 1340
516
+ },
517
+ {
518
+ "epoch": 0.4099163589782232,
519
+ "grad_norm": 0.231920063495636,
520
+ "learning_rate": 0.00030388888888888886,
521
+ "loss": 3.8707,
522
+ "step": 1360
523
+ },
524
+ {
525
+ "epoch": 0.41594454072790293,
526
+ "grad_norm": 0.27022039890289307,
527
+ "learning_rate": 0.0003001851851851852,
528
+ "loss": 3.863,
529
+ "step": 1380
530
+ },
531
+ {
532
+ "epoch": 0.4219727224775827,
533
+ "grad_norm": 0.243785560131073,
534
+ "learning_rate": 0.00029648148148148144,
535
+ "loss": 3.8562,
536
+ "step": 1400
537
+ },
538
+ {
539
+ "epoch": 0.42800090422726245,
540
+ "grad_norm": 0.2512820065021515,
541
+ "learning_rate": 0.0002927777777777778,
542
+ "loss": 3.8541,
543
+ "step": 1420
544
+ },
545
+ {
546
+ "epoch": 0.43402908597694223,
547
+ "grad_norm": 0.25888124108314514,
548
+ "learning_rate": 0.0002890740740740741,
549
+ "loss": 3.8421,
550
+ "step": 1440
551
+ },
552
+ {
553
+ "epoch": 0.44005726772662196,
554
+ "grad_norm": 0.29554685950279236,
555
+ "learning_rate": 0.0002853703703703704,
556
+ "loss": 3.8468,
557
+ "step": 1460
558
+ },
559
+ {
560
+ "epoch": 0.4460854494763017,
561
+ "grad_norm": 0.2608514130115509,
562
+ "learning_rate": 0.00028166666666666666,
563
+ "loss": 3.837,
564
+ "step": 1480
565
+ },
566
+ {
567
+ "epoch": 0.45211363122598147,
568
+ "grad_norm": 0.2781771123409271,
569
+ "learning_rate": 0.000277962962962963,
570
+ "loss": 3.8327,
571
+ "step": 1500
572
+ },
573
+ {
574
+ "epoch": 0.45211363122598147,
575
+ "eval_loss": 3.776173532413324,
576
+ "eval_perplexity": 43.6487014373908,
577
+ "eval_runtime": 112.7037,
578
+ "eval_samples_per_second": 14.72,
579
+ "eval_steps_per_second": 0.231,
580
+ "step": 1500
581
+ },
582
+ {
583
+ "epoch": 0.4581418129756612,
584
+ "grad_norm": 0.27767959237098694,
585
+ "learning_rate": 0.00027425925925925925,
586
+ "loss": 3.8264,
587
+ "step": 1520
588
+ },
589
+ {
590
+ "epoch": 0.464169994725341,
591
+ "grad_norm": 0.24143943190574646,
592
+ "learning_rate": 0.00027055555555555557,
593
+ "loss": 3.8224,
594
+ "step": 1540
595
+ },
596
+ {
597
+ "epoch": 0.4701981764750207,
598
+ "grad_norm": 0.23281621932983398,
599
+ "learning_rate": 0.00026685185185185183,
600
+ "loss": 3.8114,
601
+ "step": 1560
602
+ },
603
+ {
604
+ "epoch": 0.4762263582247005,
605
+ "grad_norm": 0.23552870750427246,
606
+ "learning_rate": 0.00026314814814814815,
607
+ "loss": 3.8086,
608
+ "step": 1580
609
+ },
610
+ {
611
+ "epoch": 0.4822545399743802,
612
+ "grad_norm": 0.25271207094192505,
613
+ "learning_rate": 0.0002594444444444444,
614
+ "loss": 3.7954,
615
+ "step": 1600
616
+ },
617
+ {
618
+ "epoch": 0.48828272172405995,
619
+ "grad_norm": 0.2609969675540924,
620
+ "learning_rate": 0.0002557407407407408,
621
+ "loss": 3.8052,
622
+ "step": 1620
623
+ },
624
+ {
625
+ "epoch": 0.49431090347373974,
626
+ "grad_norm": 0.290229469537735,
627
+ "learning_rate": 0.00025203703703703705,
628
+ "loss": 3.7946,
629
+ "step": 1640
630
+ },
631
+ {
632
+ "epoch": 0.5003390852234195,
633
+ "grad_norm": 0.2184811681509018,
634
+ "learning_rate": 0.0002483333333333333,
635
+ "loss": 3.7913,
636
+ "step": 1660
637
+ },
638
+ {
639
+ "epoch": 0.5063672669730992,
640
+ "grad_norm": 0.24770255386829376,
641
+ "learning_rate": 0.00024462962962962963,
642
+ "loss": 3.7902,
643
+ "step": 1680
644
+ },
645
+ {
646
+ "epoch": 0.512395448722779,
647
+ "grad_norm": 0.2306816428899765,
648
+ "learning_rate": 0.00024092592592592593,
649
+ "loss": 3.7775,
650
+ "step": 1700
651
+ },
652
+ {
653
+ "epoch": 0.5184236304724588,
654
+ "grad_norm": 0.2789316475391388,
655
+ "learning_rate": 0.00023722222222222222,
656
+ "loss": 3.7774,
657
+ "step": 1720
658
+ },
659
+ {
660
+ "epoch": 0.5244518122221385,
661
+ "grad_norm": 0.2576800286769867,
662
+ "learning_rate": 0.0002335185185185185,
663
+ "loss": 3.7773,
664
+ "step": 1740
665
+ },
666
+ {
667
+ "epoch": 0.5304799939718182,
668
+ "grad_norm": 0.2184872031211853,
669
+ "learning_rate": 0.0002298148148148148,
670
+ "loss": 3.7739,
671
+ "step": 1760
672
+ },
673
+ {
674
+ "epoch": 0.536508175721498,
675
+ "grad_norm": 0.27034640312194824,
676
+ "learning_rate": 0.00022611111111111112,
677
+ "loss": 3.7632,
678
+ "step": 1780
679
+ },
680
+ {
681
+ "epoch": 0.5425363574711778,
682
+ "grad_norm": 0.2661360800266266,
683
+ "learning_rate": 0.0002224074074074074,
684
+ "loss": 3.7668,
685
+ "step": 1800
686
+ },
687
+ {
688
+ "epoch": 0.5425363574711778,
689
+ "eval_loss": 3.7104278931619175,
690
+ "eval_perplexity": 40.871291331988935,
691
+ "eval_runtime": 112.585,
692
+ "eval_samples_per_second": 14.736,
693
+ "eval_steps_per_second": 0.231,
694
+ "step": 1800
695
+ },
696
+ {
697
+ "epoch": 0.5485645392208575,
698
+ "grad_norm": 0.2934229373931885,
699
+ "learning_rate": 0.0002187037037037037,
700
+ "loss": 3.7645,
701
+ "step": 1820
702
+ },
703
+ {
704
+ "epoch": 0.5545927209705372,
705
+ "grad_norm": 0.24501343071460724,
706
+ "learning_rate": 0.000215,
707
+ "loss": 3.7559,
708
+ "step": 1840
709
+ },
710
+ {
711
+ "epoch": 0.560620902720217,
712
+ "grad_norm": 0.21381346881389618,
713
+ "learning_rate": 0.00021129629629629629,
714
+ "loss": 3.7482,
715
+ "step": 1860
716
+ },
717
+ {
718
+ "epoch": 0.5666490844698968,
719
+ "grad_norm": 0.2350403219461441,
720
+ "learning_rate": 0.0002075925925925926,
721
+ "loss": 3.7488,
722
+ "step": 1880
723
+ },
724
+ {
725
+ "epoch": 0.5726772662195765,
726
+ "grad_norm": 0.23535749316215515,
727
+ "learning_rate": 0.0002038888888888889,
728
+ "loss": 3.7409,
729
+ "step": 1900
730
+ },
731
+ {
732
+ "epoch": 0.5787054479692563,
733
+ "grad_norm": 0.22763009369373322,
734
+ "learning_rate": 0.0002001851851851852,
735
+ "loss": 3.7431,
736
+ "step": 1920
737
+ },
738
+ {
739
+ "epoch": 0.584733629718936,
740
+ "grad_norm": 0.22279077768325806,
741
+ "learning_rate": 0.00019648148148148148,
742
+ "loss": 3.7373,
743
+ "step": 1940
744
+ },
745
+ {
746
+ "epoch": 0.5907618114686157,
747
+ "grad_norm": 0.19868987798690796,
748
+ "learning_rate": 0.00019277777777777777,
749
+ "loss": 3.7385,
750
+ "step": 1960
751
+ },
752
+ {
753
+ "epoch": 0.5967899932182955,
754
+ "grad_norm": 0.22577470541000366,
755
+ "learning_rate": 0.00018907407407407406,
756
+ "loss": 3.7266,
757
+ "step": 1980
758
+ },
759
+ {
760
+ "epoch": 0.6028181749679753,
761
+ "grad_norm": 0.23861481249332428,
762
+ "learning_rate": 0.00018537037037037038,
763
+ "loss": 3.7288,
764
+ "step": 2000
765
+ },
766
+ {
767
+ "epoch": 0.6088463567176551,
768
+ "grad_norm": 0.2368811070919037,
769
+ "learning_rate": 0.00018166666666666667,
770
+ "loss": 3.7251,
771
+ "step": 2020
772
+ },
773
+ {
774
+ "epoch": 0.6148745384673348,
775
+ "grad_norm": 0.23746469616889954,
776
+ "learning_rate": 0.00017796296296296296,
777
+ "loss": 3.7194,
778
+ "step": 2040
779
+ },
780
+ {
781
+ "epoch": 0.6209027202170145,
782
+ "grad_norm": 0.19934986531734467,
783
+ "learning_rate": 0.00017425925925925926,
784
+ "loss": 3.7203,
785
+ "step": 2060
786
+ },
787
+ {
788
+ "epoch": 0.6269309019666943,
789
+ "grad_norm": 0.22287386655807495,
790
+ "learning_rate": 0.00017055555555555555,
791
+ "loss": 3.7182,
792
+ "step": 2080
793
+ },
794
+ {
795
+ "epoch": 0.632959083716374,
796
+ "grad_norm": 0.21625646948814392,
797
+ "learning_rate": 0.00016685185185185187,
798
+ "loss": 3.7133,
799
+ "step": 2100
800
+ },
801
+ {
802
+ "epoch": 0.632959083716374,
803
+ "eval_loss": 3.661569493497066,
804
+ "eval_perplexity": 38.922383385070816,
805
+ "eval_runtime": 112.8832,
806
+ "eval_samples_per_second": 14.697,
807
+ "eval_steps_per_second": 0.23,
808
+ "step": 2100
809
+ },
810
+ {
811
+ "epoch": 0.6389872654660538,
812
+ "grad_norm": 0.2128862887620926,
813
+ "learning_rate": 0.00016314814814814816,
814
+ "loss": 3.7123,
815
+ "step": 2120
816
+ },
817
+ {
818
+ "epoch": 0.6450154472157336,
819
+ "grad_norm": 0.22579094767570496,
820
+ "learning_rate": 0.00015944444444444445,
821
+ "loss": 3.7103,
822
+ "step": 2140
823
+ },
824
+ {
825
+ "epoch": 0.6510436289654133,
826
+ "grad_norm": 0.19634632766246796,
827
+ "learning_rate": 0.00015574074074074074,
828
+ "loss": 3.7077,
829
+ "step": 2160
830
+ },
831
+ {
832
+ "epoch": 0.657071810715093,
833
+ "grad_norm": 0.21508827805519104,
834
+ "learning_rate": 0.00015203703703703703,
835
+ "loss": 3.7071,
836
+ "step": 2180
837
+ },
838
+ {
839
+ "epoch": 0.6630999924647728,
840
+ "grad_norm": 0.23243261873722076,
841
+ "learning_rate": 0.00014833333333333335,
842
+ "loss": 3.7035,
843
+ "step": 2200
844
+ },
845
+ {
846
+ "epoch": 0.6691281742144526,
847
+ "grad_norm": 0.22189666330814362,
848
+ "learning_rate": 0.00014462962962962964,
849
+ "loss": 3.7011,
850
+ "step": 2220
851
+ },
852
+ {
853
+ "epoch": 0.6751563559641324,
854
+ "grad_norm": 0.19845160841941833,
855
+ "learning_rate": 0.00014092592592592594,
856
+ "loss": 3.6996,
857
+ "step": 2240
858
+ },
859
+ {
860
+ "epoch": 0.681184537713812,
861
+ "grad_norm": 0.1785988211631775,
862
+ "learning_rate": 0.00013722222222222223,
863
+ "loss": 3.6866,
864
+ "step": 2260
865
+ },
866
+ {
867
+ "epoch": 0.6872127194634918,
868
+ "grad_norm": 0.2001648247241974,
869
+ "learning_rate": 0.00013351851851851852,
870
+ "loss": 3.6939,
871
+ "step": 2280
872
+ },
873
+ {
874
+ "epoch": 0.6932409012131716,
875
+ "grad_norm": 0.21330291032791138,
876
+ "learning_rate": 0.00012981481481481484,
877
+ "loss": 3.6868,
878
+ "step": 2300
879
+ },
880
+ {
881
+ "epoch": 0.6992690829628513,
882
+ "grad_norm": 0.23209834098815918,
883
+ "learning_rate": 0.00012611111111111113,
884
+ "loss": 3.6803,
885
+ "step": 2320
886
+ },
887
+ {
888
+ "epoch": 0.7052972647125311,
889
+ "grad_norm": 0.18792849779129028,
890
+ "learning_rate": 0.00012240740740740742,
891
+ "loss": 3.6824,
892
+ "step": 2340
893
+ },
894
+ {
895
+ "epoch": 0.7113254464622109,
896
+ "grad_norm": 0.19127227365970612,
897
+ "learning_rate": 0.0001187037037037037,
898
+ "loss": 3.6821,
899
+ "step": 2360
900
+ },
901
+ {
902
+ "epoch": 0.7173536282118906,
903
+ "grad_norm": 0.21657773852348328,
904
+ "learning_rate": 0.000115,
905
+ "loss": 3.6727,
906
+ "step": 2380
907
+ },
908
+ {
909
+ "epoch": 0.7233818099615703,
910
+ "grad_norm": 0.1759604662656784,
911
+ "learning_rate": 0.0001112962962962963,
912
+ "loss": 3.6809,
913
+ "step": 2400
914
+ },
915
+ {
916
+ "epoch": 0.7233818099615703,
917
+ "eval_loss": 3.62554258938625,
918
+ "eval_perplexity": 37.54508920080861,
919
+ "eval_runtime": 112.4817,
920
+ "eval_samples_per_second": 14.749,
921
+ "eval_steps_per_second": 0.231,
922
+ "step": 2400
923
+ },
924
+ {
925
+ "epoch": 0.7294099917112501,
926
+ "grad_norm": 0.20114636421203613,
927
+ "learning_rate": 0.00010759259259259259,
928
+ "loss": 3.6772,
929
+ "step": 2420
930
+ },
931
+ {
932
+ "epoch": 0.7354381734609299,
933
+ "grad_norm": 0.20904237031936646,
934
+ "learning_rate": 0.00010388888888888889,
935
+ "loss": 3.6754,
936
+ "step": 2440
937
+ },
938
+ {
939
+ "epoch": 0.7414663552106096,
940
+ "grad_norm": 0.18807630240917206,
941
+ "learning_rate": 0.00010018518518518518,
942
+ "loss": 3.6756,
943
+ "step": 2460
944
+ },
945
+ {
946
+ "epoch": 0.7474945369602893,
947
+ "grad_norm": 0.17234675586223602,
948
+ "learning_rate": 9.648148148148149e-05,
949
+ "loss": 3.6686,
950
+ "step": 2480
951
+ },
952
+ {
953
+ "epoch": 0.7535227187099691,
954
+ "grad_norm": 0.18095088005065918,
955
+ "learning_rate": 9.277777777777778e-05,
956
+ "loss": 3.6691,
957
+ "step": 2500
958
+ },
959
+ {
960
+ "epoch": 0.7595509004596489,
961
+ "grad_norm": 0.19775047898292542,
962
+ "learning_rate": 8.907407407407407e-05,
963
+ "loss": 3.6679,
964
+ "step": 2520
965
+ },
966
+ {
967
+ "epoch": 0.7655790822093286,
968
+ "grad_norm": 0.1963493674993515,
969
+ "learning_rate": 8.537037037037038e-05,
970
+ "loss": 3.668,
971
+ "step": 2540
972
+ },
973
+ {
974
+ "epoch": 0.7716072639590084,
975
+ "grad_norm": 0.16776752471923828,
976
+ "learning_rate": 8.166666666666667e-05,
977
+ "loss": 3.663,
978
+ "step": 2560
979
+ },
980
+ {
981
+ "epoch": 0.7776354457086881,
982
+ "grad_norm": 0.18634021282196045,
983
+ "learning_rate": 7.796296296296296e-05,
984
+ "loss": 3.6616,
985
+ "step": 2580
986
+ },
987
+ {
988
+ "epoch": 0.7836636274583678,
989
+ "grad_norm": 0.1853896975517273,
990
+ "learning_rate": 7.425925925925927e-05,
991
+ "loss": 3.6554,
992
+ "step": 2600
993
+ },
994
+ {
995
+ "epoch": 0.7896918092080476,
996
+ "grad_norm": 0.19131463766098022,
997
+ "learning_rate": 7.055555555555556e-05,
998
+ "loss": 3.6617,
999
+ "step": 2620
1000
+ },
1001
+ {
1002
+ "epoch": 0.7957199909577274,
1003
+ "grad_norm": 0.1861460953950882,
1004
+ "learning_rate": 6.685185185185186e-05,
1005
+ "loss": 3.6589,
1006
+ "step": 2640
1007
+ },
1008
+ {
1009
+ "epoch": 0.8017481727074072,
1010
+ "grad_norm": 0.18328429758548737,
1011
+ "learning_rate": 6.314814814814815e-05,
1012
+ "loss": 3.6581,
1013
+ "step": 2660
1014
+ },
1015
+ {
1016
+ "epoch": 0.8077763544570868,
1017
+ "grad_norm": 0.1829613447189331,
1018
+ "learning_rate": 5.9444444444444445e-05,
1019
+ "loss": 3.6508,
1020
+ "step": 2680
1021
+ },
1022
+ {
1023
+ "epoch": 0.8138045362067666,
1024
+ "grad_norm": 0.17789465188980103,
1025
+ "learning_rate": 5.5740740740740744e-05,
1026
+ "loss": 3.6536,
1027
+ "step": 2700
1028
+ },
1029
+ {
1030
+ "epoch": 0.8138045362067666,
1031
+ "eval_loss": 3.600645640400387,
1032
+ "eval_perplexity": 36.62187137207453,
1033
+ "eval_runtime": 112.2753,
1034
+ "eval_samples_per_second": 14.776,
1035
+ "eval_steps_per_second": 0.232,
1036
+ "step": 2700
1037
+ }
1038
+ ],
1039
+ "logging_steps": 20,
1040
+ "max_steps": 3000,
1041
+ "num_input_tokens_seen": 0,
1042
+ "num_train_epochs": 1,
1043
+ "save_steps": 300,
1044
+ "stateful_callbacks": {
1045
+ "TrainerControl": {
1046
+ "args": {
1047
+ "should_epoch_stop": false,
1048
+ "should_evaluate": false,
1049
+ "should_log": false,
1050
+ "should_save": true,
1051
+ "should_training_stop": false
1052
+ },
1053
+ "attributes": {}
1054
+ }
1055
+ },
1056
+ "total_flos": 1.4440968002469888e+18,
1057
+ "train_batch_size": 64,
1058
+ "trial_name": null,
1059
+ "trial_params": null
1060
+ }
checkpoint-2700/training_args.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:08d76f8b5b85f05fb7caa15e408143d3ba0686e42d70879850259702897d08d2
3
+ size 5905
checkpoint-2700/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
checkpoint-3000/config.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "SharedSpaceDecoderForCausalLM"
4
+ ],
5
+ "attention_backend": "flash_attention_2",
6
+ "attention_bias": false,
7
+ "attention_dropout_prob": 0.1,
8
+ "bos_token_id": 50256,
9
+ "classifier_dropout": null,
10
+ "dtype": "float32",
11
+ "eos_token_id": 50256,
12
+ "ffn_decompose": false,
13
+ "ffn_rank": null,
14
+ "hidden_dropout_prob": 0.1,
15
+ "hidden_size": 768,
16
+ "initializer_range": 0.02,
17
+ "intermediate_size": 2048,
18
+ "kv_shared_dim": null,
19
+ "layer_norm_eps": 1e-12,
20
+ "max_position_embeddings": 1024,
21
+ "model_type": "shared_subspace_decoder",
22
+ "nope_dims": 32,
23
+ "norm_type": "rmsnorm",
24
+ "num_attention_heads": 12,
25
+ "num_dense_layers": 0,
26
+ "num_hidden_layers": 12,
27
+ "o_shared_dim": null,
28
+ "pad_token_id": 50256,
29
+ "q_shared_dim": null,
30
+ "qk_private_dim": 64,
31
+ "rms_norm_eps": 1e-06,
32
+ "rope_dims": 32,
33
+ "rope_scaling": {
34
+ "factor": 2.0,
35
+ "type": "linear"
36
+ },
37
+ "rope_theta": 10000.0,
38
+ "transformers_version": "4.56.0",
39
+ "vo_private_dim": 64,
40
+ "vocab_rank": null,
41
+ "vocab_size": 50257,
42
+ "vocab_subspace": false
43
+ }
checkpoint-3000/feedforward.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
2
+
3
+ # `feedforward.py`
4
+
5
+ Regarding dropout:
6
+
7
+ - I don't see it applied to the MoE in DeepSeek-V3, [here](https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py).
8
+
9
+ - I don't see it applied in [modeling_llama.py](https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py#L140)
10
+
11
+ Norms:
12
+
13
+ * nn.RMSNorm [here](https://docs.pytorch.org/docs/stable/generated/torch.nn.RMSNorm.html)
14
+
15
+ ## FFN
16
+ """
17
+
18
+ import torch
19
+ import torch.nn as nn
20
+ import torch.nn.functional as F
21
+ from .shared_space_config import SharedSpaceDecoderConfig
22
+
23
+
24
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
25
+ """
26
+ Create a normalization layer based on the config norm_type.
27
+
28
+ Args:
29
+ hidden_size: The dimension to normalize over
30
+ config: Configuration containing norm_type and epsilon values
31
+
32
+ Returns:
33
+ Either a LayerNorm or RMSNorm layer
34
+ """
35
+ if config.norm_type == "layernorm":
36
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
37
+ elif config.norm_type == "rmsnorm":
38
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
39
+ else:
40
+ # This should be caught by config validation, but being defensive
41
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
42
+
43
+
44
+ # TODO - Find a shared place to put this.
45
+ class DeepseekV3RMSNorm(nn.Module):
46
+ def __init__(self, hidden_size, eps=1e-6):
47
+ """
48
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
49
+ """
50
+ super().__init__()
51
+ self.weight = nn.Parameter(torch.ones(hidden_size))
52
+ self.variance_epsilon = eps
53
+
54
+ def forward(self, hidden_states):
55
+ input_dtype = hidden_states.dtype
56
+ hidden_states = hidden_states.to(torch.float32)
57
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
58
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
59
+ return self.weight * hidden_states.to(input_dtype)
60
+
61
+ class SubspaceFeedForward(nn.Module):
62
+ """
63
+ Feed-forward block for SharedSpaceDecoder.
64
+
65
+ Implements SwiGLU:
66
+ FFN(x) = W_out( Swish(W_in(x)) ⊙ W_gate(x) ) + residual
67
+
68
+ Supports both dense and decomposed MLP variants.
69
+
70
+ Dense:
71
+ - W_in: Linear(hidden_dim → intermediate_dim)
72
+ - W_gate: Linear(hidden_dim → intermediate_dim)
73
+ - W_out: Linear(intermediate_dim → hidden_dim)
74
+
75
+ Decomposed:
76
+ - W_in_shared: Linear(hidden_dim → rank, bias=False)
77
+ - W_in_shared_norm: RMSNorm
78
+ - W_in: Linear(rank → intermediate_dim)
79
+ - W_gate_shared: Linear(hidden_dim → rank, bias=False)
80
+ - W_gate_shared_norm: RMSNorm
81
+ - W_gate: Linear(rank → intermediate_dim)
82
+ - W_out: Linear(intermediate_dim → rank, bias=False)
83
+ - W_out_shared: Linear(rank → hidden_dim)
84
+
85
+ Residual, dropout, and post-norm are handled inside the block.
86
+ """
87
+
88
+ def __init__(self, config, layer_idx):
89
+ super().__init__()
90
+
91
+
92
+ #dropout_prob = config.hidden_dropout_prob # TODO - Style -- don't define variables if only used once.
93
+
94
+ # Determine whether this is a dense or decomposed layer.
95
+ # It's dense if either:
96
+ # - ffn_decompose is disabled (no dense layers at all)
97
+ # - ffn_decompose is enabled, but this is one of the early dense layers.
98
+ self.is_dense = (not config.ffn_decompose) or (layer_idx < config.num_dense_layers)
99
+
100
+ hidden_dim = config.hidden_size
101
+ intermediate_dim = config.intermediate_size # TODO - Find something shorter, and use the same name.
102
+
103
+ # If it's one of the dense layers,
104
+ if self.is_dense:
105
+ # === Dense FFN Projections ===
106
+ self.W_in = nn.Linear(hidden_dim, intermediate_dim)
107
+ self.W_gate = nn.Linear(hidden_dim, intermediate_dim)
108
+ self.W_out = nn.Linear(intermediate_dim, hidden_dim)
109
+
110
+ # Define weights for the decomposed version.
111
+ else:
112
+ rank = config.ffn_rank
113
+
114
+ print("hidden_dim:", hidden_dim)
115
+ print("rank:", rank)
116
+
117
+ # === Input Projections ===
118
+ self.W_in_shared = nn.Linear(hidden_dim, rank, bias=False)
119
+ self.W_in_shared_norm = create_norm_layer(rank, config)
120
+ self.W_in = nn.Linear(rank, intermediate_dim, bias=True)
121
+
122
+ # === Gate Projections ===
123
+ self.W_gate_shared = nn.Linear(hidden_dim, rank, bias=False)
124
+ self.W_gate_shared_norm = create_norm_layer(rank, config)
125
+ self.W_gate = nn.Linear(rank, intermediate_dim, bias=True)
126
+
127
+ # === Output Projection ===
128
+ self.W_out = nn.Linear(intermediate_dim, rank, bias=False)
129
+ # TODO - Could experiment with this.
130
+ #self.W_out_shared_layernorm = DeepseekV3RMSNorm(rank, eps=config.eps)
131
+ self.W_out_shared = nn.Linear(rank, hidden_dim, bias=True)
132
+
133
+ # See notes no dropout
134
+ #self.dropout = nn.Dropout(config.hidden_dropout_prob)
135
+
136
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
137
+ # === Tensor Dimension Symbols ===
138
+ # B: batch_size — number of samples in the batch
139
+ # T: seq_len — number of tokens per sample
140
+ # D: hidden_dim — model embedding size
141
+ # R: ffn_rank — latent shared subspace dimension
142
+ # D_ff: intermediate_size — FFN hidden dimension
143
+
144
+ # =========================
145
+ # Gated Feedforward
146
+ # =========================
147
+
148
+ if self.is_dense:
149
+ # =============
150
+ # Dense
151
+ # =============
152
+
153
+ # Input: x [B, T, D]
154
+ # Output: x_proj [B, T, D_ff]
155
+ x_proj = self.W_in(x)
156
+
157
+ # Output: gate [B, T, D_ff]
158
+ gate = self.W_gate(x)
159
+
160
+ # SwiGLU nonlinearity
161
+ x = F.silu(x_proj) * gate # [B, T, D_ff]
162
+
163
+ # See notes on dropout
164
+ #x = self.dropout(x)
165
+
166
+ # Output: x [B, T, D]
167
+ x = self.W_out(x)
168
+
169
+ else:
170
+ # ==================
171
+ # Decomposed
172
+ # ==================
173
+
174
+ # Input: x [B, T, D]
175
+ # Output: x_proj [B, T, D_ff]
176
+ x_proj = self.W_in(self.W_in_shared_norm(self.W_in_shared(x)))
177
+
178
+ # Input: x [B, T, D]
179
+ # Output: gate [B, T, D_ff]
180
+ gate = self.W_gate(self.W_gate_shared_norm(self.W_gate_shared(x)))
181
+
182
+ # SwiGLU nonlinearity
183
+ x = F.silu(x_proj) * gate # [B, T, D_ff]
184
+
185
+ # See notes on dropout
186
+ #x = self.dropout(x)
187
+
188
+ # Output: x [B, T, D]
189
+ x = self.W_out_shared(self.W_out(x))
190
+
191
+
192
+ return x
193
+
194
+
195
+
196
+
checkpoint-3000/gla.py ADDED
@@ -0,0 +1,721 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
2
+
3
+ # `gla.py`
4
+
5
+ Based on: https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py
6
+
7
+ """
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from typing import Optional
13
+ import math
14
+
15
+ from .shared_space_config import SharedSpaceDecoderConfig
16
+
17
+
18
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
19
+ """
20
+ Create a normalization layer based on the config norm_type.
21
+
22
+ If `hidden_size` is `None`, this returns an identity layer.
23
+
24
+ Args:
25
+ hidden_size: The dimension to normalize over
26
+ config: Configuration containing norm_type and epsilon values
27
+
28
+ Returns:
29
+ Either a LayerNorm or RMSNorm layer
30
+ """
31
+ if hidden_size is None:
32
+ return nn.Identity()
33
+ elif config.norm_type == "layernorm":
34
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
35
+ elif config.norm_type == "rmsnorm":
36
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
37
+ else:
38
+ # This should be caught by config validation, but being defensive
39
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
40
+
41
+
42
+ # TODO - Find a shared place to put this.
43
+ class DeepseekV3RMSNorm(nn.Module):
44
+ def __init__(self, hidden_size, eps=1e-6):
45
+ """
46
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
47
+ """
48
+ super().__init__()
49
+ self.weight = nn.Parameter(torch.ones(hidden_size))
50
+ self.variance_epsilon = eps
51
+
52
+ def forward(self, hidden_states):
53
+ input_dtype = hidden_states.dtype
54
+ hidden_states = hidden_states.to(torch.float32)
55
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
56
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
57
+ return self.weight * hidden_states.to(input_dtype)
58
+
59
+
60
+ # Helper function needed because it's called twice during RoPE,
61
+ # but I dumped it in the comments there.
62
+ # TODO - Nah, screw it, just write it twice! At least then you get
63
+ # to use the word 'query' instead of 'x'.
64
+ def rotate_half(x):
65
+ """Rotates half the hidden dims of the input."""
66
+ x1 = x[..., : x.shape[-1] // 2]
67
+ x2 = x[..., x.shape[-1] // 2 :]
68
+ return torch.cat((-x2, x1), dim=-1)
69
+
70
+ class RotaryEmbedding(nn.Module):
71
+ """Precompute RoPE embeddings and store them as buffers."""
72
+
73
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
74
+ super().__init__()
75
+
76
+ dim = config.rope_dims
77
+ seq_len = config.max_position_embeddings
78
+
79
+ # ------------------------------
80
+ # Compute inverse frequencies
81
+ # ------------------------------
82
+ # Shape: [dim // 2]
83
+ # inv_freq[i] = 1 / (theta^(i / dim))
84
+ inv_freq = 1.0 / (
85
+ config.rope_theta
86
+ ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim)
87
+ )
88
+
89
+ # ------------------------------
90
+ # Apply RoPE scaling if configured
91
+ # ------------------------------
92
+ if config.rope_scaling is not None:
93
+ scaling_type = config.rope_scaling.get("type", "linear")
94
+ scaling_factor = config.rope_scaling.get("factor", 1.0)
95
+
96
+ if scaling_type == "linear":
97
+ # Linear scaling: divide frequencies by scaling factor
98
+ inv_freq = inv_freq / scaling_factor
99
+ elif scaling_type == "dynamic":
100
+ # Dynamic scaling: adjust based on sequence length
101
+ # This is a simplified implementation
102
+ inv_freq = inv_freq / scaling_factor
103
+ else:
104
+ print(f"Warning: Unknown RoPE scaling type '{scaling_type}', using linear scaling")
105
+ inv_freq = inv_freq / scaling_factor
106
+
107
+ # ------------------------------
108
+ # Compute position indices
109
+ # ------------------------------
110
+ # Shape: [seq_len]
111
+ t = torch.arange(seq_len, dtype=torch.float32)
112
+
113
+ # ------------------------------
114
+ # Outer product: [seq_len, dim // 2]
115
+ # Each row i contains: t[i] * inv_freq
116
+ # ------------------------------
117
+ freqs = torch.outer(t, inv_freq)
118
+
119
+ # ------------------------------
120
+ # Duplicate for interleaved sin/cos: [seq_len, dim]
121
+ # This matches the common format: [sin_0, cos_0, sin_1, cos_1, ...]
122
+ # ------------------------------
123
+ emb = torch.cat((freqs, freqs), dim=-1)
124
+
125
+ # ------------------------------
126
+ # Register cos/sin as buffers
127
+ # - Stored in float32
128
+ # - Will be moved to correct device/dtype via model.to(...)
129
+ # - Not saved with state_dict (persistent=False)
130
+ # ------------------------------
131
+ self.register_buffer("cos", emb.cos(), persistent=False)
132
+ self.register_buffer("sin", emb.sin(), persistent=False)
133
+
134
+ def forward(self, position_ids: torch.LongTensor) -> tuple[torch.Tensor, torch.Tensor]:
135
+ """ """
136
+ return None # This function is not necessary.
137
+
138
+ """## GLA"""
139
+
140
+ class GroupedLatentAttention(nn.Module):
141
+ """
142
+ This version of Multihead Latent Attention applies the re-ordering trick from DeepSeekV3.
143
+ Instead of comparing the queries and keys in the query-key space, we compare them in the
144
+ kv-shared space.
145
+
146
+ For clarity, I've re-interpreted the naming of the heads, and am framing it as MQA.
147
+ What were previously labeled the query and key heads are now treated as a low-rank decomposition
148
+ of the query heads.
149
+ What we considered the "shared key/value space" is now a single key head that is also used as the
150
+ value head.
151
+ Finally, what we previously labeled the value and output heads are now treated as a low-rank
152
+ decomposition of the output heads.
153
+
154
+ This interpretation / implementation is designed to leverage the performance benefits of GQA.
155
+ The trade-off is that the query-key matching space is now larger--it will require a greater
156
+ number of calculations to match the queries to the keys. The hope is that the memory bandwidth
157
+ savings will outweigh the increased computational cost.
158
+
159
+ The same applies to the value-output space.
160
+
161
+ Note that, although the query-key and value-output spaces are now large, the low-rank
162
+ decomposition of the query heads and output heads ensures that the heads are still effectively
163
+ low rank / not over-parameterized.
164
+
165
+ Finally, note that this implementation also supports the optional use of shared spaces on
166
+ the query and output sides.
167
+
168
+ I've named the class "GroupedLatentAttention" because I may expand it to support multiple
169
+ key/value heads (i.e., multiple groups of query heads) in the future.
170
+
171
+ ==== Adding RoPE to VO ====
172
+
173
+ ### **Attempt**
174
+
175
+ We're extending Rotary Position Embeddings (RoPE) beyond the query-key interaction to the **value-output path** in Multihead Latent Attention (MLA).
176
+
177
+ * In DeepSeek-V3's MLA framing, the same **full-rank key/value head** provides both the keys (for patterns) and the values (for messages).
178
+ * Queries and output heads are low-rank bottlenecks, effectively serving as vocabularies of **pattern directions** (Q) and **message directions** (O).
179
+ * Standard RoPE only modulates the Q–K dot product. Our attempt is to also apply RoPE phases consistently in the V–O pathway, so that **positional dependence is preserved in both the matching (QK) and messaging (VO) sides**.
180
+
181
+ --
182
+
183
+ ### **Hypothesis**
184
+
185
+ If we rotate value vectors by their **source position phase** and then apply the **inverse rotation at the destination** before output projection, the model gains a clean **relative-position equivariance** in the message path, mirroring the property RoPE provides for queries and keys.
186
+
187
+ This should:
188
+
189
+ 1. Make the 1-to-1 correspondence between "pattern templates" (Q) and "message templates" (O) more consistent.
190
+ 2. Reduce the burden on output heads to learn ad-hoc positional compensation.
191
+ 3. Improve long-context generalization, since both attention matching *and* message passing would share the same relative-position geometry.
192
+
193
+
194
+ """
195
+
196
+ def __init__(self, config: SharedSpaceDecoderConfig, layer_idx: int):
197
+ super().__init__()
198
+
199
+ self.config = config
200
+
201
+ # Used to determine if this layer is dense or uses latents.
202
+ self.layer_idx = layer_idx
203
+ self.attention_dropout_prob = config.attention_dropout_prob
204
+
205
+ self.num_heads = config.num_attention_heads
206
+
207
+ self.rope_theta = config.rope_theta
208
+ self.rope_dims = config.rope_dims
209
+ self.nope_dims = config.nope_dims
210
+
211
+ self.q_shared_dim = config.q_shared_dim
212
+ # What was previously considered the key/value shared dimension is now the
213
+ # size of the MQA style single key/value head.
214
+ self.kv_head_dim = config.kv_shared_dim
215
+ self.o_shared_dim = config.o_shared_dim
216
+
217
+ # What was previously the query/key head size is now the size of
218
+ # the query head decomposition.
219
+ self.q_inner_dim = config.qk_private_dim
220
+
221
+ # What was previously the value/output head size is now the size of
222
+ # the output head decomposition.
223
+ self.o_inner_dim = config.vo_private_dim
224
+
225
+ self.hidden_size = config.hidden_size
226
+
227
+ # =========================
228
+ # Input Projections
229
+ # =========================
230
+
231
+ # If this is one of the dense layers,
232
+ if self.layer_idx < config.num_dense_layers:
233
+
234
+ # =========================
235
+ # Dense Attention
236
+ # =========================
237
+
238
+ # No latent projections.
239
+ self.latent_spaces = False
240
+
241
+ # Define the standard QKV projection
242
+ self.qkv_proj = nn.Linear(
243
+ config.hidden_size,
244
+ self.num_heads * (self.qk_private_dim * 2 + self.vo_private_dim),
245
+ bias=config.attention_bias,
246
+ )
247
+
248
+ # Dense output projection
249
+ self.o_proj = nn.Linear(
250
+ self.num_heads * self.vo_private_dim,
251
+ config.hidden_size,
252
+ bias=config.attention_bias,
253
+ )
254
+
255
+ # If we're past the dense layers,
256
+ else:
257
+
258
+ # =========================
259
+ # Latent Attention
260
+ # =========================
261
+
262
+ # Use latent projections.
263
+ self.latent_spaces = True
264
+
265
+ # Input latent projections
266
+
267
+ print("config.q_shared_dim", config.q_shared_dim)
268
+
269
+ # ==========================
270
+ # Shared Query Space
271
+ # ==========================
272
+
273
+ # If we're using a shared query subspace,
274
+ if config.q_shared_dim is not None:
275
+ # Set a flag that we'll check in `forward`.
276
+ self.query_shared = True
277
+
278
+ self.q_shared_proj = nn.Linear(
279
+ config.hidden_size,
280
+ self.q_shared_dim,
281
+ bias=config.attention_bias,
282
+ )
283
+
284
+ self.q_shared_norm = create_norm_layer(self.q_shared_dim, config)
285
+
286
+ else:
287
+ print("Using identity for shared projection.")
288
+ # Set a flag that we'll check in `forward`.
289
+ self.query_shared = False
290
+
291
+ self.q_shared_dim = config.hidden_size
292
+
293
+ #print("Updated self.q_shared_dim to", self.q_shared_dim)
294
+
295
+ # Use identity.
296
+ self.q_shared_proj = nn.Identity()
297
+ self.q_shared_norm = nn.Identity()
298
+
299
+ # ==========================
300
+ # Shared Output Space
301
+ # ==========================
302
+
303
+ # If we're using a shared output space,
304
+ if config.o_shared_dim is not None:
305
+ # Set a flag that we'll check in `forward`.
306
+ self.output_shared = True
307
+
308
+ # Shared output projection
309
+ # The head outputs from `o_private_proj` are first summed together (across
310
+ # heads) in the latent space.
311
+ # Then we project their combined outputs (a single vector per token)
312
+ # back to model space via `o_shared_proj`.
313
+ self.o_shared_proj = nn.Linear(
314
+ self.o_shared_dim,
315
+ self.hidden_size,
316
+ bias=config.attention_bias
317
+ )
318
+
319
+ self.o_shared_norm = create_norm_layer(self.o_shared_dim, config)
320
+
321
+ else:
322
+ # Set a flag that we'll check in `forward`.
323
+ self.output_shared = False
324
+ self.o_shared_dim = config.hidden_size
325
+
326
+ # Use identity.
327
+ self.o_shared_proj = nn.Identity()
328
+ self.o_shared_norm = nn.Identity()
329
+
330
+ # ================================
331
+ # Decomposed Query Heads
332
+ # ================================
333
+
334
+ # Query down projections.
335
+ # The query head inner dimension makes the head low rank, as usual.
336
+ self.q_priv_a_proj = nn.Linear(
337
+ self.q_shared_dim,
338
+ self.num_heads * self.q_inner_dim,
339
+ bias=False
340
+ )
341
+
342
+ # Query up projections.
343
+ # We project back to the larger key/value space.
344
+ # Rather than create a linear and break it apart, we can create our
345
+ # desired shapes.
346
+ # per-head Dq_c -> Dkv (store as [H, Dq_c, Dkv])
347
+ self.q_priv_b_weight = nn.Parameter(
348
+ torch.empty(self.num_heads, self.q_inner_dim, self.kv_head_dim)
349
+ )
350
+ nn.init.kaiming_uniform_(self.q_priv_b_weight, a=math.sqrt(5))
351
+
352
+ # ====================================
353
+ # Single Joint Key/Value Head
354
+ # ====================================
355
+
356
+ # The single joint key/value head.
357
+ self.kv_priv_proj = nn.Linear(
358
+ self.hidden_size,
359
+ self.kv_head_dim,
360
+ bias=False,
361
+ )
362
+
363
+ self.kv_priv_norm = create_norm_layer(self.kv_head_dim, config)
364
+
365
+ # ================================
366
+ # Decomposed Output Heads
367
+ # ================================
368
+
369
+ # Down: values [B,H,T,Dkv] -> per-head Do_c using weights [H, Dkv, Do_c]
370
+ self.o_priv_a_weight = nn.Parameter(
371
+ torch.empty(self.num_heads, self.kv_head_dim, self.o_inner_dim)
372
+ )
373
+ nn.init.kaiming_uniform_(self.o_priv_a_weight, a=math.sqrt(5))
374
+
375
+ # Output up projections.
376
+
377
+ # We project back to the larger output subspace (or the model space,
378
+ # if no subspace is used).
379
+ self.o_priv_b_proj = nn.Linear(
380
+ self.num_heads * self.o_inner_dim,
381
+ self.o_shared_dim,
382
+ bias=False
383
+ )
384
+
385
+ # Let SDPA choose 1/sqrt(E). If you want explicit: self.kv_head_dim ** -0.5
386
+ self.softmax_scale = None
387
+
388
+
389
+ def forward(
390
+ self,
391
+ hidden_states: torch.Tensor,
392
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
393
+ attention_mask: Optional[torch.Tensor],
394
+ #past_key_value: Optional[Cache] = None, # TODO - Can I remove this?
395
+ #cache_position: Optional[torch.LongTensor] = None, # TODO - Can I remove this?
396
+ **kwargs,
397
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor], Optional[tuple[torch.Tensor]]]:
398
+ # === Tensor Dimension Symbols ===
399
+ # B: batch_size — number of samples in the batch
400
+ # T: seq_len — number of tokens per sample
401
+ # H: n_heads — number of attention heads
402
+ # D: hidden_dim — model embedding size
403
+ # Dq_c: q_inner_dim - per-head decomposition dim for Q
404
+ Dq_c = self.q_inner_dim # per-head inner dim for Q
405
+ # Do_c: o_inner_dim - per-head decomposition dim for O
406
+ Do_c = self.o_inner_dim # per-head inner dim for O
407
+ # Dkv: kv_head_dim - Head size of the joint key/value head
408
+ Dkv = self.kv_head_dim # Head size of the joint key/value head
409
+ # Dr: rope_dims - The first Dr dimensions receive rope.
410
+ # Dq_s: q_shared_dim - query shared subspace size
411
+ Dq_s = self.q_shared_dim
412
+ # Do_s: o_shared_dim - output shared subspace size
413
+ Do_s = self.o_shared_dim
414
+
415
+ # Input token embeddings
416
+ # hidden_states: [B, T, D]
417
+ B, T = hidden_states.shape[:2]
418
+ H = self.num_heads
419
+
420
+
421
+
422
+ # =============================
423
+ # Shared Query Space
424
+ # =============================
425
+ # These are set to identity if no shared query space is used.
426
+
427
+ # Project token embeddings into shared latents
428
+ # Input:
429
+ # hidden_states [B, T, D]
430
+ # q_shared_proj [D, Dq_s]
431
+ # kv_shared_proj [D, Dkv]
432
+ # Output:
433
+ # q_shared [B, T, Dq_s]
434
+ # kv_shared [B, T, Dkv]
435
+ q_shared = self.q_shared_proj(hidden_states)
436
+
437
+ # Normalize latent vectors, shapes unchanged.
438
+ q_shared = self.q_shared_norm(q_shared)
439
+
440
+ # ================================
441
+ # Decomposed Query Heads
442
+ # ================================
443
+
444
+
445
+ # Project query latents onto decomposed query heads.
446
+ #
447
+ # Down projection ('a')
448
+ # Input:
449
+ # q_shared [B, T, Dq_s]
450
+ # q_priv_a_proj [Dq_s, H*Dq_c]
451
+ # Output:
452
+ # queries_c [B, T, H*Dq_c]
453
+ queries_c = self.q_priv_a_proj(q_shared)
454
+
455
+ # Split the vectors by head
456
+ # Input:
457
+ # queries_c [B, T, H*Dq_c]
458
+ # Output:
459
+ # queries_c [B, T, H, Dq_c]
460
+ queries_c = queries_c.view(B, T, H, Dq_c)
461
+
462
+ # Up projection ('b')
463
+ # Input:
464
+ # queries_c [B, T, H, Dq_c]
465
+ # q_priv_b_weight [H, Dq_c, Dkv]
466
+ # Output:
467
+ # queries [B, H, T, Dkv]
468
+ queries = torch.einsum("bthd,hdc->bhtc", queries_c, self.q_priv_b_weight)
469
+
470
+ # ===================================
471
+ # Single Joint Key/Value Head
472
+ # ===================================
473
+
474
+ # Project token embeddings into single joint key/value head.
475
+ # Input:
476
+ # hidden_states [B, T, D]
477
+ # kv_priv_proj [D, Dkv]
478
+ # Output:
479
+ # keyvalue [B, T, Dkv]
480
+ keyvalue = self.kv_priv_proj(hidden_states)
481
+
482
+ # Apply QK normalization.
483
+ keyvalue = self.kv_priv_norm(keyvalue)
484
+
485
+ # Prepare the queries and keyvalue vectors for RoPE and flash attention.
486
+ # We have multiple query heads, and the queries are in `queries`.
487
+ # We have a single key head, and the keyvector is in `keyvalue`.
488
+
489
+ # Move the head dimension to the front, so for each head, we have
490
+ # a series of vectors for each token in the sequence.
491
+ #
492
+ # Inputs:
493
+ # keyvalue [B, T, Dkv]
494
+ # Output:
495
+ # keyvalue [B, 1, T, Dkv]
496
+ keyvalue = keyvalue.unsqueeze(1)
497
+
498
+ # ==================
499
+ # RoPE
500
+ # ==================
501
+ # Apply rotary position embeddings to the first `self.rope_dims` of
502
+ # each head.
503
+ # The slice operations are free, but the concatenation is
504
+ # not, because the outputs of the rotation operation are new data
505
+ # occupying different memory. Still considered the best option,
506
+ # though.
507
+
508
+ # 1. Unpack the precomputed cosine and sine embeddings
509
+ # Position embeddings is a tuple of
510
+ # (cos [seq_len, rope_dims],
511
+ # sin [seq_len, rope_dims])
512
+ cos, sin = position_embeddings
513
+
514
+ # 2. Split the query and key heads into the part to rotate and the part
515
+ # to pass through (early columns get position info, later ones don't)
516
+ #
517
+ # (Using queries as example)
518
+ # Inputs:
519
+ # queries [B, H, T, Dkv] Dkv = rope_dims + not_rope_dims
520
+ # Outputs:
521
+ # q_rope [B, H, T, Dr]
522
+ # q_pass [B, H, T, Dkv-Dr]
523
+ q_rope, q_pass = queries[..., :self.rope_dims], queries[..., self.rope_dims:]
524
+ k_rope, k_pass = keyvalue[..., :self.rope_dims], keyvalue[..., self.rope_dims:]
525
+
526
+ # 3. Apply the rotary embedding to the designated slice
527
+ #
528
+ # To broadcast cos and sin across the batch and head dimensions, we unsqueeze them.
529
+ # Shape change: [T, Dr] -> [1, 1, T, Dr]
530
+ cos = cos.unsqueeze(0).unsqueeze(0)
531
+ sin = sin.unsqueeze(0).unsqueeze(0)
532
+
533
+ #print("q_rope.shape[-1] // 2:", (q_rope.shape[-1] // 2))
534
+ #print("x1 = x[..., :x.shape[-1] // 2 ].shape:", q_rope[..., :q_rope.shape[-1] // 2 ].shape)
535
+ #print("sin/cos.shape:", cos.shape)
536
+ #print("q_rope.shape:", q_rope.shape)
537
+ #print("(q_rope * cos).shape:", (q_rope * cos).shape)
538
+ #print("rotate_half(q_rope).shape:", rotate_half(q_rope).shape)
539
+ #print("(rotate_half(q_rope) * sin).shape:", (rotate_half(q_rope) * sin).shape)
540
+ """
541
+ In this example batch_size = 2, hum_heads = 8, seq_len = 65, rope_dims = 16
542
+
543
+ q_rope.shape[-1] // 2: 8
544
+ x1 = x[..., :x.shape[-1] // 2 ].shape: torch.Size([2, 8, 65, 8])
545
+
546
+ sin/cos.shape: torch.Size([1, 1, 65, 16]) # After double unsqueeze.
547
+ vq_rope.shape: torch.Size([2, 8, 65, 16])
548
+
549
+ (q_rope * cos).shape: torch.Size([2, 8, 65, 16])
550
+
551
+ rotate_half(q_rope).shape: torch.Size([2, 8, 65, 16])
552
+ (rotate_half(q_rope) * sin).shape: torch.Size([2, 8, 65, 16])
553
+ """
554
+
555
+
556
+ # Let's walk through the queries as the example.
557
+ # What does rotate half do?
558
+ # dim -1 is the row vectors, the queries
559
+ #
560
+ # Step 1: Split the vector in half.
561
+ # "q_rope.shape[-1] // 2" <- How much to select. Half the length of the q_rope vector
562
+ # x1 = x[..., :x.shape[-1] // 2 ] # Select the first half of the vector.
563
+ # x2 = x[..., x.shape[-1] // 2:] # Select the second half.
564
+ #
565
+ # Step 2:
566
+ # - Apply negative to the values in the second half.
567
+ # - Reverse the order of the halves.
568
+ # return torch.cat((-x2, x1), dim=-1)
569
+ #
570
+ # ---- (q_rope * cos) ----
571
+ # Element-wise multiply the values in each `cos` vector with the
572
+ # corresponding (i.e., same sequence position) `q_rope` vector.
573
+ #
574
+ # Inputs:
575
+ # q_rope [B, H, T, Dr]
576
+ # cos [1, 1, T, Dr]
577
+ #
578
+ # Outputs:
579
+ # x [B, H, T, Dr]
580
+ #
581
+ # ---- (rotate_half(q_rope)) ----
582
+ # TODO
583
+ #
584
+ # Inputs:
585
+ # q_rope [B, T, Dr]
586
+ #
587
+ # Outputs:
588
+ # rot_q_rope [B, T, Dr]
589
+ #
590
+ # ---- rotated * sin ----
591
+ # TODO
592
+ q_rotated = (q_rope * cos) + (rotate_half(q_rope) * sin)
593
+ k_rotated = (k_rope * cos) + (rotate_half(k_rope) * sin)
594
+
595
+ # 4. Concatenate the rotated and pass-through parts back together
596
+ # Input (each): [B, H, T, Dr] and [B, H, T, Dkv-Dr]
597
+ # Output (each): [B, H, T, Dkv]
598
+ # (Where h = 1 for the key head and h = num_heads for the query heads)
599
+ queries = torch.cat((q_rotated, q_pass), dim=-1)
600
+ keyvalue = torch.cat((k_rotated, k_pass), dim=-1)
601
+
602
+ # ====================
603
+ # GQA / MQA
604
+ # ====================
605
+ # GPT says that flash attention will infer the broadcasting, so `expand` is not needed.
606
+ #
607
+ # We need to use the `expand` operation to broadcast the keyvalue vector
608
+ # across the query heads.
609
+ # Input:
610
+ # keyvalue [B, 1, T, Dkv]
611
+ # Output:
612
+ # keyvalue [B, H, T, Dkv]
613
+ #keyvalue = keyvalue.expand(-1, H, -1, -1)
614
+
615
+ # ===================
616
+ # Attention
617
+ # ===================
618
+ # We're ready for the attention score calculation.
619
+
620
+ # Only apply dropout during training.
621
+ # self.training is a pytorch flag.
622
+ if self.training:
623
+ dropout_p = self.attention_dropout_prob
624
+ else:
625
+ dropout_p = 0.0
626
+
627
+ # Call SDPA / Flash Attention
628
+ # https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html
629
+ # Apply MQA / GQA. In this case, we have a single key head, and multiple query heads.
630
+ values = F.scaled_dot_product_attention(
631
+ queries,
632
+ keyvalue, # Single key vector (joint with value) for GQA / MQA.
633
+ keyvalue, # Single value vector (joint with key) for GQA / MQA.
634
+ attn_mask=None, # attention_mask,
635
+ dropout_p=dropout_p,
636
+ scale=self.softmax_scale,
637
+ is_causal=True, # This is a decoder - apply causal masking
638
+ )
639
+
640
+ # Attention outputs:
641
+ # values [B, H, T, Dkv]
642
+
643
+ # The final Dr dims of the value vectors carry RoPE information.
644
+ # We can either (1) add position dependence to the value-output process,
645
+ # or (2) we can strip off the RoPE information and only use the non-RoPE parts.
646
+
647
+ # Let's try option 1!
648
+
649
+ # Split the values into the RoPE and non-RoPE parts.
650
+ # Input:
651
+ # values [B, H, T, Dkv]
652
+ # Output:
653
+ # values_rope [B, H, T, Dr]
654
+ # values_pass [B, H, T, Dkv-Dr]
655
+ values_rope, values_pass = values[..., :self.rope_dims], values[..., self.rope_dims:]
656
+
657
+ # Fold the query RoPE information into the value vectors.
658
+ # Inverse rotation: R_{-θ} x = (x * cos) - (rotate_half(x) * sin)
659
+ # Input:
660
+ # values_rope [B, H, T, Dr]
661
+ # cos [1, 1, T, Dr]
662
+ # sin [1, 1, T, Dr]
663
+ # Output:
664
+ # values_unrot [B, H, T, Dr]
665
+ values_unrot = (values_rope * cos) - (rotate_half(values_rope) * sin)
666
+
667
+ # Now the values have the offset information in their rope dimensions,
668
+ # and the output heads can learn to use it.
669
+ values = torch.cat((values_unrot, values_pass), dim=-1) # [B,H,T,Dkv]
670
+
671
+ # =========================
672
+ # Output Projection
673
+ # =========================
674
+
675
+
676
+ # Project the values onto the decomposed output heads.
677
+ # Output down projection heads.
678
+ # Input:
679
+ # values [B, H, T, Dkv]
680
+ # o_priv_a_weight [H, Dkv, Do_c]
681
+ # Output:
682
+ # outputs_c [B, H, T, Do_c]
683
+ outputs_c = torch.einsum("bhtd,hdc->bhtc", values, self.o_priv_a_weight)
684
+
685
+ # For the up projection, we can concatenate the 'outputs_c' vectors by head,
686
+ # (in the same way we would usually concatenate the value vectors)
687
+ # Input:
688
+ # outputs_c [B, H, T, Do_c]
689
+ # Output:
690
+ # outputs_c [B, T, H*Do_c]
691
+
692
+ outputs_c = outputs_c.permute(0, 2, 1, 3).contiguous().view(B, T, H * Do_c)
693
+
694
+ # Project up to the shared output space and sum across the output heads.
695
+ # Input:
696
+ # outputs_c [B, T, H*Do_c]
697
+ # o_priv_b_proj [H*Do_c, Do_s]
698
+ # Output:
699
+ # output_s [B, T, Do_s]
700
+ output_s = self.o_priv_b_proj(outputs_c)
701
+
702
+ # Apply normalization to the output latents
703
+ output_s = self.o_shared_norm(output_s)
704
+
705
+ # Re-project the output latent representation back to model space.
706
+ # Input:
707
+ # output_s [B, T, Do_s]
708
+ # o_shared_proj [Do_s, D]
709
+ # Output:
710
+ # attn_output [B, T, D]
711
+ attn_output = self.o_shared_proj(output_s)
712
+
713
+ # TODO - Not currently supported.
714
+ # If this is a dense layer,
715
+ # Project the values back into model space.
716
+ # attn_output = self.o_proj(attn_output)
717
+
718
+ # -----------------------------------------
719
+
720
+ return attn_output
721
+
checkpoint-3000/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
checkpoint-3000/mla.py ADDED
@@ -0,0 +1,619 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
2
+
3
+ # `mla.py`
4
+
5
+ Based on: https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py
6
+
7
+ ## RotaryEmbedding
8
+ """
9
+
10
+ import torch
11
+ import torch.nn as nn
12
+ import torch.nn.functional as F
13
+ from typing import Optional
14
+
15
+ from .shared_space_config import SharedSpaceDecoderConfig
16
+
17
+
18
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
19
+ """
20
+ Create a normalization layer based on the config norm_type.
21
+
22
+ If `hidden_size` is `None`, this returns an identity layer.
23
+
24
+ Args:
25
+ hidden_size: The dimension to normalize over
26
+ config: Configuration containing norm_type and epsilon values
27
+
28
+ Returns:
29
+ Either a LayerNorm or RMSNorm layer
30
+ """
31
+ if hidden_size is None:
32
+ return nn.Identity()
33
+ elif config.norm_type == "layernorm":
34
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
35
+ elif config.norm_type == "rmsnorm":
36
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
37
+ else:
38
+ # This should be caught by config validation, but being defensive
39
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
40
+
41
+
42
+ # TODO - Find a shared place to put this.
43
+ class DeepseekV3RMSNorm(nn.Module):
44
+ def __init__(self, hidden_size, eps=1e-6):
45
+ """
46
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
47
+ """
48
+ super().__init__()
49
+ self.weight = nn.Parameter(torch.ones(hidden_size))
50
+ self.variance_epsilon = eps
51
+
52
+ def forward(self, hidden_states):
53
+ input_dtype = hidden_states.dtype
54
+ hidden_states = hidden_states.to(torch.float32)
55
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
56
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
57
+ return self.weight * hidden_states.to(input_dtype)
58
+
59
+
60
+ # Helper function needed because it's called twice during RoPE,
61
+ # but I dumped it in the comments there.
62
+ # TODO - Nah, screw it, just write it twice! At least then you get
63
+ # to use the word 'query' instead of 'x'.
64
+ def rotate_half(x):
65
+ """Rotates half the hidden dims of the input."""
66
+ x1 = x[..., : x.shape[-1] // 2]
67
+ x2 = x[..., x.shape[-1] // 2 :]
68
+ return torch.cat((-x2, x1), dim=-1)
69
+
70
+ class RotaryEmbedding(nn.Module):
71
+ """Precompute RoPE embeddings and store them as buffers."""
72
+
73
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
74
+ super().__init__()
75
+
76
+ dim = config.rope_dims
77
+ seq_len = config.max_position_embeddings
78
+
79
+ # ------------------------------
80
+ # Compute inverse frequencies
81
+ # ------------------------------
82
+ # Shape: [dim // 2]
83
+ # inv_freq[i] = 1 / (theta^(i / dim))
84
+ inv_freq = 1.0 / (
85
+ config.rope_theta
86
+ ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim)
87
+ )
88
+
89
+ # ------------------------------
90
+ # Apply RoPE scaling if configured
91
+ # ------------------------------
92
+ if config.rope_scaling is not None:
93
+ scaling_type = config.rope_scaling.get("type", "linear")
94
+ scaling_factor = config.rope_scaling.get("factor", 1.0)
95
+
96
+ if scaling_type == "linear":
97
+ # Linear scaling: divide frequencies by scaling factor
98
+ inv_freq = inv_freq / scaling_factor
99
+ elif scaling_type == "dynamic":
100
+ # Dynamic scaling: adjust based on sequence length
101
+ # This is a simplified implementation
102
+ inv_freq = inv_freq / scaling_factor
103
+ else:
104
+ print(f"Warning: Unknown RoPE scaling type '{scaling_type}', using linear scaling")
105
+ inv_freq = inv_freq / scaling_factor
106
+
107
+ # ------------------------------
108
+ # Compute position indices
109
+ # ------------------------------
110
+ # Shape: [seq_len]
111
+ t = torch.arange(seq_len, dtype=torch.float32)
112
+
113
+ # ------------------------------
114
+ # Outer product: [seq_len, dim // 2]
115
+ # Each row i contains: t[i] * inv_freq
116
+ # ------------------------------
117
+ freqs = torch.outer(t, inv_freq)
118
+
119
+ # ------------------------------
120
+ # Duplicate for interleaved sin/cos: [seq_len, dim]
121
+ # This matches the common format: [sin_0, cos_0, sin_1, cos_1, ...]
122
+ # ------------------------------
123
+ emb = torch.cat((freqs, freqs), dim=-1)
124
+
125
+ # ------------------------------
126
+ # Register cos/sin as buffers
127
+ # - Stored in float32
128
+ # - Will be moved to correct device/dtype via model.to(...)
129
+ # - Not saved with state_dict (persistent=False)
130
+ # ------------------------------
131
+ self.register_buffer("cos", emb.cos(), persistent=False)
132
+ self.register_buffer("sin", emb.sin(), persistent=False)
133
+
134
+ def forward(self, position_ids: torch.LongTensor) -> tuple[torch.Tensor, torch.Tensor]:
135
+ """ """
136
+ return None # This function is not necessary.
137
+
138
+ """## MLA"""
139
+
140
+ class MultiheadLatentAttention(nn.Module):
141
+ """
142
+ A variant of MLA with:
143
+ - Simplified RoPE handling:
144
+ - A portion of the head dimensions are used for position information.
145
+ - Same number of queries as keys. (no MQA)
146
+ - Optional output subspace
147
+ """
148
+
149
+ def __init__(self, config: SharedSpaceDecoderConfig, layer_idx: int):
150
+ super().__init__()
151
+
152
+ self.config = config
153
+
154
+ # Used to determine if this layer is dense or uses latents.
155
+ self.layer_idx = layer_idx
156
+ self.attention_dropout_prob = config.attention_dropout_prob
157
+
158
+ self.num_heads = config.num_attention_heads
159
+
160
+ self.rope_theta = config.rope_theta
161
+ self.rope_dims = config.rope_dims
162
+ self.nope_dims = config.nope_dims
163
+
164
+ self.q_shared_dim = config.q_shared_dim
165
+ self.kv_shared_dim = config.kv_shared_dim
166
+ self.o_shared_dim = config.o_shared_dim
167
+
168
+ self.qk_private_dim = config.qk_private_dim
169
+ self.vo_private_dim = config.vo_private_dim
170
+
171
+ self.hidden_size = config.hidden_size
172
+
173
+ # =========================
174
+ # Input Projections
175
+ # =========================
176
+
177
+ # If this is one of the dense layers,
178
+ if self.layer_idx < config.num_dense_layers:
179
+
180
+ # =========================
181
+ # Dense Attention
182
+ # =========================
183
+
184
+ # No latent projections.
185
+ self.latent_spaces = False
186
+
187
+ # Define the standard QKV projection
188
+ self.qkv_proj = nn.Linear(
189
+ config.hidden_size,
190
+ self.num_heads * (self.qk_private_dim * 2 + self.vo_private_dim),
191
+ bias=config.attention_bias,
192
+ )
193
+
194
+ # Dense output projection
195
+ self.o_proj = nn.Linear(
196
+ self.num_heads * self.vo_private_dim,
197
+ config.hidden_size,
198
+ bias=config.attention_bias,
199
+ )
200
+
201
+ # If we're past the dense layers,
202
+ else:
203
+
204
+ # =========================
205
+ # Latent Attention
206
+ # =========================
207
+
208
+ # Use latent projections.
209
+ self.latent_spaces = True
210
+
211
+ # Input latent projections
212
+
213
+ print("config.q_shared_dim", config.q_shared_dim)
214
+
215
+ # If we're using a shared query subspace,
216
+ if config.q_shared_dim is not None:
217
+ # Set a flag that we'll check in `forward`.
218
+ self.query_shared = True
219
+
220
+ self.q_shared_proj = nn.Linear(
221
+ config.hidden_size,
222
+ self.q_shared_dim,
223
+ bias=config.attention_bias,
224
+ )
225
+
226
+ self.q_shared_norm = create_norm_layer(self.q_shared_dim, config)
227
+
228
+ else:
229
+ print("Using identity for shared projection.")
230
+ # Set a flag that we'll check in `forward`.
231
+ self.query_shared = False
232
+
233
+ self.q_shared_dim = config.hidden_size
234
+
235
+ #print("Updated self.q_shared_dim to", self.q_shared_dim)
236
+
237
+ # Use identity.
238
+ self.q_shared_proj = nn.Identity()
239
+ self.q_shared_norm = nn.Identity()
240
+
241
+ # If we're using a shared key/value subspace,
242
+ if config.kv_shared_dim is not None:
243
+ # Set a flag that we'll check in `forward`.
244
+ self.keyvalue_shared = True
245
+
246
+ self.kv_shared_proj = nn.Linear(
247
+ config.hidden_size,
248
+ self.kv_shared_dim,
249
+ bias=config.attention_bias,
250
+ )
251
+
252
+ self.kv_shared_norm = create_norm_layer(self.kv_shared_dim, config)
253
+
254
+ else:
255
+ # Set a flag that we'll check in `forward`.
256
+ self.keyvalue_shared = False
257
+
258
+ self.kv_shared_dim = config.hidden_size
259
+
260
+ # Use identity.
261
+ self.kv_shared_proj = nn.Identity()
262
+ self.kv_shared_norm = nn.Identity()
263
+
264
+ #print("config.q_shared_dim", config.q_shared_dim)
265
+ #print("self.qk_private_dim", self.qk_private_dim)
266
+
267
+ # Query heads
268
+ self.q_private_proj = nn.Linear(
269
+ self.q_shared_dim,
270
+ self.num_heads * self.qk_private_dim,
271
+ bias=False # TODO
272
+ )
273
+
274
+ # Key and Value heads, concatenated
275
+ self.kv_private_proj = nn.Linear(
276
+ self.kv_shared_dim,
277
+ self.num_heads * (self.qk_private_dim + self.vo_private_dim),
278
+ bias=False,
279
+ )
280
+
281
+ # Use output subspace if o_shared_dim is specified
282
+ self.output_subspace = config.o_shared_dim is not None
283
+
284
+ # If we're using an output subspace,
285
+ if self.output_subspace:
286
+
287
+ # ==========================
288
+ # Output Subspace
289
+ # ==========================
290
+
291
+ self.o_shared_dim = config.o_shared_dim
292
+
293
+ # Per-head output projections
294
+ # (Similar to original W^O, but projects the scored value vectors
295
+ # into a latent space instead of back to the model)
296
+ self.o_private_proj = nn.Linear(
297
+ self.num_heads * self.vo_private_dim,
298
+ self.o_shared_dim,
299
+ bias=False
300
+ )
301
+
302
+ # Norm layer between o_private_proj and o_shared_proj
303
+ # Note: In previous ViT experiments, this norm step hurt performance, but was beneficial
304
+ # in the DeepSeekV3 experiments.
305
+ # However, we're making it configurable so it can be tested in different contexts.
306
+ self.o_private_norm = create_norm_layer(self.o_shared_dim, config)
307
+
308
+ # Shared output projection
309
+ # The head outputs from `o_private_proj` are first summed together (across
310
+ # heads) in the latent space.
311
+ # Then we project their combined outputs (a single vector per token)
312
+ # back to model space via `o_shared_proj`.
313
+ self.o_shared_proj = nn.Linear(
314
+ self.o_shared_dim,
315
+ self.hidden_size,
316
+ bias=config.attention_bias
317
+ )
318
+ else:
319
+ # Dense output projection
320
+ self.o_proj = nn.Linear(
321
+ self.num_heads * self.vo_private_dim,
322
+ config.hidden_size,
323
+ bias=config.attention_bias,
324
+ )
325
+
326
+ # Softmax scaling factor.
327
+ self.softmax_scale = self.qk_private_dim ** (-0.5)
328
+
329
+
330
+ def forward(
331
+ self,
332
+ hidden_states: torch.Tensor,
333
+ position_embeddings: tuple[torch.Tensor, torch.Tensor],
334
+ attention_mask: Optional[torch.Tensor],
335
+ #past_key_value: Optional[Cache] = None, # TODO - Can I remove this?
336
+ #cache_position: Optional[torch.LongTensor] = None, # TODO - Can I remove this?
337
+ **kwargs,
338
+ ) -> tuple[torch.Tensor, Optional[torch.Tensor], Optional[tuple[torch.Tensor]]]:
339
+ # === Tensor Dimension Symbols ===
340
+ # B: batch_size — number of samples in the batch
341
+ # T: seq_len — number of tokens per sample
342
+ # H: n_heads — number of attention heads
343
+ # D: hidden_dim — model embedding size
344
+ # Dv: vo_private_dim - per-head value/output projection dimension
345
+ # Dr: rope_dims - The first Dr dimensions receive rope.
346
+ # Cq: q_shared_dim - query shared subspace size
347
+ # Ckv: kv_shared_dim - key-value shared subspace size
348
+ # Co: o_shared_dim - output shared subspace size
349
+
350
+ # Input token embeddings
351
+ # hidden_states: [B, T, D]
352
+ B, T = hidden_states.shape[:2]
353
+ H = self.num_heads
354
+ Dq = self.qk_private_dim # per-head dim for Q and K
355
+ Dv = self.vo_private_dim # per-head dim for V/O
356
+
357
+ Dc_q, Dc_kv = self.q_shared_dim, self.kv_shared_dim
358
+
359
+ # ==============================
360
+ # QKV Head Projections
361
+ # ==============================
362
+ # Project tokens into per-head query, key, and value vectors
363
+
364
+ # If this layer uses latent projections,
365
+ if self.latent_spaces:
366
+
367
+ # ================================
368
+ # Shared Space Projections
369
+ # ================================
370
+
371
+ # Project token embeddings into shared latents
372
+ # Input:
373
+ # hidden_states [B, T, D]
374
+ # q_shared_proj [D, Cq]
375
+ # kv_shared_proj [D, Ckv]
376
+ # Output:
377
+ # q_shared [B, T, Cq]
378
+ # kv_shared [B, T, Ckv]
379
+
380
+ # If we're using a shared query subspace,
381
+ if self.q_shared_dim is not None:
382
+ q_shared = self.q_shared_proj(hidden_states)
383
+
384
+ # Normalize latent vectors, shapes unchanged.
385
+ q_shared = self.q_shared_norm(q_shared)
386
+ # Otherwise,
387
+ else:
388
+ # Use the hidden states
389
+ q_shared = hidden_states
390
+
391
+ # If we're using a shared key/value subspace,
392
+ if self.kv_shared_dim is not None:
393
+
394
+ # Project token embeddings into shared subspace.
395
+ kv_shared = self.kv_shared_proj(hidden_states)
396
+
397
+ # Normalize latent vectors, shapes unchanged.
398
+ kv_shared = self.kv_shared_norm(kv_shared)
399
+ # Otherwise,
400
+ else:
401
+ # Use the hidden states
402
+ kv_shared = hidden_states
403
+
404
+ # ======================================
405
+ # Per-Head (Private) Projections
406
+ # ======================================
407
+
408
+ # Project query latents onto query heads.
409
+ # Input:
410
+ # q_shared [B, T, Cq]
411
+ # q_private_proj [Cq, H*Dh]
412
+ # Output:
413
+ # queries [B, T, H*Dh]
414
+ queries = self.q_private_proj(q_shared)
415
+
416
+ # Project key/value latents onto key and value heads.
417
+ # The key and value heads are all concatenated, each head occupies
418
+ # Dh columns of the kv_private_proj. This yields the key and value
419
+ # vectors concatenated in the same way.
420
+ #
421
+ # Input:
422
+ # kv_shared [B, T, Ckv]
423
+ # kv_private_proj [Ckv, 2*H*Dh]
424
+ # Output:
425
+ # keysvalues [B, T, 2*H*Dh]
426
+ keysvalues = self.kv_private_proj(kv_shared)
427
+
428
+ # Split into key and value tensors
429
+ # Each: [B, T, H * Dh]
430
+ keys, values = keysvalues.chunk(2, dim=-1)
431
+
432
+ # If this is a dense attention layer (no latent projections),
433
+ else:
434
+
435
+ # ====================
436
+ # Standard MHA
437
+ # ====================
438
+
439
+ # Standard QKV projection
440
+ # Input:
441
+ # hidden_states [B, T, D]
442
+ # qkv_proj [D, 3*H*Dh]
443
+ # Output:
444
+ # querieskeysvalues [B, T, 3*H*Dh]
445
+ querieskeysvalues = self.qkv_proj(hidden_states)
446
+
447
+ # Separate query, key, and value vectors
448
+ # Each: [B, T, H * Dh]
449
+ queries, keys, values = querieskeysvalues.chunk(3, dim=-1)
450
+
451
+ # Split up queries so that there's just one per row.
452
+ # Same for keys and values.
453
+ #
454
+ # Inputs:
455
+ # Each [B, T, H*Dh]
456
+ # Output:
457
+ # Each [B, H, T, Dh]
458
+ queries = queries.view(B, T, H, Dq).transpose(1, 2)
459
+ keys = keys.view(B, T, H, Dq).transpose(1, 2)
460
+ values = values.view(B, T, H, Dv).transpose(1, 2)
461
+
462
+ # ==================
463
+ # RoPE
464
+ # ==================
465
+ # Apply rotary position embeddings to the first `self.rope_dims` of
466
+ # each head.
467
+ # The slice operations are free, but the concatenation is
468
+ # not, because the outputs of the rotation operation are new data
469
+ # occupying different memory. Still considered the best option,
470
+ # though.
471
+
472
+ # 1. Unpack the precomputed cosine and sine embeddings
473
+ # Position embeddings is a tuple of
474
+ # (cos [seq_len, rope_dims],
475
+ # sin [seq_len, rope_dims])
476
+ cos, sin = position_embeddings
477
+
478
+ # 2. Split the query and key heads into the part to rotate and the part
479
+ # to pass through (early columns get position info, later ones don't)
480
+ #
481
+ # (Using queries as example)
482
+ # Inputs:
483
+ # queries [B, H, T, Dh] Dh = rope_dims + not_rope_dims
484
+ # Outputs:
485
+ # q_rope [B, H, T, Dr]
486
+ # q_pass [B, H, T, Dh-Dr]
487
+ q_rope, q_pass = queries[..., :self.rope_dims], queries[..., self.rope_dims:]
488
+ k_rope, k_pass = keys[..., :self.rope_dims], keys[..., self.rope_dims:]
489
+
490
+ # 3. Apply the rotary embedding to the designated slice
491
+ #
492
+ # To broadcast cos and sin across the batch and head dimensions, we unsqueeze them.
493
+ # Shape change: [T, Dr] -> [1, 1, T, Dr]
494
+ cos = cos.unsqueeze(0).unsqueeze(0)
495
+ sin = sin.unsqueeze(0).unsqueeze(0)
496
+
497
+ #print("q_rope.shape[-1] // 2:", (q_rope.shape[-1] // 2))
498
+ #print("x1 = x[..., :x.shape[-1] // 2 ].shape:", q_rope[..., :q_rope.shape[-1] // 2 ].shape)
499
+ #print("sin/cos.shape:", cos.shape)
500
+ #print("q_rope.shape:", q_rope.shape)
501
+ #print("(q_rope * cos).shape:", (q_rope * cos).shape)
502
+ #print("rotate_half(q_rope).shape:", rotate_half(q_rope).shape)
503
+ #print("(rotate_half(q_rope) * sin).shape:", (rotate_half(q_rope) * sin).shape)
504
+ """
505
+ In this example batch_size = 2, hum_heads = 8, seq_len = 65, rope_dims = 16
506
+
507
+ q_rope.shape[-1] // 2: 8
508
+ x1 = x[..., :x.shape[-1] // 2 ].shape: torch.Size([2, 8, 65, 8])
509
+
510
+ sin/cos.shape: torch.Size([1, 1, 65, 16]) # After double unsqueeze.
511
+ vq_rope.shape: torch.Size([2, 8, 65, 16])
512
+
513
+ (q_rope * cos).shape: torch.Size([2, 8, 65, 16])
514
+
515
+ rotate_half(q_rope).shape: torch.Size([2, 8, 65, 16])
516
+ (rotate_half(q_rope) * sin).shape: torch.Size([2, 8, 65, 16])
517
+ """
518
+
519
+
520
+ # Let's walk through the queries as the example.
521
+ # What does rotate half do?
522
+ # dim -1 is the row vectors, the queries
523
+ #
524
+ # Step 1: Split the vector in half.
525
+ # "q_rope.shape[-1] // 2" <- How much to select. Half the length of the q_rope vector
526
+ # x1 = x[..., :x.shape[-1] // 2 ] # Select the first half of the vector.
527
+ # x2 = x[..., x.shape[-1] // 2:] # Select the second half.
528
+ #
529
+ # Step 2:
530
+ # - Apply negative to the values in the second half.
531
+ # - Reverse the order of the halves.
532
+ # return torch.cat((-x2, x1), dim=-1)
533
+ #
534
+ # ---- (q_rope * cos) ----
535
+ # Element-wise multiply the values in each `cos` vector with the
536
+ # corresponding (i.e., same sequence position) `q_rope` vector.
537
+ #
538
+ # Inputs:
539
+ # q_rope [B, H, T, Dr]
540
+ # cos [1, 1, T, Dr]
541
+ #
542
+ # Outputs:
543
+ # x [B, H, T, Dr]
544
+ #
545
+ # ---- (rotate_half(q_rope)) ----
546
+ # TODO
547
+ #
548
+ # Inputs:
549
+ # q_rope [B, T, Dr]
550
+ #
551
+ # Outputs:
552
+ # rot_q_rope [B, T, Dr]
553
+ #
554
+ # ---- rotated * sin ----
555
+ # TODO
556
+ q_rotated = (q_rope * cos) + (rotate_half(q_rope) * sin)
557
+ k_rotated = (k_rope * cos) + (rotate_half(k_rope) * sin)
558
+
559
+ # 4. Concatenate the rotated and pass-through parts back together
560
+ # Input (each): [B, H, T, Dr] and [B, H, T, Dq-Dr]
561
+ # Output (each): [B, H, T, Dq]
562
+ queries = torch.cat((q_rotated, q_pass), dim=-1)
563
+ keys = torch.cat((k_rotated, k_pass), dim=-1)
564
+
565
+ # ===================
566
+ # Attention
567
+ # ===================
568
+ # The tensors (queries, keys, values) now have shape [B, H, T, Dq]
569
+ # and are ready for the attention score calculation.
570
+
571
+ # Only apply dropout during training.
572
+ # self.training is a pytorch flag.
573
+ if self.training:
574
+ dropout_p = self.attention_dropout_prob
575
+ else:
576
+ dropout_p = 0.0
577
+
578
+ # Call SDPA / Flash Attention
579
+ # https://docs.pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html
580
+ attn_output = F.scaled_dot_product_attention(
581
+ queries,
582
+ keys,
583
+ values,
584
+ attn_mask=None, # attention_mask,
585
+ dropout_p=dropout_p,
586
+ scale=self.softmax_scale,
587
+ is_causal=True, # This is a decoder - apply causal masking
588
+ )
589
+
590
+ # Reshape output back to [B, T, H * Dv] from [B, H, T, Dv]
591
+ attn_output = attn_output.transpose(1, 2).contiguous().view(B, T, H * Dv)
592
+
593
+ # =========================
594
+ # Output Projection
595
+ # =========================
596
+
597
+ # If we are using an output latent projection,
598
+ if self.latent_spaces and self.output_subspace:
599
+
600
+ # Project the attention output into the output latent space.
601
+ # This is analogous to the W^O matrix in standard attention but
602
+ # projects to an intermediate latent dimension.
603
+ attn_output = self.o_private_proj(attn_output)
604
+
605
+ # Apply normalization to the output latents
606
+ attn_output = self.o_private_norm(attn_output)
607
+
608
+ # Re-project the output latent representation back to model space.
609
+ attn_output = self.o_shared_proj(attn_output)
610
+
611
+ # If this is a dense layer,
612
+ else:
613
+ # Project the values back into model space.
614
+ attn_output = self.o_proj(attn_output)
615
+
616
+ # -----------------------------------------
617
+
618
+ return attn_output
619
+
checkpoint-3000/optimizer.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f6919065c808b2b25bd22da1e5d8cd5f6ee1111b1996e2c9ef132a5bd57e383d
3
+ size 988989899
checkpoint-3000/pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:02c749023ca02a2260541bcbe926f5ccb8aaea29a6b8d40e44cffcc695c4bdf0
3
+ size 494483579
checkpoint-3000/rng_state.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0cd23626013be2cf1b8f351eb1880911bc653b0d6a7fc40aa3f0c07b9f92b902
3
+ size 14645
checkpoint-3000/scheduler.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:de993877decafa3dbec3a2190f9cbfc7ce6efc997a47f7abd25897f127fbf6ba
3
+ size 1465
checkpoint-3000/shared_space_config.py ADDED
@@ -0,0 +1,329 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """# `shared_space_config.py`
2
+
3
+ #### `*Config`
4
+ """
5
+
6
+ from typing import Optional
7
+
8
+ import torch
9
+ from torch import nn
10
+
11
+ from transformers.configuration_utils import PretrainedConfig
12
+ from transformers.modeling_utils import PreTrainedModel
13
+
14
+ """`def make_shorthand`"""
15
+
16
+ def make_shorthand(model_cfg):
17
+ """
18
+ Takes an instance subencoder `*Config` and constructs a shorthand
19
+ name for the model based on settings.
20
+ """
21
+
22
+ dense_str = str(model_cfg.num_dense_layers) + "mha + "
23
+
24
+ if model_cfg.o_shared_dim is not None:
25
+ o_str = "." + str(model_cfg.o_shared_dim)
26
+ else:
27
+ o_str = ""
28
+
29
+ # If no output subspace is used, the dimension will show as -1.
30
+ attn_str = (
31
+ dense_str
32
+ + "mla."
33
+ + str(model_cfg.q_shared_dim)
34
+ + "."
35
+ + str(model_cfg.kv_shared_dim)
36
+ + o_str
37
+ )
38
+
39
+ # MLP Configuration
40
+ if model_cfg.ffn_decompose:
41
+ dense_str = (
42
+ str(model_cfg.num_dense_layers)
43
+ + "mlp."
44
+ + str(model_cfg.intermediate_size)
45
+ + " + "
46
+ )
47
+
48
+ mlp_str = (
49
+ dense_str
50
+ + str(model_cfg.num_hidden_layers - model_cfg.num_dense_layers)
51
+ + "dcmp."
52
+ + "x"
53
+ + str(model_cfg.intermediate_size)
54
+ + "."
55
+ + str(model_cfg.ffn_rank)
56
+ )
57
+ else:
58
+ mlp_str = "mlp." + str(model_cfg.intermediate_size)
59
+
60
+ # Assemble string
61
+ shorthand = (
62
+ f"{attn_str} - {mlp_str} - "
63
+ f"h{model_cfg.hidden_size} - l{model_cfg.num_hidden_layers}"
64
+ )
65
+
66
+ """
67
+ The run name includes training settings
68
+
69
+ run_name = (
70
+ f"{config['stats']['total_elements']} - "
71
+ f"{attn_str} - {mlp_str} - "
72
+ f"h{model_cfg.hidden_size} - l{model_cfg.num_hidden_layers} - "
73
+ f"bs{ptrain_cfg['train_batch_size']} - lr{lr_str} - "
74
+ f"seq{ptrain_cfg['max_seq_length']}"
75
+ )
76
+ """
77
+
78
+ return shorthand
79
+
80
+
81
+ class SharedSpaceDecoderConfig(PretrainedConfig):
82
+ r"""
83
+ Configuration class for SharedSpaceDecoderConfig.
84
+
85
+ Extends the HuggingFace `PretrainedConfig` to support architectural
86
+ variations including:
87
+ - Multi-Head Latent Attention (MLA)
88
+ - Decomposed MLPs (low-rank FFNs)
89
+ - Flexible attention backends (eager, flash, sdpa)
90
+ - Explicit shared subspaces for Q, K, V, and O projections
91
+
92
+ This config does not infer any defaults based on `hidden_size`. All
93
+ dimensions and ranks must be explicitly specified. If required values are
94
+ missing, a `ValueError` is raised during initialization.
95
+
96
+ ----------------------
97
+ Core Model Parameters:
98
+ ----------------------
99
+ - vocab_size (`int`) — Vocabulary size.
100
+ - hidden_size (`int`) — Model hidden dimension.
101
+ - num_hidden_layers (`int`) — Number of transformer blocks.
102
+ - intermediate_size (`int`) — Feed-forward hidden dimension.
103
+ - hidden_act (`str`) — Activation function.
104
+ - hidden_dropout_prob (`float`) — Dropout after projections and FFNs.
105
+ - attention_dropout_prob (`float`) — Dropout applied to attention scores.
106
+ - max_position_embeddings (`int`) — Max sequence length.
107
+ - initializer_range (`float`) — Stddev of weight init.
108
+
109
+ - layer_norm_eps (`float`) — Epsilon for LayerNorm.
110
+ - rms_norm_ps (`float`) — Epsilon for RMSNorm
111
+
112
+ - classifier_dropout (`float` or None) — Dropout for final classifier.
113
+
114
+ - vocab_subspace
115
+ - vocab_rank
116
+
117
+ ----------------------------------
118
+ Multi-Head Latent Attention (MLA):
119
+ ----------------------------------
120
+ - num_attention_heads (`int`) — Number of attention heads.
121
+
122
+ - q_shared_dim (`int`) — Rank of the shared query subspace.
123
+ - kv_shared_dim (`int`) — Rank of the shared key/value subspace.
124
+
125
+ - output_subspace (`bool`) — Whether to use a shared latent subspace for output projections.
126
+ - o_shared_dim (`int`) — Rank of the shared output subspace (required if `output_subspace=True`).
127
+ - qk_private_dim (`int`) — Query/key private dimension per head.
128
+ - vo_private_dim (`int`) — Value/output private dimension per head.
129
+
130
+ - rope_dims (`int`) — Number of head dimensions carrying RoPE.
131
+ - nope_dims (`int`) — Non-positional encoding dimensions.
132
+ - rope_theta (`float`) — Base frequency used for RoPE.
133
+ - rope_scaling (`dict` or None) — HF-style scaling dict for RoPE.
134
+ - attention_bias (`bool`) — Whether to include bias terms in Q/K/V projections.
135
+ - num_dense_layers (`int`) — Number of leading layers that do not use
136
+ subspaces for attention or FFNs.
137
+ - attention_backend (`str`) — Must be one of `"eager"`, `"flash_attention_2"`, or `"sdpa"`.
138
+
139
+ ----------------------
140
+ Decomposed MLP (Low-Rank FFN):
141
+ ----------------------
142
+ - ffn_decompose (`bool`) — Whether to enable low-rank FFNs.
143
+ - ffn_rank (`int`) — Rank of the shared FFN latent space (required if `ffn_decompose=True`).
144
+
145
+ ----------------------
146
+ Validation Behavior:
147
+ ----------------------
148
+ Raises `ValueError` at init time if:
149
+ - FFN decomposition is enabled without specifying `ffn_rank`.
150
+ - An unknown `attention_backend` is provided.
151
+ """
152
+
153
+ model_type = "shared_subspace_decoder"
154
+
155
+ def __init__(
156
+ self,
157
+
158
+ # === Core Model ===
159
+ vocab_size: int = 30522,
160
+ hidden_size: int = 512,
161
+ num_hidden_layers: int = 12,
162
+
163
+ intermediate_size: int = 3072,
164
+
165
+ hidden_dropout_prob=0.1,
166
+ attention_dropout_prob=0.1,
167
+ max_position_embeddings: int = 2048,
168
+ initializer_range=0.02,
169
+ layer_norm_eps=1e-12,
170
+ rms_norm_eps=1e-6, # Their default, but confirm in config.
171
+ norm_type="layernorm", # Choice between "layernorm" and "rmsnorm"
172
+ classifier_dropout=None,
173
+
174
+ vocab_subspace=False,
175
+ vocab_rank=None,
176
+ tie_word_embeddings=True,
177
+
178
+ # === Multi-Head Latent Attention ===
179
+ num_attention_heads: int = 16,
180
+ rope_dims: int = 16,
181
+
182
+ q_shared_dim: int = None,
183
+ kv_shared_dim: int = None,
184
+
185
+ o_shared_dim=None, # If None, no output subspace is used
186
+
187
+ # Private head dimensions
188
+ qk_private_dim: int = None, # Query/key private dimension per head
189
+ vo_private_dim: int = None, # Value/output private dimension per head
190
+ nope_dims: int = None, # Non-positional encoding dimensions
191
+
192
+ attention_backend="eager",
193
+ rope_theta=10000.0,
194
+ rope_scaling=None,
195
+ attention_bias=False,
196
+
197
+ # === MLA Composition ===
198
+ num_dense_layers=12, # dense MHA layers before MLA starts
199
+
200
+ # === Decomposed MLP ===
201
+ ffn_decompose=False,
202
+ ffn_rank=None,
203
+ **kwargs
204
+ ) -> None:
205
+ super().__init__(**kwargs)
206
+
207
+
208
+
209
+ # === Core Model ===
210
+ self.vocab_size = vocab_size
211
+ self.hidden_size = hidden_size
212
+ self.num_hidden_layers = num_hidden_layers
213
+ self.intermediate_size = intermediate_size
214
+ self.hidden_dropout_prob = hidden_dropout_prob
215
+ self.attention_dropout_prob = attention_dropout_prob
216
+ self.max_position_embeddings = max_position_embeddings
217
+ self.initializer_range = initializer_range
218
+ self.layer_norm_eps = layer_norm_eps
219
+ self.rms_norm_eps = rms_norm_eps
220
+ self.norm_type = norm_type
221
+ self.classifier_dropout = classifier_dropout
222
+
223
+ self.vocab_subspace = vocab_subspace
224
+ self.vocab_rank = vocab_rank
225
+ self.tie_word_embeddings = tie_word_embeddings
226
+
227
+ # === MLA ===
228
+ self.num_attention_heads = num_attention_heads
229
+ self.rope_dims = rope_dims
230
+
231
+ self.q_shared_dim = q_shared_dim
232
+ self.kv_shared_dim = kv_shared_dim
233
+ self.o_shared_dim = o_shared_dim
234
+
235
+ # Private head dimensions
236
+ self.qk_private_dim = qk_private_dim
237
+ self.vo_private_dim = vo_private_dim
238
+ self.nope_dims = nope_dims
239
+ self.rope_theta = rope_theta
240
+ self.rope_scaling = rope_scaling
241
+ self.attention_bias = attention_bias
242
+ self.num_dense_layers = num_dense_layers
243
+
244
+ # === Decomposed FFN ===
245
+ self.ffn_decompose = ffn_decompose
246
+ self.ffn_rank = ffn_rank
247
+
248
+ # === Attention backend ===
249
+ self.attention_backend = attention_backend
250
+
251
+ # === Validation ===
252
+ # TODO - Somewhere during training these get instantiated with bad
253
+ # values...
254
+ #self._validate()
255
+
256
+ #print(f" > SubEnc *Config.init: {make_shorthand(self)}\n")
257
+
258
+
259
+ def _validate(self):
260
+ # === Model ===
261
+ if self.num_dense_layers > self.num_hidden_layers:
262
+ raise ValueError("`num_dense_layers` must be <= `num_hidden_layers`")
263
+ if self.vocab_subspace and self.vocab_rank is None:
264
+ raise ValueError("`vocab_rank` must be set when `vocab_subspace=True`")
265
+
266
+ # === MLA Validation ===
267
+ # At least one of q_shared_dim or kv_shared_dim must be set if we have subspace layers
268
+ if self.num_dense_layers < self.num_hidden_layers and self.q_shared_dim is None and self.kv_shared_dim is None:
269
+ raise ValueError("At least one of q_shared_dim or kv_shared_dim must be set when there are subspace layers")
270
+
271
+ # Validate that private dimensions are set
272
+ if self.qk_private_dim is None or self.vo_private_dim is None:
273
+ raise ValueError("Must set qk_private_dim and vo_private_dim")
274
+ if self.nope_dims is None:
275
+ raise ValueError("Must set nope_dims")
276
+
277
+ # === Decomposed FFN ===
278
+ if self.ffn_decompose and self.ffn_rank is None:
279
+ raise ValueError("`ffn_rank` must be set when `ffn_decompose=True`")
280
+ if self.ffn_decompose and self.num_dense_layers >= self.num_hidden_layers:
281
+ raise ValueError("`ffn_decompose` was set but `num_dense` is >= number of layers")
282
+
283
+ # === Attention Backend ===
284
+ valid_backends = ["eager", "flash_attention_2", "sdpa"]
285
+ if self.attention_backend not in valid_backends:
286
+ raise ValueError(f"Unknown attention backend: {self.attention_backend}, options are {valid_backends}")
287
+
288
+ # === Norm Type ===
289
+ valid_norm_types = ["layernorm", "rmsnorm"]
290
+ if self.norm_type not in valid_norm_types:
291
+ raise ValueError(f"Unknown norm type: {self.norm_type}, options are {valid_norm_types}")
292
+
293
+ #### `get_config`
294
+
295
+ import json
296
+
297
+ def get_config(filename):
298
+
299
+ # Load the config file.
300
+ with open(filename) as f:
301
+ full_cfg = json.load(f)
302
+
303
+ # Strict key check on the model configuration.
304
+
305
+ # Get the list of keys allowed / required by `*Config`
306
+ valid_keys = SharedSpaceDecoderConfig.__init__.__code__.co_varnames
307
+ # Remove `self` and `kwargs`
308
+ valid_keys = set(valid_keys) - {"self", "kwargs"}
309
+
310
+ # Compare the set of keys in the json file vs `*Config`
311
+ extra_keys = set(full_cfg["model"]) - valid_keys
312
+ missing_keys = valid_keys - set(full_cfg["model"])
313
+
314
+ # If there any in the `json` that aren't in `*Config`,
315
+ if extra_keys:
316
+ # List them for the user.
317
+ raise ValueError(f"Unknown keys in config: {sorted(extra_keys)}")
318
+
319
+ # If the json config is missing required keys,
320
+ if missing_keys:
321
+ # List them for the user.
322
+ raise ValueError(f"config json is missing: {sorted(missing_keys)}")
323
+
324
+ # Will raise TypeError, by design, if required args are missing
325
+ # The asterisks unpack the dictionary into a list of keywords as though
326
+ # all of the settings were writting out individually.
327
+ model_cfg = SharedSpaceDecoderConfig(**full_cfg["model"])
328
+
329
+ return full_cfg, model_cfg
checkpoint-3000/shared_space_decoder.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ """# shared_subspace_encoder.py"""
4
+
5
+ from typing import Optional
6
+
7
+ import torch
8
+ from torch import nn
9
+
10
+ from transformers.configuration_utils import PretrainedConfig
11
+ from transformers.modeling_utils import PreTrainedModel
12
+ from transformers.modeling_attn_mask_utils import _prepare_4d_attention_mask_for_sdpa
13
+
14
+ from .mla import MultiheadLatentAttention, RotaryEmbedding
15
+ from .feedforward import SubspaceFeedForward
16
+ from .shared_space_config import SharedSpaceDecoderConfig
17
+
18
+ """`RMSNorm`
19
+
20
+ From:
21
+ https://huggingface.co/deepseek-ai/DeepSeek-R1/blob/main/modeling_deepseek.py
22
+
23
+ TODO - May not need?
24
+ """
25
+
26
+ class DeepseekV3RMSNorm(nn.Module):
27
+ def __init__(self, hidden_size, eps=1e-6):
28
+ """
29
+ DeepseekV3RMSNorm is equivalent to T5LayerNorm
30
+ """
31
+ super().__init__()
32
+ self.weight = nn.Parameter(torch.ones(hidden_size))
33
+ self.variance_epsilon = eps
34
+
35
+ def forward(self, hidden_states):
36
+ input_dtype = hidden_states.dtype
37
+ hidden_states = hidden_states.to(torch.float32)
38
+ variance = hidden_states.pow(2).mean(-1, keepdim=True)
39
+ hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
40
+ return self.weight * hidden_states.to(input_dtype)
41
+
42
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
43
+ """
44
+ Create a normalization layer based on the config norm_type.
45
+
46
+ Args:
47
+ hidden_size: The dimension to normalize over
48
+ config: Configuration containing norm_type and epsilon values
49
+
50
+ Returns:
51
+ Either a LayerNorm or RMSNorm layer
52
+ """
53
+ if config.norm_type == "layernorm":
54
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
55
+ elif config.norm_type == "rmsnorm":
56
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
57
+ else:
58
+ # This should be caught by config validation, but being defensive
59
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
60
+
61
+ """#### *PreTrainedModel"""
62
+
63
+ class SharedSpaceDecoderPreTrainedModel(PreTrainedModel):
64
+ """
65
+ The **PreTrainedModel object:
66
+ - Is instantiated when TODO
67
+ - Initializes:
68
+ - TODO
69
+ - Provides access to TODO
70
+ - Executes TODO
71
+ """
72
+
73
+ config_class = SharedSpaceDecoderConfig
74
+ base_model_prefix = "model"
75
+
76
+ def _init_weights(self, module: nn.Module) -> None:
77
+ """Weight initialization hook used by :class:`PreTrainedModel`.
78
+
79
+ ``PreTrainedModel.post_init`` will recursively apply this function to
80
+ every submodule right after construction. HuggingFace models override
81
+ it so that creating a model from scratch yields the same initialization
82
+ as ``from_pretrained`` when no checkpoint is supplied.
83
+
84
+ This decoder-specific initialization strategy includes:
85
+ - Proper handling of configurable normalization layers (LayerNorm or RMSNorm)
86
+ - Special initialization for language modeling heads
87
+ - Considerations for causal attention and autoregressive modeling
88
+ - Support for both dense and decomposed vocabulary embeddings
89
+ """
90
+
91
+ if isinstance(module, nn.Linear):
92
+ # Standard linear layer initialization
93
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
94
+ if module.bias is not None:
95
+ module.bias.data.zero_()
96
+
97
+ elif isinstance(module, nn.Embedding):
98
+ # Initialize embeddings with normal distribution
99
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
100
+ if module.padding_idx is not None:
101
+ module.weight.data[module.padding_idx].zero_()
102
+
103
+ elif isinstance(module, DeepseekV3RMSNorm):
104
+ # RMSNorm initialization: weight to 1.0, no bias term
105
+ module.weight.data.fill_(1.0)
106
+
107
+ elif isinstance(module, nn.LayerNorm):
108
+ # LayerNorm initialization: bias to 0, weight to 1.0
109
+ module.bias.data.zero_()
110
+ module.weight.data.fill_(1.0)
111
+
112
+ """# ▂▂▂▂▂▂▂▂▂▂▂▂
113
+
114
+ # Classes
115
+ """
116
+
117
+ """#### `*Layer`"""
118
+
119
+ class SharedSpaceDecoderLayer(nn.Module):
120
+ """
121
+ The **Layer object:
122
+ - Is instantiated by :class:`SharedSpaceDecoderModel` for each
123
+ Transformer block in the decoder.
124
+ - Initializes:
125
+ - ``self_attn`` – multi-head latent attention implementing either
126
+ dense or latent projections depending on the configuration.
127
+ - ``ffn`` – a :class:`SubspaceFeedForward` block.
128
+ - RMSNorm layers for pre-attention and pre-FFN normalization.
129
+ - Provides access to the attention and feed-forward submodules via the
130
+ attributes ``self_attn`` and ``ffn``.
131
+ - Executes a single decoder block in :meth:`forward`.
132
+ """
133
+
134
+ def __init__(self, config: SharedSpaceDecoderConfig, layer_idx: int) -> None:
135
+
136
+ super().__init__()
137
+
138
+ # Norm applied prior to attention.
139
+ self.attn_input_norm = create_norm_layer(config.hidden_size, config)
140
+
141
+ # Attention block
142
+ self.self_attn = MultiheadLatentAttention(config, layer_idx)
143
+
144
+ # Norm applied prior to FFN
145
+ self.ffn_input_norm = create_norm_layer(config.hidden_size, config)
146
+
147
+ # Feed-forward network used after attention
148
+ self.ffn = SubspaceFeedForward(config, layer_idx)
149
+
150
+ def forward(
151
+ self,
152
+ hidden_states: torch.Tensor,
153
+ position_embeddings: tuple[torch.Tensor, torch.Tensor], # RoPE embeddings
154
+ attention_mask: Optional[torch.Tensor],
155
+ ) -> torch.Tensor:
156
+
157
+ # ========================
158
+ # Self Attention
159
+ # ========================
160
+ residual_strm = hidden_states
161
+
162
+ # Normalize the hidden states to create the input to attention.
163
+ attn_input = self.attn_input_norm(hidden_states)
164
+
165
+ # Evaluate
166
+ attn_output = self.self_attn(
167
+ attn_input,
168
+ position_embeddings,
169
+ attention_mask,
170
+ )
171
+
172
+ # Add the attention output (the residual) back to the non-normalized
173
+ # hidden_states.
174
+ hidden_states = residual_strm + attn_output
175
+
176
+ # ===========================
177
+ # Feed-Forward Network
178
+ # ===========================
179
+ residual_strm = hidden_states
180
+
181
+ # Normalize the updated hidden states prior to the FFN
182
+ ffn_input = self.ffn_input_norm(hidden_states)
183
+
184
+ # Evaluate
185
+ ffn_output = self.ffn(ffn_input)
186
+
187
+ # Add the output the un-normalized hidden states.
188
+ hidden_states = residual_strm + ffn_output
189
+
190
+ return hidden_states
191
+
192
+ """#### *Model"""
193
+
194
+ class SharedSpaceDecoderModel(SharedSpaceDecoderPreTrainedModel):
195
+ """
196
+ The **Model object:
197
+ - Initializes:
198
+ - The vocabulary embeddings (and optional decomposition)
199
+ - Position embeddings (calculated in RotaryEmbedding)
200
+ - All of the **Layer objects.
201
+ - Provides interface to vocab embeddings.
202
+ - Executes the whole decoder model in `forward` with causal attention.
203
+
204
+ This is the base decoder without the language modeling head.
205
+ Use SubspaceDecoderForCausalLM for language modeling tasks.
206
+ """
207
+
208
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
209
+ super().__init__(config)
210
+
211
+ # ============================
212
+ # Vocabulary Embeddings
213
+ # ============================
214
+ # Decomposing the vocabulary (if enabled) defines a shared projection
215
+ # which constrains the model to store semantic information (and
216
+ # whatever other static token knowledge) into a limited set of
217
+ # feature directions.
218
+
219
+ # If we're decomposing the token embeddings,
220
+ # TODO - Rename to vocab_subspace.
221
+ if config.vocab_subspace:
222
+
223
+ # Create the embedding table. Vocabulary embeddings are learned
224
+ # in a lower dimensional latent space.
225
+ self.vocab_embed = nn.Embedding(
226
+ config.vocab_size, # Number of tokens
227
+ config.vocab_rank # Subspace dimension
228
+ )
229
+
230
+ # Create a
231
+ # Selected token latents will be projected up to model size.
232
+ # vocab_proj has shape [vocab_rank x model_size]
233
+ self.vocab_proj = nn.Linear(
234
+ config.vocab_rank, # Size of latents
235
+ config.hidden_size, # Model size
236
+ bias=False
237
+ )
238
+
239
+ # Otherwise, for a dense vocabulary,
240
+ else:
241
+ # Create the dense embedding table in model space.
242
+ self.vocab_embed = nn.Embedding(
243
+ config.vocab_size, # Number of tokens
244
+ config.hidden_size # Model size
245
+ )
246
+
247
+ self.vocab_proj = None
248
+
249
+ # =====================
250
+ # RoPE Embeddings
251
+ # =====================
252
+
253
+ # Pre-computes the table of RoPE embeddings, leaving them in
254
+ # GPU memory.
255
+ self.rope = RotaryEmbedding(config)
256
+
257
+ # ===================
258
+ # Create Layers
259
+ # ===================
260
+
261
+ layers = []
262
+
263
+ # For each layer,
264
+ for i in range(config.num_hidden_layers):
265
+ # Create a **Layer, providing the config and indicating its number.
266
+ layers.append(
267
+ SharedSpaceDecoderLayer(
268
+ config,
269
+ layer_idx = i
270
+ )
271
+ )
272
+
273
+ # Wrap in torch ModuleList
274
+ self.layers = nn.ModuleList(layers)
275
+
276
+ # Whatever huggingface does behind the scenes...
277
+ self.post_init()
278
+
279
+ # Agents: Do not define boilerplate helpers, e.g., get/set_input_embeddings
280
+
281
+
282
+ def embed(self, input_ids: torch.LongTensor) -> torch.Tensor:
283
+ """
284
+ Return token embeddings for input ids.
285
+ This will perform the up projection to model space if the vocabulary is
286
+ decomposed.
287
+
288
+ input_ids have shape [batch_size, seq_len]
289
+ """
290
+
291
+ # If the vocabulary is decomposed,
292
+ if self.vocab_proj is not None:
293
+
294
+ # Retrieve the latents
295
+ # input_ids: [batch_size, seq_len]
296
+ # x: [batch_size, seq_len, latent_dim]
297
+ x = self.vocab_embed(input_ids)
298
+
299
+ # Project the latents back to model space and return.
300
+ return(self.vocab_proj(x))
301
+
302
+ # If the vocabulary is dense,
303
+ else:
304
+ # Just return the embeddings.
305
+ return self.vocab_embed(input_ids)
306
+
307
+ def forward(
308
+ self,
309
+ input_ids: torch.LongTensor,
310
+ attention_mask: Optional[torch.Tensor] = None,
311
+ **kwargs,
312
+ ) -> torch.Tensor:
313
+ """
314
+ Run the full decoder stack with causal attention.
315
+
316
+ Inputs:
317
+ input_ids [batch_size, seq_len]
318
+ attention_mask [batch_size, seq_len] - 1 for real tokens, 0 for padding
319
+
320
+ Returns:
321
+ Final decoder layer output [batch_size, seq_len, model_size]
322
+ """
323
+
324
+ # Retrieve the token embeddings for this sequence.
325
+ # These are model_size, regardless of whether the vocab is decompd.
326
+ hidden_states = self.embed(input_ids)
327
+
328
+ # Retrieve the rotary position embeddings for all of the positions in
329
+ # our current input sequence.
330
+
331
+ seq_len = hidden_states.size(1)
332
+
333
+ # Retrieves just the ones necessary for the sequence length of the
334
+ # input. These are vectors, two per token. Their length is the
335
+ # number of head dimensions we're applying RoPE to.
336
+ # Input
337
+ # cos: [max_seq_len, rope_dims]
338
+ # sin: [max_seq_len, rope_dims]
339
+ # Outputs:
340
+ # R_cos [seq_len, rope_dims]
341
+ # R_sin [seq_len, rope_dims]
342
+ R_cos = self.rope.cos[:seq_len]
343
+ R_sin = self.rope.sin[:seq_len]
344
+
345
+
346
+ # ===============================
347
+ # Attention Mask Conversion
348
+ # ===============================
349
+
350
+ """
351
+ use_sdpa_attention_masks = (
352
+ self.attn_implementation == "sdpa"
353
+ and self.position_embedding_type == "absolute"
354
+ and head_mask is None
355
+ and not output_attentions
356
+ )
357
+ """
358
+
359
+ # Expand the attention mask
360
+ #if use_sdpa_attention_masks and attention_mask.dim() == 2:
361
+ if True:
362
+ # Expand the attention mask for SDPA.
363
+ # [bsz, seq_len] -> [bsz, 1, seq_len, seq_len]
364
+ extended_attention_mask = _prepare_4d_attention_mask_for_sdpa(
365
+ attention_mask,
366
+ hidden_states.dtype,
367
+ tgt_len = seq_len
368
+ )
369
+ attention_mask = extended_attention_mask
370
+
371
+
372
+ # Run the model!
373
+
374
+ # For each decoder layer,
375
+ for layer_i, layer in enumerate(self.layers):
376
+
377
+ # Evaluate the layer
378
+ hidden_states = layer(
379
+ hidden_states, # Token embeddings
380
+ (R_cos, R_sin), # Rope embeddings, passed as a tuple.
381
+ attention_mask, # Attn mask
382
+ )
383
+
384
+ # Return the final output of the decoder stack.
385
+ return hidden_states
386
+
checkpoint-3000/special_tokens_map.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": "<|endoftext|>",
3
+ "eos_token": "<|endoftext|>",
4
+ "pad_token": "<|endoftext|>",
5
+ "unk_token": "<|endoftext|>"
6
+ }
checkpoint-3000/task_heads.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+ from typing import Optional, Union
6
+
7
+ from transformers.modeling_outputs import CausalLMOutputWithPast
8
+
9
+ from .shared_space_config import SharedSpaceDecoderConfig
10
+ from .shared_space_decoder import (
11
+ SharedSpaceDecoderPreTrainedModel,
12
+ SharedSpaceDecoderModel,
13
+ DeepseekV3RMSNorm
14
+ )
15
+
16
+ def create_norm_layer(hidden_size: int, config: SharedSpaceDecoderConfig) -> nn.Module:
17
+ """
18
+ Create a normalization layer based on the config norm_type.
19
+
20
+ Args:
21
+ hidden_size: The dimension to normalize over
22
+ config: Configuration containing norm_type and epsilon values
23
+
24
+ Returns:
25
+ Either a LayerNorm or RMSNorm layer
26
+ """
27
+ if config.norm_type == "layernorm":
28
+ return nn.LayerNorm(hidden_size, eps=config.layer_norm_eps)
29
+ elif config.norm_type == "rmsnorm":
30
+ from .shared_space_decoder import DeepseekV3RMSNorm
31
+ return DeepseekV3RMSNorm(hidden_size, eps=config.rms_norm_eps)
32
+ else:
33
+ # This should be caught by config validation, but being defensive
34
+ raise ValueError(f"Unknown norm_type: {config.norm_type}")
35
+
36
+
37
+ class SharedSpaceDecoderForCausalLM(SharedSpaceDecoderPreTrainedModel):
38
+ """
39
+ Subspace Decoder model with a causal language modeling head.
40
+
41
+ This model extends the SharedSpaceDecoderModel with:
42
+ - A language modeling head that projects hidden states to vocabulary logits
43
+ - Support for computing cross-entropy loss for language modeling
44
+ - Proper HuggingFace compatibility for causal language modeling tasks
45
+ - Decoder-specific initialization strategies
46
+
47
+ The model can be used for:
48
+ - Text generation
49
+ - Language modeling pretraining
50
+ - Fine-tuning on downstream tasks
51
+ """
52
+
53
+ def __init__(self, config: SharedSpaceDecoderConfig) -> None:
54
+ super().__init__(config)
55
+
56
+ # Initialize the base decoder model
57
+ self.model = SharedSpaceDecoderModel(config)
58
+
59
+ # Final layer norm before the language modeling head
60
+ self.norm = create_norm_layer(config.hidden_size, config)
61
+
62
+ # Language modeling head
63
+ # Projects from hidden_size to vocab_size to get logits for each token
64
+ self.lm_head = nn.Linear(
65
+ config.hidden_size,
66
+ config.vocab_size,
67
+ bias=False # Following common practice in modern LMs
68
+ )
69
+
70
+ # Initialize weights with decoder-specific strategy
71
+ # Note: tie_weights() will be called automatically by post_init() if config.tie_word_embeddings=True
72
+ self.post_init()
73
+
74
+ def _init_weights(self, module: nn.Module) -> None:
75
+ """
76
+ Decoder-specific weight initialization with special handling for language modeling head.
77
+
78
+ Key differences from encoder initialization:
79
+ - Language modeling head gets specialized initialization for stability
80
+ - Configurable normalization layers (LayerNorm or RMSNorm) are properly handled
81
+ - Weight tying considerations for embedding/lm_head relationship
82
+ """
83
+
84
+ # Use the base class initialization for most modules
85
+ super()._init_weights(module)
86
+
87
+ # Special handling for language modeling head
88
+ if module is self.lm_head:
89
+ # Use smaller initialization for the language modeling head
90
+ # This helps with training stability in autoregressive generation
91
+ # Common practice is to use std=initializer_range or smaller
92
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
93
+
94
+ # If weight tying is not used, we might want even smaller init
95
+ if self.model.vocab_proj is not None:
96
+ # For vocab subspace models where weights aren't tied,
97
+ # use a smaller scale to prevent initial logits from being too large
98
+ module.weight.data.normal_(mean=0.0, std=self.config.initializer_range * 0.5)
99
+
100
+ def get_input_embeddings(self):
101
+ """Return the input embedding layer for compatibility with HuggingFace."""
102
+ return self.model.vocab_embed
103
+
104
+ def set_input_embeddings(self, value):
105
+ """Set the input embedding layer for compatibility with HuggingFace."""
106
+ self.model.vocab_embed = value
107
+
108
+ def get_output_embeddings(self):
109
+ """Return the output embedding layer (lm_head) for compatibility."""
110
+ return self.lm_head
111
+
112
+ def set_output_embeddings(self, new_embeddings):
113
+ """Set the output embedding layer for compatibility."""
114
+ self.lm_head = new_embeddings
115
+
116
+ def tie_weights(self):
117
+ """
118
+ Tie the input and output embedding weights.
119
+
120
+ This method sets the language modeling head's weight to be the same as
121
+ the input embedding weight. This reduces the number of parameters and
122
+ is a common practice in modern language models.
123
+
124
+ Note: For vocab subspace models, we need to handle the case where
125
+ input embeddings go through a projection layer.
126
+ """
127
+ # Only tie when embeddings live in model space (no vocab_proj)
128
+ if getattr(self.model, "vocab_proj", None) is None:
129
+ # Use HF utility for correct tying/cloning semantics
130
+ self._tie_or_clone_weights(self.lm_head, self.model.vocab_embed)
131
+ # else: leave untied for subspace case
132
+
133
+
134
+ def forward(
135
+ self,
136
+ input_ids: torch.LongTensor,
137
+ attention_mask: Optional[torch.Tensor] = None,
138
+ labels: Optional[torch.LongTensor] = None,
139
+ **kwargs,
140
+ ) -> Union[CausalLMOutputWithPast, tuple]:
141
+ """
142
+ Forward pass for causal language modeling.
143
+
144
+ Args:
145
+ input_ids: Token ids of shape [batch_size, seq_len]
146
+ attention_mask: Attention mask of shape [batch_size, seq_len]
147
+ (1 for real tokens, 0 for padding)
148
+ labels: Ground truth token ids for computing loss. Same shape as input_ids.
149
+ If provided, loss will be computed. Typically input_ids shifted by 1.
150
+
151
+ Returns:
152
+ CausalLMOutputWithPast containing:
153
+ - logits: Prediction logits of shape [batch_size, seq_len, vocab_size]
154
+ - loss: Cross-entropy loss if labels provided, else None
155
+ - hidden_states: Final layer hidden states [batch_size, seq_len, hidden_size]
156
+ """
157
+
158
+ # Run the base decoder model
159
+ # This applies all the transformer layers with causal attention
160
+ hidden_states = self.model(
161
+ input_ids=input_ids,
162
+ attention_mask=attention_mask,
163
+ **kwargs
164
+ )
165
+
166
+ # Apply final layer normalization
167
+ # This normalizes the final hidden states before the language modeling head
168
+ hidden_states = self.norm(hidden_states)
169
+
170
+ # Project to vocabulary logits
171
+ # Shape: [batch_size, seq_len, vocab_size]
172
+ logits = self.lm_head(hidden_states)
173
+
174
+ # Compute loss if labels are provided
175
+ # Previously, we had custom loss computation here, but now we use the
176
+ # standard HuggingFace loss function.
177
+ loss = None
178
+ if labels is not None:
179
+ # Flatten the tokens
180
+ loss = self.loss_function(
181
+ logits,
182
+ labels,
183
+ vocab_size=self.config.vocab_size,
184
+ **kwargs,
185
+ )
186
+
187
+ # Return in HuggingFace format
188
+ return CausalLMOutputWithPast(
189
+ loss=loss,
190
+ logits=logits,
191
+ past_key_values=None, # Not implementing KV cache yet
192
+ #hidden_states=hidden_states,
193
+ hidden_states=hidden_states if kwargs.get("output_hidden_states", False) else None,
194
+ attentions=None,
195
+ )
196
+
checkpoint-3000/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
checkpoint-3000/tokenizer_config.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "50256": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": true,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ }
12
+ },
13
+ "bos_token": "<|endoftext|>",
14
+ "clean_up_tokenization_spaces": false,
15
+ "eos_token": "<|endoftext|>",
16
+ "extra_special_tokens": {},
17
+ "model_max_length": 1024,
18
+ "pad_token": "<|endoftext|>",
19
+ "tokenizer_class": "GPT2Tokenizer",
20
+ "unk_token": "<|endoftext|>"
21
+ }
checkpoint-3000/trainer_state.json ADDED
@@ -0,0 +1,1174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "best_global_step": 3000,
3
+ "best_metric": 3.587533058962724,
4
+ "best_model_checkpoint": "checkpoints/gpt-2_seq1024_mla0-0-0/checkpoint-3000",
5
+ "epoch": 0.9042272624519629,
6
+ "eval_steps": 300,
7
+ "global_step": 3000,
8
+ "is_hyper_param_search": false,
9
+ "is_local_process_zero": true,
10
+ "is_world_process_zero": true,
11
+ "log_history": [
12
+ {
13
+ "epoch": 0.006028181749679753,
14
+ "grad_norm": 2.0441031455993652,
15
+ "learning_rate": 3.166666666666667e-05,
16
+ "loss": 10.3921,
17
+ "step": 20
18
+ },
19
+ {
20
+ "epoch": 0.012056363499359506,
21
+ "grad_norm": 1.7166392803192139,
22
+ "learning_rate": 6.500000000000001e-05,
23
+ "loss": 9.241,
24
+ "step": 40
25
+ },
26
+ {
27
+ "epoch": 0.01808454524903926,
28
+ "grad_norm": 0.7614754438400269,
29
+ "learning_rate": 9.833333333333333e-05,
30
+ "loss": 8.2219,
31
+ "step": 60
32
+ },
33
+ {
34
+ "epoch": 0.02411272699871901,
35
+ "grad_norm": 0.46116286516189575,
36
+ "learning_rate": 0.00013166666666666665,
37
+ "loss": 7.5368,
38
+ "step": 80
39
+ },
40
+ {
41
+ "epoch": 0.030140908748398764,
42
+ "grad_norm": 1.6069883108139038,
43
+ "learning_rate": 0.000165,
44
+ "loss": 7.21,
45
+ "step": 100
46
+ },
47
+ {
48
+ "epoch": 0.03616909049807852,
49
+ "grad_norm": 1.2077178955078125,
50
+ "learning_rate": 0.00019833333333333335,
51
+ "loss": 6.8976,
52
+ "step": 120
53
+ },
54
+ {
55
+ "epoch": 0.04219727224775827,
56
+ "grad_norm": 0.642643928527832,
57
+ "learning_rate": 0.00023166666666666667,
58
+ "loss": 6.641,
59
+ "step": 140
60
+ },
61
+ {
62
+ "epoch": 0.04822545399743802,
63
+ "grad_norm": 0.7632517218589783,
64
+ "learning_rate": 0.00026500000000000004,
65
+ "loss": 6.4194,
66
+ "step": 160
67
+ },
68
+ {
69
+ "epoch": 0.05425363574711778,
70
+ "grad_norm": 1.2542935609817505,
71
+ "learning_rate": 0.00029833333333333334,
72
+ "loss": 6.2428,
73
+ "step": 180
74
+ },
75
+ {
76
+ "epoch": 0.06028181749679753,
77
+ "grad_norm": 1.1738799810409546,
78
+ "learning_rate": 0.0003316666666666667,
79
+ "loss": 6.1026,
80
+ "step": 200
81
+ },
82
+ {
83
+ "epoch": 0.06630999924647728,
84
+ "grad_norm": 0.46843603253364563,
85
+ "learning_rate": 0.000365,
86
+ "loss": 5.9586,
87
+ "step": 220
88
+ },
89
+ {
90
+ "epoch": 0.07233818099615703,
91
+ "grad_norm": 0.3949953019618988,
92
+ "learning_rate": 0.00039833333333333333,
93
+ "loss": 5.8304,
94
+ "step": 240
95
+ },
96
+ {
97
+ "epoch": 0.07836636274583679,
98
+ "grad_norm": 1.0866719484329224,
99
+ "learning_rate": 0.0004316666666666667,
100
+ "loss": 5.7185,
101
+ "step": 260
102
+ },
103
+ {
104
+ "epoch": 0.08439454449551655,
105
+ "grad_norm": 0.34839189052581787,
106
+ "learning_rate": 0.000465,
107
+ "loss": 5.6037,
108
+ "step": 280
109
+ },
110
+ {
111
+ "epoch": 0.09042272624519629,
112
+ "grad_norm": 0.5791395902633667,
113
+ "learning_rate": 0.0004983333333333334,
114
+ "loss": 5.5003,
115
+ "step": 300
116
+ },
117
+ {
118
+ "epoch": 0.09042272624519629,
119
+ "eval_loss": 5.428642945231348,
120
+ "eval_perplexity": 227.839844387096,
121
+ "eval_runtime": 113.1707,
122
+ "eval_samples_per_second": 14.659,
123
+ "eval_steps_per_second": 0.23,
124
+ "step": 300
125
+ },
126
+ {
127
+ "epoch": 0.09645090799487605,
128
+ "grad_norm": 0.532134473323822,
129
+ "learning_rate": 0.0004964814814814814,
130
+ "loss": 5.3805,
131
+ "step": 320
132
+ },
133
+ {
134
+ "epoch": 0.1024790897445558,
135
+ "grad_norm": 0.5876124501228333,
136
+ "learning_rate": 0.0004927777777777777,
137
+ "loss": 5.2775,
138
+ "step": 340
139
+ },
140
+ {
141
+ "epoch": 0.10850727149423556,
142
+ "grad_norm": 0.4140375256538391,
143
+ "learning_rate": 0.0004890740740740741,
144
+ "loss": 5.193,
145
+ "step": 360
146
+ },
147
+ {
148
+ "epoch": 0.1145354532439153,
149
+ "grad_norm": 0.5529780387878418,
150
+ "learning_rate": 0.0004853703703703704,
151
+ "loss": 5.0912,
152
+ "step": 380
153
+ },
154
+ {
155
+ "epoch": 0.12056363499359506,
156
+ "grad_norm": 0.3331276774406433,
157
+ "learning_rate": 0.0004816666666666667,
158
+ "loss": 5.0266,
159
+ "step": 400
160
+ },
161
+ {
162
+ "epoch": 0.1265918167432748,
163
+ "grad_norm": 0.6916081309318542,
164
+ "learning_rate": 0.00047796296296296297,
165
+ "loss": 4.9375,
166
+ "step": 420
167
+ },
168
+ {
169
+ "epoch": 0.13261999849295456,
170
+ "grad_norm": 0.31799590587615967,
171
+ "learning_rate": 0.0004742592592592593,
172
+ "loss": 4.9026,
173
+ "step": 440
174
+ },
175
+ {
176
+ "epoch": 0.1386481802426343,
177
+ "grad_norm": 0.5735257267951965,
178
+ "learning_rate": 0.00047055555555555555,
179
+ "loss": 4.8075,
180
+ "step": 460
181
+ },
182
+ {
183
+ "epoch": 0.14467636199231407,
184
+ "grad_norm": 0.5078163146972656,
185
+ "learning_rate": 0.00046685185185185187,
186
+ "loss": 4.759,
187
+ "step": 480
188
+ },
189
+ {
190
+ "epoch": 0.15070454374199382,
191
+ "grad_norm": 0.3884360194206238,
192
+ "learning_rate": 0.00046314814814814813,
193
+ "loss": 4.6706,
194
+ "step": 500
195
+ },
196
+ {
197
+ "epoch": 0.15673272549167358,
198
+ "grad_norm": 0.5591968297958374,
199
+ "learning_rate": 0.00045944444444444445,
200
+ "loss": 4.627,
201
+ "step": 520
202
+ },
203
+ {
204
+ "epoch": 0.16276090724135334,
205
+ "grad_norm": 0.29390859603881836,
206
+ "learning_rate": 0.0004557407407407407,
207
+ "loss": 4.5691,
208
+ "step": 540
209
+ },
210
+ {
211
+ "epoch": 0.1687890889910331,
212
+ "grad_norm": 0.3524036407470703,
213
+ "learning_rate": 0.00045203703703703703,
214
+ "loss": 4.5066,
215
+ "step": 560
216
+ },
217
+ {
218
+ "epoch": 0.17481727074071282,
219
+ "grad_norm": 0.4607946574687958,
220
+ "learning_rate": 0.0004483333333333333,
221
+ "loss": 4.4661,
222
+ "step": 580
223
+ },
224
+ {
225
+ "epoch": 0.18084545249039258,
226
+ "grad_norm": 0.2523379623889923,
227
+ "learning_rate": 0.00044462962962962967,
228
+ "loss": 4.4331,
229
+ "step": 600
230
+ },
231
+ {
232
+ "epoch": 0.18084545249039258,
233
+ "eval_loss": 4.357323692651888,
234
+ "eval_perplexity": 78.04797429242741,
235
+ "eval_runtime": 112.5783,
236
+ "eval_samples_per_second": 14.736,
237
+ "eval_steps_per_second": 0.231,
238
+ "step": 600
239
+ },
240
+ {
241
+ "epoch": 0.18687363424007233,
242
+ "grad_norm": 0.3953287601470947,
243
+ "learning_rate": 0.00044092592592592594,
244
+ "loss": 4.3877,
245
+ "step": 620
246
+ },
247
+ {
248
+ "epoch": 0.1929018159897521,
249
+ "grad_norm": 0.38012024760246277,
250
+ "learning_rate": 0.00043722222222222225,
251
+ "loss": 4.3619,
252
+ "step": 640
253
+ },
254
+ {
255
+ "epoch": 0.19892999773943185,
256
+ "grad_norm": 0.3135126233100891,
257
+ "learning_rate": 0.0004335185185185185,
258
+ "loss": 4.3442,
259
+ "step": 660
260
+ },
261
+ {
262
+ "epoch": 0.2049581794891116,
263
+ "grad_norm": 0.49422895908355713,
264
+ "learning_rate": 0.00042981481481481484,
265
+ "loss": 4.3045,
266
+ "step": 680
267
+ },
268
+ {
269
+ "epoch": 0.21098636123879136,
270
+ "grad_norm": 0.27019643783569336,
271
+ "learning_rate": 0.0004261111111111111,
272
+ "loss": 4.2808,
273
+ "step": 700
274
+ },
275
+ {
276
+ "epoch": 0.21701454298847112,
277
+ "grad_norm": 0.3935423791408539,
278
+ "learning_rate": 0.0004224074074074074,
279
+ "loss": 4.2467,
280
+ "step": 720
281
+ },
282
+ {
283
+ "epoch": 0.22304272473815084,
284
+ "grad_norm": 0.28830042481422424,
285
+ "learning_rate": 0.0004187037037037037,
286
+ "loss": 4.2274,
287
+ "step": 740
288
+ },
289
+ {
290
+ "epoch": 0.2290709064878306,
291
+ "grad_norm": 0.2877708673477173,
292
+ "learning_rate": 0.000415,
293
+ "loss": 4.2075,
294
+ "step": 760
295
+ },
296
+ {
297
+ "epoch": 0.23509908823751036,
298
+ "grad_norm": 0.3449930250644684,
299
+ "learning_rate": 0.00041129629629629627,
300
+ "loss": 4.1909,
301
+ "step": 780
302
+ },
303
+ {
304
+ "epoch": 0.2411272699871901,
305
+ "grad_norm": 0.326265424489975,
306
+ "learning_rate": 0.00040759259259259264,
307
+ "loss": 4.1684,
308
+ "step": 800
309
+ },
310
+ {
311
+ "epoch": 0.24715545173686987,
312
+ "grad_norm": 0.3821180760860443,
313
+ "learning_rate": 0.0004038888888888889,
314
+ "loss": 4.1513,
315
+ "step": 820
316
+ },
317
+ {
318
+ "epoch": 0.2531836334865496,
319
+ "grad_norm": 0.2768200635910034,
320
+ "learning_rate": 0.0004001851851851852,
321
+ "loss": 4.1317,
322
+ "step": 840
323
+ },
324
+ {
325
+ "epoch": 0.2592118152362294,
326
+ "grad_norm": 0.29724735021591187,
327
+ "learning_rate": 0.0003964814814814815,
328
+ "loss": 4.1171,
329
+ "step": 860
330
+ },
331
+ {
332
+ "epoch": 0.2652399969859091,
333
+ "grad_norm": 0.2814749479293823,
334
+ "learning_rate": 0.0003927777777777778,
335
+ "loss": 4.1049,
336
+ "step": 880
337
+ },
338
+ {
339
+ "epoch": 0.2712681787355889,
340
+ "grad_norm": 0.26310989260673523,
341
+ "learning_rate": 0.00038907407407407407,
342
+ "loss": 4.0858,
343
+ "step": 900
344
+ },
345
+ {
346
+ "epoch": 0.2712681787355889,
347
+ "eval_loss": 4.030442206068737,
348
+ "eval_perplexity": 56.285795665128816,
349
+ "eval_runtime": 112.6912,
350
+ "eval_samples_per_second": 14.722,
351
+ "eval_steps_per_second": 0.231,
352
+ "step": 900
353
+ },
354
+ {
355
+ "epoch": 0.2772963604852686,
356
+ "grad_norm": 0.3063352108001709,
357
+ "learning_rate": 0.0003853703703703704,
358
+ "loss": 4.0813,
359
+ "step": 920
360
+ },
361
+ {
362
+ "epoch": 0.2833245422349484,
363
+ "grad_norm": 0.4063352346420288,
364
+ "learning_rate": 0.00038166666666666666,
365
+ "loss": 4.0647,
366
+ "step": 940
367
+ },
368
+ {
369
+ "epoch": 0.28935272398462814,
370
+ "grad_norm": 0.2601182758808136,
371
+ "learning_rate": 0.000377962962962963,
372
+ "loss": 4.0447,
373
+ "step": 960
374
+ },
375
+ {
376
+ "epoch": 0.29538090573430786,
377
+ "grad_norm": 0.3153649568557739,
378
+ "learning_rate": 0.00037425925925925924,
379
+ "loss": 4.0417,
380
+ "step": 980
381
+ },
382
+ {
383
+ "epoch": 0.30140908748398765,
384
+ "grad_norm": 0.26004716753959656,
385
+ "learning_rate": 0.0003705555555555556,
386
+ "loss": 4.0279,
387
+ "step": 1000
388
+ },
389
+ {
390
+ "epoch": 0.3074372692336674,
391
+ "grad_norm": 0.43524181842803955,
392
+ "learning_rate": 0.0003668518518518519,
393
+ "loss": 4.0152,
394
+ "step": 1020
395
+ },
396
+ {
397
+ "epoch": 0.31346545098334716,
398
+ "grad_norm": 0.2601913511753082,
399
+ "learning_rate": 0.0003631481481481482,
400
+ "loss": 4.0026,
401
+ "step": 1040
402
+ },
403
+ {
404
+ "epoch": 0.3194936327330269,
405
+ "grad_norm": 0.25712424516677856,
406
+ "learning_rate": 0.00035944444444444446,
407
+ "loss": 3.9933,
408
+ "step": 1060
409
+ },
410
+ {
411
+ "epoch": 0.3255218144827067,
412
+ "grad_norm": 0.3313097357749939,
413
+ "learning_rate": 0.0003557407407407408,
414
+ "loss": 3.9842,
415
+ "step": 1080
416
+ },
417
+ {
418
+ "epoch": 0.3315499962323864,
419
+ "grad_norm": 0.238124281167984,
420
+ "learning_rate": 0.00035203703703703704,
421
+ "loss": 3.9745,
422
+ "step": 1100
423
+ },
424
+ {
425
+ "epoch": 0.3375781779820662,
426
+ "grad_norm": 0.28039032220840454,
427
+ "learning_rate": 0.00034833333333333336,
428
+ "loss": 3.9588,
429
+ "step": 1120
430
+ },
431
+ {
432
+ "epoch": 0.3436063597317459,
433
+ "grad_norm": 0.3661600649356842,
434
+ "learning_rate": 0.0003446296296296296,
435
+ "loss": 3.9532,
436
+ "step": 1140
437
+ },
438
+ {
439
+ "epoch": 0.34963454148142564,
440
+ "grad_norm": 0.22854666411876678,
441
+ "learning_rate": 0.0003409259259259259,
442
+ "loss": 3.9392,
443
+ "step": 1160
444
+ },
445
+ {
446
+ "epoch": 0.3556627232311054,
447
+ "grad_norm": 0.2930833697319031,
448
+ "learning_rate": 0.0003372222222222222,
449
+ "loss": 3.9312,
450
+ "step": 1180
451
+ },
452
+ {
453
+ "epoch": 0.36169090498078516,
454
+ "grad_norm": 0.25500425696372986,
455
+ "learning_rate": 0.0003335185185185185,
456
+ "loss": 3.9295,
457
+ "step": 1200
458
+ },
459
+ {
460
+ "epoch": 0.36169090498078516,
461
+ "eval_loss": 3.874079793811062,
462
+ "eval_perplexity": 48.13838066773452,
463
+ "eval_runtime": 112.5895,
464
+ "eval_samples_per_second": 14.735,
465
+ "eval_steps_per_second": 0.231,
466
+ "step": 1200
467
+ },
468
+ {
469
+ "epoch": 0.36771908673046494,
470
+ "grad_norm": 0.27924397587776184,
471
+ "learning_rate": 0.00032981481481481485,
472
+ "loss": 3.9157,
473
+ "step": 1220
474
+ },
475
+ {
476
+ "epoch": 0.37374726848014467,
477
+ "grad_norm": 0.2649654448032379,
478
+ "learning_rate": 0.0003261111111111111,
479
+ "loss": 3.9136,
480
+ "step": 1240
481
+ },
482
+ {
483
+ "epoch": 0.37977545022982445,
484
+ "grad_norm": 0.27920904755592346,
485
+ "learning_rate": 0.00032240740740740743,
486
+ "loss": 3.899,
487
+ "step": 1260
488
+ },
489
+ {
490
+ "epoch": 0.3858036319795042,
491
+ "grad_norm": 0.238219752907753,
492
+ "learning_rate": 0.0003187037037037037,
493
+ "loss": 3.8965,
494
+ "step": 1280
495
+ },
496
+ {
497
+ "epoch": 0.3918318137291839,
498
+ "grad_norm": 0.2615567743778229,
499
+ "learning_rate": 0.000315,
500
+ "loss": 3.8877,
501
+ "step": 1300
502
+ },
503
+ {
504
+ "epoch": 0.3978599954788637,
505
+ "grad_norm": 0.266513466835022,
506
+ "learning_rate": 0.0003112962962962963,
507
+ "loss": 3.8806,
508
+ "step": 1320
509
+ },
510
+ {
511
+ "epoch": 0.4038881772285434,
512
+ "grad_norm": 0.3212108314037323,
513
+ "learning_rate": 0.0003075925925925926,
514
+ "loss": 3.8774,
515
+ "step": 1340
516
+ },
517
+ {
518
+ "epoch": 0.4099163589782232,
519
+ "grad_norm": 0.231920063495636,
520
+ "learning_rate": 0.00030388888888888886,
521
+ "loss": 3.8707,
522
+ "step": 1360
523
+ },
524
+ {
525
+ "epoch": 0.41594454072790293,
526
+ "grad_norm": 0.27022039890289307,
527
+ "learning_rate": 0.0003001851851851852,
528
+ "loss": 3.863,
529
+ "step": 1380
530
+ },
531
+ {
532
+ "epoch": 0.4219727224775827,
533
+ "grad_norm": 0.243785560131073,
534
+ "learning_rate": 0.00029648148148148144,
535
+ "loss": 3.8562,
536
+ "step": 1400
537
+ },
538
+ {
539
+ "epoch": 0.42800090422726245,
540
+ "grad_norm": 0.2512820065021515,
541
+ "learning_rate": 0.0002927777777777778,
542
+ "loss": 3.8541,
543
+ "step": 1420
544
+ },
545
+ {
546
+ "epoch": 0.43402908597694223,
547
+ "grad_norm": 0.25888124108314514,
548
+ "learning_rate": 0.0002890740740740741,
549
+ "loss": 3.8421,
550
+ "step": 1440
551
+ },
552
+ {
553
+ "epoch": 0.44005726772662196,
554
+ "grad_norm": 0.29554685950279236,
555
+ "learning_rate": 0.0002853703703703704,
556
+ "loss": 3.8468,
557
+ "step": 1460
558
+ },
559
+ {
560
+ "epoch": 0.4460854494763017,
561
+ "grad_norm": 0.2608514130115509,
562
+ "learning_rate": 0.00028166666666666666,
563
+ "loss": 3.837,
564
+ "step": 1480
565
+ },
566
+ {
567
+ "epoch": 0.45211363122598147,
568
+ "grad_norm": 0.2781771123409271,
569
+ "learning_rate": 0.000277962962962963,
570
+ "loss": 3.8327,
571
+ "step": 1500
572
+ },
573
+ {
574
+ "epoch": 0.45211363122598147,
575
+ "eval_loss": 3.776173532413324,
576
+ "eval_perplexity": 43.6487014373908,
577
+ "eval_runtime": 112.7037,
578
+ "eval_samples_per_second": 14.72,
579
+ "eval_steps_per_second": 0.231,
580
+ "step": 1500
581
+ },
582
+ {
583
+ "epoch": 0.4581418129756612,
584
+ "grad_norm": 0.27767959237098694,
585
+ "learning_rate": 0.00027425925925925925,
586
+ "loss": 3.8264,
587
+ "step": 1520
588
+ },
589
+ {
590
+ "epoch": 0.464169994725341,
591
+ "grad_norm": 0.24143943190574646,
592
+ "learning_rate": 0.00027055555555555557,
593
+ "loss": 3.8224,
594
+ "step": 1540
595
+ },
596
+ {
597
+ "epoch": 0.4701981764750207,
598
+ "grad_norm": 0.23281621932983398,
599
+ "learning_rate": 0.00026685185185185183,
600
+ "loss": 3.8114,
601
+ "step": 1560
602
+ },
603
+ {
604
+ "epoch": 0.4762263582247005,
605
+ "grad_norm": 0.23552870750427246,
606
+ "learning_rate": 0.00026314814814814815,
607
+ "loss": 3.8086,
608
+ "step": 1580
609
+ },
610
+ {
611
+ "epoch": 0.4822545399743802,
612
+ "grad_norm": 0.25271207094192505,
613
+ "learning_rate": 0.0002594444444444444,
614
+ "loss": 3.7954,
615
+ "step": 1600
616
+ },
617
+ {
618
+ "epoch": 0.48828272172405995,
619
+ "grad_norm": 0.2609969675540924,
620
+ "learning_rate": 0.0002557407407407408,
621
+ "loss": 3.8052,
622
+ "step": 1620
623
+ },
624
+ {
625
+ "epoch": 0.49431090347373974,
626
+ "grad_norm": 0.290229469537735,
627
+ "learning_rate": 0.00025203703703703705,
628
+ "loss": 3.7946,
629
+ "step": 1640
630
+ },
631
+ {
632
+ "epoch": 0.5003390852234195,
633
+ "grad_norm": 0.2184811681509018,
634
+ "learning_rate": 0.0002483333333333333,
635
+ "loss": 3.7913,
636
+ "step": 1660
637
+ },
638
+ {
639
+ "epoch": 0.5063672669730992,
640
+ "grad_norm": 0.24770255386829376,
641
+ "learning_rate": 0.00024462962962962963,
642
+ "loss": 3.7902,
643
+ "step": 1680
644
+ },
645
+ {
646
+ "epoch": 0.512395448722779,
647
+ "grad_norm": 0.2306816428899765,
648
+ "learning_rate": 0.00024092592592592593,
649
+ "loss": 3.7775,
650
+ "step": 1700
651
+ },
652
+ {
653
+ "epoch": 0.5184236304724588,
654
+ "grad_norm": 0.2789316475391388,
655
+ "learning_rate": 0.00023722222222222222,
656
+ "loss": 3.7774,
657
+ "step": 1720
658
+ },
659
+ {
660
+ "epoch": 0.5244518122221385,
661
+ "grad_norm": 0.2576800286769867,
662
+ "learning_rate": 0.0002335185185185185,
663
+ "loss": 3.7773,
664
+ "step": 1740
665
+ },
666
+ {
667
+ "epoch": 0.5304799939718182,
668
+ "grad_norm": 0.2184872031211853,
669
+ "learning_rate": 0.0002298148148148148,
670
+ "loss": 3.7739,
671
+ "step": 1760
672
+ },
673
+ {
674
+ "epoch": 0.536508175721498,
675
+ "grad_norm": 0.27034640312194824,
676
+ "learning_rate": 0.00022611111111111112,
677
+ "loss": 3.7632,
678
+ "step": 1780
679
+ },
680
+ {
681
+ "epoch": 0.5425363574711778,
682
+ "grad_norm": 0.2661360800266266,
683
+ "learning_rate": 0.0002224074074074074,
684
+ "loss": 3.7668,
685
+ "step": 1800
686
+ },
687
+ {
688
+ "epoch": 0.5425363574711778,
689
+ "eval_loss": 3.7104278931619175,
690
+ "eval_perplexity": 40.871291331988935,
691
+ "eval_runtime": 112.585,
692
+ "eval_samples_per_second": 14.736,
693
+ "eval_steps_per_second": 0.231,
694
+ "step": 1800
695
+ },
696
+ {
697
+ "epoch": 0.5485645392208575,
698
+ "grad_norm": 0.2934229373931885,
699
+ "learning_rate": 0.0002187037037037037,
700
+ "loss": 3.7645,
701
+ "step": 1820
702
+ },
703
+ {
704
+ "epoch": 0.5545927209705372,
705
+ "grad_norm": 0.24501343071460724,
706
+ "learning_rate": 0.000215,
707
+ "loss": 3.7559,
708
+ "step": 1840
709
+ },
710
+ {
711
+ "epoch": 0.560620902720217,
712
+ "grad_norm": 0.21381346881389618,
713
+ "learning_rate": 0.00021129629629629629,
714
+ "loss": 3.7482,
715
+ "step": 1860
716
+ },
717
+ {
718
+ "epoch": 0.5666490844698968,
719
+ "grad_norm": 0.2350403219461441,
720
+ "learning_rate": 0.0002075925925925926,
721
+ "loss": 3.7488,
722
+ "step": 1880
723
+ },
724
+ {
725
+ "epoch": 0.5726772662195765,
726
+ "grad_norm": 0.23535749316215515,
727
+ "learning_rate": 0.0002038888888888889,
728
+ "loss": 3.7409,
729
+ "step": 1900
730
+ },
731
+ {
732
+ "epoch": 0.5787054479692563,
733
+ "grad_norm": 0.22763009369373322,
734
+ "learning_rate": 0.0002001851851851852,
735
+ "loss": 3.7431,
736
+ "step": 1920
737
+ },
738
+ {
739
+ "epoch": 0.584733629718936,
740
+ "grad_norm": 0.22279077768325806,
741
+ "learning_rate": 0.00019648148148148148,
742
+ "loss": 3.7373,
743
+ "step": 1940
744
+ },
745
+ {
746
+ "epoch": 0.5907618114686157,
747
+ "grad_norm": 0.19868987798690796,
748
+ "learning_rate": 0.00019277777777777777,
749
+ "loss": 3.7385,
750
+ "step": 1960
751
+ },
752
+ {
753
+ "epoch": 0.5967899932182955,
754
+ "grad_norm": 0.22577470541000366,
755
+ "learning_rate": 0.00018907407407407406,
756
+ "loss": 3.7266,
757
+ "step": 1980
758
+ },
759
+ {
760
+ "epoch": 0.6028181749679753,
761
+ "grad_norm": 0.23861481249332428,
762
+ "learning_rate": 0.00018537037037037038,
763
+ "loss": 3.7288,
764
+ "step": 2000
765
+ },
766
+ {
767
+ "epoch": 0.6088463567176551,
768
+ "grad_norm": 0.2368811070919037,
769
+ "learning_rate": 0.00018166666666666667,
770
+ "loss": 3.7251,
771
+ "step": 2020
772
+ },
773
+ {
774
+ "epoch": 0.6148745384673348,
775
+ "grad_norm": 0.23746469616889954,
776
+ "learning_rate": 0.00017796296296296296,
777
+ "loss": 3.7194,
778
+ "step": 2040
779
+ },
780
+ {
781
+ "epoch": 0.6209027202170145,
782
+ "grad_norm": 0.19934986531734467,
783
+ "learning_rate": 0.00017425925925925926,
784
+ "loss": 3.7203,
785
+ "step": 2060
786
+ },
787
+ {
788
+ "epoch": 0.6269309019666943,
789
+ "grad_norm": 0.22287386655807495,
790
+ "learning_rate": 0.00017055555555555555,
791
+ "loss": 3.7182,
792
+ "step": 2080
793
+ },
794
+ {
795
+ "epoch": 0.632959083716374,
796
+ "grad_norm": 0.21625646948814392,
797
+ "learning_rate": 0.00016685185185185187,
798
+ "loss": 3.7133,
799
+ "step": 2100
800
+ },
801
+ {
802
+ "epoch": 0.632959083716374,
803
+ "eval_loss": 3.661569493497066,
804
+ "eval_perplexity": 38.922383385070816,
805
+ "eval_runtime": 112.8832,
806
+ "eval_samples_per_second": 14.697,
807
+ "eval_steps_per_second": 0.23,
808
+ "step": 2100
809
+ },
810
+ {
811
+ "epoch": 0.6389872654660538,
812
+ "grad_norm": 0.2128862887620926,
813
+ "learning_rate": 0.00016314814814814816,
814
+ "loss": 3.7123,
815
+ "step": 2120
816
+ },
817
+ {
818
+ "epoch": 0.6450154472157336,
819
+ "grad_norm": 0.22579094767570496,
820
+ "learning_rate": 0.00015944444444444445,
821
+ "loss": 3.7103,
822
+ "step": 2140
823
+ },
824
+ {
825
+ "epoch": 0.6510436289654133,
826
+ "grad_norm": 0.19634632766246796,
827
+ "learning_rate": 0.00015574074074074074,
828
+ "loss": 3.7077,
829
+ "step": 2160
830
+ },
831
+ {
832
+ "epoch": 0.657071810715093,
833
+ "grad_norm": 0.21508827805519104,
834
+ "learning_rate": 0.00015203703703703703,
835
+ "loss": 3.7071,
836
+ "step": 2180
837
+ },
838
+ {
839
+ "epoch": 0.6630999924647728,
840
+ "grad_norm": 0.23243261873722076,
841
+ "learning_rate": 0.00014833333333333335,
842
+ "loss": 3.7035,
843
+ "step": 2200
844
+ },
845
+ {
846
+ "epoch": 0.6691281742144526,
847
+ "grad_norm": 0.22189666330814362,
848
+ "learning_rate": 0.00014462962962962964,
849
+ "loss": 3.7011,
850
+ "step": 2220
851
+ },
852
+ {
853
+ "epoch": 0.6751563559641324,
854
+ "grad_norm": 0.19845160841941833,
855
+ "learning_rate": 0.00014092592592592594,
856
+ "loss": 3.6996,
857
+ "step": 2240
858
+ },
859
+ {
860
+ "epoch": 0.681184537713812,
861
+ "grad_norm": 0.1785988211631775,
862
+ "learning_rate": 0.00013722222222222223,
863
+ "loss": 3.6866,
864
+ "step": 2260
865
+ },
866
+ {
867
+ "epoch": 0.6872127194634918,
868
+ "grad_norm": 0.2001648247241974,
869
+ "learning_rate": 0.00013351851851851852,
870
+ "loss": 3.6939,
871
+ "step": 2280
872
+ },
873
+ {
874
+ "epoch": 0.6932409012131716,
875
+ "grad_norm": 0.21330291032791138,
876
+ "learning_rate": 0.00012981481481481484,
877
+ "loss": 3.6868,
878
+ "step": 2300
879
+ },
880
+ {
881
+ "epoch": 0.6992690829628513,
882
+ "grad_norm": 0.23209834098815918,
883
+ "learning_rate": 0.00012611111111111113,
884
+ "loss": 3.6803,
885
+ "step": 2320
886
+ },
887
+ {
888
+ "epoch": 0.7052972647125311,
889
+ "grad_norm": 0.18792849779129028,
890
+ "learning_rate": 0.00012240740740740742,
891
+ "loss": 3.6824,
892
+ "step": 2340
893
+ },
894
+ {
895
+ "epoch": 0.7113254464622109,
896
+ "grad_norm": 0.19127227365970612,
897
+ "learning_rate": 0.0001187037037037037,
898
+ "loss": 3.6821,
899
+ "step": 2360
900
+ },
901
+ {
902
+ "epoch": 0.7173536282118906,
903
+ "grad_norm": 0.21657773852348328,
904
+ "learning_rate": 0.000115,
905
+ "loss": 3.6727,
906
+ "step": 2380
907
+ },
908
+ {
909
+ "epoch": 0.7233818099615703,
910
+ "grad_norm": 0.1759604662656784,
911
+ "learning_rate": 0.0001112962962962963,
912
+ "loss": 3.6809,
913
+ "step": 2400
914
+ },
915
+ {
916
+ "epoch": 0.7233818099615703,
917
+ "eval_loss": 3.62554258938625,
918
+ "eval_perplexity": 37.54508920080861,
919
+ "eval_runtime": 112.4817,
920
+ "eval_samples_per_second": 14.749,
921
+ "eval_steps_per_second": 0.231,
922
+ "step": 2400
923
+ },
924
+ {
925
+ "epoch": 0.7294099917112501,
926
+ "grad_norm": 0.20114636421203613,
927
+ "learning_rate": 0.00010759259259259259,
928
+ "loss": 3.6772,
929
+ "step": 2420
930
+ },
931
+ {
932
+ "epoch": 0.7354381734609299,
933
+ "grad_norm": 0.20904237031936646,
934
+ "learning_rate": 0.00010388888888888889,
935
+ "loss": 3.6754,
936
+ "step": 2440
937
+ },
938
+ {
939
+ "epoch": 0.7414663552106096,
940
+ "grad_norm": 0.18807630240917206,
941
+ "learning_rate": 0.00010018518518518518,
942
+ "loss": 3.6756,
943
+ "step": 2460
944
+ },
945
+ {
946
+ "epoch": 0.7474945369602893,
947
+ "grad_norm": 0.17234675586223602,
948
+ "learning_rate": 9.648148148148149e-05,
949
+ "loss": 3.6686,
950
+ "step": 2480
951
+ },
952
+ {
953
+ "epoch": 0.7535227187099691,
954
+ "grad_norm": 0.18095088005065918,
955
+ "learning_rate": 9.277777777777778e-05,
956
+ "loss": 3.6691,
957
+ "step": 2500
958
+ },
959
+ {
960
+ "epoch": 0.7595509004596489,
961
+ "grad_norm": 0.19775047898292542,
962
+ "learning_rate": 8.907407407407407e-05,
963
+ "loss": 3.6679,
964
+ "step": 2520
965
+ },
966
+ {
967
+ "epoch": 0.7655790822093286,
968
+ "grad_norm": 0.1963493674993515,
969
+ "learning_rate": 8.537037037037038e-05,
970
+ "loss": 3.668,
971
+ "step": 2540
972
+ },
973
+ {
974
+ "epoch": 0.7716072639590084,
975
+ "grad_norm": 0.16776752471923828,
976
+ "learning_rate": 8.166666666666667e-05,
977
+ "loss": 3.663,
978
+ "step": 2560
979
+ },
980
+ {
981
+ "epoch": 0.7776354457086881,
982
+ "grad_norm": 0.18634021282196045,
983
+ "learning_rate": 7.796296296296296e-05,
984
+ "loss": 3.6616,
985
+ "step": 2580
986
+ },
987
+ {
988
+ "epoch": 0.7836636274583678,
989
+ "grad_norm": 0.1853896975517273,
990
+ "learning_rate": 7.425925925925927e-05,
991
+ "loss": 3.6554,
992
+ "step": 2600
993
+ },
994
+ {
995
+ "epoch": 0.7896918092080476,
996
+ "grad_norm": 0.19131463766098022,
997
+ "learning_rate": 7.055555555555556e-05,
998
+ "loss": 3.6617,
999
+ "step": 2620
1000
+ },
1001
+ {
1002
+ "epoch": 0.7957199909577274,
1003
+ "grad_norm": 0.1861460953950882,
1004
+ "learning_rate": 6.685185185185186e-05,
1005
+ "loss": 3.6589,
1006
+ "step": 2640
1007
+ },
1008
+ {
1009
+ "epoch": 0.8017481727074072,
1010
+ "grad_norm": 0.18328429758548737,
1011
+ "learning_rate": 6.314814814814815e-05,
1012
+ "loss": 3.6581,
1013
+ "step": 2660
1014
+ },
1015
+ {
1016
+ "epoch": 0.8077763544570868,
1017
+ "grad_norm": 0.1829613447189331,
1018
+ "learning_rate": 5.9444444444444445e-05,
1019
+ "loss": 3.6508,
1020
+ "step": 2680
1021
+ },
1022
+ {
1023
+ "epoch": 0.8138045362067666,
1024
+ "grad_norm": 0.17789465188980103,
1025
+ "learning_rate": 5.5740740740740744e-05,
1026
+ "loss": 3.6536,
1027
+ "step": 2700
1028
+ },
1029
+ {
1030
+ "epoch": 0.8138045362067666,
1031
+ "eval_loss": 3.600645640400387,
1032
+ "eval_perplexity": 36.62187137207453,
1033
+ "eval_runtime": 112.2753,
1034
+ "eval_samples_per_second": 14.776,
1035
+ "eval_steps_per_second": 0.232,
1036
+ "step": 2700
1037
+ },
1038
+ {
1039
+ "epoch": 0.8198327179564464,
1040
+ "grad_norm": 0.16772860288619995,
1041
+ "learning_rate": 5.2037037037037035e-05,
1042
+ "loss": 3.6515,
1043
+ "step": 2720
1044
+ },
1045
+ {
1046
+ "epoch": 0.8258608997061262,
1047
+ "grad_norm": 0.16776631772518158,
1048
+ "learning_rate": 4.8333333333333334e-05,
1049
+ "loss": 3.6539,
1050
+ "step": 2740
1051
+ },
1052
+ {
1053
+ "epoch": 0.8318890814558059,
1054
+ "grad_norm": 0.1612899899482727,
1055
+ "learning_rate": 4.462962962962963e-05,
1056
+ "loss": 3.6494,
1057
+ "step": 2760
1058
+ },
1059
+ {
1060
+ "epoch": 0.8379172632054857,
1061
+ "grad_norm": 0.16370627284049988,
1062
+ "learning_rate": 4.092592592592593e-05,
1063
+ "loss": 3.648,
1064
+ "step": 2780
1065
+ },
1066
+ {
1067
+ "epoch": 0.8439454449551654,
1068
+ "grad_norm": 0.1611148715019226,
1069
+ "learning_rate": 3.722222222222222e-05,
1070
+ "loss": 3.6498,
1071
+ "step": 2800
1072
+ },
1073
+ {
1074
+ "epoch": 0.8499736267048451,
1075
+ "grad_norm": 0.16145454347133636,
1076
+ "learning_rate": 3.351851851851852e-05,
1077
+ "loss": 3.6518,
1078
+ "step": 2820
1079
+ },
1080
+ {
1081
+ "epoch": 0.8560018084545249,
1082
+ "grad_norm": 0.1517009735107422,
1083
+ "learning_rate": 2.9814814814814815e-05,
1084
+ "loss": 3.644,
1085
+ "step": 2840
1086
+ },
1087
+ {
1088
+ "epoch": 0.8620299902042047,
1089
+ "grad_norm": 0.1570337861776352,
1090
+ "learning_rate": 2.6111111111111114e-05,
1091
+ "loss": 3.6417,
1092
+ "step": 2860
1093
+ },
1094
+ {
1095
+ "epoch": 0.8680581719538845,
1096
+ "grad_norm": 0.16112424433231354,
1097
+ "learning_rate": 2.240740740740741e-05,
1098
+ "loss": 3.6459,
1099
+ "step": 2880
1100
+ },
1101
+ {
1102
+ "epoch": 0.8740863537035641,
1103
+ "grad_norm": 0.15278516709804535,
1104
+ "learning_rate": 1.8703703703703707e-05,
1105
+ "loss": 3.6408,
1106
+ "step": 2900
1107
+ },
1108
+ {
1109
+ "epoch": 0.8801145354532439,
1110
+ "grad_norm": 0.15267758071422577,
1111
+ "learning_rate": 1.5e-05,
1112
+ "loss": 3.6452,
1113
+ "step": 2920
1114
+ },
1115
+ {
1116
+ "epoch": 0.8861427172029237,
1117
+ "grad_norm": 0.14383205771446228,
1118
+ "learning_rate": 1.1296296296296295e-05,
1119
+ "loss": 3.6364,
1120
+ "step": 2940
1121
+ },
1122
+ {
1123
+ "epoch": 0.8921708989526034,
1124
+ "grad_norm": 0.14794571697711945,
1125
+ "learning_rate": 7.592592592592593e-06,
1126
+ "loss": 3.6325,
1127
+ "step": 2960
1128
+ },
1129
+ {
1130
+ "epoch": 0.8981990807022832,
1131
+ "grad_norm": 0.14148849248886108,
1132
+ "learning_rate": 3.888888888888889e-06,
1133
+ "loss": 3.64,
1134
+ "step": 2980
1135
+ },
1136
+ {
1137
+ "epoch": 0.9042272624519629,
1138
+ "grad_norm": 0.1426716446876526,
1139
+ "learning_rate": 1.8518518518518518e-07,
1140
+ "loss": 3.6443,
1141
+ "step": 3000
1142
+ },
1143
+ {
1144
+ "epoch": 0.9042272624519629,
1145
+ "eval_loss": 3.587533058962724,
1146
+ "eval_perplexity": 36.1447987636509,
1147
+ "eval_runtime": 112.2843,
1148
+ "eval_samples_per_second": 14.775,
1149
+ "eval_steps_per_second": 0.232,
1150
+ "step": 3000
1151
+ }
1152
+ ],
1153
+ "logging_steps": 20,
1154
+ "max_steps": 3000,
1155
+ "num_input_tokens_seen": 0,
1156
+ "num_train_epochs": 1,
1157
+ "save_steps": 300,
1158
+ "stateful_callbacks": {
1159
+ "TrainerControl": {
1160
+ "args": {
1161
+ "should_epoch_stop": false,
1162
+ "should_evaluate": false,
1163
+ "should_log": false,
1164
+ "should_save": true,
1165
+ "should_training_stop": true
1166
+ },
1167
+ "attributes": {}
1168
+ }
1169
+ },
1170
+ "total_flos": 1.604552000274432e+18,
1171
+ "train_batch_size": 64,
1172
+ "trial_name": null,
1173
+ "trial_params": null
1174
+ }
checkpoint-3000/training_args.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:08d76f8b5b85f05fb7caa15e408143d3ba0686e42d70879850259702897d08d2
3
+ size 5905
checkpoint-3000/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
full_config.json ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "shorthand": "model.768.lyr.12 - seqlen.1024 - mla.0.0.0 - ah12.64 - rd32.32",
3
+ "notes": "GPT-2 run with essentially MHA.",
4
+ "model": {
5
+ "hidden_size": 768,
6
+ "num_hidden_layers": 12,
7
+ "intermediate_size": 2048,
8
+ "vocab_size": 50257,
9
+ "tie_word_embeddings": true,
10
+ "max_position_embeddings": 1024,
11
+ "norm_type": "rmsnorm",
12
+ "layer_norm_eps": 1e-12,
13
+ "rms_norm_eps": 1e-06,
14
+ "num_dense_layers": 0,
15
+ "num_attention_heads": 12,
16
+ "q_shared_dim": null,
17
+ "kv_shared_dim": null,
18
+ "o_shared_dim": null,
19
+ "qk_private_dim": 64,
20
+ "vo_private_dim": 64,
21
+ "rope_dims": 32,
22
+ "nope_dims": 32,
23
+ "rope_theta": 10000.0,
24
+ "rope_scaling": {
25
+ "type": "linear",
26
+ "factor": 2.0
27
+ },
28
+ "attention_bias": false,
29
+ "attention_backend": "flash_attention_2",
30
+ "ffn_decompose": false,
31
+ "ffn_rank": null,
32
+ "vocab_subspace": false,
33
+ "vocab_rank": null,
34
+ "hidden_dropout_prob": 0.1,
35
+ "attention_dropout_prob": 0.1,
36
+ "classifier_dropout": null,
37
+ "initializer_range": 0.02
38
+ },
39
+ "pre_train": {
40
+ "wandb_project": "decoder-pretrain-c4",
41
+ "output_dir": "checkpoints/gpt-2_seq1024_mla0-0-0",
42
+ "seed": 42,
43
+ "logging_steps": 20,
44
+ "save_steps": 300,
45
+ "train_batch_size": 64,
46
+ "gradient_accumulation_steps": 16,
47
+ "learning_rate": 0.0005,
48
+ "num_train_steps": 3000,
49
+ "eval_steps": 300,
50
+ "weight_decay": 0.01,
51
+ "num_workers": 8,
52
+ "pin_memory": true,
53
+ "_comment_dataset": "Use preprocessed_dataset_path instead of dataset streaming",
54
+ "preprocessed_dataset_path": "/home/ubuntu/c4_en_pct0.02_seq1024/c4_en_pct0.02_seq1024/dataset",
55
+ "dataset_name": "allenai/c4",
56
+ "dataset_config": "en",
57
+ "dataset_subset_pct": 0.02,
58
+ "max_seq_length": 1024,
59
+ "eval_batch_size": 64,
60
+ "fp16": false,
61
+ "bf16": true,
62
+ "torch_compile": true,
63
+ "torch_compile_backend": "inductor",
64
+ "torch_compile_mode": "default",
65
+ "run_name": "117.88M - model.768.lyr.12 - seqlen.1024 - mla.0.0.0 - ah12.64 - rd32.32",
66
+ "run_id": "15ixey47",
67
+ "run_url": "https://wandb.ai/chrismccormick/decoder-pretrain-c4/runs/15ixey47",
68
+ "best_checkpoint": "checkpoints/gpt-2_seq1024_mla0-0-0/checkpoint-3000"
69
+ },
70
+ "stats": {
71
+ "total_elements": "117.88M"
72
+ }
73
+ }