Pretraining a 0.5B model on one rented GPU

A 489M-parameter model trained from scratch on 4.2B tokens for $13.70, what it scores, and two things that did not work.

I trained a 489M-parameter Llama-style model from scratch on a single rented RTX 5090. The run is finished: three phases, 4.19 billion tokens, $13.70 of GPU time. This post covers what I built, how it scores, and two things I tried that did not work.

The final weights are on the Hub as osjayaprakash/llm-0.5b-fineweb-edu, under MIT. It loads as a plain LlamaForCausalLM, so nothing custom is needed to run it.

The setup

The model is a standard decoder-only transformer, written in plain PyTorch:

Parameters
489.3M (448.3M excluding embeddings)
Layers and width
24 layers, d_model 1280
Attention
Grouped-query, 20 query heads sharing 4 key/value heads
Feed-forward
SwiGLU, d_ff 3840
Normalization and positions
Pre-norm RMSNorm, RoPE
Vocabulary
32,000-token byte-level BPE, trained on the same corpus
Context
2048 tokens
Batch
524,288 tokens per step

The training data is 2.03B tokens of FineWeb-Edu, with 50M held out for validation. The GPU was a 32 GB RTX 5090 rented on Vast.ai at $0.479 an hour. It trained at 48,000 tokens a second, about 85% of the card’s theoretical peak.

Results

  Phase 1 Phase 2 Phase 3
Training tokens 1.05B 2.10B 4.19B
Validation loss 3.323 3.139 2.998
Zero-shot average, 9 tasks 0.412 0.433 0.445
MMLU, 5-shot   0.254 0.272
Wall clock 6.4 h 6.4 h 12.2 h

Each doubling of the tokens paid, and each paid a little less than the one before. The first took validation loss down 0.18 and average accuracy up 2 points; the second, 0.14 and 1.2 points. Neither curve has bent toward a floor. At 4.2B tokens the model has seen about 8.5 tokens per parameter, still under half the Chinchilla-optimal ratio. Tokens were the limit from start to finish. I stopped because the budget ran out, not because the model stopped learning.

Validation loss against tokens Validation loss against training tokens, both axes logarithmic. The points fall on a near-straight line from 6.10 at 0.05B tokens to 2.998 at 4.19B, with a fitted slope of -0.106 over the second half. A straight line means the run is still in the power-law regime and has not begun to flatten. validation loss, log scale 3.0 3.5 4.0 4.5 5.0 5.5 6.0 50M 100M 500M 1B 2B 4B training tokens, log scale fitted slope -0.106 0.05B tokens: validation loss 6.1040 0.10B tokens: validation loss 5.3402 0.16B tokens: validation loss 4.7384 0.21B tokens: validation loss 4.3870 0.26B tokens: validation loss 4.1264 0.31B tokens: validation loss 3.9457 0.37B tokens: validation loss 3.8117 0.42B tokens: validation loss 3.7120 0.47B tokens: validation loss 3.6366 0.52B tokens: validation loss 3.5790 0.58B tokens: validation loss 3.5292 0.63B tokens: validation loss 3.4889 0.68B tokens: validation loss 3.4524 0.73B tokens: validation loss 3.4203 0.79B tokens: validation loss 3.3948 0.84B tokens: validation loss 3.3722 0.89B tokens: validation loss 3.3553 0.94B tokens: validation loss 3.3419 1.00B tokens: validation loss 3.3314 1.05B tokens: validation loss 3.3226 1.10B tokens: validation loss 3.3822 1.15B tokens: validation loss 3.3827 1.21B tokens: validation loss 3.3633 1.26B tokens: validation loss 3.3412 1.31B tokens: validation loss 3.3265 1.36B tokens: validation loss 3.3085 1.42B tokens: validation loss 3.2900 1.47B tokens: validation loss 3.2711 1.52B tokens: validation loss 3.2525 1.57B tokens: validation loss 3.2397 1.63B tokens: validation loss 3.2236 1.68B tokens: validation loss 3.2089 1.73B tokens: validation loss 3.1955 1.78B tokens: validation loss 3.1823 1.84B tokens: validation loss 3.1707 1.89B tokens: validation loss 3.1618 1.94B tokens: validation loss 3.1532 1.99B tokens: validation loss 3.1471 2.04B tokens: validation loss 3.1424 2.10B tokens: validation loss 3.1387 2.15B tokens: validation loss 3.1833 2.20B tokens: validation loss 3.1931 2.25B tokens: validation loss 3.1888 2.31B tokens: validation loss 3.1825 2.36B tokens: validation loss 3.1781 2.41B tokens: validation loss 3.1715 2.46B tokens: validation loss 3.1634 2.52B tokens: validation loss 3.1540 2.57B tokens: validation loss 3.1467 2.62B tokens: validation loss 3.1393 2.67B tokens: validation loss 3.1314 2.73B tokens: validation loss 3.1235 2.78B tokens: validation loss 3.1157 2.83B tokens: validation loss 3.1117 2.88B tokens: validation loss 3.1044 2.94B tokens: validation loss 3.0959 2.99B tokens: validation loss 3.0900 3.04B tokens: validation loss 3.0832 3.09B tokens: validation loss 3.0749 3.15B tokens: validation loss 3.0696 3.20B tokens: validation loss 3.0641 3.25B tokens: validation loss 3.0578 3.30B tokens: validation loss 3.0514 3.36B tokens: validation loss 3.0464 3.41B tokens: validation loss 3.0430 3.46B tokens: validation loss 3.0379 3.51B tokens: validation loss 3.0330 3.57B tokens: validation loss 3.0268 3.62B tokens: validation loss 3.0234 3.67B tokens: validation loss 3.0200 3.72B tokens: validation loss 3.0165 3.77B tokens: validation loss 3.0130 3.83B tokens: validation loss 3.0103 3.88B tokens: validation loss 3.0084 3.93B tokens: validation loss 3.0053 3.98B tokens: validation loss 3.0038 4.04B tokens: validation loss 3.0025 4.09B tokens: validation loss 3.0007 4.14B tokens: validation loss 2.9990 4.19B tokens: validation loss 2.9982 2.998
Validation loss against tokens with both axes logarithmic. A straight line here means the model is still in the regime where each doubling of data buys a fixed fraction of the remaining loss. Mine is still straight at the end, which is why I say the budget stopped the run rather than the model. Hover a point for its exact value.

Training was stable throughout: across all 8,000 steps there were no loss spikes and no non-finite gradients, and gradient clipping stopped triggering after step 540.

