| --- |
| language: en |
| license: mit |
| tags: |
| - tiny-llm |
| - tinystories |
| - from-scratch |
| - educational |
| - speculative-decoding |
| - dpo |
| datasets: |
| - roneneldan/TinyStories |
| pipeline_tag: text-generation |
| --- |
| |
| # tiny-llm β a 27M-parameter LLM built from scratch, end to end |
|
|
| A complete modern LLM pipeline built by hand as a learning mission β every |
| stage written from scratch in readable PyTorch (no HF Transformers, no |
| external tokenizer), trained on free Colab T4 and a Mac CPU. |
|
|
| **Pipeline:** own byte-level BPE tokenizer β pretraining β SFT (instruction |
| following) β DPO (preference alignment) β distilled draft model + speculative |
| decoding β RAG with copy-tuning β this release. |
|
|
| ## Sizes |
|
|
| | File | Model | Params | What it is | |
| |------|-------|-------:|------------| |
| | `dpo-m4c.pt` | main | **27.0M** (dim 512, 8 layers, 8 heads, vocab 4096, ctx 512) | pretrained β SFT β DPO story-writer | |
| | `rag-m6.pt` | RAG variant | 27.0M | same model copy-tuned to quote retrieved context faithfully | |
| | `draft-m5.pt` | draft | **1.28M** (dim 128, 4 layers) | distilled from the main model for speculative decoding (1.4Γ on CPU) | |
| | `tokenizer.json` | BPE | 4096 merges | byte-level BPE trained from scratch on TinyStories | |
|
|
| ## Training data |
|
|
| - **Only dataset:** [TinyStories](https://huggingface.co/datasets/roneneldan/TinyStories) |
| (synthetic children's stories, English). The validation file was deduplicated |
| against train (33% of it duplicated train stories) before any evaluation. |
| - SFT pairs: `"Write a story about X.\n\n" + story`, where X is strictly the |
| story's first-sentence subject appearing β₯2 times (data-quality lesson: |
| a noisier heuristic taught the model to ignore instructions). |
| - DPO pairs: chosen = human story, rejected = the SFT model's own sample. |
|
|
| ## Honest limitations |
|
|
| - Writes **only simple children's stories in English**. Nothing else. |
| - It does not know facts about the world, cannot do math, cannot chat in |
| Russian or any other language. |
| - Instruction following ("about X") works on ~7/10 held-out topics; very rare |
| words (e.g. "unicorn") may be ignored. |
| - The RAG variant only quotes from a supplied context line; without context it |
| invents. |
| - Trained on ~500M tokens of synthetic text at 27M params β a *toy*, roughly |
| 25,000Γ smaller than frontier models. Built for learning, not for use. |
|
|
| ## Usage |
|
|
| ```python |
| import torch |
| from model import TinyLLM, ModelConfig # model.py from this repo |
| from bpe import BPETokenizer # bpe.py from this repo |
| |
| tok = BPETokenizer.load("tokenizer.json") |
| ck = torch.load("dpo-m4c.pt", map_location="cpu") |
| m = TinyLLM(ModelConfig(**ck["cfg"])); m.load_state_dict(ck["model"]); m.eval() |
| |
| # IMPORTANT: encode word-by-word (the same word-cache encoding used in training) |
| import re |
| ids = [] |
| for w in re.findall(r"\S+\s*", "Write a story about dragon.\n\n"): |
| ids += tok.encode(w) |
| out = m.generate(torch.tensor([ids]), 120, temperature=0.7) |
| print(tok.decode(out[0].tolist())) |
| ``` |
|
|
| Speculative decoding (`speculative.py`) makes greedy generation ~1.4Γ faster |
| on CPU with byte-identical output; `rag.py` + `rag-corpus.txt` show the RAG |
| setup. |
|
|
| ## Validation |
|
|
| Every stage was gated by a frozen validation contract (18 assertions): |
| pretrain val loss 1.656 (β€2.3), instruction following judged blind 7/10, |
| DPO preferred blind in 90% of 20 pairs, speculative decoding exact on 20/20 |
| prompts at 1.40Γ, RAG answers contain the fact on 9/10 questions (0/10 |
| without retrieval). Fresh-context judges never saw the training code. |
|
|