For a full description of the assignment, see the assignment handout at cs336_spring2025_assignment1_basics.pdf
If you see any issues with the assignment handout or code, please feel free to raise a GitHub issue or open a pull request with a fix.
We manage our environments with uv to ensure reproducibility, portability, and ease of use.
Install uv here (recommended), or run pip install uv/brew install uv.
We recommend reading a bit about managing projects in uv here (you will not regret it!).
You can now run any code in the repo using
uv run <python_file_path>and the environment will be automatically solved and activated when necessary.
uv run pytestDownload the TinyStories data and a subsample of OpenWebText
mkdir -p data
cd data
wget https://huggingface.co/datasets/roneneldan/TinyStories/resolve/main/TinyStoriesV2-GPT4-train.txt
wget https://huggingface.co/datasets/roneneldan/TinyStories/resolve/main/TinyStoriesV2-GPT4-valid.txt
wget https://huggingface.co/datasets/stanford-cs336/owt-sample/resolve/main/owt_train.txt.gz
gunzip owt_train.txt.gz
wget https://huggingface.co/datasets/stanford-cs336/owt-sample/resolve/main/owt_valid.txt.gz
gunzip owt_valid.txt.gz
cd ..-
train_bpe.py: BPE training utilities and pipeline- Splits the file into CPU-aligned chunks and aligns boundaries to the next special token (
find_chunk_boundaries). - Splits each chunk by special tokens, then counts pre-tokenized segments in parallel.
- Greedy adjacent-pair merging loop to produce
merges(ties broken lexicographically). - Final vocab order: special tokens → 256 raw byte tokens → learned merge tokens.
- Returns
(vocab: dict[int, bytes], merges: list[tuple[bytes, bytes]]).
- Splits the file into CPU-aligned chunks and aligns boundaries to the next special token (
-
tokenizer.py: Byte-level BPE tokenizer- Uses the GPT‑2 pre-tokenization regex, then applies BPE merges.
- Special-token aware: splits input on provided special tokens and preserves their IDs.
Tokenizer.from_files(...)loads GPT‑2 stylevocab.json/merges.txt(with byte↔unicode mapping).encode/encode_iterablehandle streaming inputs without breaking specials;decoderestores UTF‑8.
-
nn_modules.py: Core neural modulesLinear: no bias,trunc_normal_init (σ²=2/(d_in+d_out), ±3σ),einops.einsummatmul.Embedding:trunc_normal_init; returns embeddings via index lookup.RMSNorm: normalize by RMS then apply learned scale.SiLU: x·sigmoid(x).SwiGLU:W2(SiLU(W1x) ⊙ W3x)form.RotaryPositionalEmbedding(RoPE): caches cos/sin withregister_buffer(persistent=False), expands on demand, rotates even/odd dims.softmax: numerically stable (subtract max).scaled_dot_product_attention: mask uses True=allowed/False=masked; efficient witheinops.MultiheadSelfAttention: QKV projections → head split → optional RoPE → causal mask → output projection.TransformerBlock: pre-norm residual (Attention, FFN).TransformerLM: token embeddings → L blocks → finalRMSNorm→Linearlogits.
-
optimizer.py:AdamW- Standard Adam moments with bias correction and decoupled weight decay (
-lr*wdapplied directly to params). No sparse grads.
- Standard Adam moments with bias correction and decoupled weight decay (
-
scheduler.py: cosine scheduler with linear warmup- Implements
cosine_annealing_with_linear_warmup(t, eta_max, eta_min, Tw, Tc).
- Implements
-
loss.py: cross entropy- Treats last dim as vocab; stable
logsumexpformulation; returns mean loss.
- Treats last dim as vocab; stable
-
clipping.py: gradient clipping- Computes global L2 norm across all parameter grads and scales by
max_l2_norm.
- Computes global L2 norm across all parameter grads and scales by
-
dataloader.py: batch sampling- Samples contiguous windows from a 1D token array to produce
(inputs, targets)on the requested device.
- Samples contiguous windows from a 1D token array to produce
-
checkpoint.py: checkpoint I/Osave_checkpoint/load_checkpointfor model/optimizer states and iteration.