Throughput Training throughput across the run, median 48.4 thousand tokens per second at 85% model-FLOPs utilisation. The dips are benchmark evaluations sharing the GPU with training. thousand tokens per second 0 10 20 30 40 50 0% 25% 50% 75% 100% MFU 2000 4000 6000 8000 step Step 10: 46.9k tokens per second, 82.6% MFU Step 90: 41.1k tokens per second, 72.4% MFU Step 170: 48.1k tokens per second, 84.7% MFU Step 250: 48.3k tokens per second, 85.2% MFU Step 330: 39.1k tokens per second, 68.9% MFU Step 410: 48.3k tokens per second, 85.1% MFU Step 490: 48.3k tokens per second, 85.0% MFU Step 570: 36.5k tokens per second, 64.3% MFU Step 650: 48.3k tokens per second, 85.2% MFU Step 730: 48.4k tokens per second, 85.2% MFU Step 810: 48.4k tokens per second, 85.3% MFU Step 890: 48.3k tokens per second, 85.1% MFU Step 970: 48.3k tokens per second, 85.1% MFU Step 1050: 37.6k tokens per second, 66.3% MFU Step 1130: 48.4k tokens per second, 85.2% MFU Step 1210: 48.4k tokens per second, 85.2% MFU Step 1290: 48.3k tokens per second, 85.1% MFU Step 1370: 48.3k tokens per second, 85.1% MFU Step 1450: 48.3k tokens per second, 85.1% MFU Step 1530: 48.2k tokens per second, 84.8% MFU Step 1610: 48.5k tokens per second, 85.4% MFU Step 1690: 48.5k tokens per second, 85.4% MFU Step 1770: 48.3k tokens per second, 85.2% MFU Step 1850: 48.3k tokens per second, 85.1% MFU Step 1930: 48.4k tokens per second, 85.3% MFU Step 2010: 46.4k tokens per second, 81.8% MFU Step 2090: 48.4k tokens per second, 85.3% MFU Step 2170: 48.5k tokens per second, 85.5% MFU Step 2250: 37.3k tokens per second, 65.8% MFU Step 2330: 38.5k tokens per second, 67.8% MFU Step 2410: 38.1k tokens per second, 67.1% MFU Step 2490: 38.0k tokens per second, 67.0% MFU Step 2570: 36.5k tokens per second, 64.3% MFU Step 2650: 35.7k tokens per second, 62.9% MFU Step 2730: 48.5k tokens per second, 85.5% MFU Step 2810: 48.6k tokens per second, 85.5% MFU Step 2890: 48.4k tokens per second, 85.3% MFU Step 2970: 48.5k tokens per second, 85.4% MFU Step 3050: 48.5k tokens per second, 85.4% MFU Step 3130: 48.5k tokens per second, 85.5% MFU Step 3210: 48.6k tokens per second, 85.5% MFU Step 3290: 48.5k tokens per second, 85.5% MFU Step 3370: 48.5k tokens per second, 85.4% MFU Step 3450: 48.4k tokens per second, 85.3% MFU Step 3530: 48.5k tokens per second, 85.5% MFU Step 3610: 48.6k tokens per second, 85.6% MFU Step 3690: 48.6k tokens per second, 85.5% MFU Step 3770: 48.5k tokens per second, 85.4% MFU Step 3850: 48.4k tokens per second, 85.3% MFU Step 3930: 48.6k tokens per second, 85.6% MFU Step 4010: 46.2k tokens per second, 81.3% MFU Step 4090: 48.5k tokens per second, 85.4% MFU Step 4170: 48.6k tokens per second, 85.5% MFU Step 4250: 48.5k tokens per second, 85.5% MFU Step 4330: 48.6k tokens per second, 85.5% MFU Step 4410: 48.5k tokens per second, 85.4% MFU Step 4490: 48.5k tokens per second, 85.4% MFU Step 4570: 48.6k tokens per second, 85.6% MFU Step 4650: 48.5k tokens per second, 85.5% MFU Step 4730: 48.6k tokens per second, 85.6% MFU Step 4810: 48.6k tokens per second, 85.6% MFU Step 4890: 48.5k tokens per second, 85.4% MFU Step 4970: 48.5k tokens per second, 85.4% MFU Step 5050: 48.5k tokens per second, 85.5% MFU Step 5130: 48.6k tokens per second, 85.6% MFU Step 5210: 48.5k tokens per second, 85.4% MFU Step 5290: 48.5k tokens per second, 85.4% MFU Step 5370: 48.4k tokens per second, 85.2% MFU Step 5450: 48.3k tokens per second, 85.1% MFU Step 5530: 48.5k tokens per second, 85.4% MFU Step 5610: 48.4k tokens per second, 85.3% MFU Step 5690: 48.4k tokens per second, 85.3% MFU Step 5770: 48.4k tokens per second, 85.3% MFU Step 5850: 48.3k tokens per second, 85.1% MFU Step 5930: 48.3k tokens per second, 85.1% MFU Step 6010: 48.5k tokens per second, 85.4% MFU Step 6090: 48.4k tokens per second, 85.2% MFU Step 6170: 48.4k tokens per second, 85.3% MFU Step 6250: 48.3k tokens per second, 85.2% MFU Step 6330: 48.3k tokens per second, 85.0% MFU Step 6410: 48.3k tokens per second, 85.0% MFU Step 6490: 48.4k tokens per second, 85.2% MFU Step 6570: 48.3k tokens per second, 85.2% MFU Step 6650: 48.3k tokens per second, 85.1% MFU Step 6730: 48.4k tokens per second, 85.3% MFU Step 6810: 48.3k tokens per second, 85.1% MFU Step 6890: 48.3k tokens per second, 85.1% MFU Step 6970: 48.4k tokens per second, 85.3% MFU Step 7050: 48.4k tokens per second, 85.2% MFU Step 7130: 48.4k tokens per second, 85.2% MFU Step 7210: 48.4k tokens per second, 85.3% MFU Step 7290: 48.3k tokens per second, 85.1% MFU Step 7370: 48.2k tokens per second, 84.9% MFU Step 7450: 48.2k tokens per second, 84.9% MFU Step 7530: 48.3k tokens per second, 85.0% MFU Step 7610: 48.3k tokens per second, 85.0% MFU Step 7690: 48.2k tokens per second, 85.0% MFU Step 7770: 48.1k tokens per second, 84.8% MFU Step 7850: 48.1k tokens per second, 84.7% MFU Step 7930: 48.2k tokens per second, 85.0% MFU
Throughput and model-FLOPs utilisation over the run. It held 48,000 tokens a second at 85% of the card's theoretical peak from the first step to the last. The dips are benchmark runs sharing the GPU with training, which is the price of measuring as you go.

Against public models

I ran every model through the same lm-evaluation-harness tasks on the same machine. Before evaluating my checkpoints, I converted them to the Hugging Face Llama format and confirmed the converted model gives the same outputs as the original.

  • My model, at each checkpoint
  • Pythia-410M
  • Other public models
Accuracy against training tokens Average accuracy against training tokens on a log scale. My model climbs from 0.328 at 262M tokens to 0.445 at 4.2B. Pythia-410M scores 0.348 at 2.1B tokens and 0.493 at 300B. Pythia-1B scores 0.298 at 1.07B. SmolLM2-360M scores 0.587 at 4T tokens and Qwen2.5-0.5B 0.565 at 18T. average zero-shot accuracy, 9 tasks 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 100M 1B 10B 100B 1T 10T training tokens, log scale Pythia-410M, 1.07B tokens: 0.299 Pythia-410M, 2.1B tokens: 0.348 Pythia-410M, 300B tokens: 0.493 My model, 0.26B tokens: 0.328 My model, 0.52B tokens: 0.393 My model, 0.79B tokens: 0.404 My model, 1.05B tokens: 0.412 My model, 2.10B tokens: 0.433 My model, 4.19B tokens: 0.445 Pythia-1B, 1.07B tokens: 0.298 Pythia-1B SmolLM2-360M, 4000B tokens: 0.587 SmolLM2-360M Qwen2.5-0.5B, 18000B tokens: 0.565 Qwen2.5-0.5B Mine, 4.2B: 0.445 Pythia-410M, 2.1B: 0.348 Pythia-410M, 300B: 0.493
Average zero-shot accuracy on nine tasks against training tokens, on a log scale. Pythia-410M was only measured at the three points shown; the dotted line just joins them. At 1.07B tokens, Pythia-1B and Pythia-410M score almost the same (0.298 and 0.299), so their dots overlap.
Every model compared Average zero-shot accuracy for every model measured, sorted low to high. My checkpoints are the filled bars: 0.412 at 1.05B tokens, 0.433 at 2.10B and 0.445 at 4.19B, with the weight-averaged version just behind at 0.443. Pythia-410M scores 0.348 at a matched 2.1B tokens and 0.493 fully trained; SmolLM2-360M leads at 0.587. average zero-shot accuracy, 9 tasks 0.0 0.2 0.4 0.6 Pythia-1B, 1.07B tokens: 0.298 0.298 Pythia 1B, 1.07B Pythia-410M, 1.07B tokens: 0.299 0.299 Pythia 410M, 1.07B Pythia-410M, 2.1B tokens: 0.348 0.348 Pythia 410M, 2.1B Mine, 1.05B tokens: 0.412 0.412 Mine 1.05B Mine, 2.10B tokens: 0.433 0.433 Mine 2.10B Mine, EMA, 4.19B tokens: 0.443 0.443 Mine, EMA 4.19B Mine, 4.19B tokens: 0.445 0.445 Mine 4.19B Pythia-410M, 300B tokens: 0.493 0.493 Pythia 410M, 300B Qwen2.5-0.5B, 18T tokens: 0.565 0.565 Qwen2.5 0.5B, 18T SmolLM2-360M, 4T tokens: 0.587 0.587 SmolLM2 360M, 4T
Every model I measured, sorted by score. Filled bars are mine. The gap between my best and the fully trained Pythia-410M is the cost of 72 times less data; the gap from there to SmolLM2 is mostly what data selection buys.
Show every task for every model
Model Tokens Avg LAMBADA SciQ ARC-Easy BoolQ PIQA OpenBookQA HellaSwag WinoGrande ARC-Challenge WikiText ppl
Mine 4.19B 0.445 0.230 0.660 0.458 0.621 0.628 0.312 0.326 0.502 0.265 42.1
Mine, weight-averaged 4.19B 0.443 0.228 0.655 0.460 0.621 0.631 0.312 0.321 0.495 0.265 42.5
Pythia-410M 1.07B 0.299 0.000 0.246 0.285 0.386 0.523 0.268 0.251 0.495 0.237 974.8
Pythia-1B 1.07B 0.297 0.000 0.261 0.294 0.379 0.522 0.268 0.252 0.493 0.208 598.1
Pythia-410M 2.1B 0.348 0.038 0.415 0.295 0.597 0.534 0.250 0.260 0.516 0.222 172.4
Pythia-410M 300B 0.493 0.479 0.735 0.458 0.598 0.675 0.300 0.406 0.538 0.247 20.8
SmolLM2-360M 4T 0.587 0.539 0.857 0.656 0.616 0.725 0.370 0.564 0.588 0.365 15.8
Qwen2.5-0.5B 18T 0.565 0.519 0.906 0.584 0.622 0.697 0.352 0.522 0.565 0.319 —

