Views
No views yet
PRs welcome! Add a row to the table below and link to your log / run config.
| Rank | Trainer | Hardware | Tokens Trained | Val Loss | Time to Target | Throughput (approx) | Training Script | Command |
|---|---|---|---|---|---|---|---|---|
| 🥇 1 | DevParker | 1× RTX 4090 | ~0.92B | 3.286 @ step 1750 | ~115 minutes | ~130–140k tokens/s | train_gpt_improved.py | python train_gpt_improved.py |
train_gpt_improved.py.sequence_length = 32 * 1024skip_weights to blend encoder states into decoderx_backout) and subtract it at the end, scaled by a learned backout_lambdavalue_embeds (nn.Embedding) injected into attention as alternative value streamslamb within attention to interpolate between standard V and the value embeddingst > 0, add a gated fraction of token t-1 into token t, scaled by smear_lambdaattn_gate that produces per-head gates from the input, controlling how much each head contributes at each positionlogits = 30 * tanh(logits / 30)torch.nn.attention.flex_attention with a custom block_mask:50256 as a separator)attn_blocksizeattn_blocksize grows over training:optimizer1)optimizer2)optimizer3)zeropower_via_newtonschulz5) to gradients of 2D weight matriceslr = 0.05, momentum 0.95, Nesterov styleoptimizer4)lambdas (per block mixing scalars)skip_weights (U-Net skips)smear_lambda, backout_lambdawarmup_iters = 0)cooldown_iters = 640 iterations (over 1750 total)data/fineweb10B/fineweb_train_*.bin20240520)1)ntok)ntok tokens as uint16 (e.g. GPT-2 BPE IDs)T = 32768x = tokens[:-1], y = tokens[1:]T * num_processes tokens and loops across filesval_tokens = 10,485,760 (10M tokens)val_steps = val_tokens // T = 320 sequences per eval1batch_size = 16 # gradient accumulation steps
2sequence_length = 32 * 1024 # 32K context
3num_iterations = 1750 # total optimizer steps
4val_loss_every = 125
5val_tokens = 10_485_760 # ~10M tokens of val data
* **Effective tokens per step**
* 1 sequence per forward pass, length = 32,768
* 16 gradient accumulation steps per optimizer step
* → 32,768 × 16 = **524,288 tokens / optimizer step**
* **Total tokens trained**
* 524,288 × 1750 ≈ **917,504,000 tokens** (~0.92B)
* **Final metrics (as reported in logs)**
* `step:1750/1750 train_loss:3.1758`
* `step:1750/1750 val_loss:3.2860`
* Perplexity ≈ `exp(3.286) ≈ 26.7`
* **Throughput & runtime**
* Wall-clock time ≈ **115 minutes** on a single RTX 4090
* Effective training throughput ≈ **130k–140k tokens/sec**
---
## Repository Layout (typical)
* `train_gpt_improved.py`
Main training script with:
* Model definition (`GPT`, `Block`, `CausalSelfAttention`, etc.)
* Data loader
* Optimizers & schedulers
* Training loop & logging
* `inference_standalone.py`
Simple script to:
* Load a saved checkpoint (`checkpoint_stepXXXXXX_lossY.YYYY.pt`)
* Run a few canned prompts at different temperatures
* Print generations to stdout
* `logs/`
* Run logs and checkpoints:
* `logs/<run_id>.txt`
* `logs/<run_id>/checkpoint_step001750_loss3.2860.pt`
* `data/fineweb10B/` (not included, user-supplied)
* Custom binary shards:
* `fineweb_train_*.bin`
* `fineweb_val_*.bin`
---
## Installation
You’ll need:
* A recent **PyTorch** build with:
* `torch.compile`
* `torch.nn.attention.flex_attention`
* **CUDA** + compatible driver
* **Triton** (installed automatically via recent PyTorch wheels)
* A GPU with at least **16–20 GB VRAM** (24 GB recommended for 32K context as configured here)
Example (conda):
```bash
conda create -n nanogpt-124m python=3.10 -y
conda activate nanogpt-124m
# Install PyTorch + CUDA (adjust command for your system)
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121
# Optional: other utilities
pip install numpy tqdm
```
> **Note:** The exact install line for PyTorch depends on your CUDA + OS; check the official PyTorch installation instructions if you run into issues.
---
## Data Preparation
This repo expects **pre-tokenized, binary** data compatible with the `DistributedDataLoader`:
* Each `*.bin` shard contains:
* 256 × int32 header:
* `header[0] = 20240520` (magic)
* `header[1] = 1` (version)
* `header[2] = ntok` (number of tokens)
* `ntok` tokens as `uint16`
If you don’t already have data in that format, you’ll need a preprocessing script that:
1. Tokenizes your text (e.g., with GPT-2 tokenizer).
2. Writes the header & token buffer in the expected binary layout.
Paths are configured in `Hyperparameters`:
```python
@dataclass
class Hyperparameters:
input_bin: str = 'data/fineweb10B/fineweb_train_*.bin'
input_val_bin: str = 'data/fineweb10B/fineweb_val_*.bin'
...
```
Update `input_bin` and `input_val_bin` to match your own dataset paths.
---
## Training
Once you have:
* Installed dependencies
* Prepared your dataset shards
You can launch training with:
```bash
python train_gpt_improved.py
```
This will:
* Initialize the 124M-parameter GPT model
* Start streaming training data from `input_bin`
* Periodically evaluate on `input_val_bin`
* Log to `logs/<run_id>.txt`
* Save checkpoints under `logs/<run_id>/checkpoint_stepXXXXXX_lossYYYY.pt`
Key knobs (edit in `Hyperparameters`):
* `batch_size` (gradient accumulation steps)
* `sequence_length` (context length, default 32K)
* `num_iterations`
* `val_loss_every`, `val_tokens`
* `cooldown_iters` (length of LR linear decay phase)
---
## Inference
The simplest way to play with the trained model is via `inference_standalone.py` or a small PyTorch snippet.
### Example (minimal PyTorch snippet)
```python
import torch
from train_gpt_improved import GPT, GPTConfig
device = "cuda"
ckpt_path = "logs/<run_id>/checkpoint_step001750_loss3.2860.pt"
ckpt = torch.load(ckpt_path, map_location=device)
model = GPT(GPTConfig()).to(device).bfloat16()
model.load_state_dict(ckpt["model"])
model.eval()
tokenizer = ... # load GPT-2 tokenizer compatible with your training data
prompt = "The capital of France is"
input_ids = torch.tensor(tokenizer.encode(prompt), device=device, dtype=torch.long)[None]
with torch.no_grad():
for _ in range(50):
logits = model(input_ids[0], input_ids[0], attn_blocksize=torch.tensor(1792, device=device))
logits = logits[:, -1, :] # last-token logits
next_id = torch.distributions.Categorical(logits=logits).sample()
input_ids = torch.cat([input_ids, next_id[:, None]], dim=1)
print(tokenizer.decode(input_ids[0].tolist()))
```
You can also use the provided `inference_standalone.py` as a reference — it prints several test prompts with different temperatures and shows how the model behaves at the end of training.
---
## Acknowledgements & Inspiration
* **NanoGPT** by Andrej Karpathy for the “train GPT from scratch with minimal code” baseline.
* Modded NanoGPT speedruns and training code [https://github.com/KellerJordan/modded-nanogpt](https://github.com/KellerJordan/modded-nanogpt) (this is for 8xH100 but I adapted many of its features to this 1x4090 run).
* The PyTorch team for `torch.compile` and `flex_attention`, which make this kind of experiment actually feasible.
* Various community experiments with Muon, Triton kernels, and long-context training that inspired many of the tricks here.
---
license: mit
---
---
license: mit
---