Text Generation
Transformers
Safetensors
English
odinnext
hgrn2
linear-attention
recurrent
causal-lm
custom_code
base-model
fp16
amd
rocm
Instructions to use joelhenwang/OdinNext-138M-Base with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use joelhenwang/OdinNext-138M-Base with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="joelhenwang/OdinNext-138M-Base", trust_remote_code=True)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("joelhenwang/OdinNext-138M-Base", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use joelhenwang/OdinNext-138M-Base with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "joelhenwang/OdinNext-138M-Base" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "joelhenwang/OdinNext-138M-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/joelhenwang/OdinNext-138M-Base
- SGLang
How to use joelhenwang/OdinNext-138M-Base with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "joelhenwang/OdinNext-138M-Base" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "joelhenwang/OdinNext-138M-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "joelhenwang/OdinNext-138M-Base" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "joelhenwang/OdinNext-138M-Base", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use joelhenwang/OdinNext-138M-Base with Docker Model Runner:
docker model run hf.co/joelhenwang/OdinNext-138M-Base
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.
|