Qwen2.5-0.5B has no WikiText figure: its 152,000-token vocabulary ran out of GPU memory on that task’s long rolling windows while training was using the same card, so I re-ran it without WikiText rather than interrupt the run.

At a matched 2.1B tokens, my model scored 8.5 points above Pythia-410M. Finishing at 4.19B puts it 9.7 points above that checkpoint and 4.8 points behind the fully trained Pythia-410M, which saw 72 times as much data.

SmolLM2-360M beats Qwen2.5-0.5B with fewer parameters and less than a quarter of the tokens. That gap comes from how its training data was chosen and mixed. I haven’t worked on data selection at all yet, so it’s the most promising next step once tokens stop being the bottleneck.

On MMLU (5-shot) the model finished at 0.272, up from 0.254 at half the tokens. Chance is 0.25 on a four-way multiple choice, so this is the first sign of that kind of knowledge appearing, and not much more than a sign: social sciences carries it at 0.320 while humanities is still at chance. I leave MMLU out of the average.

Show MMLU by category
MMLU, 5-shot At 2.10B tokens At 4.19B tokens Change
All 57 subjects 0.254 0.272 +0.018
STEM 0.272 0.273 +0.002
Social sciences 0.256 0.320 +0.064
Other 0.260 0.258 -0.002
Humanities 0.236 0.248 +0.012
Chance 0.250 0.250  

Nearly all of the movement is in social sciences. The other three categories are still within a point or two of chance, which is what you would expect from a model this size trained on this little.

Restarting the learning-rate schedule has a cost

Each phase used a cosine schedule: warm the learning rate up, then decay it to a tenth of its peak. To continue after phase 1, I warmed the learning rate back up to 2e-4 and decayed it again.

