--- id: pretraining-data title: Pre-Training Data Pipelines code: PP subtitle: Clean, dedup, download, tokenize, shard and window a pretraining corpus. Python from the lessons. hue: 28 sources: phases/10-llms-from-scratch/03-data-pipelines, phases/19-capstone-projects/31-tokenized-dataset-sliding-window, phases/19-capstone-projects/42-large-corpus-downloader, phases/19-capstone-projects/43-hdf5-tokenized-corpus source_hash: 4e29cc278516394f --- ## Tasks type: task-table from: phases/10-llms-from-scratch/03-data-pipelines/code/main.py, phases/19-capstone-projects/31-tokenized-dataset-sliding-window/code/main.py, phases/19-capstone-projects/42-large-corpus-downloader/code, phases/19-capstone-projects/43-hdf5-tokenized-corpus/code | Task | Code | |---|---| | Run a lesson demo | `python3 code/main.py` | | Run the tests | `python3 -m unittest discover code/tests -v` | | Drop near duplicates | `deduplicate(filtered_docs, threshold=0.8)` | | Pack ids into sequences | `pack_sequences(token_ids, seq_length, pad_id=0)` | | Download one shard | `process_shard(plan, downloader, dedup, manifest)` | | Write HDF5 shards | `pipeline.write_corpus(shards)` | | Check shard hashes | `validate_corpus(entries)` | | Read a token range | `store.get_slice(start, stop)` | ## Corpus to batch type: architecture from: phases/19-capstone-projects/42-large-corpus-downloader/docs/en.md, phases/19-capstone-projects/43-hdf5-tokenized-corpus/docs/en.md ```arch node | url | 1,1 | Shard URLs | ShardPlanner | client node | dl | 2,1 | StreamingDownloader | Range resume | process node | zst | 3,1 | ZstdDocIterator | one doc per line | process node | dedup | 4,1 | Dedup | MinHasher + LSHIndex | process node | man | 4,2 | manifest.json | shard sha256 | store node | h5 | 3,2 | HDF5ShardWriter | one .h5 per shard | store node | store | 2,2 | MmapTokenStore | swmr reads | store node | win | 1,2 | SlidingWindowDataloader | input, target | gpu edge | url | dl | GET edge | dl | zst | bytes edge | zst | dedup | docs edge | dedup | man | verdicts edge | man | h5 | JSONL shards edge | h5 | store | shards.json edge | store | win | get_slice ``` ## Clean and filter type: annotated-code lang: python from: phases/10-llms-from-scratch/03-data-pipelines/code/main.py, phases/10-llms-from-scratch/03-data-pipelines/docs/en.md ```python def clean_text(text): text = re.sub(r"<[^>]+>", "", text) # strip HTML tags text = re.sub(r"http\S+", "", text) # drop URLs text = re.sub(r"[^\x20-\x7E\n]", "", text) # printable ASCII only text = re.sub(r"\n{3,}", "\n\n", text) # collapse blank lines text = re.sub(r" {2,}", " ", text) # collapse spaces return text.strip() def quality_filter(text, min_words=50, max_ratio_caps=0.3, max_ratio_special=0.1): ... # False for stubs, ALL CAPS spam, symbol noise ``` ## Cleaning stages type: flow from: phases/10-llms-from-scratch/03-data-pipelines/docs/en.md 1. **HTML strip**: keep only the visible text. 2. **Language detection**: fastText lid.176.bin. Below 0.8 confidence is not clean English. 3. **Quality filter**: high perplexity against a Wikipedia model means spam. 4. **Deduplication**: MinHash plus LSH. Remove one copy above 0.8 Jaccard. 5. **PII removal**: regex for structured PII, NER models for names. 6. **Tokenize and pack**: append `tokenizer.eos_id` after each document. ## Sliding window dataset type: annotated-code lang: python from: phases/19-capstone-projects/31-tokenized-dataset-sliding-window/code/main.py ```python ds = SlidingWindowDataset(ids, context_length=16, stride=8) # stride None means context_length SlidingWindowDataset.count_windows(num_ids, context_length, stride) # 1 + usable // stride x, y = ds[0] # window[:-1], window[1:] loader = make_dataloader(ds, batch_size=4, base_seed=7, epoch=0) generator.manual_seed(base_seed + epoch) # same seed, same order ``` ## Resume a download type: flow from: phases/19-capstone-projects/42-large-corpus-downloader/code/main.py, phases/19-capstone-projects/42-large-corpus-downloader/docs/en.md 1. **StreamingDownloader**: reads `.partial.json` next to `.zst`. 2. **_verify_partial**: file size must equal `verified_bytes`. The sha256 must equal `sha256_prefix_hex`. 3. **Mismatch**: delete the shard and checkpoint. Restart from byte zero. 4. **Match**: send `Range` as `bytes={resume_from}-` and open the shard in `ab` mode. 5. **Response check**: status must be 206 with a matching `Content-Range`. Else do a full GET. 6. **Each chunk**: `_write_checkpoint` with `os.replace`, then `out.write(buf)`. ## Dedup and filter defaults type: defaults from: phases/10-llms-from-scratch/03-data-pipelines/code/main.py, phases/19-capstone-projects/42-large-corpus-downloader/code/main.py | Setting | Default | Note | |---|---|---| | `min_words` | 50 | Stub pages fail | | `max_ratio_caps` | 0.3 | ALL CAPS spam fails | | `max_ratio_special` | 0.1 | Symbol noise fails | | `threshold` | 0.8 | Jaccard to drop a copy | | `num_hashes` | 128 | Signature length | | `bands` | 16 | Lesson 03. Lesson 42 uses `DEFAULT_BANDS = 32` | | `DEFAULT_SHINGLE_WIDTH` | 5 | Demo uses `shingle_width=3` | | `CHUNK_BYTES` | `1 << 16` | Download read size | ## Storage defaults type: defaults from: phases/19-capstone-projects/43-hdf5-tokenized-corpus/code/main.py, phases/19-capstone-projects/43-hdf5-tokenized-corpus/docs/en.md | Setting | Default | Note | |---|---|---| | `DEFAULT_CHUNK_SIZE` | 8192 | Demo uses `chunk_size=512` | | `DEFAULT_WINDOW_SIZE` | 64 | Reads `window_size + 1` tokens | | `BOUNDARY_TOKEN_ID` | 0 | Separator between documents | | `TOKEN_DTYPE` | `np.uint16` | Byte ids offset by one | | `maxshape` | `(None,)` | Resizable dataset | | `libver` | `"latest"` | Required on the writer for SWMR | ## Numbers and formulas type: concepts from: phases/10-llms-from-scratch/03-data-pipelines/docs/en.md, phases/19-capstone-projects/31-tokenized-dataset-sliding-window/docs/en.md, phases/19-capstone-projects/42-large-corpus-downloader/docs/en.md, phases/19-capstone-projects/42-large-corpus-downloader/code/main.py - **Window count**: `max(0, 1 + (N - (T + 1)) // S)` for N ids, context T, stride S. - **Stride**: `T // 2` doubles the dataset. `1` grows it by a factor of `T`. - **LSH collision**: `1 - (1 - s^r)^b` with `k = b * r`. - **LSH threshold**: near `(1/b)^(1/r)`. For b=32, r=4 it is near s = 0.42. - **Compression**: English is about 3-4 characters per token. - **Sequence utilization**: below 90% means packing wastes compute. - **Dedup yield**: the Llama team removed approximately 38% of web data. - **Chinchilla**: scale parameters and tokens roughly equally. ## Troubleshooting type: troubleshooting from: phases/19-capstone-projects/42-large-corpus-downloader/docs/en.md, phases/19-capstone-projects/42-large-corpus-downloader/code/main.py, phases/19-capstone-projects/43-hdf5-tokenized-corpus/docs/en.md, phases/19-capstone-projects/31-tokenized-dataset-sliding-window/docs/en.md, phases/10-llms-from-scratch/03-data-pipelines/docs/en.md | Symptom | Cause | Fix | |---|---|---| | Resumed shard holds garbage | Offset and file differ | Check the sha256 prefix first | | Server ignores `Range` | Status is not 206 | Close it and do a full GET | | Duplicated suffix after power loss | Bytes written before checkpoint | Checkpoint first, then write | | Model learns to predict zero | Reader reads zero padding | Truncate at `token_count` | | "file is locked" | No `libver="latest"` or late SWMR | Create datasets, then set `swmr_mode` | | Throughput halves | Chunk does not match window | Chunk a multiple of `window_size` | | Runs diverge for no reason | No shuffle seed | Pass `base_seed` per epoch | | `ValueError` from `LSHIndex` | `bands` does not divide `num_hashes` | Pick bands that divide 128 | ## Q&A type: qa from: phases/10-llms-from-scratch/03-data-pipelines/docs/en.md, phases/19-capstone-projects/31-tokenized-dataset-sliding-window/docs/en.md, phases/19-capstone-projects/42-large-corpus-downloader/docs/en.md, phases/19-capstone-projects/43-hdf5-tokenized-corpus/docs/en.md - **Why pack instead of pad?** Padding wastes compute on tokens that teach nothing. - **Why a block-diagonal mask?** Doc A tokens must not attend to Doc B tokens. - **What does the slicer do with a short tail?** It drops the last window. - **Why dedup before tokenization?** Tokenization is expensive. Do not pay it twice. - **Why tombstone duplicates?** The manifest keeps the link to the keeper. - **Why one HDF5 per source shard?** A crash loses at most one shard. ## Tips type: tips from: phases/19-capstone-projects/42-large-corpus-downloader/docs/en.md, phases/19-capstone-projects/43-hdf5-tokenized-corpus/docs/en.md, phases/19-capstone-projects/31-tokenized-dataset-sliding-window/docs/en.md - Trainers read `shards.json`, not the directory listing. - Verify the manifest sha256 in `manifest.lock` before you trust shard rows. - Call `dataset.flush()` after each resize in SWMR mode. - Buffer tokens to chunk size, then resize. Never write one document at a time. - Most runs use a stride equal to the context length.