Update README.md
Browse files
README.md
CHANGED
|
@@ -12,37 +12,19 @@ pipeline_tag: text-generation
|
|
| 12 |
library_name: pytorch
|
| 13 |
tags:
|
| 14 |
- text-generation
|
| 15 |
-
- text-generation-inference
|
| 16 |
- small-language-model
|
| 17 |
- slm
|
| 18 |
-
- tiny-lm
|
| 19 |
- from-scratch
|
| 20 |
-
- pretrained-from-scratch
|
| 21 |
- causal-lm
|
| 22 |
- decoder-only
|
| 23 |
- transformer
|
| 24 |
- gqa
|
| 25 |
-
- grouped-query-attention
|
| 26 |
- rope
|
| 27 |
-
- rotary-position-embeddings
|
| 28 |
- swiglu
|
| 29 |
-
-
|
| 30 |
-
- tied-embeddings
|
| 31 |
-
- muon-optimizer
|
| 32 |
-
- wsd-schedule
|
| 33 |
-
- warmup-stable-decay
|
| 34 |
- multi-token-prediction
|
| 35 |
-
- mtp
|
| 36 |
- triton
|
| 37 |
-
- torch
|
| 38 |
- pytorch
|
| 39 |
-
- bf16
|
| 40 |
-
- english
|
| 41 |
-
- baseline
|
| 42 |
-
- research
|
| 43 |
-
- test
|
| 44 |
-
- openweights
|
| 45 |
-
- apache-2.0
|
| 46 |
---
|
| 47 |
|
| 48 |
<div align="center">
|
|
@@ -89,6 +71,7 @@ tags:
|
|
| 89 |
| Vocabulary | 16,384 BPE |
|
| 90 |
| Layers | 16 |
|
| 91 |
| Heads | 12 Q · 6 KV (GQA) |
|
|
|
|
| 92 |
|
| 93 |
</td>
|
| 94 |
<td valign="top" width="50%">
|
|
@@ -123,7 +106,7 @@ Pragya is a from-scratch small language model project. Every layer, kernel, and
|
|
| 123 |
|
| 124 |
Concretely, this run was built to verify:
|
| 125 |
|
| 126 |
-
- **Numerical correctness** — fused Triton kernels (attention post-processing, QK-norm + RoPE, add + RMSNorm, MoE group-GEMMs) match an eager reference to bf16 tolerance.
|
| 127 |
- **Convergence stability** — no loss spikes, no diverging runs, no NaN gradients across 11,000 steps.
|
| 128 |
- **Schedule sensitivity** — a longer Warmup–Stable–Decay (WSD) tail produces a sharp, measurable drop in loss.
|
| 129 |
- **Data-budget sensitivity** — fewer unique tokens seen twice beats more unique tokens seen once, at fixed compute.
|
|
@@ -141,7 +124,9 @@ The model itself is disposable. The demonstration is not.
|
|
| 141 |
| **Total parameters** | ~27M |
|
| 142 |
| **Architecture** | Decoder-only transformer |
|
| 143 |
| **Layers** | 16 |
|
| 144 |
-
| **Attention** |
|
|
|
|
|
|
|
| 145 |
| **Hidden size** | 384 |
|
| 146 |
| **Head dimension** | 32 |
|
| 147 |
| **FFN** | SwiGLU (`ffn_mult = 8/3`) |
|
|
@@ -157,6 +142,49 @@ The model itself is disposable. The demonstration is not.
|
|
| 157 |
|
| 158 |
---
|
| 159 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
## Training
|
| 161 |
|
| 162 |
<table>
|
|
@@ -226,8 +254,6 @@ Two checkpoints from the same training stack. Same model, same compute budget pe
|
|
| 226 |
|
| 227 |
### Difference table
|
| 228 |
|
| 229 |
-
What changed between test2 and test3, at a glance:
|
| 230 |
-
|
| 231 |
| | test2 | test3 | Δ | Direction |
|
| 232 |
|:---|:---:|:---:|:---:|:---:|
|
| 233 |
| **Backbone (non-embedding)** | 21.25M | 21.25M | 0 | = identical |
|
|
@@ -332,7 +358,7 @@ At this size, tight sampling matters more than usual — the model has very litt
|
|
| 332 |
```
|
| 333 |
pragya.pt ← checkpoint (state_dict + config)
|
| 334 |
tokenizer/tokenizer.pkl ← pickled tiktoken Encoding (vocab 16,384)
|
| 335 |
-
model.py ← GPT architecture (GPT / GPTConfig)
|
| 336 |
inference.py ← generate(), load_model(), sampling helpers
|
| 337 |
```
|
| 338 |
|
|
@@ -376,7 +402,7 @@ print(texts[0])
|
|
| 376 |
|
| 377 |
`inference.py` handles checkpoint loading, KV-cached generation, the sampling stack (top-k / top-p / repetition penalty / no-repeat n-grams), and streaming output.
|
| 378 |
|
| 379 |
-
`model.py` contains the full architecture — no external dependencies beyond PyTorch and the tokenizer.
|
| 380 |
|
| 381 |
---
|
| 382 |
|
|
@@ -392,6 +418,12 @@ print(texts[0])
|
|
| 392 |
|
| 393 |
## FAQ
|
| 394 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 395 |
<details>
|
| 396 |
<summary><b>Can I load this with <code>AutoModelForCausalLM.from_pretrained</code>?</b></summary>
|
| 397 |
|
|
@@ -430,7 +462,7 @@ If you use this checkpoint in research, please link to this repository. There is
|
|
| 430 |
|
| 431 |
```bibtex
|
| 432 |
@misc{pragya-test3,
|
| 433 |
-
title = {Pragya test3: a 27M from-scratch decoder-only language model},
|
| 434 |
author = {Arush Kumar},
|
| 435 |
year = {2026},
|
| 436 |
note = {Test checkpoint, not for production use},
|
|
|
|
| 12 |
library_name: pytorch
|
| 13 |
tags:
|
| 14 |
- text-generation
|
|
|
|
| 15 |
- small-language-model
|
| 16 |
- slm
|
|
|
|
| 17 |
- from-scratch
|
|
|
|
| 18 |
- causal-lm
|
| 19 |
- decoder-only
|
| 20 |
- transformer
|
| 21 |
- gqa
|
|
|
|
| 22 |
- rope
|
|
|
|
| 23 |
- swiglu
|
| 24 |
+
- exclusive-gated-attention
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
- multi-token-prediction
|
|
|
|
| 26 |
- triton
|
|
|
|
| 27 |
- pytorch
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
---
|
| 29 |
|
| 30 |
<div align="center">
|
|
|
|
| 71 |
| Vocabulary | 16,384 BPE |
|
| 72 |
| Layers | 16 |
|
| 73 |
| Heads | 12 Q · 6 KV (GQA) |
|
| 74 |
+
| Attention | **Exclusive Gated** |
|
| 75 |
|
| 76 |
</td>
|
| 77 |
<td valign="top" width="50%">
|
|
|
|
| 106 |
|
| 107 |
Concretely, this run was built to verify:
|
| 108 |
|
| 109 |
+
- **Numerical correctness** — fused Triton kernels (exclusive gated attention post-processing, QK-norm + RoPE, add + RMSNorm, MoE group-GEMMs) match an eager reference to bf16 tolerance.
|
| 110 |
- **Convergence stability** — no loss spikes, no diverging runs, no NaN gradients across 11,000 steps.
|
| 111 |
- **Schedule sensitivity** — a longer Warmup–Stable–Decay (WSD) tail produces a sharp, measurable drop in loss.
|
| 112 |
- **Data-budget sensitivity** — fewer unique tokens seen twice beats more unique tokens seen once, at fixed compute.
|
|
|
|
| 124 |
| **Total parameters** | ~27M |
|
| 125 |
| **Architecture** | Decoder-only transformer |
|
| 126 |
| **Layers** | 16 |
|
| 127 |
+
| **Attention** | Exclusive Gated Attention |
|
| 128 |
+
| **Query heads** | 12 |
|
| 129 |
+
| **Key/value heads** | 6 (GQA) |
|
| 130 |
| **Hidden size** | 384 |
|
| 131 |
| **Head dimension** | 32 |
|
| 132 |
| **FFN** | SwiGLU (`ffn_mult = 8/3`) |
|
|
|
|
| 142 |
|
| 143 |
---
|
| 144 |
|
| 145 |
+
## Attention: Exclusive Gated Attention
|
| 146 |
+
|
| 147 |
+
The model uses **Exclusive Gated Attention** — a composition of two per-head gating operations, both always on, both zero-initialized to identity at step 0, applied to the SDPA output before the output projection.
|
| 148 |
+
|
| 149 |
+
### What it is
|
| 150 |
+
|
| 151 |
+
Standard multi-head attention computes `context = softmax(QKᵀ/√d)·V` and projects it. This model inserts two additional operations between the attention output and the output projection:
|
| 152 |
+
|
| 153 |
+
**1. Gated Attention (Qiu et al., NeurIPS 2025)**
|
| 154 |
+
|
| 155 |
+
A per-head sigmoid gate modulates the attention output. The gate reads a small window of the block's *input* (the first 16 hidden dims), producing one scalar per head:
|
| 156 |
+
|
| 157 |
+
```
|
| 158 |
+
gate = 2 · sigmoid(W_gate · x[:16])
|
| 159 |
+
context = context · gate
|
| 160 |
+
```
|
| 161 |
+
|
| 162 |
+
The `2 · sigmoid(·)` form means `gate = 1.0` at `W_gate = 0`, so a zero-initialized projection gives an exact identity op at step 0 — the head's output is passed through unmodified. Over training, each head learns to suppress (gate → 0) or amplify (gate → 2) its own contribution.
|
| 163 |
+
|
| 164 |
+
**2. Exclusive Self-Attention (XSA)**
|
| 165 |
+
|
| 166 |
+
After the gate, the model subtracts a scaled projection of the *self-value direction* from the context. This removes the component of the attention output that is just a copy of the value vector itself — "exclusive" because it excludes self-information:
|
| 167 |
+
|
| 168 |
+
```
|
| 169 |
+
v_unit = v / ‖v‖
|
| 170 |
+
proj_coeff = (context · v_unit)
|
| 171 |
+
correction = tanh(α) · proj_coeff · v_unit
|
| 172 |
+
context = context − correction
|
| 173 |
+
```
|
| 174 |
+
|
| 175 |
+
`α` is a per-head learnable scalar, zero-initialized, so `tanh(α) = 0` at step 0 → identity. Each head learns how much (if any) self-value component to remove. **Position 0 is masked off** — at position 0, causal attention only sees itself, so subtracting the self component would remove 100% of the signal. The correction is zeroed at that position.
|
| 176 |
+
|
| 177 |
+
### Why it matters at this scale
|
| 178 |
+
|
| 179 |
+
Both gates are **zero-init to identity** — the model starts as vanilla attention and learns the gates incrementally. This avoids the training instability you'd get from random-initialized multiplicative gates at 21M parameters. The composite effect is that each head independently learns:
|
| 180 |
+
|
| 181 |
+
- **How loud to be** (gate magnitude, 0 to 2×)
|
| 182 |
+
- **How much of its output is redundant self-information** (XSA coefficient, −1 to +1)
|
| 183 |
+
|
| 184 |
+
Both operations are fused into a single Triton kernel (`_attn_post_fwd_kernel` / `_attn_post_bwd_kernel`), so the effective cost over vanilla attention is roughly one extra elementwise pass over the context tensor, plus a small reduction.
|
| 185 |
+
|
| 186 |
+
---
|
| 187 |
+
|
| 188 |
## Training
|
| 189 |
|
| 190 |
<table>
|
|
|
|
| 254 |
|
| 255 |
### Difference table
|
| 256 |
|
|
|
|
|
|
|
| 257 |
| | test2 | test3 | Δ | Direction |
|
| 258 |
|:---|:---:|:---:|:---:|:---:|
|
| 259 |
| **Backbone (non-embedding)** | 21.25M | 21.25M | 0 | = identical |
|
|
|
|
| 358 |
```
|
| 359 |
pragya.pt ← checkpoint (state_dict + config)
|
| 360 |
tokenizer/tokenizer.pkl ← pickled tiktoken Encoding (vocab 16,384)
|
| 361 |
+
model.py ← GPT architecture (GPT / GPTConfig) + Exclusive Gated Attention
|
| 362 |
inference.py ← generate(), load_model(), sampling helpers
|
| 363 |
```
|
| 364 |
|
|
|
|
| 402 |
|
| 403 |
`inference.py` handles checkpoint loading, KV-cached generation, the sampling stack (top-k / top-p / repetition penalty / no-repeat n-grams), and streaming output.
|
| 404 |
|
| 405 |
+
`model.py` contains the full architecture — including the fused Exclusive Gated Attention implementation — with no external dependencies beyond PyTorch and the tokenizer.
|
| 406 |
|
| 407 |
---
|
| 408 |
|
|
|
|
| 418 |
|
| 419 |
## FAQ
|
| 420 |
|
| 421 |
+
<details>
|
| 422 |
+
<summary><b>What is Exclusive Gated Attention?</b></summary>
|
| 423 |
+
|
| 424 |
+
A composition of two per-head gates applied to the attention output: a **sigmoid gate** that scales each head's output (Qiu et al., NeurIPS 2025), and a **subtractive self-projection** that removes the component of the output that is just a copy of the value vector (Exclusive Self-Attention, XSA). Both gates are zero-initialized to identity, so the model starts as vanilla attention and learns the gates during training. See [Attention](#attention-exclusive-gated-attention) for the full explanation.
|
| 425 |
+
</details>
|
| 426 |
+
|
| 427 |
<details>
|
| 428 |
<summary><b>Can I load this with <code>AutoModelForCausalLM.from_pretrained</code>?</b></summary>
|
| 429 |
|
|
|
|
| 462 |
|
| 463 |
```bibtex
|
| 464 |
@misc{pragya-test3,
|
| 465 |
+
title = {Pragya test3: a 27M from-scratch decoder-only language model with Exclusive Gated Attention},
|
| 466 |
author = {Arush Kumar},
|
| 467 |
year = {2026},
|
| 468 |
note = {Test checkpoint, not for production use},
|