Validation loss and learning rate Two panels sharing the training-token axis. Top: validation loss falls from 3.579 to 2.998 across 3 phases. Each restart pushes it back above the previous phase's final loss; the shaded wedges show those debts, costing 600, 1100 steps. Bottom: the learning rate, decayed and restarted once per phase. validation loss 3.0 3.1 3.2 3.3 3.4 3.5 3.6 600 steps to recover 1100 steps to recover phase 2 starts phase 3 starts Step 1000, 0.52B tokens: validation loss 3.5790 Step 1100, 0.58B tokens: validation loss 3.5292 Step 1200, 0.63B tokens: validation loss 3.4889 Step 1300, 0.68B tokens: validation loss 3.4524 Step 1400, 0.73B tokens: validation loss 3.4203 Step 1500, 0.79B tokens: validation loss 3.3948 Step 1600, 0.84B tokens: validation loss 3.3722 Step 1700, 0.89B tokens: validation loss 3.3553 Step 1800, 0.94B tokens: validation loss 3.3419 Step 1900, 1.00B tokens: validation loss 3.3314 Step 2000, 1.05B tokens: validation loss 3.3226 Step 2100, 1.10B tokens: validation loss 3.3822 Step 2200, 1.15B tokens: validation loss 3.3827 Step 2300, 1.21B tokens: validation loss 3.3633 Step 2400, 1.26B tokens: validation loss 3.3412 Step 2500, 1.31B tokens: validation loss 3.3265 Step 2600, 1.36B tokens: validation loss 3.3085 Step 2700, 1.42B tokens: validation loss 3.2900 Step 2800, 1.47B tokens: validation loss 3.2711 Step 2900, 1.52B tokens: validation loss 3.2525 Step 3000, 1.57B tokens: validation loss 3.2397 Step 3100, 1.63B tokens: validation loss 3.2236 Step 3200, 1.68B tokens: validation loss 3.2089 Step 3300, 1.73B tokens: validation loss 3.1955 Step 3400, 1.78B tokens: validation loss 3.1823 Step 3500, 1.84B tokens: validation loss 3.1707 Step 3600, 1.89B tokens: validation loss 3.1618 Step 3700, 1.94B tokens: validation loss 3.1532 Step 3800, 1.99B tokens: validation loss 3.1471 Step 3900, 2.04B tokens: validation loss 3.1424 Step 4000, 2.10B tokens: validation loss 3.1387 Step 4100, 2.15B tokens: validation loss 3.1833 Step 4200, 2.20B tokens: validation loss 3.1931 Step 4300, 2.25B tokens: validation loss 3.1888 Step 4400, 2.31B tokens: validation loss 3.1825 Step 4500, 2.36B tokens: validation loss 3.1781 Step 4600, 2.41B tokens: validation loss 3.1715 Step 4700, 2.46B tokens: validation loss 3.1634 Step 4800, 2.52B tokens: validation loss 3.1540 Step 4900, 2.57B tokens: validation loss 3.1467 Step 5000, 2.62B tokens: validation loss 3.1393 Step 5100, 2.67B tokens: validation loss 3.1314 Step 5200, 2.73B tokens: validation loss 3.1235 Step 5300, 2.78B tokens: validation loss 3.1157 Step 5400, 2.83B tokens: validation loss 3.1117 Step 5500, 2.88B tokens: validation loss 3.1044 Step 5600, 2.94B tokens: validation loss 3.0959 Step 5700, 2.99B tokens: validation loss 3.0900 Step 5800, 3.04B tokens: validation loss 3.0832 Step 5900, 3.09B tokens: validation loss 3.0749 Step 6000, 3.15B tokens: validation loss 3.0696 Step 6100, 3.20B tokens: validation loss 3.0641 Step 6200, 3.25B tokens: validation loss 3.0578 Step 6300, 3.30B tokens: validation loss 3.0514 Step 6400, 3.36B tokens: validation loss 3.0464 Step 6500, 3.41B tokens: validation loss 3.0430 Step 6600, 3.46B tokens: validation loss 3.0379 Step 6700, 3.51B tokens: validation loss 3.0330 Step 6800, 3.57B tokens: validation loss 3.0268 Step 6900, 3.62B tokens: validation loss 3.0234 Step 7000, 3.67B tokens: validation loss 3.0200 Step 7100, 3.72B tokens: validation loss 3.0165 Step 7200, 3.77B tokens: validation loss 3.0130 Step 7300, 3.83B tokens: validation loss 3.0103 Step 7400, 3.88B tokens: validation loss 3.0084 Step 7500, 3.93B tokens: validation loss 3.0053 Step 7600, 3.98B tokens: validation loss 3.0038 Step 7700, 4.04B tokens: validation loss 3.0025 Step 7800, 4.09B tokens: validation loss 3.0007 Step 7900, 4.14B tokens: validation loss 2.9990 Step 8000, 4.19B tokens: validation loss 2.9982 3.323 3.139 2.998 learning rate 0 1e-4 2e-4 Step 960, 0.50B tokens: learning rate 1.98e-04 Step 1060, 0.56B tokens: learning rate 1.75e-04 Step 1160, 0.61B tokens: learning rate 1.51e-04 Step 1260, 0.66B tokens: learning rate 1.28e-04 Step 1360, 0.71B tokens: learning rate 1.06e-04 Step 1460, 0.77B tokens: learning rate 8.58e-05 Step 1560, 0.82B tokens: learning rate 6.81e-05 Step 1660, 0.87B tokens: learning rate 5.32e-05 Step 1760, 0.92B tokens: learning rate 4.18e-05 Step 1860, 0.98B tokens: learning rate 3.41e-05 Step 1960, 1.03B tokens: learning rate 3.03e-05 Step 2060, 1.08B tokens: learning rate 1.20e-04 Step 2160, 1.13B tokens: learning rate 2.00e-04 Step 2260, 1.18B tokens: learning rate 1.97e-04 Step 2360, 1.24B tokens: learning rate 1.92e-04 Step 2460, 1.29B tokens: learning rate 1.85e-04 Step 2560, 1.34B tokens: learning rate 1.75e-04 Step 2660, 1.39B tokens: learning rate 1.64e-04 Step 2760, 1.45B tokens: learning rate 1.52e-04 Step 2860, 1.50B tokens: learning rate 1.38e-04 Step 2960, 1.55B tokens: learning rate 1.23e-04 Step 3060, 1.60B tokens: learning rate 1.09e-04 Step 3160, 1.66B tokens: learning rate 9.39e-05 Step 3260, 1.71B tokens: learning rate 7.95e-05 Step 3360, 1.76B tokens: learning rate 6.60e-05 Step 3460, 1.81B tokens: learning rate 5.37e-05 Step 3560, 1.87B tokens: learning rate 4.29e-05 Step 3660, 1.92B tokens: learning rate 3.39e-05 Step 3760, 1.97B tokens: learning rate 2.71e-05 Step 3860, 2.02B tokens: learning rate 2.24e-05 Step 3960, 2.08B tokens: learning rate 2.02e-05 Step 4060, 2.13B tokens: learning rate 9.00e-05 Step 4160, 2.18B tokens: learning rate 1.50e-04 Step 4260, 2.23B tokens: learning rate 1.49e-04 Step 4360, 2.29B tokens: learning rate 1.48e-04 Step 4460, 2.34B tokens: learning rate 1.47e-04 Step 4560, 2.39B tokens: learning rate 1.45e-04 Step 4660, 2.44B tokens: learning rate 1.43e-04 Step 4760, 2.50B tokens: learning rate 1.40e-04 Step 4860, 2.55B tokens: learning rate 1.37e-04 Step 4960, 2.60B tokens: learning rate 1.34e-04 Step 5060, 2.65B tokens: learning rate 1.30e-04 Step 5160, 2.71B tokens: learning rate 1.26e-04 Step 5260, 2.76B tokens: learning rate 1.22e-04 Step 5360, 2.81B tokens: learning rate 1.17e-04 Step 5460, 2.86B tokens: learning rate 1.12e-04 Step 5560, 2.92B tokens: learning rate 1.07e-04 Step 5660, 2.97B tokens: learning rate 1.02e-04 Step 5760, 3.02B tokens: learning rate 9.63e-05 Step 5860, 3.07B tokens: learning rate 9.07e-05 Step 5960, 3.12B tokens: learning rate 8.51e-05 Step 6060, 3.18B tokens: learning rate 7.95e-05 Step 6160, 3.23B tokens: learning rate 7.39e-05 Step 6260, 3.28B tokens: learning rate 6.83e-05 Step 6360, 3.33B tokens: learning rate 6.28e-05 Step 6460, 3.39B tokens: learning rate 5.74e-05 Step 6560, 3.44B tokens: learning rate 5.21e-05 Step 6660, 3.49B tokens: learning rate 4.70e-05 Step 6760, 3.54B tokens: learning rate 4.22e-05 Step 6860, 3.60B tokens: learning rate 3.75e-05 Step 6960, 3.65B tokens: learning rate 3.32e-05 Step 7060, 3.70B tokens: learning rate 2.92e-05 Step 7160, 3.75B tokens: learning rate 2.55e-05 Step 7260, 3.81B tokens: learning rate 2.21e-05 Step 7360, 3.86B tokens: learning rate 1.91e-05 Step 7460, 3.91B tokens: learning rate 1.65e-05 Step 7560, 3.96B tokens: learning rate 1.44e-05 Step 7660, 4.02B tokens: learning rate 1.26e-05 Step 7760, 4.07B tokens: learning rate 1.13e-05 Step 7860, 4.12B tokens: learning rate 1.05e-05 Step 7960, 4.17B tokens: learning rate 1.00e-05 1B 2B 3B 4B training tokens
Validation loss from 0.5B tokens on, with the learning rate underneath on the same axis. The shaded areas are where each phase sits above the previous phase's final loss. Hover a point to see its exact value; on a phone, scroll the chart sideways.

Raising the learning rate on a model that had just been annealed undid part of that annealing. Validation loss rose from 3.323 to 3.383 and took 600 steps to get back below 3.323, about a third of phase 2. The shaded areas in the chart are that cost.

Phase 3 repeated it and showed what governs the size of the bill. It rose from 3.139 to 3.193, then needed 1,100 steps to recover, nearly twice phase 2’s 600. The restart itself wasn’t worse; phase 3’s cosine simply runs over 4,000 steps instead of 2,000, so it holds the learning rate near its peak for twice as long. The cost tracks how long the schedule stays hot, not the act of restarting.

Both phases finished well ahead, so both restarts were worth doing. But together they spent 1,700 of the run’s 8,000 steps, 21% of the budget, re-earning ground already taken. A warmup-stable-decay schedule avoids this entirely: hold the learning rate constant and decay it only at the very end. It’s the better choice whenever the total training budget isn’t fixed in advance, which for me it usually isn’t.

