Uunan commited on
Commit
642bb4b
·
verified ·
1 Parent(s): 1fc19e4

LaminarNet-50m v0.6.2 — best checkpoint (step 115500, val_loss=3.7881)

Browse files
README.md ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: apache-2.0
5
+ tags:
6
+ - laminarnet
7
+ - language-model
8
+ - causal-lm
9
+ - text-generation
10
+ - state-space-model
11
+ - custom-architecture
12
+ - rope
13
+ - geometric-drift-field
14
+ library_name: laminarnet
15
+ pipeline_tag: text-generation
16
+ model-index:
17
+ - name: LaminarNet-50m
18
+ results:
19
+ - task:
20
+ type: text-generation
21
+ metrics:
22
+ - name: Validation Loss
23
+ type: loss
24
+ value: 3.7881
25
+ ---
26
+
27
+ # 🧠 LaminarNet-50m
28
+
29
+ **LaminarNet v0.6.2** — A novel **O(N) causal language model** featuring Geometric Drift Fields, Rotary Position Embeddings (RoPE), and multi-strata hierarchical processing. Designed as a faster, more efficient alternative to traditional Transformer architectures.
30
+
31
+ > **⚡ Key Innovation**: LaminarNet replaces standard attention with a **Geometric Drift Field** — an O(N) selective state-space mechanism using vectorized parallel scan, achieving linear complexity instead of quadratic.
32
+
33
+ ---
34
+
35
+ ## 📊 Model Details
36
+
37
+ | Property | Value |
38
+ |---|---|
39
+ | **Parameters** | **49.4M** |
40
+ | Architecture | LaminarNet v0.6.2 |
41
+ | `d_model` | 320 |
42
+ | `n_heads` | 5 |
43
+ | `n_layers` | 10 |
44
+ | `d_ff` | 1200 |
45
+ | `n_strata` | 2 |
46
+ | `strata_ratios` | (1, 2, 4) |
47
+ | Sequence Length | 1024 |
48
+ | Vocabulary | GPT-2 BPE (50,257 tokens) |
49
+ | Best Val Loss | **3.7881** |
50
+ | Training Steps | 115,500 |
51
+ | Training Tokens | ~1B (FineWeb) |
52
+
53
+ ---
54
+
55
+ ## 🚀 Quick Start
56
+
57
+ ### 1. Installation
58
+
59
+ ```bash
60
+ pip install laminarnet safetensors transformers torch
61
+ ```
62
+
63
+ Or install from source:
64
+
65
+ ```bash
66
+ git clone https://huggingface.co/Uunan/LaminarNet-50m
67
+ cd LaminarNet-50m
68
+ pip install -e ./laminarnet
69
+ ```
70
+
71
+ ### 2. Download & Load Model
72
+
73
+ ```python
74
+ import torch
75
+ from collections import Counter
76
+ import torch.nn.functional as F
77
+ from transformers import AutoTokenizer
78
+ from huggingface_hub import hf_hub_download
79
+
80
+ # Download model files
81
+ config_path = hf_hub_download("Uunan/LaminarNet-50m", "config.json")
82
+ model_path = hf_hub_download("Uunan/LaminarNet-50m", "model.safetensors")
83
+
84
+ # Build model
85
+ from laminarnet import LaminarNet, LaminarNetConfig
86
+
87
+ config = LaminarNetConfig(
88
+ vocab_size=50257, d_model=320, n_heads=5, n_layers=10,
89
+ d_ff=1200, n_strata=2, strata_ratios=(1, 2, 4),
90
+ seq_len=1024, dropout=0.1, conv_kernel=4, rope_base=10000.0,
91
+ )
92
+ model = LaminarNet(config)
93
+
94
+ # Load weights
95
+ from safetensors.torch import load_file
96
+ state = load_file(model_path)
97
+ model.load_state_dict(state)
98
+ model.eval()
99
+
100
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
101
+ model = model.to(device)
102
+
103
+ print(f"✅ LaminarNet-50m loaded! ({sum(p.numel() for p in model.parameters()) / 1e6:.1f}M params)")
104
+ ```
105
+
106
+ ### 3. Generate Text
107
+
108
+ ```python
109
+ tokenizer = AutoTokenizer.from_pretrained("gpt2")
110
+
111
+ @torch.no_grad()
112
+ def generate(model, tokenizer, prompt, max_new_tokens=200,
113
+ temperature=0.8, top_k=50, top_p=0.9, device="cpu",
114
+ repetition_penalty=1.2, no_repeat_ngram=3, frequency_penalty=0.3):
115
+ """
116
+ Autoregressive text generation with full sampling controls.
117
+
118
+ Args:
119
+ prompt: Input text to continue from.
120
+ max_new_tokens: Maximum number of tokens to generate.
121
+ temperature: Sampling temperature (0.1 = conservative, 1.5 = creative).
122
+ top_k: Top-k sampling (0 = disabled).
123
+ top_p: Nucleus sampling threshold (0-1).
124
+ repetition_penalty: Penalize already-seen tokens (1.0 = off, 1.2+ = recommended).
125
+ no_repeat_ngram: Block repeated n-grams (3 = no trigram repeats, 0 = off).
126
+ frequency_penalty: Penalize tokens by their generation frequency (0.0 = off).
127
+ """
128
+ SEQ_LEN = 1024
129
+ input_ids = tokenizer.encode(prompt, return_tensors="pt").to(device)
130
+ prompt_len = input_ids.shape[1]
131
+
132
+ if input_ids.shape[1] > SEQ_LEN:
133
+ input_ids = input_ids[:, -SEQ_LEN:]
134
+
135
+ eos_id = tokenizer.eos_token_id
136
+
137
+ for _ in range(max_new_tokens):
138
+ ctx = input_ids[:, -SEQ_LEN:]
139
+ logits = model(ctx)[:, -1, :]
140
+
141
+ # Repetition Penalty
142
+ if repetition_penalty != 1.0:
143
+ for tok_id in set(input_ids[0].tolist()):
144
+ if logits[0, tok_id] > 0:
145
+ logits[0, tok_id] /= repetition_penalty
146
+ else:
147
+ logits[0, tok_id] *= repetition_penalty
148
+
149
+ # Frequency Penalty
150
+ if frequency_penalty > 0:
151
+ token_counts = Counter(input_ids[0].tolist()[prompt_len:])
152
+ for tok_id, count in token_counts.items():
153
+ logits[0, tok_id] -= frequency_penalty * count
154
+
155
+ # N-gram Blocking
156
+ if no_repeat_ngram > 0 and input_ids.shape[1] >= no_repeat_ngram:
157
+ generated = input_ids[0].tolist()
158
+ prefix = tuple(generated[-(no_repeat_ngram - 1):])
159
+ for i in range(len(generated) - no_repeat_ngram + 1):
160
+ if tuple(generated[i:i + no_repeat_ngram - 1]) == prefix:
161
+ logits[0, generated[i + no_repeat_ngram - 1]] = float("-inf")
162
+
163
+ logits = logits / temperature
164
+
165
+ # Top-k
166
+ if top_k > 0:
167
+ vals, _ = torch.topk(logits, top_k)
168
+ logits[logits < vals[:, -1:]] = float("-inf")
169
+
170
+ # Top-p (nucleus)
171
+ if 0 < top_p < 1.0:
172
+ sorted_logits, sorted_idx = torch.sort(logits, descending=True)
173
+ cum_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)
174
+ remove_mask = cum_probs - F.softmax(sorted_logits, dim=-1) >= top_p
175
+ sorted_logits[remove_mask] = float("-inf")
176
+ logits = sorted_logits.scatter(1, sorted_idx, sorted_logits)
177
+
178
+ probs = F.softmax(logits, dim=-1)
179
+ next_tok = torch.multinomial(probs, num_samples=1)
180
+ input_ids = torch.cat([input_ids, next_tok], dim=1)
181
+
182
+ if next_tok.item() == eos_id:
183
+ break
184
+
185
+ return tokenizer.decode(input_ids[0], skip_special_tokens=True)
186
+
187
+
188
+ # Generate!
189
+ text = generate(model, tokenizer, "The meaning of life is", device=device)
190
+ print(text)
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 🎛️ Generation Parameters Guide
196
+
197
+ | Parameter | Default | Range | Description |
198
+ |---|---|---|---|
199
+ | `temperature` | 0.8 | 0.1 — 2.0 | Lower = more focused, higher = more creative |
200
+ | `top_k` | 50 | 0 — vocab_size | Keep only top-k most likely tokens |
201
+ | `top_p` | 0.9 | 0.0 — 1.0 | Nucleus sampling — keep tokens until cumulative prob ≥ p |
202
+ | `repetition_penalty` | 1.2 | 1.0 — 2.0 | Penalize previously generated tokens (1.0 = off) |
203
+ | `no_repeat_ngram` | 3 | 0 — 5 | Block repeated n-grams (0 = off) |
204
+ | `frequency_penalty` | 0.3 | 0.0 — 1.0 | Penalize tokens proportional to usage count (0 = off) |
205
+ | `max_new_tokens` | 200 | 1 — 1024 | Maximum tokens to generate |
206
+
207
+ ### Recommended Presets
208
+
209
+ ```python
210
+ # 📝 Factual / Focused
211
+ text = generate(model, tokenizer, prompt, temperature=0.5, top_k=30, top_p=0.85, device=device)
212
+
213
+ # 🎨 Creative / Story Writing
214
+ text = generate(model, tokenizer, prompt, temperature=1.0, top_k=80, top_p=0.95,
215
+ repetition_penalty=1.3, frequency_penalty=0.4, device=device)
216
+
217
+ # ⚡ Greedy (deterministic)
218
+ text = generate(model, tokenizer, prompt, temperature=0.1, top_k=1, top_p=1.0,
219
+ repetition_penalty=1.0, device=device)
220
+ ```
221
+
222
+ ---
223
+
224
+ ## 🏗️ Architecture Deep Dive
225
+
226
+ LaminarNet introduces a unique **multi-strata** architecture that processes information at multiple temporal resolutions simultaneously:
227
+
228
+ ```
229
+ Input Tokens
230
+
231
+
232
+ ┌─────────────┐
233
+ │ Embedding │ Token → d_model (320)
234
+ └──────┬──────┘
235
+
236
+ ├──────── Stratum 0 (Fine, ratio=1) ── Full resolution
237
+
238
+ └──────── Stratum 1 (Coarse, ratio=2) ── Half resolution
239
+
240
+ ┌────┴────┐
241
+ │ x10 │ LaminarBlock layers
242
+ │ Layers │
243
+ └────┬────┘
244
+
245
+ Each LaminarBlock:
246
+ ┌─────────────────────────────────────────┐
247
+ │ 1. GeometricDriftField (per stratum) │ ← O(N) parallel scan + RoPE
248
+ │ 2. CrossStratumRouting (between strata) │ ← Dual-gated information exchange
249
+ │ 3. SwiGLU FFN (per stratum) │ ← Gated feed-forward
250
+ └─────────────────────────────────────────┘
251
+
252
+
253
+ ┌─────────────┐
254
+ │ LM Head │ d_model → vocab (weight-tied with embedding)
255
+ └─────────────┘
256
+ ```
257
+
258
+ ### Core Components
259
+
260
+ | Component | Description |
261
+ |---|---|
262
+ | **Geometric Drift Field** | Replaces self-attention with an O(N) selective state-space mechanism. Uses chunked parallel scan (chunk_size=256) with vectorized inter-chunk carry propagation. |
263
+ | **RoPE** | Rotary Position Embeddings applied to value vectors within the drift field for relative positional encoding. |
264
+ | **Cross-Stratum Routing** | Bidirectional gated information flow between fine and coarse strata using causal downsampling (left-padded AvgPool) and nearest-neighbor upsampling. |
265
+ | **SwiGLU FFN** | Gated feed-forward: `SiLU(W1·x) ⊙ W3·x` projected back via `W2`. |
266
+ | **RMSNorm** | Pre-norm with Root Mean Square normalization (float32 stable). |
267
+ | **Causal Conv1d** | Depthwise causal convolution (kernel=4) before drift field projections. |
268
+
269
+ ---
270
+
271
+ ## 📈 Training Details
272
+
273
+ | Property | Value |
274
+ |---|---|
275
+ | **Dataset** | FineWeb (~1B tokens, packed, no padding) |
276
+ | **Tokenizer** | GPT-2 BPE (50,257 tokens) |
277
+ | **Optimizer** | AdamW (lr=3e-4, weight_decay=0.01, betas=(0.9, 0.999)) |
278
+ | **LR Schedule** | Linear warmup (4000 steps) + cosine decay (min ratio 0.1) |
279
+ | **Batch Size** | 8 × 1024 = 8,192 tokens/step |
280
+ | **Gradient Clipping** | max_norm=1.0 |
281
+ | **Mixed Precision** | AMP (FP16) with GradScaler |
282
+ | **Epochs** | 1 |
283
+ | **Total Steps** | ~115,500 |
284
+ | **Training Hardware** | Google Colab (single GPU) |
285
+
286
+ ---
287
+
288
+ ## 📋 Sample Outputs
289
+
290
+ **Prompt**: *"The meaning of life is"*
291
+
292
+ > The meaning of life is that it takes a good deal of time to understand the nature of our lives. When we look at it, you're not only one who can live in an illusion or experience other than just feeling like someone else and then having lost control over everything as well as knowing that there are many things that come down into your psyche but also for us all this stuff needs to be done right.
293
+
294
+ **Prompt**: *"The meaning of life is"*
295
+
296
+ > The meaning of life is so intense that the person who makes it to Him will be able to accept a different image, one that he has been living in. His love for God and his grace was born out in her mind when she'd just finished living through what she knew – but I can imagine this: "My goodness knows that you are not alone!"
297
+
298
+ ---
299
+
300
+ ## ⚠️ Limitations
301
+
302
+ - **50M parameters** — This is a small research model, not suitable for production use.
303
+ - **English only** — Trained exclusively on English text from FineWeb.
304
+ - **No instruction tuning** — Base model only, not aligned or fine-tuned for chat/instructions.
305
+ - **May generate** incorrect facts, biased content, or repetitive text.
306
+ - **1024 token context** — Maximum sequence length is 1024 tokens.
307
+
308
+ ---
309
+
310
+ ## 📜 Citation
311
+
312
+ ```bibtex
313
+ @misc{laminarnet2025,
314
+ title={LaminarNet: O(N) Language Model with Geometric Drift Fields},
315
+ author={Uunan},
316
+ year={2025},
317
+ url={https://huggingface.co/Uunan/LaminarNet-50m}
318
+ }
319
+ ```
320
+
321
+ ## 📄 License
322
+
323
+ Apache 2.0 — free for research and commercial use.
config.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LaminarNet"
4
+ ],
5
+ "model_type": "laminarnet",
6
+ "vocab_size": 50257,
7
+ "d_model": 320,
8
+ "n_heads": 5,
9
+ "n_layers": 10,
10
+ "d_ff": 1200,
11
+ "n_strata": 2,
12
+ "strata_ratios": [
13
+ 1,
14
+ 2,
15
+ 4
16
+ ],
17
+ "seq_len": 1024,
18
+ "dropout": 0.1,
19
+ "conv_kernel": 4,
20
+ "rope_base": 10000.0,
21
+ "total_params": 49420160,
22
+ "best_val_loss": 3.788057290315628,
23
+ "training_steps": 115500
24
+ }
laminarnet/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from .model import LaminarNet, LaminarNetConfig
2
+
3
+ __all__ = ["LaminarNet", "LaminarNetConfig"]
laminarnet/model.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ LaminarNet v0.6.0 — RoPE, Dual-Gate CSR, Parallel Carry, Strata Validation
3
+ Faster than Transformer: larger chunks, streamlined architecture, vectorized carry.
4
+ All temporal operations are strictly causal — no future information leakage.
5
+ """
6
+
7
+ import math
8
+ from dataclasses import dataclass
9
+ from typing import Optional, List
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.functional as F
14
+
15
+
16
+ @dataclass
17
+ class LaminarNetConfig:
18
+ vocab_size: int = 50257
19
+ d_model: int = 256
20
+ n_heads: int = 8
21
+ n_layers: int = 8
22
+ d_ff: int = 1024
23
+ n_strata: int = 2
24
+ strata_ratios: tuple = (1, 2, 4)
25
+ seq_len: int = 1024
26
+ dropout: float = 0.1
27
+ conv_kernel: int = 4
28
+ rope_base: float = 10000.0
29
+
30
+ def __post_init__(self):
31
+ if len(self.strata_ratios) < self.n_strata:
32
+ raise ValueError(
33
+ f"strata_ratios length ({len(self.strata_ratios)}) must be "
34
+ f">= n_strata ({self.n_strata}). "
35
+ f"Provide at least {self.n_strata} ratios."
36
+ )
37
+ if self.strata_ratios[0] != 1:
38
+ raise ValueError(
39
+ f"strata_ratios[0] must be 1 (fine stratum), got {self.strata_ratios[0]}"
40
+ )
41
+ for i, r in enumerate(self.strata_ratios):
42
+ if not isinstance(r, int) or r < 1:
43
+ raise ValueError(
44
+ f"strata_ratios[{i}] must be a positive integer, got {r}"
45
+ )
46
+
47
+
48
+ class RMSNorm(nn.Module):
49
+ def __init__(self, d, eps=1e-6):
50
+ super().__init__()
51
+ self.scale = nn.Parameter(torch.ones(d))
52
+ self.eps = eps
53
+ def forward(self, x):
54
+ orig_dtype = x.dtype
55
+ x_f32 = x.float()
56
+ rms = x_f32.pow(2).mean(-1, keepdim=True).add(self.eps).rsqrt()
57
+ return (self.scale * (x_f32 * rms)).to(orig_dtype)
58
+
59
+
60
+ # ─────────────────────────────────────────────────────────────
61
+ # Rotary Position Embedding
62
+ # ─────────────────────────────────────────────────────────────
63
+
64
+ class RotaryPositionEmbedding(nn.Module):
65
+ """RoPE — computes sincos on-the-fly, works for any sequence length."""
66
+ def __init__(self, dim: int, base: float = 10000.0):
67
+ super().__init__()
68
+ inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
69
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
70
+
71
+ def forward(self, seq_len: int, device: torch.device, dtype: torch.dtype):
72
+ t = torch.arange(seq_len, device=device, dtype=torch.float32)
73
+ freqs = torch.outer(t, self.inv_freq) # (N, dim//2)
74
+ cos_f = freqs.cos().to(dtype) # (N, dim//2)
75
+ sin_f = freqs.sin().to(dtype) # (N, dim//2)
76
+ return cos_f, sin_f
77
+
78
+
79
+ def apply_rope(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
80
+ """Apply RoPE to x of shape (B, N, H, D). cos/sin are (N, D//2)."""
81
+ half = x.shape[-1] // 2
82
+ x1, x2 = x[..., :half], x[..., half:]
83
+ cos = cos.unsqueeze(0).unsqueeze(2) # (1, N, 1, D//2)
84
+ sin = sin.unsqueeze(0).unsqueeze(2)
85
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
86
+
87
+
88
+ # ─────────────────────────────────────────────────────────────
89
+ # 1. O(N) Selective Geometric Drift Field — with RoPE
90
+ # ─────────────────────────────────────────────────────────────
91
+
92
+ class GeometricDriftField(nn.Module):
93
+ """
94
+ Geometric Drift Field v6.0 — O(N) Vectorized Parallel Scan
95
+ with RoPE and fully parallel inter-chunk carry.
96
+ """
97
+
98
+ def __init__(self, d_model: int, n_heads: int, dropout: float = 0.1,
99
+ conv_kernel: int = 4, rope_base: float = 10000.0):
100
+ super().__init__()
101
+ self.d_model = d_model
102
+ self.n_heads = n_heads
103
+ self.d_head = d_model // n_heads
104
+
105
+ # Fused Projections — now 3-way (no separate theta needed; RoPE replaces it)
106
+ self.in_proj = nn.Linear(d_model, d_model * 3, bias=False)
107
+ self.conv1d = nn.Conv1d(d_model, d_model, kernel_size=conv_kernel,
108
+ padding=conv_kernel-1, groups=d_model)
109
+
110
+ self.out_proj = nn.Linear(d_model, d_model, bias=False)
111
+ self.norm = RMSNorm(d_model)
112
+ self.dropout = nn.Dropout(dropout)
113
+
114
+ self.dt_bias = nn.Parameter(torch.ones(d_model) * -3.0)
115
+ self.rope = RotaryPositionEmbedding(self.d_head, base=rope_base)
116
+
117
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
118
+ residual = x
119
+ x = self.norm(x)
120
+ B, N, D = x.shape
121
+
122
+ # 1. Context & Proj (causal conv)
123
+ x_conv = self.conv1d(x.transpose(1, 2))[..., :N].transpose(1, 2)
124
+ x_conv = F.silu(x_conv)
125
+
126
+ fused = self.in_proj(x_conv)
127
+ dt_raw, v, gate = fused.chunk(3, dim=-1)
128
+
129
+ # 2. Selective Parameters
130
+ dt = F.softplus(dt_raw.float() + self.dt_bias.float()).clamp(min=0.001, max=2.0).to(dt_raw.dtype)
131
+ gate = torch.sigmoid(gate)
132
+ log_alpha = -dt
133
+
134
+ # 3. RoPE-based Positional Rotation
135
+ cos_f, sin_f = self.rope(N, device=x.device, dtype=x.dtype)
136
+ v_view = v.view(B, N, self.n_heads, self.d_head)
137
+ v_rotated = apply_rope(v_view, cos_f, sin_f).reshape(B, N, D)
138
+
139
+ # 4. O(N) Vectorized Parallel Scan — chunk_size=256 for speed
140
+ chunk_size = 256
141
+ v_in = v_rotated * dt
142
+
143
+ # Pad to nearest chunk multiple
144
+ orig_N = N
145
+ remainder = N % chunk_size
146
+ if remainder != 0:
147
+ pad_len = chunk_size - remainder
148
+ v_in = F.pad(v_in, (0, 0, 0, pad_len))
149
+ log_alpha = F.pad(log_alpha, (0, 0, 0, pad_len))
150
+
151
+ N_padded = v_in.shape[1]
152
+ num_chunks = N_padded // chunk_size
153
+
154
+ v_chunks = v_in.view(B, num_chunks, chunk_size, D)
155
+ la_chunks = log_alpha.view(B, num_chunks, chunk_size, D)
156
+
157
+ # Cumulative log-decay within each chunk
158
+ L_chunks = torch.cumsum(la_chunks, dim=2) # (B, C, T, D)
159
+ L_chunks = L_chunks.float().clamp(min=-20.0, max=0.0) # stabilize
160
+
161
+ # O(N) intra-chunk scan via cumsum (float32 for precision + stability)
162
+ L_max = L_chunks.max(dim=2, keepdim=True).values
163
+ L_stable = L_chunks - L_max
164
+ exp_neg_L_stable = torch.exp(-L_stable)
165
+ scaled_v = exp_neg_L_stable * v_chunks.float()
166
+ cum_scaled = torch.cumsum(scaled_v, dim=2)
167
+ exp_L_stable = torch.exp(L_stable)
168
+ chunk_out = exp_L_stable * cum_scaled # stay float32
169
+
170
+ # 5. Parallel inter-chunk carry (no Python for-loop) — all in float32
171
+ if num_chunks > 1:
172
+ chunk_boundary_decay = L_chunks[:, :, -1, :] # (B, C, D) already float32
173
+ chunk_boundary_out = chunk_out[:, :, -1, :] # (B, C, D) already float32
174
+
175
+ # Parallel prefix sum in log-space
176
+ cum_decay = torch.cumsum(chunk_boundary_decay, dim=1) # (B, C, D)
177
+ cum_decay = cum_decay.clamp(min=-80.0, max=0.0) # prevent extreme values
178
+
179
+ # Log-space stabilized parallel carry
180
+ stabilizer = cum_decay.max(dim=1, keepdim=True).values
181
+ norm_cum_decay = (cum_decay - stabilizer).clamp(min=-20.0, max=0.0)
182
+
183
+ seeds = chunk_boundary_out * torch.exp(-norm_cum_decay)
184
+
185
+ # Shift seeds right (carry[0] = 0, carry[c] uses chunks 0..c-1)
186
+ shifted_seeds = F.pad(seeds[:, :-1], (0, 0, 1, 0))
187
+ cum_seeds = torch.cumsum(shifted_seeds, dim=1)
188
+
189
+ carries = cum_seeds * torch.exp(norm_cum_decay)
190
+
191
+ # Apply all carries in parallel (L_chunks already clamped)
192
+ final_out = chunk_out + carries.unsqueeze(2) * torch.exp(L_chunks)
193
+ final_out = final_out.to(x.dtype) # cast back after all float32 math
194
+ final_out = final_out.view(B, -1, D)
195
+ else:
196
+ final_out = chunk_out.to(x.dtype)
197
+ final_out = final_out.view(B, -1, D)
198
+
199
+ final_out = final_out[:, :orig_N, :]
200
+
201
+ # 6. Output
202
+ out = self.out_proj(final_out * gate)
203
+ return residual + self.dropout(out)
204
+
205
+
206
+ # ─────────────────────────────────────────────────────────────
207
+ # 2. Standard Infrastructure
208
+ # ─────────────────────────────────────────────────────────────
209
+
210
+ class CrossStratumRouting(nn.Module):
211
+ def __init__(self, d_model: int, stride: int):
212
+ super().__init__()
213
+ self.stride = stride
214
+ self.down = nn.AvgPool1d(kernel_size=stride, stride=stride)
215
+ self.up = nn.Upsample(scale_factor=stride, mode='nearest')
216
+ self.gate_f2c = nn.Sequential(nn.Linear(d_model, d_model), nn.Sigmoid())
217
+ self.gate_c2f = nn.Sequential(nn.Linear(d_model, d_model), nn.Sigmoid())
218
+
219
+ def forward(self, h_fine: torch.Tensor, h_coarse: torch.Tensor):
220
+ fine_t = h_fine.transpose(1, 2)
221
+ k = self.down.kernel_size if isinstance(self.down.kernel_size, int) else self.down.kernel_size[0]
222
+ fine_t = F.pad(fine_t, (k - 1, 0))
223
+ f_to_c = self.down(fine_t).transpose(1, 2)
224
+ Lc = h_coarse.shape[1]
225
+ if f_to_c.shape[1] < Lc:
226
+ f_to_c = F.pad(f_to_c, (0, 0, 0, Lc - f_to_c.shape[1]))
227
+ h_coarse = h_coarse + self.gate_f2c(f_to_c[:, :Lc, :]) * f_to_c[:, :Lc, :]
228
+ c_to_f = self.up(h_coarse.transpose(1, 2)).transpose(1, 2)
229
+ Lf = h_fine.shape[1]
230
+ if c_to_f.shape[1] < Lf:
231
+ c_to_f = F.pad(c_to_f, (0, 0, 0, Lf - c_to_f.shape[1]))
232
+ h_fine = h_fine + self.gate_c2f(c_to_f[:, :Lf, :]) * c_to_f[:, :Lf, :]
233
+ return h_fine, h_coarse
234
+
235
+ class SwiGLUFFN(nn.Module):
236
+ def __init__(self, d_model: int, d_ff: int, dropout: float = 0.1):
237
+ super().__init__()
238
+ self.norm = RMSNorm(d_model)
239
+ self.w1, self.w2, self.w3 = nn.Linear(d_model, d_ff, bias=False), nn.Linear(d_ff, d_model, bias=False), nn.Linear(d_model, d_ff, bias=False)
240
+ self.dropout = nn.Dropout(dropout)
241
+ def forward(self, x):
242
+ res = x
243
+ x = self.norm(x)
244
+ return res + self.dropout(self.w2(F.silu(self.w1(x)) * self.w3(x)))
245
+
246
+ class LaminarNet(nn.Module):
247
+ def __init__(self, config: LaminarNetConfig):
248
+ super().__init__()
249
+ self.config, d = config, config.d_model
250
+ self.tok_emb = nn.Embedding(config.vocab_size, d)
251
+ self.dropout = nn.Dropout(config.dropout)
252
+ self.strata_init = nn.ModuleList([nn.AvgPool1d(kernel_size=r, stride=r) for r in config.strata_ratios[1:config.n_strata]])
253
+ self.blocks = nn.ModuleList([LaminarBlock(config) for _ in range(config.n_layers)])
254
+ self.norm_out = RMSNorm(d)
255
+ self.head = nn.Linear(d, config.vocab_size, bias=False)
256
+ self.head.weight = self.tok_emb.weight
257
+ self.apply(lambda m: nn.init.normal_(m.weight, std=0.02) if isinstance(m, (nn.Linear, nn.Embedding)) else None)
258
+
259
+ def forward(self, ids):
260
+ B, N = ids.shape
261
+ x = self.dropout(self.tok_emb(ids))
262
+ # CAUSAL strata init: left-pad so each coarse position only sees past/current
263
+ coarse_strata = []
264
+ for pool in self.strata_init:
265
+ x_t = x.transpose(1, 2)
266
+ k = pool.kernel_size[0]
267
+ x_t = F.pad(x_t, (k - 1, 0))
268
+ coarse_strata.append(pool(x_t).transpose(1, 2))
269
+ strata = [x] + coarse_strata
270
+ for b in self.blocks: strata = b(strata)
271
+ return self.head(self.norm_out(strata[0]))
272
+
273
+ def count_parameters(self): return sum(p.numel() for p in self.parameters() if p.requires_grad)
274
+
275
+ class LaminarBlock(nn.Module):
276
+ def __init__(self, config):
277
+ super().__init__()
278
+ self.S = config.n_strata
279
+ self.gdfs = nn.ModuleList([GeometricDriftField(config.d_model, config.n_heads, config.dropout, config.conv_kernel, config.rope_base) for _ in range(self.S)])
280
+ self.csrs = nn.ModuleList([CrossStratumRouting(config.d_model, config.strata_ratios[s+1]//config.strata_ratios[s]) for s in range(self.S-1)])
281
+ self.ffns = nn.ModuleList([SwiGLUFFN(config.d_model, config.d_ff, config.dropout) for _ in range(self.S)])
282
+ def forward(self, strata):
283
+ for s in range(self.S): strata[s] = self.gdfs[s](strata[s])
284
+ for s in range(self.S - 1): strata[s], strata[s+1] = self.csrs[s](strata[s], strata[s+1])
285
+ for s in range(self.S): strata[s] = self.ffns[s](strata[s])
286
+ return strata
287
+
288
+ if __name__ == "__main__":
289
+ conf = LaminarNetConfig()
290
+ model = LaminarNet(conf)
291
+ x = torch.randint(0, conf.vocab_size, (2, 128))
292
+ print(f"LaminarNet v0.6.0 | Out: {model(x).shape}")
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f692c6044d94253ed0c4cc3198fa2e9c2ef12efe65413f67f2f915189fc92db4
3
+ size 197704472
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": "<|endoftext|>",
5
+ "eos_token": "<|endoftext|>",
6
+ "errors": "replace",
7
+ "is_local": false,
8
+ "model_max_length": 1024,
9
+ "pad_token": null,
10
+ "tokenizer_class": "GPT2Tokenizer",
11
+ "unk_token": "<|endoftext|>"
12
+ }
Free AI Image Generator No sign-up. Instant results. Open Now