File size: 10,475 Bytes
0ef192a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119733d
0ef192a
 
bdab591
 
 
0ef192a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119733d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85fbff7
 
119733d
 
 
 
 
 
 
 
 
85fbff7
 
 
 
 
 
 
 
 
 
119733d
 
 
 
 
 
 
 
 
85fbff7
119733d
 
0ef192a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bdab591
 
0ef192a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
---
license: apache-2.0
language:
  - en
library_name: transformers
pipeline_tag: text-generation
tags:
  - odinnext
  - hgrn2
  - linear-attention
  - recurrent
  - causal-lm
  - custom_code
  - base-model
  - fp16
  - amd
  - rocm
  - arxiv:2404.07904
  - arxiv:2605.06546
  - arxiv:2407.12665
  - arxiv:2506.14202
---

# OdinNext-138M-Base

**OdinNext** is a 138M-parameter causal language model that replaces softmax
self-attention with an **HGRN2-style gated linear recurrence**. This repository
is the **base pretrained model** — trained from scratch on ~101.6B tokens of
curated data (the Dolmino mix) on two AMD Strix Halo (gfx1151) machines.

This is a **base model**: it completes and continues text. It is **not** an
instruction-tuned or chat model — no SFT, DPO, RLHF, or chat template. An
instruction-tuned variant is available at
[`joelhenwang/OdinNext-138M-Instruct`](https://huggingface.co/joelhenwang/OdinNext-138M-Instruct).

- **Repo:** `joelhenwang/OdinNext-138M-Base`
- **`main`:** EMA-shadowed weights (decay 0.999), recommended.
- **`live`:** raw training weights at the same step.
- **Context window:** 2,048 tokens in the released inference code.
- **License:** Apache-2.0.

> Uses custom Transformers code. Loading with `trust_remote_code=True` executes
> Python from this repo. Review the files or pin a commit before trusting it.

## At a glance

| Item | Value |
|---|---:|
| Unique tied parameters | **138,449,696** |
| Non-embedding parameters | **113,283,872** |
| Layers | 16 |
| Hidden size | 768 |
| Heads | 6 |
| Head state dims | 128 × 128 per head |
| FFN inner size | 2,048 |
| Vocabulary | 32,768 custom BPE tokens |
| Max sequence length | 2,048 |
| Checkpoint dtype | fp16 |
| Architecture | HGRN2 recurrence + alternating RoPE + SwiGLU² FFN + ZCRMSNorm |
| Cache type | Fixed-size recurrent state, not a growing KV cache |

## Architecture

Decoder-only causal LM, 16 identical pre-norm blocks:

```text
x = x + sigmoid(gate_attn) * HGRN2(ZCRMSNorm(x))
x = x + sigmoid(gate_ffn)  * SwiGLU²(ZCRMSNorm(x))
```

The HGRN2 recurrent state updates per token as:

```text
S_t = diag(exp(g_t)) S_{t-1} + k_t ⊗ v_t
o_t = q_t S_t
```

with a per-layer state shaped `[B, n_heads, head_f_dim, head_i_dim]` =
`[B, 6, 128, 128]`. This state is **constant in size with respect to context
length**, giving O(1)-per-token decoding rather than a growing KV cache.

**Hybrid RoPE:** even layers (0, 2, …, 14) apply RoPE to q/k (θ = 100,000);
odd layers are position-free. Tied embedding / LM head. No linear biases.

## Memory: recurrent state vs Transformer KV cache

For batch size 1 in fp16 the recurrent state is constant:

```text
layers × heads × head_f_dim × head_i_dim × bytes
= 16 × 6 × 128 × 128 × 2 = 3,145,728 bytes ≈ 3.0 MiB
```

independent of generated length (the pure-PyTorch fallback promotes the scan
state to fp32, ≈ 6.0 MiB). A same-depth fp16 Transformer KV cache would grow
linearly (≈ 48 MiB at 1K tokens, ≈ 768 MiB at 16K). This is a cache-state
comparison only, not a claim about total memory or usable context.

## Training snapshot

| Field | Value |
|---|---|
| Data | Dolmino mix (~101.6B tokens, odin-32k tokenizer) |
| Hardware | 2× AMD Strix Halo / gfx1151, ROCm 7.13 |
| Interconnect | Thunderbolt 4, DDP over gloo |
| Precision | fp16 + GradScaler |
| Optimizers | NorMuon (2D tensors) + AdamW (1D / embeddings) |
| LR | peak 8e-4, warmup, cosine decay |
| Stabilization | z-loss 1e-4, attention soft-cap 50, EMA decay 0.999 |
| Curriculum | Phase 1: Token-Superposition Training (bag-size 4) + DiffusionBlocks (block-wise) for ~24K steps; Phase 2: standard end-to-end autoregressive recovery |
| Released weights | `main` = `ema_state_dict`; `live` = raw online weights |

The two-phase curriculum trains most of the budget under a block-wise
DiffusionBlocks + token-superposition objective for throughput, then recovers
ordinary left-to-right generation with a standard end-to-end phase. The
released weights are from the end-to-end recovery phase and produce coherent
continuations.

## Data & curation

Pretraining used the **Dolmino mix**
([`allenai/dolma3_dolmino_mix-100B-1025`](https://huggingface.co/datasets/allenai/dolma3_dolmino_mix-100B-1025)),
curated by dropping the synthetic / noisy partitions and keeping the natural
text + code:

- **Excluded:** all synthetic reasoning-trace subsets (Gemini / QwQ / R1 /
  OpenThoughts2 / Llama-Nemotron, math- and code-meta-reasoning, omr-rewrite,
  verifiable GPT-4.1 / o4-mini), adult content, and OCR'd science PDFs.
- **Kept:** natural web text, code (stack-edu, cranecode; FIM markers stripped),
  math, and reference text — the mix's native proportions minus the exclusions.
- **Tokenizer:** custom 32K BPE (`odin-32k`); ~**101.6B tokens** after tokenization.

## How we accelerated pretraining

Pretraining ran on **two AMD Ryzen AI MAX+ 395 (Strix Halo, gfx1151 / RDNA 3.5)**
mini-PCs (128 GB unified LPDDR5X each), over **Thunderbolt 4** with DDP on the
**gloo** backend. Three techniques compounded:

1. **TST — Token Superposition Training** (bag-size 4): each position is the mean
   of 4 stochastic sub-word tokenizations of the same text, so the model digests
   **~4× the tokens per step**; the bag size anneals 4 → 2 → 1 over training.
2. **DiffusionBlocks** (B=4): the 16 layers form 4 four-layer blocks trained to
   denoise their input, **block-parallel across the two machines with essentially
   no gradient all-reduce** (Machine A: blocks 1–2; Machine B: blocks 3–4)
3. **Two-machine DDP** over TB4

Together this phase trained **roughly 10–20× faster** than a conventional
end-to-end autoregressive pass on the *same two machines* (and far faster than a
single accelerator) — which is what made a 101.6B-token pretrain feasible in days
on consumer hardware. A final, shorter standard end-to-end phase then restores
ordinary generation; the released weights (EMA, decay 0.999) come from it.

## Results

Zero-shot, **lm-evaluation-harness** (HellaSwag = acc_norm, ARC = mean of
Easy + Challenge acc, PIQA = acc), measured on the **full** validation/test sets.
Other rows are **as reported by Axiomic Labs** on the
[GPT-X2-125M](https://huggingface.co/AxiomicLabs/GPT-X2-125M) card.

> **Correction (2026-06-09):** an earlier version of this card reported HellaSwag
> 33.05%. That number was computed on only the first 2,000 HellaSwag validation
> examples, which score ~5–6 points higher than the full 10,042-example set. The
> table below is the corrected, full-set result and reproduces under both our
> harness and lm-eval (thanks to the Axiomic Labs leaderboard for catching this).

| Company | Model | HellaSwag | ARC (avg) | PIQA | Training tokens |
|---|---|---|---|---|---|
| HuggingFace | SmolLM2-135M | 43.22% | 44.62% | 67.52% | 2T |
| Axiomic Labs | GPT-X2-125M | 40.55% | 39.90% | 66.97% | 75B |
| OpenAI | GPT-2 (124M) | 31.49% | 31.40% | 63.28% | ~10B |
| EleutherAI | Pythia-160M | 30.46% | 29.95% | 57.94% | ~225B |
| Facebook | OPT-125M | 31.39% | 31.53% | 62.02% | 180B |
| EleutherAI | GPT-Neo-125M | 30.55% | 31.43% | 61.75% | 300B |
| joelhenwang | **OdinNext-138M-Base** | **27.99%** | **34.31%** | **59.25%** | **101.6B** |


## What this model is good for

- Text continuation and completion in English.
- Research on compact recurrent / linear-attention LMs and fixed-state decoding.
- A base for instruction tuning, alignment, and context extension.

Do **not** use it for chat / instruction following (not tuned yet), safety-
sensitive generation, or benchmark claims without running your own evaluation.

## Usage

```bash
pip install "transformers>=4.46" torch safetensors
```

```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

repo = "joelhenwang/OdinNext-138M-Base"
revision = "main"  # EMA weights; pin a commit for reproducibility

device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = torch.float16 if device == "cuda" else torch.float32

tok = AutoTokenizer.from_pretrained(repo, revision=revision)
model = AutoModelForCausalLM.from_pretrained(
    repo, revision=revision, trust_remote_code=True, torch_dtype=dtype,
).to(device).eval()

prompt = "The discovery of penicillin"
inputs = tok(prompt, return_tensors="pt").to(device)
remaining = model.config.max_position_embeddings - inputs.input_ids.shape[1]
with torch.inference_mode():
    out = model.generate(
        **inputs,
        max_new_tokens=max(0, min(100, remaining)),
        do_sample=True, temperature=0.8, top_p=0.95, repetition_penalty=1.1,
        pad_token_id=tok.pad_token_id, use_cache=True,
    )
print(tok.decode(out[0], skip_special_tokens=True))
```

### Batching guidance

The recurrent scan does not apply an attention mask. For correct batched
generation: avoid left padding, prefer same-length prompts, and verify batched
output against single-sample output before relying on it. Single-prompt
generation is the safest path.

## Limitations

- **Base model only:** no instruction tuning, alignment, or chat template.
- **No safety training:** outputs can be biased, false, or incoherent.
- **Hard 2,048-token cap:** recurrent state is constant, but the released RoPE
  cache limits cumulative positions to 2,048.
- **`attention_mask` ignored** in the backbone; padding affects recurrent state.
- **English-focused;** multilingual / code ability is uncharacterized.
- **Benchmarks above** are zero-shot on our own harness and not perfectly
  comparable across tooling — run your own evaluation.

## Revisions

- `main`: EMA-shadowed weights (decay 0.999), recommended for evaluation.
- `live`: raw training weights at the same step.

Pin a commit hash rather than a moving branch for reproducible experiments.

## Citation

```bibtex
@misc{odinnext_138m_base_2026,
  title        = {OdinNext-138M-Base},
  author       = {Wang, Joel},
  year         = {2026},
  howpublished = {\url{https://huggingface.co/joelhenwang/OdinNext-138M-Base}},
  note         = {138M HGRN2 recurrent language-model base checkpoint}
}
```

## References

- Zhen Qin et al. **HGRN2: Gated Linear RNNs with State Expansion.** arXiv:2404.07904.
- Bowen Peng et al. **Efficient Pre-Training with Token Superposition.** arXiv:2605.06546.
- Chenze Shao et al. **Patch-Level Training for Large Language Models.** arXiv:2407.12665.
- Makoto Shing et al. **DiffusionBlocks: Block-wise Neural Network Training via Diffusion Interpretation.** arXiv:2506.14202.