What moved and what didn’t

  • My model
  • Pythia-410M after 300B tokens
  • Chance
  • LAMBADA 0.230

    LAMBADA accuracy LAMBADA accuracy rises from 0.021 at 262M tokens to 0.230 at 4.2B. Fully trained Pythia-410M scores 0.479. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Pythia-410M after 300B tokens: 0.479 LAMBADA, 0.26B tokens: 0.021 LAMBADA, 0.52B tokens: 0.107 LAMBADA, 0.79B tokens: 0.141 LAMBADA, 1.05B tokens: 0.151 LAMBADA, 2.10B tokens: 0.212 LAMBADA, 4.19B tokens: 0.230
  • SciQ 0.660

    SciQ accuracy SciQ accuracy rises from 0.397 at 262M tokens to 0.660 at 4.2B, against chance at 0.25. Fully trained Pythia-410M scores 0.735. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.25 Pythia-410M after 300B tokens: 0.735 SciQ, 0.26B tokens: 0.397 SciQ, 0.52B tokens: 0.573 SciQ, 0.79B tokens: 0.580 SciQ, 1.05B tokens: 0.610 SciQ, 2.10B tokens: 0.628 SciQ, 4.19B tokens: 0.660
  • ARC-Easy 0.458

    ARC-Easy accuracy ARC-Easy accuracy rises from 0.333 at 262M tokens to 0.458 at 4.2B, against chance at 0.25. Fully trained Pythia-410M scores 0.458. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.25 Pythia-410M after 300B tokens: 0.458 ARC-Easy, 0.26B tokens: 0.333 ARC-Easy, 0.52B tokens: 0.387 ARC-Easy, 0.79B tokens: 0.405 ARC-Easy, 1.05B tokens: 0.415 ARC-Easy, 2.10B tokens: 0.447 ARC-Easy, 4.19B tokens: 0.458
  • BoolQ 0.621

    BoolQ accuracy BoolQ accuracy rises from 0.423 at 262M tokens to 0.621 at 4.2B, against chance at 0.50. Fully trained Pythia-410M scores 0.598. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.50 Pythia-410M after 300B tokens: 0.598 BoolQ, 0.26B tokens: 0.423 BoolQ, 0.52B tokens: 0.588 BoolQ, 0.79B tokens: 0.621 BoolQ, 1.05B tokens: 0.621 BoolQ, 2.10B tokens: 0.622 BoolQ, 4.19B tokens: 0.621
  • PIQA 0.628

    PIQA accuracy PIQA accuracy rises from 0.545 at 262M tokens to 0.628 at 4.2B, against chance at 0.50. Fully trained Pythia-410M scores 0.675. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.50 Pythia-410M after 300B tokens: 0.675 PIQA, 0.26B tokens: 0.545 PIQA, 0.52B tokens: 0.573 PIQA, 0.79B tokens: 0.589 PIQA, 1.05B tokens: 0.594 PIQA, 2.10B tokens: 0.614 PIQA, 4.19B tokens: 0.628
  • OpenBookQA 0.312

    OpenBookQA accuracy OpenBookQA accuracy rises from 0.254 at 262M tokens to 0.312 at 4.2B, against chance at 0.25. Fully trained Pythia-410M scores 0.300. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.25 Pythia-410M after 300B tokens: 0.300 OpenBookQA, 0.26B tokens: 0.254 OpenBookQA, 0.52B tokens: 0.282 OpenBookQA, 0.79B tokens: 0.278 OpenBookQA, 1.05B tokens: 0.280 OpenBookQA, 2.10B tokens: 0.304 OpenBookQA, 4.19B tokens: 0.312
  • HellaSwag 0.326

    HellaSwag accuracy HellaSwag accuracy rises from 0.260 at 262M tokens to 0.326 at 4.2B, against chance at 0.25. Fully trained Pythia-410M scores 0.406. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.25 Pythia-410M after 300B tokens: 0.406 HellaSwag, 0.26B tokens: 0.260 HellaSwag, 0.52B tokens: 0.271 HellaSwag, 0.79B tokens: 0.277 HellaSwag, 1.05B tokens: 0.282 HellaSwag, 2.10B tokens: 0.298 HellaSwag, 4.19B tokens: 0.326
  • WinoGrande 0.502

    WinoGrande accuracy WinoGrande accuracy rises from 0.489 at 262M tokens to 0.502 at 4.2B, against chance at 0.50. Fully trained Pythia-410M scores 0.538. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.50 Pythia-410M after 300B tokens: 0.538 WinoGrande, 0.26B tokens: 0.489 WinoGrande, 0.52B tokens: 0.535 WinoGrande, 0.79B tokens: 0.515 WinoGrande, 1.05B tokens: 0.524 WinoGrande, 2.10B tokens: 0.520 WinoGrande, 4.19B tokens: 0.502
  • ARC-Challenge 0.265

    ARC-Challenge accuracy ARC-Challenge accuracy rises from 0.232 at 262M tokens to 0.265 at 4.2B, against chance at 0.25. Fully trained Pythia-410M scores 0.247. 0.0 0.2 0.4 0.6 0.8 1B 2B 3B 4B Chance: 0.25 Pythia-410M after 300B tokens: 0.247 ARC-Challenge, 0.26B tokens: 0.232 ARC-Challenge, 0.52B tokens: 0.224 ARC-Challenge, 0.79B tokens: 0.231 ARC-Challenge, 1.05B tokens: 0.233 ARC-Challenge, 2.10B tokens: 0.249 ARC-Challenge, 4.19B tokens: 0.265
Accuracy on each task against training tokens, all on the same 0 to 0.8 scale. The number beside each name is the final score at 4.19B tokens. LAMBADA asks for a free-text word, so it has no chance line.
Show the numbers
Task 262M 524M 786M 1.05B 2.10B 4.19B
LAMBADA 0.021 0.107 0.141 0.151 0.212 0.230
SciQ 0.397 0.573 0.580 0.610 0.628 0.660
ARC-Easy 0.332 0.387 0.404 0.415 0.447 0.458
BoolQ 0.423 0.588 0.620 0.621 0.622 0.621
PIQA 0.545 0.573 0.589 0.594 0.614 0.628
OpenBookQA 0.254 0.282 0.278 0.280 0.304 0.312
HellaSwag 0.260 0.270 0.277 0.282 0.298 0.326
WinoGrande 0.489 0.535 0.515 0.524 0.520 0.502
ARC-Challenge 0.232 0.224 0.231 0.233 0.249 0.265
Average 0.328 0.393 0.404 0.412 0.433 0.445
WikiText perplexity 185.2 86.7 68.1 62.1 49.5 42.1

LAMBADA, which asks the model to predict the last word of a passage, rose elevenfold from 0.021 to 0.230, making it the most useful single sign of progress. SciQ nearly doubled. HellaSwag sat nearly still for two phases and then finally began to move in phase 3, from 0.298 to 0.326.

ARC-Challenge ended at 0.265 and WinoGrande at 0.502, both at or near chance after the whole run, and Pythia’s checkpoints at the same token counts behave the same way. At this scale those two cost evaluation time without informing a single decision. I’d drop them from the tracking suite and watch validation perplexity and LAMBADA instead.

Averaging the weights didn’t help

Phase 3 also kept an exponential moving average of the weights, on the usual reasoning that averaging away the noise the last steps leave in each parameter is worth a few tenths of a point. It wasn’t. The averaged weights scored 0.443 against the final checkpoint’s 0.445, and were slightly worse on validation perplexity too, 42.5 against 42.1. That’s within noise, but it is certainly not a gain.

The reason makes sense in hindsight. Averaging helps when training ends while the learning rate is still high and the weights are still being jostled around. This run ends at 1e-5 after a full cosine decay, so the last thousand steps are already taking tiny, quiet steps. The decay had done the averaging already. The two techniques are substitutes, not complements.

Show the head-to-head
  Final weights Weight-averaged Difference
Average accuracy 0.4448 0.4430 -0.0018
LAMBADA 0.230 0.228 -0.002
SciQ 0.660 0.655 -0.005
ARC-Easy 0.458 0.460 +0.003
BoolQ 0.621 0.621 -0.000
PIQA 0.628 0.631 +0.003
OpenBookQA 0.312 0.312 +0.000
HellaSwag 0.326 0.321 -0.006
WinoGrande 0.502 0.495 -0.007
ARC-Challenge 0.265 0.265 -0.001
WikiText perplexity 42.13 42.53 +0.39

So: if you can afford to decay the learning rate properly, do that and skip the averaging. Keep it for runs that end while the rate is still high, which is what happens with a constant-rate schedule, an early stop, or a budget that runs out mid-decay. Finding this out cost one gigabyte of disk and no measurable training time, which is a fair price for knowing.

Training health

I also logged per-layer gradient norms, activation sizes, and prediction entropy throughout. None of them needed action this time, but each would have caught a problem long before it showed up in the loss curve.

