ZeroToGPT-134M

A 134M-parameter decoder-only transformer, written from scratch in PyTorch and pretrained on FineWeb-Edu on a single free-tier notebook GPU.

This is a learning-scale research artifact, not a useful assistant. It has no instruction tuning, no alignment, and it saw roughly 1.2B tokens, which is about 1% of what a modern small model gets. It writes locally fluent English and is frequently wrong about facts. It is published because the training code, the run logs, and a full audit of its own flaws are published with it.

Code, audit, and reproduction instructions: https://github.com/umer-ateeq/GPT-Pretraining

Architecture

Component Choice
Type decoder-only transformer, GPT-2 style
Parameters 134,077,440 trainable (+524,288 causal-mask buffers)
Layers 8
Attention heads 12 (head dim 64)
Model width 768
FFN 4x expansion, ReLU
Normalization custom LayerNorm with learned scale/shift, pre-norm
Positional encoding learned embeddings
Vocabulary 50257, GPT-2 BPE via tiktoken
Output head untied from the input embedding
Context length 256 configured, 128 actually trained (see below)

Every row above was recovered from the checkpoint's tensor shapes by audit_checkpoint.py, not copied from a config file.

Read this before evaluating it: the context is 128, not 256

The config says 256. The model was trained at 128 because a notebook cell rebound the globals the batch sampler read. The positional embedding table proves it: rows 0-127 have mean norm 0.2175, rows 128-255 have mean norm 0.002346, a 93x cliff exactly at the boundary, because untrained rows received no gradient and were decayed toward zero by AdamW weight decay.

Evaluate and generate at context 128. At 256 you are scoring the model on positional rows it has never seen, and perplexity roughly doubles as a result. The full story, with four bugs and the proof for each, is in AUDIT.md.

Training

Corpus FineWeb-Edu, CC-MAIN-2024-10, tokenized to an 8B-token uint16 memmap
Tokens seen ~1.23B (300 cycles x 1000 batches x 32 rows x 128 tokens), sampled as random windows
Batch 32 rows x 128 tokens, with gradient accumulation
Optimizer AdamW, lr 4e-4 flat, weight decay 0.1
Precision mixed precision (fp16 autocast)
Hardware a single free-tier notebook GPU (16 GB)

The learning rate was flat, not cosine-decayed. The notebook built a warmup plus cosine schedule but bound it to an optimizer it then discarded, so the schedule never reached the weights. This is Bug 2 in the audit. The train.py in the repo implements warmup and cosine decay correctly and logs the per-step learning rate, but this checkpoint predates it.

Evaluation

Perplexity via the standard strided sliding window, overlap tokens masked out of the loss so nothing is double counted. Reproduce any row with the command next to it.

Benchmark Context Perplexity Command
FineWeb-Edu held out, CC-MAIN-2024-18 128 38.89 python evaluate.py --ckpt weights8b_300epoch.pth --data-bin val.bin --context 128
FineWeb-Edu held out, CC-MAIN-2024-18 256 74.70 same, --context 256. Outside the trained regime
TinyStories validation 128 35.41 python evaluate.py --ckpt ... --data-bin tinystories_val.bin --context 128
WikiText-2 raw test, full 128 184.96 python eval_wikitext.py --ckpt weights8b_300epoch.pth --max-length 128
WikiText-2, GPT-2-small on the identical harness 128 59.69 python eval_wikitext.py --model gpt2 --max-length 128

The held-out set is a different Common Crawl snapshot than the training data: distribution-matched but fully disjoint.

This model is 3.10x worse than GPT-2-small on WikiText-2, measured by pushing GPT-2-small through the identical scoring function on the same 285,396 tokens. That is the expected outcome: GPT-2-small saw roughly 8B tokens of WebText against this model's 1.23B of filtered educational web text, and WikiText-2 is encyclopedic prose far from FineWeb-Edu. The same comparison validates the harness, since GPT-2-small's published ~29.4 at context 1024 degrading to 59.69 at context 128 is the right direction and magnitude. Full detail in RESULTS.md.

Usage

import tiktoken, torch
from model import GPTModel   # from the GitHub repo, also uploaded here

CONFIG = {"vocab_size": 50257, "context_length": 256, "emb_dim": 768,
          "n_heads": 12, "n_layers": 8, "drop_rate": 0.1, "qkv_bias": False}

model = GPTModel(CONFIG)
model.load_state_dict(torch.load("weights8b_300epoch.pth", map_location="cpu",
                                 weights_only=True))
model.eval()

enc = tiktoken.get_encoding("gpt2")
ids = torch.tensor([enc.encode_ordinary("Photosynthesis is the process by which")])

with torch.no_grad():
    for _ in range(50):
        logits = model(ids[:, -128:])[:, -1, :] / 0.8   # keep within trained context
        kth = logits.topk(50).values[:, -1:]
        logits = logits.masked_fill(logits < kth, -float("inf"))
        ids = torch.cat([ids, torch.multinomial(torch.softmax(logits, -1), 1)], dim=1)

print(enc.decode(ids[0].tolist()))

Or use the repo's script, which handles the context window for you:

python generate.py --ckpt weights8b_300epoch.pth --prompt "Photosynthesis is"

Limitations and intended use

  • Not an assistant. No instruction tuning, no RLHF, no safety tuning. It completes text and nothing else.
  • Undertrained. ~1.23B tokens at 134M parameters is far below compute-optimal. Expect confident factual errors.
  • 128-token effective context. Longer prompts silently degrade.
  • Inherits FineWeb-Edu's biases. The corpus is filtered educational web text, English only, and carries whatever biases the filtering left behind.
  • Intended use: studying transformer pretraining, reproducing the training pipeline, and as a baseline for the architecture ablations described in the repo's ABLATIONS.md.

Attribution

Model code started from Sebastian Raschka's Build a Large Language Model (From Scratch). Memory-mapped data loading and parts of the training loop follow Andrej Karpathy's nanoGPT. Training data is FineWeb-Edu.

Citation

@misc{siddiqui2026zerotogpt,
  author = {Umer Ateeq Siddiqui},
  title  = {ZeroToGPT-134M: pretraining a GPT from scratch on a free-tier GPU,
            with a full audit of the run},
  year   = {2026},
  url    = {https://github.com/umer-ateeq/GPT-Pretraining}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train umerateeq/zerotogpt-134m