--- license: apache-2.0 pipeline_tag: text-generation language: en tags: - tiny - tiny-lm - tiny-model - slm - small-language-model - from-scratch - tinystories - bpe - gpt datasets: - roneneldan/TinyStories metrics: - perplexity --- # TinyStories-24m A **24.59M-parameter** BPE language model trained **from scratch** on [roneneldan/TinyStories](https://huggingface.co/datasets/roneneldan/TinyStories), producing coherent short stories with proper dialogue, names, punctuation and narrative flow. ## What it is - **Architecture:** decoder-only GPT, weight-tied embeddings, RMSNorm, fused qkv multi-head causal attention (SDPA), GELU FFN. - **Shape:** D=384, L=12 layers, H=8 heads, FFN=1536, SEQ=512, vocab=8192 (BPE). - **Params:** 24,585,600 (verified against the safetensors header). - **Data:** roneneldan/TinyStories — 447.8M train tokens, 2M held-out val. - **Training:** 1 epoch ≈ 13,600 steps, AdamW, cosine LR 6e-4 + 500 warmup, bf16 autocast, on a single RTX 5090. ## Quality - **Val perplexity:** 8.76 (2.1618 nats/token on the 2M held-out val set). - **Generation:** coherent. Sampled 9/9 seeded generations (3 seeds × 3 prompts) produce proper dialogue, character names (Ben, Lily, Mom, Tom, Sarah, Max), punctuation and narrative flow. This model is a story generator for its training domain — it is **not** a general-purpose assistant and will not answer questions it was not trained on. ## Honest caveats - **Divergence:** the full 13,600-step run diverged to NaN at step 9,350 (LR 6e-4 is too hot for a 24M model). The **best** checkpoint (step 6,000, val 2.1618) is what is published here — it is clean and coherent. The divergence is late, so a clean early checkpoint is the right artifact; always sample the best checkpoint, not the final one. - **Domain-bound:** trained only on TinyStories. Out-of-domain text (code, questions, general conversation) is out of scope. ## Usage Not a `transformers` model — load with the bundled `modeling.py`: ```python import sys, torch sys.path.insert(0, "path/to/this/repo") from modeling import TinyStoriesGPT from tokenizers import Tokenizer m = TinyStoriesGPT.from_pretrained("path/to/this/repo", device="cpu") tok = Tokenizer.from_file("path/to/this/repo/tokenizer.json") ids = tok.encode("Ben was playing in the park.", add_special_tokens=False).ids x = torch.tensor([ids], dtype=torch.long) with torch.no_grad(): for _ in range(80): logits = m(x[:, -512:])[:, -1] nxt = torch.multinomial(torch.softmax(logits / 0.8, -1), 1).item() ids.append(nxt) x = torch.tensor([ids[-512:]], dtype=torch.long) print(tok.decode(ids, skip_special_tokens=True)) ``` ## Files | file | bytes | what | |------|-------|------| | `model.safetensors` | 98,349,056 | 75 tensors, float32 | | `config.json` | — | architecture + training metadata | | `modeling.py` | — | the `TinyStoriesGPT` class (load with `from_pretrained`) | | `tokenizer.json` | 560,804 | BPE-8k tokenizer (HF `tokenizers` format) |