Gradient norm Global gradient norm over the run, measured before clipping. It spikes above the clipping threshold of 1.0 21 times, all within the first 540 steps, then settles between 0.2 and 0.4 for the remaining 7460 steps and never triggers clipping again. global gradient norm, before clipping 0 1 2 3 4 5 6 clipping threshold, 1.0 Step 10: gradient norm 5.86, clipped to 1.0 Step 20: gradient norm 2.04, clipped to 1.0 Step 30: gradient norm 3.04, clipped to 1.0 Step 40: gradient norm 2.41, clipped to 1.0 Step 60: gradient norm 1.23, clipped to 1.0 Step 70: gradient norm 1.22, clipped to 1.0 Step 90: gradient norm 1.43, clipped to 1.0 Step 100: gradient norm 1.06, clipped to 1.0 Step 120: gradient norm 1.48, clipped to 1.0 Step 130: gradient norm 1.65, clipped to 1.0 Step 140: gradient norm 1.52, clipped to 1.0 Step 150: gradient norm 1.04, clipped to 1.0 Step 190: gradient norm 1.08, clipped to 1.0 Step 200: gradient norm 2.57, clipped to 1.0 Step 210: gradient norm 1.25, clipped to 1.0 Step 220: gradient norm 1.46, clipped to 1.0 Step 320: gradient norm 1.17, clipped to 1.0 Step 330: gradient norm 1.11, clipped to 1.0 Step 480: gradient norm 1.95, clipped to 1.0 Step 520: gradient norm 4.91, clipped to 1.0 Step 540: gradient norm 2.06, clipped to 1.0 Step 10: gradient norm 5.865 Step 110: gradient norm 0.823 Step 210: gradient norm 1.251 Step 310: gradient norm 0.673 Step 410: gradient norm 0.396 Step 510: gradient norm 0.383 Step 610: gradient norm 0.417 Step 710: gradient norm 0.372 Step 810: gradient norm 0.293 Step 910: gradient norm 0.301 Step 1010: gradient norm 0.378 Step 1110: gradient norm 0.289 Step 1210: gradient norm 0.269 Step 1310: gradient norm 0.293 Step 1410: gradient norm 0.282 Step 1510: gradient norm 0.251 Step 1610: gradient norm 0.254 Step 1710: gradient norm 0.261 Step 1810: gradient norm 0.255 Step 1910: gradient norm 0.247 Step 2010: gradient norm 0.247 Step 2110: gradient norm 0.360 Step 2210: gradient norm 0.335 Step 2310: gradient norm 0.313 Step 2410: gradient norm 0.299 Step 2510: gradient norm 0.322 Step 2610: gradient norm 0.293 Step 2710: gradient norm 0.308 Step 2810: gradient norm 0.260 Step 2910: gradient norm 0.273 Step 3010: gradient norm 0.265 Step 3110: gradient norm 0.253 Step 3210: gradient norm 0.268 Step 3310: gradient norm 0.249 Step 3410: gradient norm 0.255 Step 3510: gradient norm 0.247 Step 3610: gradient norm 0.244 Step 3710: gradient norm 0.245 Step 3810: gradient norm 0.238 Step 3910: gradient norm 0.237 Step 4010: gradient norm 0.238 Step 4110: gradient norm 0.313 Step 4210: gradient norm 0.303 Step 4310: gradient norm 0.283 Step 4410: gradient norm 0.310 Step 4510: gradient norm 0.279 Step 4610: gradient norm 0.287 Step 4710: gradient norm 0.289 Step 4810: gradient norm 0.271 Step 4910: gradient norm 0.271 Step 5010: gradient norm 0.268 Step 5110: gradient norm 0.292 Step 5210: gradient norm 0.265 Step 5310: gradient norm 0.261 Step 5410: gradient norm 0.286 Step 5510: gradient norm 0.264 Step 5610: gradient norm 0.265 Step 5710: gradient norm 0.259 Step 5810: gradient norm 0.271 Step 5910: gradient norm 0.255 Step 6010: gradient norm 0.249 Step 6110: gradient norm 0.260 Step 6210: gradient norm 0.267 Step 6310: gradient norm 0.261 Step 6410: gradient norm 0.259 Step 6510: gradient norm 0.262 Step 6610: gradient norm 0.259 Step 6710: gradient norm 0.250 Step 6810: gradient norm 0.254 Step 6910: gradient norm 0.250 Step 7010: gradient norm 0.251 Step 7110: gradient norm 0.246 Step 7210: gradient norm 0.255 Step 7310: gradient norm 0.250 Step 7410: gradient norm 0.249 Step 7510: gradient norm 0.250 Step 7610: gradient norm 0.248 Step 7710: gradient norm 0.251 Step 7810: gradient norm 0.250 Step 7910: gradient norm 0.252 2000 4000 6000 8000 step
The global gradient norm, measured before clipping, with the clipped steps marked. Clipping only ever bound early: 21 steps in total, the last at step 540, and never again across the remaining 7,460.
Gradient norm by layer Heatmap of gradient norm for each of the 24 layers at every 100 steps. Layer 0 is consistently the darkest, with roughly four times the gradient of the early-middle layers, and the second half of the network runs darker than the first. All layers lighten together as training proceeds, darken slightly when the learning rate restarts at steps 2000 and 4000, and no layer drifts away from the rest. layer 0 layer 6 layer 12 layer 18 layer 23 100 2000 4000 6000 8000 training step Step 100: layer 0 0.469, median layer 0.142, layer 23 0.201 Step 200: layer 0 1.951, median layer 0.211, layer 23 0.261 Step 300: layer 0 0.185, median layer 0.058, layer 23 0.082 Step 400: layer 0 0.213, median layer 0.061, layer 23 0.077 Step 500: layer 0 0.308, median layer 0.077, layer 23 0.107 Step 600: layer 0 0.234, median layer 0.053, layer 23 0.073 Step 700: layer 0 0.203, median layer 0.053, layer 23 0.082 Step 800: layer 0 0.174, median layer 0.053, layer 23 0.072 Step 900: layer 0 0.195, median layer 0.048, layer 23 0.060 Step 1000: layer 0 0.179, median layer 0.047, layer 23 0.069 Step 1100: layer 0 0.152, median layer 0.048, layer 23 0.058 Step 1200: layer 0 0.148, median layer 0.049, layer 23 0.065 Step 1300: layer 0 0.142, median layer 0.048, layer 23 0.061 Step 1400: layer 0 0.123, median layer 0.049, layer 23 0.058 Step 1500: layer 0 0.115, median layer 0.048, layer 23 0.058 Step 1600: layer 0 0.109, median layer 0.048, layer 23 0.059 Step 1700: layer 0 0.112, median layer 0.049, layer 23 0.058 Step 1800: layer 0 0.104, median layer 0.049, layer 23 0.057 Step 1900: layer 0 0.103, median layer 0.048, layer 23 0.056 Step 2000: layer 0 0.107, median layer 0.050, layer 23 0.057 Step 2100: layer 0 0.155, median layer 0.061, layer 23 0.084 Step 2200: layer 0 0.180, median layer 0.060, layer 23 0.074 Step 2300: layer 0 0.141, median layer 0.054, layer 23 0.075 Step 2400: layer 0 0.134, median layer 0.054, layer 23 0.074 Step 2500: layer 0 0.132, median layer 0.050, layer 23 0.066 Step 2600: layer 0 0.134, median layer 0.050, layer 23 0.065 Step 2700: layer 0 0.119, median layer 0.050, layer 23 0.066 Step 2800: layer 0 0.121, median layer 0.053, layer 23 0.070 Step 2900: layer 0 0.129, median layer 0.050, layer 23 0.062 Step 3000: layer 0 0.123, median layer 0.050, layer 23 0.062 Step 3100: layer 0 0.106, median layer 0.049, layer 23 0.062 Step 3200: layer 0 0.096, median layer 0.049, layer 23 0.062 Step 3300: layer 0 0.098, median layer 0.049, layer 23 0.062 Step 3400: layer 0 0.092, median layer 0.049, layer 23 0.061 Step 3500: layer 0 0.096, median layer 0.049, layer 23 0.061 Step 3600: layer 0 0.089, median layer 0.047, layer 23 0.061 Step 3700: layer 0 0.087, median layer 0.047, layer 23 0.058 Step 3800: layer 0 0.088, median layer 0.047, layer 23 0.061 Step 3900: layer 0 0.088, median layer 0.048, layer 23 0.060 Step 4000: layer 0 0.091, median layer 0.049, layer 23 0.060 Step 4100: layer 0 0.109, median layer 0.057, layer 23 0.073 Step 4200: layer 0 0.134, median layer 0.059, layer 23 0.074 Step 4300: layer 0 0.113, median layer 0.053, layer 23 0.076 Step 4400: layer 0 0.120, median layer 0.057, layer 23 0.072 Step 4500: layer 0 0.108, median layer 0.051, layer 23 0.066 Step 4600: layer 0 0.111, median layer 0.052, layer 23 0.070 Step 4700: layer 0 0.120, median layer 0.055, layer 23 0.066 Step 4800: layer 0 0.111, median layer 0.053, layer 23 0.077 Step 4900: layer 0 0.114, median layer 0.052, layer 23 0.066 Step 5000: layer 0 0.111, median layer 0.053, layer 23 0.068 Step 5100: layer 0 0.107, median layer 0.050, layer 23 0.064 Step 5200: layer 0 0.115, median layer 0.051, layer 23 0.065 Step 5300: layer 0 0.097, median layer 0.052, layer 23 0.066 Step 5400: layer 0 0.104, median layer 0.051, layer 23 0.068 Step 5500: layer 0 0.107, median layer 0.053, layer 23 0.070 Step 5600: layer 0 0.098, median layer 0.050, layer 23 0.066 Step 5700: layer 0 0.096, median layer 0.049, layer 23 0.067 Step 5800: layer 0 0.096, median layer 0.050, layer 23 0.068 Step 5900: layer 0 0.094, median layer 0.051, layer 23 0.063 Step 6000: layer 0 0.091, median layer 0.048, layer 23 0.063 Step 6100: layer 0 0.097, median layer 0.050, layer 23 0.065 Step 6200: layer 0 0.089, median layer 0.049, layer 23 0.066 Step 6300: layer 0 0.088, median layer 0.049, layer 23 0.063 Step 6400: layer 0 0.089, median layer 0.051, layer 23 0.072 Step 6500: layer 0 0.087, median layer 0.049, layer 23 0.064 Step 6600: layer 0 0.091, median layer 0.051, layer 23 0.064 Step 6700: layer 0 0.088, median layer 0.050, layer 23 0.066 Step 6800: layer 0 0.089, median layer 0.050, layer 23 0.065 Step 6900: layer 0 0.088, median layer 0.050, layer 23 0.065 Step 7000: layer 0 0.089, median layer 0.050, layer 23 0.065 Step 7100: layer 0 0.084, median layer 0.050, layer 23 0.063 Step 7200: layer 0 0.084, median layer 0.049, layer 23 0.065 Step 7300: layer 0 0.084, median layer 0.050, layer 23 0.064 Step 7400: layer 0 0.089, median layer 0.050, layer 23 0.064 Step 7500: layer 0 0.083, median layer 0.049, layer 23 0.063 Step 7600: layer 0 0.085, median layer 0.051, layer 23 0.064 Step 7700: layer 0 0.084, median layer 0.049, layer 23 0.063 Step 7800: layer 0 0.089, median layer 0.050, layer 23 0.064 Step 7900: layer 0 0.085, median layer 0.050, layer 23 0.064 Step 8000: layer 0 0.083, median layer 0.049, layer 23 0.064 smaller larger gradient norm (0.02 to 0.5, log scale)
Gradient norm for each of the 24 layers, every 100 steps, before clipping. Stronger color means a larger gradient. Hover a column to see its values.

The first layer carries the largest gradients throughout, four to six times those of the early-middle layers, and the second half of the network runs higher than the first. All 24 layers shrink together, and each learning-rate restart shows up as a faint band at steps 2000 and 4000. No layer ever drifted away from the rest across the whole run. A layer whose gradients grew or collapsed on its own would be the first sign of an unstable run, and nothing here ever needed me to intervene.

Residual stream size by layer Heatmap of the root-mean-square size of the residual stream leaving each of the 24 layers, every 100 steps. The picture is banded by depth rather than by time: each layer adds to a running sum, so the stream grows steadily from layer 0 to layer 23 and the bottom of the chart stays light while the top stays dark. The gradient is smooth, with no single layer breaking away from its neighbours. layer 0 layer 6 layer 12 layer 18 layer 23 100 2000 4000 6000 8000 training step Step 100: layer 0 0.105, median layer 0.580, layer 23 1.071 Step 200: layer 0 0.221, median layer 0.763, layer 23 1.373 Step 300: layer 0 0.265, median layer 0.745, layer 23 1.497 Step 400: layer 0 0.256, median layer 0.677, layer 23 1.500 Step 500: layer 0 0.279, median layer 0.714, layer 23 1.594 Step 600: layer 0 0.333, median layer 0.725, layer 23 1.710 Step 700: layer 0 0.339, median layer 0.722, layer 23 1.840 Step 800: layer 0 0.325, median layer 0.722, layer 23 1.964 Step 900: layer 0 0.338, median layer 0.737, layer 23 1.932 Step 1000: layer 0 0.343, median layer 0.749, layer 23 2.010 Step 1100: layer 0 0.351, median layer 0.744, layer 23 2.050 Step 1200: layer 0 0.333, median layer 0.698, layer 23 2.053 Step 1300: layer 0 0.349, median layer 0.723, layer 23 2.059 Step 1400: layer 0 0.338, median layer 0.702, layer 23 2.041 Step 1500: layer 0 0.321, median layer 0.691, layer 23 2.016 Step 1600: layer 0 0.322, median layer 0.670, layer 23 2.117 Step 1700: layer 0 0.326, median layer 0.653, layer 23 2.053 Step 1800: layer 0 0.318, median layer 0.640, layer 23 1.938 Step 1900: layer 0 0.308, median layer 0.644, layer 23 1.967 Step 2000: layer 0 0.304, median layer 0.619, layer 23 1.983 Step 2100: layer 0 0.328, median layer 0.663, layer 23 2.038 Step 2200: layer 0 0.348, median layer 0.730, layer 23 2.171 Step 2300: layer 0 0.352, median layer 0.760, layer 23 2.216 Step 2400: layer 0 0.359, median layer 0.725, layer 23 2.284 Step 2500: layer 0 0.365, median layer 0.812, layer 23 2.287 Step 2600: layer 0 0.377, median layer 0.786, layer 23 2.428 Step 2700: layer 0 0.376, median layer 0.771, layer 23 2.393 Step 2800: layer 0 0.371, median layer 0.731, layer 23 2.477 Step 2900: layer 0 0.371, median layer 0.760, layer 23 2.555 Step 3000: layer 0 0.356, median layer 0.673, layer 23 2.609 Step 3100: layer 0 0.370, median layer 0.816, layer 23 2.491 Step 3200: layer 0 0.363, median layer 0.766, layer 23 2.415 Step 3300: layer 0 0.371, median layer 0.689, layer 23 2.417 Step 3400: layer 0 0.343, median layer 0.655, layer 23 2.401 Step 3500: layer 0 0.340, median layer 0.689, layer 23 2.593 Step 3600: layer 0 0.353, median layer 0.768, layer 23 2.465 Step 3700: layer 0 0.342, median layer 0.746, layer 23 2.445 Step 3800: layer 0 0.348, median layer 0.746, layer 23 2.344 Step 3900: layer 0 0.334, median layer 0.667, layer 23 2.364 Step 4000: layer 0 0.324, median layer 0.686, layer 23 2.432 Step 4100: layer 0 0.343, median layer 0.779, layer 23 2.494 Step 4200: layer 0 0.359, median layer 0.716, layer 23 2.475 Step 4300: layer 0 0.362, median layer 0.775, layer 23 2.499 Step 4400: layer 0 0.363, median layer 0.823, layer 23 2.616 Step 4500: layer 0 0.380, median layer 0.709, layer 23 2.624 Step 4600: layer 0 0.375, median layer 0.691, layer 23 2.659 Step 4700: layer 0 0.378, median layer 0.810, layer 23 2.680 Step 4800: layer 0 0.382, median layer 0.819, layer 23 2.699 Step 4900: layer 0 0.375, median layer 0.877, layer 23 2.630 Step 5000: layer 0 0.370, median layer 0.707, layer 23 2.746 Step 5100: layer 0 0.374, median layer 0.710, layer 23 2.724 Step 5200: layer 0 0.377, median layer 0.920, layer 23 2.845 Step 5300: layer 0 0.380, median layer 0.877, layer 23 2.525 Step 5400: layer 0 0.379, median layer 0.881, layer 23 2.884 Step 5500: layer 0 0.364, median layer 0.705, layer 23 2.781 Step 5600: layer 0 0.373, median layer 0.878, layer 23 2.901 Step 5700: layer 0 0.365, median layer 0.790, layer 23 2.890 Step 5800: layer 0 0.372, median layer 0.835, layer 23 2.902 Step 5900: layer 0 0.373, median layer 0.829, layer 23 2.749 Step 6000: layer 0 0.352, median layer 0.877, layer 23 2.873 Step 6100: layer 0 0.356, median layer 0.921, layer 23 2.827 Step 6200: layer 0 0.356, median layer 0.696, layer 23 2.902 Step 6300: layer 0 0.362, median layer 0.973, layer 23 2.873 Step 6400: layer 0 0.347, median layer 0.735, layer 23 2.643 Step 6500: layer 0 0.341, median layer 0.811, layer 23 2.792 Step 6600: layer 0 0.347, median layer 0.766, layer 23 2.790 Step 6700: layer 0 0.339, median layer 0.997, layer 23 2.902 Step 6800: layer 0 0.345, median layer 0.951, layer 23 2.823 Step 6900: layer 0 0.336, median layer 0.856, layer 23 2.798 Step 7000: layer 0 0.327, median layer 0.905, layer 23 2.728 Step 7100: layer 0 0.329, median layer 0.731, layer 23 2.897 Step 7200: layer 0 0.343, median layer 0.747, layer 23 2.750 Step 7300: layer 0 0.339, median layer 0.783, layer 23 2.725 Step 7400: layer 0 0.321, median layer 0.842, layer 23 2.733 Step 7500: layer 0 0.341, median layer 0.676, layer 23 2.710 Step 7600: layer 0 0.324, median layer 0.844, layer 23 2.632 Step 7700: layer 0 0.343, median layer 0.660, layer 23 2.721 Step 7800: layer 0 0.331, median layer 0.888, layer 23 2.832 Step 7900: layer 0 0.320, median layer 0.671, layer 23 2.805 Step 8000: layer 0 0.334, median layer 0.781, layer 23 2.696 smaller larger activation size (0.10 to 2.9, linear scale)
Size of the residual stream leaving each layer, on the same sampling. This one is banded by depth rather than by time, so the pattern to look for is different.

The residual stream tells a different story: it’s banded by depth, not by time. Each layer adds its output to a running sum that only gets normalised on the way into the next block, so the stream grows steadily from layer 0 at the bottom to layer 23 at the top. That gradient is the signature of a healthy pre-norm network. What you don’t want is a single row suddenly brightening, which is what a layer heading for numerical trouble looks like well before the loss notices.

Entropy and update size Two panels sharing the step axis. Top: mean prediction entropy falls from 7.44 nats to 3.03 as the model becomes more certain of its next token. Bottom: the size of each optimizer update relative to the weight it changes, on a log scale, for the embedding table and the attention output projections of layers 0, 12 and 23. All of them shrink as the learning rate decays, and step back up at each restart. prediction entropy, nats 3 4 5 6 7 Step 50: entropy 7.44 nats Step 250: entropy 5.10 nats Step 450: entropy 4.59 nats Step 650: entropy 3.36 nats Step 850: entropy 3.83 nats Step 1050: entropy 3.66 nats Step 1250: entropy 3.43 nats Step 1450: entropy 3.33 nats Step 1650: entropy 3.38 nats Step 1850: entropy 3.55 nats Step 2050: entropy 3.25 nats Step 2250: entropy 3.69 nats Step 2450: entropy 3.31 nats Step 2650: entropy 3.63 nats Step 2850: entropy 3.29 nats Step 3050: entropy 3.15 nats Step 3250: entropy 3.05 nats Step 3450: entropy 3.41 nats Step 3650: entropy 2.64 nats Step 3850: entropy 3.39 nats Step 4050: entropy 3.27 nats Step 4250: entropy 3.18 nats Step 4450: entropy 3.05 nats Step 4650: entropy 3.22 nats Step 4850: entropy 3.23 nats Step 5050: entropy 3.22 nats Step 5250: entropy 3.52 nats Step 5450: entropy 2.91 nats Step 5650: entropy 3.33 nats Step 5850: entropy 3.23 nats Step 6050: entropy 3.04 nats Step 6250: entropy 2.85 nats Step 6450: entropy 3.03 nats Step 6650: entropy 3.19 nats Step 6850: entropy 2.42 nats Step 7050: entropy 3.31 nats Step 7250: entropy 2.61 nats Step 7450: entropy 2.37 nats Step 7650: entropy 3.69 nats Step 7850: entropy 3.33 nats 3.03 update size relative to weight size, log scale 1e-2 1e-1 L0.attn.wo L12.attn.wo L23.attn.wo tok_emb 2000 4000 6000 8000 step
Two more signals over the run. Top: mean prediction entropy, how uncertain the model is about its next token. Bottom: how large each optimizer update is relative to the weight it changes, for the embedding table and three attention projections, on a log scale.

Prediction entropy drops steeply during warmup, from 7.44 nats to about 3.5 by the end of phase 1, and then stops falling. It spends phases 2 and 3 wandering around 3 nats, bouncing half a nat either way because I measure it on a single batch. That plateau is worth noticing: the model kept getting better at predicting the right token long after it stopped getting more confident on average. Loss and confidence are not the same thing, and only one of them was still improving.

The update sizes shrink as the learning rate decays and step back up at each restart, which is the loss curve’s story told from the optimizer’s side. None of this needed action. That’s rather the point of logging it: it’s cheap, and the run where one of these goes wrong is the run where you want it already there.

Cost

Stage Hours Cost
Tokenizer and corpus preparation 0.65 $0.32
Phase 1 6.4 $3.08
Phase 2 6.4 $3.08
Phase 3 12.2 $5.83
Benchmarks, including public baselines 2.9 $1.39
Total 28.6 $13.70

What I’d do next

The run is done, and it never hit a wall I could fix with engineering. Ranked by what would actually pay:

Change the data mix, don’t just add more of it. The cheap token gains are largely spent, and the corpus is the binding constraint now. The benchmarks that stayed flat are flat because FineWeb-Edu contains none of what they test: no code, little reference text, nothing requiring multi-step reasoning. SmolLM2-360M beating Qwen2.5-0.5B on a quarter of the tokens is the evidence that mixture outweighs volume from here.

If you do add tokens, use one warmup-stable-decay schedule. Another doubling would still pay, since the curve is straight to the end. Running it as a single schedule recovers the fifth of the budget my two restarts cost.

Skip the weight averaging if you can decay properly, per the measurement above.

Drop ARC-Challenge and WinoGrande from the tracking suite at this scale. Both sat at chance for the whole run.

What I wouldn’t bother with at this budget: architecture changes, a different optimizer, or a hyperparameter sweep. Nothing in the diagnostics ever suggested the model was the limiting factor. No instability, no dead layers, no gradient pathology, 85% of the card’s peak throughput from the first step to the last. It was the data all along.

Getting the model

from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("osjayaprakash/llm-0.5b-fineweb-edu")
tok = AutoTokenizer.from_pretrained("osjayaprakash/llm-0.5b-fineweb-edu")

It’s a base model: no instruction tuning, no chat template, no alignment. It continues text and nothing else, and at this size it produces fluent, plausible, frequently wrong prose. Ask it about mitochondria and it will tell you they are the powerhouse of the cell, three times, before moving on. Treat it as a reference point for what a small budget buys rather than as something to build on. The model card carries the full numbers and limitations.