LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 196 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/9
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningBayesian Inference from EvidenceStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/15
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageStatistical Learning and GeneralizationConformal Prediction and UncertaintyClustering and PCAProbabilistic Generative ModelsCore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingCausal Inference and CounterfactualsPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/25
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernancePrivacy-Preserving Machine LearningData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Reproducible ML Study
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/31
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceAccelerator Architecture Field GuideCorrect GPU Profiling and BenchmarkingGPU Kernel Performance Engineering LabGPU Parallel Primitives LabGPU Compilers and Kernel LanguagesGEMM From Naive CUDA to Tensor CoresLow-Precision GPU ProgrammingGPU Runtime Execution LabAI-Generated Kernel EngineeringModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingGPU Failure OperationsDistributed Inference Data PlaneServing Benchmark EngineeringA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnAdvanced Training & AdaptationPre-training Data at Scale
⚡HardFine-Tuning & Training

Pre-training Data at Scale

Understand how web-scale pre-training data is extracted, filtered, deduplicated, mixed, tokenized, and packed into training-ready shards, including decontamination, late-stage annealing, and synthetic-data tradeoffs.

39 min read
Learning path
Step 104 of 196 in the full curriculum
Scaling Laws & Compute-Optimal TrainingBuild GPT from Scratch Lab

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

The last chapter turned a FLOP budget into a token target. This one asks what those tokens actually are. A 70B dense model using Chinchilla scaling at roughly 20 tokens per parameter needs about 1.4T training tokens. That number is a volume target, not a corpus. Raw crawls, public git trees, and book dumps still contain broken HTML, mirrored pages, spam, private strings, and leaked benchmark questions.

Suppose a 2T-token run completes and its first checkpoint looks healthy. Later, a code evaluation regresses because one shard overrepresented mirrors while a language filter removed symbol-heavy files. A raw token counter won't show either failure; lineage, yield, and source mix will.

A coding-assistant mix needs public code, API docs, runbooks, and design notes. You can't dump those sources into training as-is. The pipeline's job is to turn a messy source lake into documented shards: extract text, drop low-signal records, remove duplicates, scrub sensitive material, keep evaluation sets out, then tokenize and pack what remains.

Track yield after each gate, not just raw download volume. If 2T extracted tokens lose 30% to quality filters and another 20% of the remainder to deduplication, only 1.12T tokens survive. That corpus misses a 1.4T target even though the original crawl looked comfortably large.

From token budget to training inventory

Start with the inventory, not the downloader. A token target tells you how many training events you want; it doesn't tell you which sources fill them or whether a later shard can be traced back to a policy decision.

Three ideas from earlier in the curriculum sit underneath every later choice:

  • Tokens: A language model doesn't read words. It reads tokens: reusable pieces such as ship, ping, punctuation, or byte sequences. The tokenizer converts text into integers, and the model learns to predict the next integer.
  • Next-token prediction: During pre-training, the model sees a partial sequence and guesses what comes next. Broader, cleaner sequences give it more to learn from.
  • Scaling laws: The previous chapter turned model size into a token target. That target still needs extract, filter, dedup, pack, and shard steps before those tokens become training inventory.

If tokens or next-token prediction feel fuzzy, review Language Modeling & Next Tokens before continuing.

How much data is enough?

Ask what the 1.4T figure means before treating it as a procurement number. It estimates training-token volume under one scaling-law setup; it doesn't promise unique, clean, or equally useful tokens.

Hoffmann et al. studied that tradeoff in the Chinchilla scaling laws. Under their fixed-compute dense-transformer setup, model size and training-token count grew together. A useful planning rule from that study is about 20 training tokens per parameter.[1]Reference 1Training Compute-Optimal Large Language Models.https://arxiv.org/abs/2203.15556

For a 70B model, 70×109×20=1.4×101270 \times 10^9 \times 20 = 1.4 \times 10^{12}70×109×20=1.4×1012 tokens. That's a lot of books, pages, and repositories, which is why the pipeline needs industrial machinery.

A companion planning formula is training FLOPs of about 6ND6ND6ND, where NNN is a consistently counted dense model size and DDD is the number of training tokens. It's an approximation. Details such as whether output-layer parameters are counted can move fitted optima, but it's useful for capacity estimates.[1]Reference 1Training Compute-Optimal Large Language Models.https://arxiv.org/abs/2203.15556[2]Reference 2Resolving Discrepancies in Compute-Optimal Scaling of Language Modelshttps://arxiv.org/abs/2406.19146

Raw token counts still mislead. A smaller corpus of textbook-quality tokens can beat a much larger pile of noisy crawl text. Extra tokens help only when they still add information.

Meta reports pre-training Llama 3's 405B model on 15.6T tokens, about 38.5 tokens per parameter, and says that flagship configuration is approximately compute-optimal under its own fitted laws and training budget. Separately, Meta reports training its smaller models longer than compute-optimal because those models performed better at the same inference budget.[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783 Treat the 20x ratio as a planning baseline, not a hard law.

token-target-and-flop-budget.py
1def dense_training_flops(parameters: float, tokens: float) -> float: 2 return 6 * parameters * tokens 3 4parameters = 70e9 5target_tokens = 20 * parameters 6llama_405b_ratio = 15.6e12 / 405e9 7 8print(f"Chinchilla-style token target: {target_tokens / 1e12:.1f}T") 9print(f"Dense training FLOP estimate: {dense_training_flops(parameters, target_tokens):.2e}") 10print(f"Llama 3 405B reported ratio: {llama_405b_ratio:.1f} tokens/parameter")
Output
1Chinchilla-style token target: 1.4T 2Dense training FLOP estimate: 5.88e+23 3Llama 3 405B reported ratio: 38.5 tokens/parameter

Why is a token target not enough to define a pre-training corpus?

Answer

Token count measures volume, not signal. You still need source mix, filtering, deduplication, privacy scrubbing, benchmark decontamination, and tokenizer fit before those tokens become useful training inventory.

The raw corpus and the clean training mix

The raw internet is a noisy source lake. Useful records sit next to duplicate pages, broken markup, spam, and unsafe material. A pre-training data pipeline is the repeatable system that extracts useful records and turns them into a training-ready mix.

You don't write the text. You design a processing system that handles large partitions repeatably, records each decision, and avoids throwing out high-value records.

Every gate makes a different claim about a record. Keep source identity and policy metadata attached, because dropping a malformed HTML page and routing a high-signal code file to a separate recipe are different decisions.

The modern pipeline has three major phases:

  1. Ingestion: Pull raw data from web crawls, code hosts, and curated archives.
  2. Cleaning: Filter, deduplicate, decontaminate (strip leaked evaluation-benchmark examples), and scrub for safety.
  3. Preparation: Tokenize, shuffle, pack, and split into training shards.
Diagram showing 1. Ingestion & Extraction, 2. Quality Filtering & Deduplication, 3. Preparation & Sharding, and Ingest raw sources WARC / git / books.
1. Ingestion & Extraction, 2. Quality Filtering & Deduplication, 3. Preparation & Sharding, and Ingest raw sources WARC / git / books.
Illustrative 100-record pre-training funnel. Extraction keeps 82 records, quality filtering keeps 42, near-deduplication keeps 31, and policy plus evaluation checks keep 29 for tokenization and packing. A stacked bar accounts for all 100 outcomes: 18 extraction failures, 40 low-signal drops, 11 duplicates, 2 policy or eval drops, and 29 retained.
In this illustrative 100-record batch, 18 records fail extraction, 40 fail quality checks, 11 are near-duplicates, and 2 fail policy or evaluation checks, leaving 29 for tokenization and packing. Real retention rates must be measured for each source.

Where the text comes from

Common Crawl doesn't ship paragraphs. It ships WARC files of HTML. Extraction is the first real gate: a parser has to keep a runbook's steps and drop the navigation chrome around them. FineWeb extracts text from WARC snapshots; Llama 3 reports a custom HTML parser tuned for boilerplate removal and for keeping math and code structure.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

After extraction, sources still aren't interchangeable. Web data gives breadth and freshness. Code is dense in syntax and exact structure. Books and papers give long-form argument. Carefully curated synthetic or textbook-style data can raise signal density further. Phi-1 is a clear example: its authors report strong coding-benchmark performance from a 1.3B model trained on textbook-quality and synthetic data.[5]Reference 5Textbooks Are All You Needhttps://arxiv.org/abs/2306.11644

Before choosing weights, ask what each source can lose. A web filter that removes navigation may improve prose, while the same rule can erase code context or a license header that an audit needs. Preserve source and license metadata so a yield change has an explanation.

SourceWhat it contributesMain curation question
Common Crawl snapshotsBroad web coverage at large scaleWhich extraction, language, quality, and deduplication rules raise signal without collapsing yield?
Books and papersLong-form explanations and sustained argumentWhich licenses, provenance rules, and subject areas fit the intended model?
WikipediaStructured reference text across many topics and languagesWhich languages and snapshots belong in the mixture?
Code (for example, public repositories)Syntax, APIs, and examples where exact structure mattersWhich licenses, repository-level rules, and file filters remove generated or low-value code?
Curated web (for example, technical forums)Focused discussions and worked answersHow do you preserve useful niche material without replaying copied pages?
Synthetic dataTargeted examples for gaps that raw sources cover poorlyDoes the generated slice preserve factual fidelity, diversity, and downstream quality?

Note: Some papers disclose approximate mixtures while many don't. Llama 3 reports a final pre-training mix of roughly 50% general knowledge, 25% mathematical and reasoning data, 17% code, and 8% multilingual data.[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783 Mixture weights are decisions, not raw-byte proportions.

Mixture weights, curriculum, and data scheduling

Source quality is only half the decision. You also have to decide how often each source appears and whether that weighting stays fixed through the whole run.

If clean code is only 10% of the retained pool, should it occupy 10% of training? Maybe not. Upsampling changes the model's exposure without pretending that the source produced more unique tokens.

Three knobs matter:

  1. Source weighting: web, code, books, papers, synthetic data
  2. Schedule over time: fixed mix vs later-stage reweighting
  3. Within-source weighting: whether some slices replay more often than others

The wrong default is "sample in proportion to raw bytes." Raw crawl volume isn't the same thing as training value. The Pile is still useful as a reference because it made mixture design explicit instead of treating web text as one giant bucket.[6]Reference 6The Pile: An 800GB Dataset of Diverse Text for Language Modeling.https://arxiv.org/abs/2101.00027 Llama 3 shows a later-stage version of the same idea: even after assembling a huge corpus, training shifted toward higher-value slices during annealing.[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

reported-mixture-token-budget.py
1reported_mix = { 2 "general knowledge": 0.50, 3 "math and reasoning": 0.25, 4 "code": 0.17, 5 "multilingual": 0.08, 6} 7budget = 1e12 8 9assert abs(sum(reported_mix.values()) - 1.0) < 1e-9 10for source, fraction in reported_mix.items(): 11 print(f"{source:<19}: {budget * fraction / 1e9:>3.0f}B tokens")
Output
1general knowledge : 500B tokens 2math and reasoning : 250B tokens 3code : 170B tokens 4multilingual : 80B tokens
KnobWhat changesTypical reason
Upsampling / downsamplinghow often each source appearscode, math, books, or multilingual text may deserve more weight than raw size suggests
Curriculum schedulewhat the model sees earlier vs laterkeep early coverage broad, then spend late tokens on harder or cleaner data
Per-example weightswhich records inside one source repeat morekeep rare but important domains from being drowned by generic text

This is practical curriculum learning in pretraining. It usually isn't "easy lessons first, hard lessons later." More often it means changing source weights over time so the model sees a different mix at different stages.

Two common patterns:

  • Static high-quality mix: choose one weighted mixture and keep it stable through most of training
  • Late-stage curriculum: keep broad coverage early, then upweight cleaner or more target-relevant slices later[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

Don't confuse curriculum with annealing alone. Annealing usually means late-stage learning-rate decay plus a higher-quality mix. Curriculum is broader: any deliberate schedule that changes what the model sees as training progresses.

It also helps to know the public datasets that anchored a lot of later recipes:

DatasetWhat it emphasizedWhy people still cite it
C4[7]Reference 7Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer.https://arxiv.org/abs/1910.10683Aggressive heuristic cleanup of Common CrawlCanonical example of turning noisy crawl text into a cleaner English web corpus
The Pile[6]Reference 6The Pile: An 800GB Dataset of Diverse Text for Language Modeling.https://arxiv.org/abs/2101.00027Deliberate source diversity across code, papers, books, forums, and web textUseful contrast to pure web-crawl pipelines because mixture design is the core idea
FineWeb[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557Web-scale extraction, filtering, and deduplication ablations over 96 Common Crawl snapshotsGood modern reference for how pipeline details measurably change downstream quality

First quality check: heuristic filtering

Before using expensive neural models to classify text, basic heuristic filters drop the lowest-signal material from web crawls. C4 (Colossal Clean Crawled Corpus) is the classic published example of that first line of defense.[7]Reference 7Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer.https://arxiv.org/abs/1910.10683

The snippet below takes a single document and returns True only if it passes every check. The thresholds are visible on purpose. A real recipe has to measure retention and downstream quality on its own crawl slices before copying them.[7]Reference 7Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer.https://arxiv.org/abs/1910.10683[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557

Predict two outcomes before reading the code: a long runbook should pass, while a short but symbol-dense source file may fail its general-text checks. That second result is a routing signal, not proof that the file has no training value.

first-quality-gate-heuristic-filtering.py
1def load_bad_words() -> list[str]: 2 # In production, this would come from a reviewed policy list. 3 return ["toxic_word_1", "toxic_word_2"] 4 5def quality_filter(doc: str) -> bool: 6 """Illustrative web-text filter; thresholds require corpus-level validation.""" 7 words = doc.split() 8 9 # Length filter: drop documents that are too short or likely concatenated. 10 if len(words) < 50 or len(words) > 100_000: 11 return False 12 13 # Repetition filter: repeated n-grams are common in spam and boilerplate. 14 for n in [2, 3, 4]: 15 ngrams = [tuple(words[i:i+n]) for i in range(len(words) - n + 1)] 16 if len(ngrams) > 0: 17 frac_duplicates = 1 - len(set(ngrams)) / len(ngrams) 18 if frac_duplicates > 0.3: # >30% repeated n-grams 19 return False 20 21 # Policy-list filter: check the ratio of reviewed blocklisted terms. 22 bad_words = set(load_bad_words()) 23 bad_count = sum(1 for w in words if w.lower() in bad_words) 24 if bad_count / len(words) > 0.01: 25 return False 26 27 # Alphabetic character ratio: drop documents that are mostly symbols/code. 28 alpha_chars = sum(c.isalpha() for c in doc) 29 if alpha_chars / len(doc) < 0.5: 30 return False 31 32 # Sentence-ending punctuation check. 33 sentences = doc.split('.') 34 if len(sentences) < 3: 35 return False 36 37 return True 38 39procedure_doc = ( 40 "The key-rotation runbook explains how stale service-account keys are reviewed. " 41 "Operators verify the audit signal, check the owning service, " 42 "and create a rotation task when the account is eligible. " 43 "This document contains specific procedural details, normal punctuation, " 44 "and enough natural language context to be useful for model training. " 45 "It avoids repeated boilerplate and gives on-call engineers a clear workflow." 46) 47 48cases = { 49 "procedure": (procedure_doc, True), 50 "short": ("Rotation tasks are available.", False), 51 "repeated": ("sale sale sale sale sale sale sale sale sale sale " * 8, False), 52 "policy-list": (procedure_doc + " toxic_word_1 toxic_word_2", False), 53} 54 55for name, (text, expected) in cases.items(): 56 kept = quality_filter(text) 57 assert kept is expected 58 print(f"{name:<11} -> {'keep' if kept else 'drop'}")
Output
1procedure -> keep 2short -> drop 3repeated -> drop 4policy-list -> drop

Each gate is a different failure mode:

  • Length: very short documents often carry little context; extremely long extractions may be concatenated pages or indexes.
  • Repetition: high repeated n-gram fractions are a useful spam or boilerplate signal, but legitimate templates can also repeat.
  • Policy list: a reviewed list can exclude content a specific corpus policy doesn't want. The threshold is a policy choice, not a universal quality label.
  • Character ratio: a general-text recipe can discard symbol-heavy extractions. A code corpus needs a different recipe.
  • Sentence terminators: few periods can signal a malformed extraction, but they're a poor universal language or format rule.

These heuristics usually run on general web text before the final mix is assembled. Code corpora often use a parallel recipe, because symbol-heavy files that look low-quality to a web-text filter can still be high-signal pre-training data.

Second quality check: classifier-based filtering

After heuristic filtering, modern pipelines use classifiers trained to distinguish high-quality educational text from low-quality web chatter:

  1. Language ID: A fastText classifier screens whether the document matches the intended training languages.
  2. Quality classifier: A classifier scores whether a document looks like reference-quality material rather than random crawl text. FineWeb-Edu uses an educational-quality classifier trained on LLM-judged scores, DCLM trains a fastText classifier on instruction-formatted and ELI5 text and keeps only the top ~10% by score, and Meta reports separate Llama 3 classifiers for general quality, code, and reasoning signals.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557[8]Reference 8DataComp-LM: In Search of the Next Generation of Training Sets for Language Modelshttps://arxiv.org/abs/2406.11794[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783
  3. Perplexity filtering: A language model such as an n-gram model can score a document against a reference distribution. Unusually high or low scores can flag text for corpus-specific retention rules; CCNet is a published example.[9]Reference 9CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Datahttps://arxiv.org/abs/1911.00359

A classifier score is a ranking signal, not ground truth. The threshold is a choice about which errors and how much yield the next training experiment can afford.

FilterEffectExample
URL blocklistRemove known low-quality or unsafe domainsCommon in production pipelines
Language ID (fastText)Keep target language(s)CCNet[9]Reference 9CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Datahttps://arxiv.org/abs/1911.00359, FineWeb[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557
Heuristic rulesLength, repetition, char ratiosC4[7]Reference 7Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer.https://arxiv.org/abs/1910.10683, RedPajama[10]Reference 10RedPajama: An Open Source Recipe to Reproduce LLaMA training datasethttps://github.com/togethercomputer/RedPajama-Data, FineWeb[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557
ClassifierQuality score thresholdFineWeb-Edu[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557, DCLM[8]Reference 8DataComp-LM: In Search of the Next Generation of Training Sets for Language Modelshttps://arxiv.org/abs/2406.11794, Llama 3[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783
Perplexity filterRank documents by fit to a reference distributionCCNet[9]Reference 9CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Datahttps://arxiv.org/abs/1911.00359

Filtering decisions trade yield for the type of data retained. DCLM selected a fastText filter that retained its top 10% of documents after evaluating trained models, rather than assuming a score threshold was automatically better.[8]Reference 8DataComp-LM: In Search of the Next Generation of Training Sets for Language Modelshttps://arxiv.org/abs/2406.11794

The next snippet applies one threshold to a five-document toy mix. It doesn't prove the cutoff is good. It only shows how token yield collapses as the score floor rises.

quality-score-threshold-yield.py
1documents = [ 2 {"source": "proof", "tokens": 120, "score": 0.98}, 3 {"source": "api-doc", "tokens": 160, "score": 0.92}, 4 {"source": "forum", "tokens": 200, "score": 0.79}, 5 {"source": "news", "tokens": 240, "score": 0.63}, 6 {"source": "scrape", "tokens": 280, "score": 0.31}, 7] 8 9threshold = 0.90 10kept = [doc for doc in documents if doc["score"] >= threshold] 11kept_tokens = sum(doc["tokens"] for doc in kept) 12total_tokens = sum(doc["tokens"] for doc in documents) 13 14print("kept sources:", ", ".join(doc["source"] for doc in kept)) 15print(f"token yield: {kept_tokens}/{total_tokens} ({kept_tokens / total_tokens:.0%})")
Output
1kept sources: proof, api-doc 2token yield: 280/1000 (28%)

Removing duplicates

Deduplication is a core quality step. The internet contains boilerplate headers, repeated SEO text, mirrored sites, copied documentation, and reposted articles. Lee et al. found that, on the corpora and model sizes they tested, deduplication reduced emitted memorized text by about 10x and reached the same or better accuracy in fewer training steps.[11]Reference 11Deduplicating Training Data Makes Language Models Better.https://arxiv.org/abs/2107.06499

Exact deduplication

Take a cryptographic hash such as SHA-256 of each document and drop exact matches. It's fast, and it misses near-duplicates: a policy page where only the timestamp or one verb changed.

MinHash + LSH (near-deduplication)

MinHash with Locality-Sensitive Hashing (LSH) is one widely used approach for fuzzy deduplication at scale.[12]Reference 12On the Resemblance and Containment of Documents.https://www.cs.princeton.edu/courses/archive/spring13/cos598C/broder97resemblance.pdf[11]Reference 11Deduplicating Training Data Makes Language Models Better.https://arxiv.org/abs/2107.06499 FineWeb applied MinHash independently per crawl using word 5-grams and parameters intended to target documents with at least 75% similarity. Its experiments favored per-crawl rather than global deduplication.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557

The idea, by hand. Take three short documents:

  • Doc A: "The key policy says stale accounts need security review."
  • Doc B: "The key policy says stale accounts require security review."
  • Doc C: "Audit logs record deployment rollback events."

Doc A and Doc B share almost every word. Break them into overlapping 2-word chunks (shingles):

  • Doc A shingles: ["The key", "key policy", "policy says", "says stale", ...]
  • Doc B shingles: ["The key", "key policy", "policy says", "says stale", ...]

The overlap is high. Doc C shares zero shingles with A or B. Jaccard similarity is ∣A∩B∣/∣A∪B∣|A \cap B| / |A \cup B|∣A∩B∣/∣A∪B∣. For these two policy pages that's 6/10=0.606 / 10 = 0.606/10=0.60. MinHash turns each document into a small numeric sketch that estimates this overlap. LSH then routes similar sketches into the same candidate set so you inspect likely duplicates rather than comparing every pair. Because LSH is approximate, a candidate still needs a final similarity decision.

Worked near-deduplication example for three documents. Documents A and B each have eight unique bigrams, with six in their intersection and ten in their union, giving exact Jaccard similarity 0.60. An illustrative six-value MinHash sketch agrees in four positions and collides in the first LSH band, so exact verification compares them and drops B at a 0.50 threshold. Document C has five bigrams, no overlap with A or B, and is kept.
For the lesson's toy documents, A and B share 6 of 10 unique bigrams, so exact Jaccard similarity is 0.60. The figure uses a six-value sketch so you can count agreements by eye. The code below uses 32 hashes; LSH only proposes the pair, and the exact threshold makes the drop decision.

Use a candidate-then-verdict boundary. hashlib and banded LSH make likely pairs cheap to find; exact Jaccard and an explicit representative rule decide whether a document gets dropped.

minhash-lsh-near-deduplication.py
1import hashlib 2import re 3from collections import defaultdict 4 5def normalize(text: str) -> list[str]: 6 return re.findall(r"[a-z0-9]+", text.lower()) 7 8def shingles(text: str, n: int = 2) -> set[tuple[str, ...]]: 9 tokens = normalize(text) 10 if len(tokens) < n: 11 raise ValueError("Document is too short for the chosen shingle size.") 12 return {tuple(tokens[i : i + n]) for i in range(len(tokens) - n + 1)} 13 14def jaccard(left: set[tuple[str, ...]], right: set[tuple[str, ...]]) -> float: 15 return len(left & right) / len(left | right) 16 17def salted_hash(item: tuple[str, ...], salt: int) -> int: 18 payload = f"{salt}|{' '.join(item)}".encode() 19 return int.from_bytes(hashlib.blake2b(payload, digest_size=8).digest(), "big") 20 21def minhash(items: set[tuple[str, ...]], num_perm: int = 32) -> tuple[int, ...]: 22 return tuple(min(salted_hash(item, salt) for item in items) for salt in range(num_perm)) 23 24def minhash_similarity(left: tuple[int, ...], right: tuple[int, ...]) -> float: 25 return sum(a == b for a, b in zip(left, right)) / len(left) 26 27def lsh_bands(signature: tuple[int, ...], n_bands: int = 8) -> list[tuple[int, ...]]: 28 width = len(signature) // n_bands 29 return [signature[i * width : (i + 1) * width] for i in range(n_bands)] 30 31documents = [ 32 ("A", "The key policy says stale accounts need security review."), 33 ("B", "The key policy says stale accounts require security review."), 34 ("C", "Audit logs record deployment rollback events."), 35] 36sets = {doc_id: shingles(text) for doc_id, text in documents} 37sigs = {doc_id: minhash(items) for doc_id, items in sets.items()} 38 39assert abs(jaccard(sets["A"], sets["B"]) - 0.60) < 1e-12 40assert jaccard(sets["A"], sets["C"]) == 0.0 41assert minhash_similarity(sigs["A"], sigs["B"]) > minhash_similarity(sigs["A"], sigs["C"]) 42 43print(f"A vs B exact Jaccard: {jaccard(sets['A'], sets['B']):.2f}") 44print(f"A vs C exact Jaccard: {jaccard(sets['A'], sets['C']):.2f}") 45print(f"MinHash estimate A-B: {minhash_similarity(sigs['A'], sigs['B']):.2f}") 46print( 47 "LSH band collisions A-B:", 48 sum(a == b for a, b in zip(lsh_bands(sigs["A"]), lsh_bands(sigs["B"]))), 49 "/ 8", 50) 51 52threshold = 0.50 53index: dict[tuple[int, ...], list[str]] = defaultdict(list) 54kept: list[str] = [] 55for doc_id, items in sets.items(): 56 bands = lsh_bands(sigs[doc_id]) 57 candidates = {other for band in bands for other in index[band]} 58 duplicate = next( 59 (other for other in sorted(candidates) if jaccard(items, sets[other]) >= threshold), 60 None, 61 ) 62 if duplicate: 63 print(f"{doc_id}: drop near duplicate of {duplicate}") 64 else: 65 kept.append(doc_id) 66 for band in bands: 67 index[band].append(doc_id) 68 print(f"{doc_id}: keep") 69 70print(f"Kept {len(kept)} of {len(documents)} documents.")
Output
1A vs B exact Jaccard: 0.60 2A vs C exact Jaccard: 0.00 3MinHash estimate A-B: 0.72 4LSH band collisions A-B: 2 / 8 5A: keep 6B: drop near duplicate of A 7C: keep 8Kept 2 of 3 documents.

A is inserted first. When B arrives, two LSH bands collide, so A becomes a candidate. Exact Jaccard 0.60 clears the 0.50 threshold, so B drops. C has no band collision and no overlap, so it's kept. Published recipes make different final decisions after MinHash collisions. Lee et al. verified candidate pairs with actual Jaccard and edit similarity, while FineWeb used matching MinHash buckets and transitive clustering. Production thresholds, shingle sizes, verification rules, and whether deduplication operates per crawl or globally must be evaluated for the corpus.[11]Reference 11Deduplicating Training Data Makes Language Models Better.https://arxiv.org/abs/2107.06499[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557

MethodSpeedPrecisionRecallBest For
Exact hash (SHA-256)Very fastPerfectLow (exact only)Removing byte-identical documents
MinHash + LSHFast candidate searchTunableTunableLarge-corpus near-deduplication recipes[12]Reference 12On the Resemblance and Containment of Documents.https://www.cs.princeton.edu/courses/archive/spring13/cos598C/broder97resemblance.pdf[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557
Suffix array / suffix treeMediumVery HighVery HighExact repeated spans and long substring deduplication
SimHashFastMediumMediumCheap approximate similarity when memory is extremely tight

Why does near-deduplication matter even after exact hashing?

Answer

Exact hashes catch only byte-identical copies. Web corpora contain mirrored pages, lightly edited boilerplate, and reposts, so MinHash/LSH catches duplicates that waste training compute and increase memorization risk.

Keeping benchmarks clean: decontamination

Decontamination means keeping evaluation benchmarks out of the pre-training data. If a model sees MMLU, HumanEval, or GSM8K examples during pre-training, reported scores can reflect memorization instead of generalization.

The risk isn't hypothetical. Web crawls contain GitHub repos with interview questions, educational sites with standardized tests, and forums where people paste benchmark prompts. Training corpora and evaluation sets often draw from the same public web, so contamination is a recurring failure mode.

Deduplication and decontamination answer different questions. A benchmark prompt can appear once in the crawl, so it isn't a duplicate and can still invalidate an evaluation.

N-gram overlap filtering

One common approach is n-gram overlap detection. For each training document, check whether it contains spans from an evaluation set. The n-gram size, normalization, removal threshold, and code-specific rules must be recorded with the released corpus. GPT-3 attempted pre-training filtering with 13-gram overlaps, then reported that a filtering bug left some overlaps in place. Its post-hoc benchmark analysis used variable n-gram lengths capped at 13. Llama 3 reports excluding benchmark training sets from its annealing data.[13]Reference 13Language Models are Few-Shot Learners.https://arxiv.org/abs/2005.14165[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

CheckWhat it catchesWhat it misses
Exact string or n-gram overlapCopied benchmark prompts, answers, or code spansParaphrases and renamed identifiers
Fuzzy or task-specific similarityLightly edited versions worth inspectionRequires calibrated thresholds
Repository or source exclusionArtifacts from a known evaluation sourceCopies hosted elsewhere

Exact-match filtering isn't enough. A coding problem with renamed variables or a question with shuffled answer choices can still leak. Pipelines may add fuzzy or task-specific checks, then document what they removed so benchmark-clean claims are auditable.

The snippet below shows that exact 4-grams catch a copied sentence and miss a paraphrase. That's the point: one detector isn't a complete screen.

ngram-decontamination-screen.py
1import re 2 3def ngrams(text: str, n: int) -> set[tuple[str, ...]]: 4 tokens = re.findall(r"[a-z0-9]+", text.lower()) 5 return {tuple(tokens[i:i + n]) for i in range(len(tokens) - n + 1)} 6 7benchmark = "A rotation is approved when security verifies a stale service account." 8candidates = { 9 "direct-copy": "Internal guide: a rotation is approved when security verifies a stale service account.", 10 "paraphrase": "Allow key refresh after the risk signal has been checked.", 11} 12protected = ngrams(benchmark, n=4) 13 14for name, document in candidates.items(): 15 flagged = bool(protected & ngrams(document, n=4)) 16 print(f"{name:<11} -> {'flag' if flagged else 'not caught by exact n-grams'}")
Output
1direct-copy -> flag 2paraphrase -> not caught by exact n-grams

What makes benchmark contamination different from ordinary duplicate text?

Answer

Contamination corrupts evaluation. If benchmark examples leak into pre-training, reported scores can reflect memorization rather than generalization, so the training run may look stronger than it really is.

Benchmark decontamination table. A copied prompt is caught by exact n-grams and dropped. A renamed coding solution is caught by fuzzy or code-aware matching and dropped. A known benchmark repository is caught by a source rule and dropped. A clean key-rotation runbook clears every detector and is kept. Deduplication would not catch a unique leaked prompt.
Each leak shape is caught by a different detector, then dropped. A clean runbook clears every column and stays. A unique copied prompt isn't a near-duplicate, so ordinary dedup wouldn't have saved the eval.

Safety and privacy scrub

After deduplication and decontamination, a pipeline may scrub personally identifiable information (PII) and unsafe content according to its data policy and legal obligations. A model trained on scraped identifiers can reproduce sensitive strings at inference time. FineWeb reports anonymizing email and public-IP addresses; Llama 3 reports removing domains likely to contain high volumes of PII or adult content.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

A high-quality score doesn't make a document safe to train on. PII can sit inside a well-written runbook, so privacy controls need their own evidence and audit trail.

PII removal uses a layered approach:

  • Regex patterns: Rule-based detection can catch structured patterns such as email addresses or public IP addresses cheaply.
  • Entity or policy classifiers: Context-aware models can identify classes of content that rigid patterns miss, but they need false-positive evaluation.
  • Source and domain rules: Known high-risk sources can be excluded before training, as reported for Llama 3.[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

Unsafe-content filtering is policy-specific and imperfect. FineWeb applies URL-level filtering for adult content but notes that harmful documents can remain. Llama 3 combines domain rules with dirty-word counting for adult websites that domain blocklists miss.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783 Audit retained and removed samples across languages and source types instead of treating one score threshold as a universal safety boundary.

Turning text into numbers: tokenization

Tokenization converts raw text into integer IDs the model can process. At the scale of trillions of tokens, tokenization itself needs parallel workers.

Choosing a tokenizer

Vocabulary size, sequence length, and language coverage trade off. A smaller vocabulary can force text to split into more subwords, increasing sequence length and the cost of attention. A larger vocabulary can improve compression when it matches the corpus, but it also requires a larger embedding matrix.

Measure compression by source and language before freezing the vocabulary. One global average can hide a multilingual or code shard that consumes far more context than the rest.

Common subword algorithms:

TokenizerAlgorithmVocabularyUsed By
Byte-level BPE[14]Reference 14Neural Machine Translation of Rare Words with Subword Units.https://arxiv.org/abs/1508.07909[15]Reference 15Language Models are Unsupervised Multitask Learners.https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783Start from byte-representable symbols, then add frequent merges32K-128K+GPT-style models, Llama 3
WordPiece[16]Reference 16BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.https://arxiv.org/abs/1810.04805Subword vocabulary with greedy longest-match encoding~30KBERT
SentencePiece[17]Reference 17SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing.https://arxiv.org/abs/1808.06226Framework for BPE or Unigram on raw text32K-256KLlama 2, T5, multilingual models

Training a BPE tokenizer

When you train a model family from scratch, the tokenizer should be trained on a representative sample of the pre-training data so it learns the common subword patterns. Reusing a mature tokenizer can be a good engineering choice, but a mismatched tokenizer wastes context length, especially for multilingual or domain-heavy corpora.

The next demo is a tiny character-level BPE. Production pipelines use byte-level BPE and much larger samples. The merge mechanic is the same: count adjacent pairs, merge the most frequent pair, repeat. After a few merges, repeated words such as after collapse into fewer tokens.

tiny-bpe-from-scratch.py
1from collections import Counter 2 3EOW = "</w>" 4 5def split_words(text: str) -> list[list[str]]: 6 return [list(word) + [EOW] for word in text.split()] 7 8def pair_counts(words: list[list[str]]) -> Counter[tuple[str, str]]: 9 counts: Counter[tuple[str, str]] = Counter() 10 for word in words: 11 counts.update(zip(word, word[1:])) 12 return counts 13 14def apply_merge(words: list[list[str]], pair: tuple[str, str]) -> list[list[str]]: 15 left, right = pair 16 merged = left + right 17 rewritten: list[list[str]] = [] 18 for word in words: 19 new_word: list[str] = [] 20 i = 0 21 while i < len(word): 22 if i + 1 < len(word) and word[i] == left and word[i + 1] == right: 23 new_word.append(merged) 24 i += 2 25 else: 26 new_word.append(word[i]) 27 i += 1 28 rewritten.append(new_word) 29 return rewritten 30 31corpus = [ 32 "rotate stale keys after review", 33 "rotate stale keys after audit", 34 "rollback deployment after review", 35] 36words: list[list[str]] = [] 37for line in corpus: 38 words.extend(split_words(line)) 39 40before = sum(len(word) for word in words) 41merges: list[tuple[str, str]] = [] 42for _ in range(8): 43 pair, _count = pair_counts(words).most_common(1)[0] 44 merges.append(pair) 45 words = apply_merge(words, pair) 46 47sample = "rotate keys after review" 48sample_words = split_words(sample) 49sample_before = sum(len(word) for word in sample_words) 50for pair in merges: 51 sample_words = apply_merge(sample_words, pair) 52sample_after = sum(len(word) for word in sample_words) 53 54assert sample_after < sample_before 55print(f"corpus tokens before merges: {before}") 56print(f"corpus tokens after {len(merges)} merges: {sum(len(word) for word in words)}") 57print(f"sample tokens: {sample_before} -> {sample_after}") 58print("learned merges:", " ".join(f"{a}+{b}" for a, b in merges))
Output
1corpus tokens before merges: 94 2corpus tokens after 8 merges: 68 3sample tokens: 25 -> 16 4learned merges: t+e t+a r+o a+f af+te afte+r after+</w> ro+ta

In a byte-level setup you often don't need an <unk> token, because any UTF-8 byte sequence can be represented. Vocabulary size is still a real design decision. A larger vocabulary can improve compression when its extra tokens match the target text, but it also increases embedding-table size. Meta reports that Llama 3 moved to a 128K-token vocabulary, starting from a tiktoken base plus 28K extra tokens, and improved English compression from 3.17 to 3.94 characters per token relative to Llama 2.[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

Running the pipeline at scale

Large corpus pipelines need distributed execution beyond demonstration scripts. DCLM reports starting with a 240T-token Common Crawl pool containing about 200B documents and 370TB of compressed text, and processing crawl data on hundreds of AWS CPU nodes.[8]Reference 8DataComp-LM: In Search of the Next Generation of Training Sets for Language Modelshttps://arxiv.org/abs/2406.11794

At that scale, data is partitioned for extraction and filtering, intermediate artifacts are stored durably, and every transformation needs enough metadata to reproduce which records reached training.

The failure boundary changes here. A malformed shard can waste a multi-node run even when document-level filters passed, so shard manifests need the same lineage as individual records.

Deduplication changes the system shape: signatures can be computed independently, but candidate grouping needs records with related signatures to meet. Whether that step uses a global operation or a restricted partition, such as FineWeb's per-crawl recipe, changes both resource cost and retained data quality.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557

Trillion-token scale challenges

DCLM's 240T-token, 370TB crawl pool is too large to treat as one job. Split the work along the same seams the later training job will audit:

  • Ingestion and filtering: stream extraction, language ID, rules, and classifier scores without dropping the source URL or filter version.
  • Deduplication: compute signatures in parallel; then pick an explicit partition (per crawl vs global) before candidate grouping.
  • Training order: shuffle tokenized shards with a recorded seed so one host or one dump doesn't own a whole epoch.
  • Reproducibility: given one suspicious training example, recover its source document, filter version, mixture weight, and shard.

Data packing and sequence efficiency

Documents vary widely in length: an article might be thousands of tokens while a forum post is short. Padding each document to a fixed sequence length spends compute on padding tokens. Best-fit packing groups documents into fixed-length token blocks to reduce that waste.

best-fit-packing-utilization.py
1lengths = [7, 6, 5, 5, 3, 2] 2capacity = 10 3 4def best_fit_pack(items: list[int], block_size: int) -> list[list[int]]: 5 bins: list[list[int]] = [] 6 for length in sorted(items, reverse=True): 7 options = [bucket for bucket in bins if sum(bucket) + length <= block_size] 8 if options: 9 min(options, key=lambda bucket: block_size - sum(bucket) - length).append(length) 10 else: 11 bins.append([length]) 12 return bins 13 14naive_slots = len(lengths) * capacity 15packed = best_fit_pack(lengths, capacity) 16packed_slots = len(packed) * capacity 17tokens = sum(lengths) 18 19print("packed blocks:", packed) 20print(f"naive utilization: {tokens / naive_slots:.0%}") 21print(f"packed utilization: {tokens / packed_slots:.0%}")
Output
1packed blocks: [[7, 3], [6, 2], [5, 5]] 2naive utilization: 47% 3packed utilization: 93%

Packing creates another design decision: if multiple documents share one sequence, should tokens in one document attend to tokens from another? Some causal-language-model recipes concatenate documents with end-of-document separators and keep the ordinary causal mask. Others isolate documents with a block-diagonal mask so one document can't read tokens from an earlier document in the same packed block. The isolated version below prevents artificial cross-document context while retaining packing efficiency.

For the packed IDs [0, 0, 0, 1, 1], predict the first row for document 1: it should contain no attention edges into document 0. The mask makes that boundary observable instead of leaving it to a delimiter token and hope.

packed-document-attention-mask.py
1document_ids = [0, 0, 0, 1, 1] 2 3mask = [ 4 [ 5 int(previous <= current and document_ids[previous] == document_ids[current]) 6 for previous in range(len(document_ids)) 7 ] 8 for current in range(len(document_ids)) 9] 10 11for row in mask: 12 print(" ".join(map(str, row))) 13print("doc 1 token attends to doc 0:", bool(mask[3][2]))
Output
11 0 0 0 0 21 1 0 0 0 31 1 1 0 0 40 0 0 1 0 50 0 0 1 1 6doc 1 token attends to doc 0: False

Data annealing is a late-stage recipe adjustment where the learning rate decays and the data mix shifts toward higher-value slices. It isn't a universal "final 10%" rule. Llama 3 reports annealing over the final 40B tokens while upsampling very high-quality sources and excluding benchmark training sets from the annealing pool.[3]Reference 3The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

Quality and quantity must be measured together

Recent model and dataset papers show that data quality and token yield must be measured together once a corpus is already large.

The question now changes from “did the record pass?” to “did the retained data improve a trained model?” A filter proxy can rise while useful coverage or token supply falls.

The Phi lesson

Phi-1 reported strong coding-benchmark performance for a 1.3B model trained with textbook-quality data, worked examples, and synthetic exercises.[5]Reference 5Textbooks Are All You Needhttps://arxiv.org/abs/2306.11644 That result motivates controlled curation experiments. It doesn't make one data recipe universal.

FineWeb and FineWeb-Edu

FineWeb scales the same idea to web-scale curation. The paper builds a 15T-token dataset from 96 Common Crawl snapshots and then extracts FineWeb-Edu, a 1.3T educational subset filtered with a classifier trained on LLM-judged educational scores. The main lesson is that pipeline design matters: individual per-crawl MinHash deduplication and additional filtering each improved downstream results over weaker baselines.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557

Modern open corpora

Three published open-corpus reports illustrate different tradeoffs after FineWeb. Each changes a different part of the yield-versus-quality problem.

CorpusScale and scopeRole
DCLM-Baseline[8]Reference 8DataComp-LM: In Search of the Next Generation of Training Sets for Language Modelshttps://arxiv.org/abs/2406.117943.8T-token set filtered from a 240T-token Common Crawl poolA fastText filter retained its top 10% of documents; a 7B model trained on 2.6T tokens reached 64% 5-shot MMLU
Nemotron-CC[18]Reference 18Nemotron-CC: Transforming Common Crawl into a Refined Long-Horizon Pretraining Datasethttps://arxiv.org/abs/2412.025956.3T tokens: 4.4T globally deduplicated original tokens plus 1.9T synthetic tokensClassifier ensembling and source-conditioned rephrasing target larger unique-token yield; its 1.1T high-quality subset improved MMLU by 5.6 points over DCLM in the reported 8B, 1T-token setup
FineWeb2[19]Reference 19FineWeb2: One Pipeline to Scale Them All - Adapting Pre-Training Data Processing to Every Languagehttps://arxiv.org/abs/2506.20920About 20TB and 5B documents across 1,000+ languages from 96 Common Crawl snapshotsLanguage-adapted filtering and dedup-informed rebalancing were evaluated on nine canary languages before scale-up

These reports don't establish one universally best filter. DCLM optimized benchmark quality under its evaluation setup with aggressive retention. Nemotron-CC explicitly targeted a larger long-horizon token supply and reported both quality and quantity comparisons. FineWeb2 addresses the separate multilingual problem: thresholds, word segmentation, language identification, and deduplication behavior don't transfer cleanly from English to every language.[8]Reference 8DataComp-LM: In Search of the Next Generation of Training Sets for Language Modelshttps://arxiv.org/abs/2406.11794[18]Reference 18Nemotron-CC: Transforming Common Crawl into a Refined Long-Horizon Pretraining Datasethttps://arxiv.org/abs/2412.02595[19]Reference 19FineWeb2: One Pipeline to Scale Them All - Adapting Pre-Training Data Processing to Every Languagehttps://arxiv.org/abs/2506.20920

The data wall

This token-yield pressure is often called the data wall. Villalobos et al. estimate an effective stock of public human text at about 320T tokens after quality and multi-epoch adjustments, with a broad 95% interval from 65T to 1700T. The paper's exhaustion-point figure is about 400T (4×10144 \times 10^{14}4×1014). Under their assumptions about continued dataset growth, they project full utilization between 2026 and 2032, with a median of 2028. A 5x overtraining scenario shifts that earlier by about one year.[20]Reference 20Will We Run Out of Data? Limits of LLM Scaling Based on Human-Generated Datahttps://arxiv.org/abs/2211.04325 This is a scenario projection, not evidence that usable public text is already exhausted.

projected-public-text-stock-context.py
1effective_stock = 320e12 2training_budgets = { 3 "1T-token study": 1e12, 4 "Llama 3 405B report": 15.6e12, 5 "100T-token scenario": 100e12, 6} 7 8for label, tokens in training_budgets.items(): 9 print(f"{label:<22}: {tokens / effective_stock:>5.1%} of 320T reference stock") 10print("Comparison only: it isn't a claim that stock has been consumed.")
Output
11T-token study : 0.3% of 320T reference stock 2Llama 3 405B report : 4.9% of 320T reference stock 3100T-token scenario : 31.2% of 320T reference stock 4Comparison only: it isn't a claim that stock has been consumed.

DCLM's selected filter keeps its top 10% of documents by classifier score. Why might a team designing a longer-horizon run test a Nemotron-CC-style approach as well?

Answer

Aggressive filtering can shrink unique-token supply. Nemotron-CC targets a different tradeoff through classifier ensembling and source-conditioned synthetic variants; a team should test whether that additional yield preserves quality for its own horizon and evaluation suite.

Exact threshold charts for the lesson five-document example. At classifier thresholds 0.00, 0.50, 0.70, 0.90, and 0.95, token yield is 100, 72, 48, 28, and 12 percent while token-weighted mean retained score is 0.661, 0.797, 0.881, 0.946, and 0.980. The selected 0.90 threshold keeps 280 of 1000 tokens from proof and api-doc only.
In the lesson's five-document example, raising the threshold from 0.00 to 0.90 cuts token yield from 100% to 28% while the token-weighted mean retained classifier score rises from 0.661 to 0.946. That score is still a filter proxy; proxy-model training and downstream evaluations decide whether the threshold improves the corpus.

Additional crawl volume and stronger curation must be compared empirically. FineWeb is a good example: in its ablations, extraction, per-crawl deduplication, and filtering choices measurably changed downstream results.[4]Reference 4The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scalehttps://arxiv.org/abs/2406.17557

Synthetic data: supplement, not substitute

Synthetic data can raise signal density, but it works best when it fills a specific gap rather than replacing the whole corpus.

Where synthetic data helps

Phi-1 is one clear example. Instead of trying to mimic the raw web distribution, the dataset emphasized textbook-style explanations, exercises, and synthetic examples.[5]Reference 5Textbooks Are All You Needhttps://arxiv.org/abs/2306.11644 That makes synthetic data useful when you want more reasoning traces, worked solutions, or domain-specific exemplars than the open web naturally provides.

One proposed response to token-yield pressure is synthetic expansion. Nemotron-CC generates variants from source documents, including question-answer pairs and distilled passages, and reports improvements in specific training comparisons.[18]Reference 18Nemotron-CC: Transforming Common Crawl into a Refined Long-Horizon Pretraining Datasethttps://arxiv.org/abs/2412.02595 Source conditioning gives the generated text provenance, but the authors state that they didn't verify factual accuracy or fidelity for rephrased data. Grounding therefore needs validation rather than assumption.

Why provenance and diversity still matter

Synthetic text inherits teacher errors, style biases, and coverage gaps. Shumailov et al. study degradation when successive model generations train recursively on generated data, a failure mode often called model collapse.[21]Reference 21AI models collapse when trained on recursively generated datahttps://www.nature.com/articles/s41586-024-07566-y This doesn't prohibit synthetic supplementation. It means mixture weight, provenance, factual fidelity, and diversity need evaluation.

Source conditioning gives you a trail to inspect, not a guarantee that generated text preserved the source. Keep that distinction visible when a synthetic slice enters a training shard.

Don't conflate verified synthetic-data generation with post-training reinforcement learning. Pre-training pipelines more often use offline generation plus filtering or programmatic checks before tokens are admitted.

Common mistakes and how to catch them

Read each row as a small incident: observe the symptom, name the boundary that failed, then make one controlled change and rerun the smallest faithful slice.

MistakeSymptomCauseFix
Ignoring deduplicationModel repeats memorized boilerplate; token budget spends on repeatsDuplicate text overweights copied passagesEvaluate dedup granularity; FineWeb selected per-crawl MinHash over global dedup
Filtering non-English too aggressivelyModel loses code or math reasoning strengthCode and math contain many universal symbols that language classifiers mislabelUse separate recipes for code corpora and multilingual text
Overlooking benchmark contaminationInflated evaluation scoresEvaluation examples leaked into training data via public sourcesSpecify exact-overlap and task-specific fuzzy rules; audit removals
Forgetting PII policyModel outputs personal identifiersRaw crawls contain user-generated content with personal dataApply documented identifier/domain controls and audit a sample before training
Using an English-centric tokenizer for multilingual modelsTerrible compression and slow inference for non-English languagesVocabulary was trained on mostly English textTrain the tokenizer on a representative multilingual sample; expect 32K-128K+ vocabularies
Treating synthetic data as automatically faithfulRewrites introduce errors or narrow stylesSource-conditioned generation was admitted without validationMeasure fidelity, diversity, and downstream effects before changing mixture weight
Assuming one annealing schedule fits every modelLate-stage training gives inconsistent gainsCopied another team's annealing recipe without matching data mixTreat annealing as a hyperparameter; test on a small model first

Before a trillion-token run

Use one suspicious shard as the lab. Trace a record back to its source, inspect each filter and dedupe decision, calculate yield, then decide whether the shard should be rerun or reweighted.

The readiness record should include:

  1. Define source mix, sampling weights, language coverage, deduplication threshold, benchmark-decontamination rules, and PII scrub policy.
  2. Add retention metrics by source and language so quality filters can be audited for false positives.
  3. Record tokenizer compression rates for target languages and domains before freezing the vocabulary.
  4. Specify shard metadata: source, license or policy class, filter version, dedupe cluster, tokenizer version, and split assignment.

The checklist should make the training corpus reproducible, auditable, and measurable before any expensive run starts.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score 75% or higher to mark this lesson complete.

1.A dense 70B model is planned at 20 tokens per parameter. What token target follows before corpus quality is considered?

Correct answer: About 1.4T tokens, from 70B times the 20-token-per-parameter planning rule.

The planning rule gives 70 billion parameters multiplied by 20, or 1.4 trillion tokens. That is only a volume target; it does not make a raw crawl suitable for training.

2.A coding-assistant corpus mixes source code, API docs, runbooks, and ordinary web text. Which filtering decision is most defensible?

Correct answer: Use source-specific quality and language recipes, preserving provenance while comparing retained coverage and downstream quality.

Code and math contain symbols that generic web filters can misclassify, while runbooks and docs have different quality signals. Separate recipes make those tradeoffs measurable instead of hiding them in one threshold.

3.A SHA-256 pass misses pages with small edits. What near-duplicate pipeline matches the article?

Correct answer: Use MinHash and LSH to propose candidates, then verify each candidate with exact similarity before dropping a copy.

MinHash and LSH make fuzzy comparison tractable, but collisions are approximate. Exact Jaccard or another documented similarity rule must decide the duplicate relationship and representative.

4.Why can an n-gram decontamination pass miss a paraphrased benchmark solution?

Correct answer: Changed wording can remove shared n-grams, so task-specific fuzzy rules and manual audits may still be needed.

N-gram overlap is useful for literal or lightly edited leakage but is not semantic equivalence. Paraphrases can evade the threshold, which is why decontamination needs task-aware fuzzy checks and audit samples.

5.A raw crawl includes emails, user IDs, and sensitive URLs. Which PII control is aligned with the pipeline contract?

Correct answer: Use layered identifier and domain controls, log the policy version, and audit a sample before training.

PII appears in high-quality as well as low-quality text. Layered rules, provenance, and sample audits provide evidence that the policy was applied and catch misses before they become model behavior.

6.A team considers a much larger BPE vocabulary to reduce sequence length. What tradeoff should it measure?

Correct answer: Vocabulary size trades token compression against embedding/output-head parameters, memory, and rare-token coverage.

A larger vocabulary may shorten sequences, but it adds rows and can change coverage and parameter memory. The article treats tokenizer design as a systems tradeoff rather than a one-direction compression win.

7.A fixed-length packed block contains several independent documents, and later tokens must not read earlier documents. Which mechanism is required?

Correct answer: Use a block-diagonal causal mask that enforces causal order within each document and isolation across documents.

Position resets change position features but do not remove attention edges. A block-diagonal mask is what prevents leakage while retaining causal attention inside each packed document.

8.What does late-stage data annealing change in a pre-training run?

Correct answer: It decays the learning rate while shifting toward a higher-quality or targeted data mix, then validates the tradeoff.

Annealing is a schedule over optimization and data composition. There is no universal final mix, so teams must measure whether improved target-domain quality outweighs lost breadth or diversity.

9.A team adds source-conditioned synthetic passages to increase token supply. What evidence is still required?

Correct answer: Keep provenance and diversity metadata, then validate factual fidelity and downstream behavior instead of assuming source conditioning is proof.

Synthetic expansion can improve yield and coverage, but the generated text may distort or omit source facts. Provenance helps audit the process; it does not replace factual, diversity, and downstream validation.

10.Why might a long-horizon run evaluate a Nemotron-CC-style pipeline alongside a DCLM-style top-10% filter?

Correct answer: DCLM emphasizes aggressive classifier retention, while Nemotron-CC targets larger unique-token supply through ensembles and source-conditioned variants.

The reported corpora make different quality-yield tradeoffs. A longer training horizon can expose a data-supply bottleneck, so both retention quality and unique-token yield need evaluation on the target model and suite.

10 questions remaining.

Next Step
Continue to Build GPT from Scratch Lab

You now know how large corpora are collected, filtered, deduplicated, tokenized, packed, and documented. The next lab turns those packed token blocks into a tiny decoder-only training run so you can watch next-token labels, validation loss, and checkpoints behave as one concrete pipeline.

PreviousScaling Laws & Compute-Optimal Training
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Training Compute-Optimal Large Language Models.

Hoffmann, J., et al. · 2022 · NeurIPS 2022

https://arxiv.org/abs/2203.15556

Resolving Discrepancies in Compute-Optimal Scaling of Language Models

Porian, T., Wortsman, M., Jitsev, J., Schmidt, L., & Carmon, Y. · 2024

https://arxiv.org/abs/2406.19146

The Llama 3 Herd of Models.

Dubey, A., et al. · 2024 · arXiv preprint

https://arxiv.org/abs/2407.21783

The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scale

Penedo, G., et al. · 2024 · NeurIPS 2024

https://arxiv.org/abs/2406.17557

Textbooks Are All You Need

Gunasekar, S., et al. · 2023 · NeurIPS 2023

https://arxiv.org/abs/2306.11644

The Pile: An 800GB Dataset of Diverse Text for Language Modeling.

Gao et al. · 2020

https://arxiv.org/abs/2101.00027

Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer.

Raffel, C., et al. · 2020 · JMLR

https://arxiv.org/abs/1910.10683

DataComp-LM: In Search of the Next Generation of Training Sets for Language Models

Li, J., et al. · 2024

https://arxiv.org/abs/2406.11794

CCNet: Extracting High Quality Monolingual Datasets from Web Crawl Data

Wenzek, G., et al. · 2019 · LREC 2020

https://arxiv.org/abs/1911.00359

RedPajama: An Open Source Recipe to Reproduce LLaMA training dataset

Computer, Together · 2023 · GitHub

https://github.com/togethercomputer/RedPajama-Data

Deduplicating Training Data Makes Language Models Better.

Lee, K., Ippolito, D., et al. · 2022 · NeurIPS 2022

https://arxiv.org/abs/2107.06499

On the Resemblance and Containment of Documents.

Broder, A. Z. · 1997

https://www.cs.princeton.edu/courses/archive/spring13/cos598C/broder97resemblance.pdf

Language Models are Few-Shot Learners.

Brown, T., et al. · 2020 · NeurIPS 2020

https://arxiv.org/abs/2005.14165

Neural Machine Translation of Rare Words with Subword Units.

Sennrich, R., Haddow, B., & Birch, A. · 2016 · ACL 2016

https://arxiv.org/abs/1508.07909

Language Models are Unsupervised Multitask Learners.

Radford, A., et al. · 2019

https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.

Devlin, J., et al. · 2019 · NAACL 2019

https://arxiv.org/abs/1810.04805

SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing.

Kudo, T. & Richardson, J. · 2018 · EMNLP 2018

https://arxiv.org/abs/1808.06226

Nemotron-CC: Transforming Common Crawl into a Refined Long-Horizon Pretraining Dataset

Su, D., et al. · 2024

https://arxiv.org/abs/2412.02595

FineWeb2: One Pipeline to Scale Them All - Adapting Pre-Training Data Processing to Every Language

Penedo, G., et al. · 2025

https://arxiv.org/abs/2506.20920

Will We Run Out of Data? Limits of LLM Scaling Based on Human-Generated Data

Villalobos, P., et al. (Epoch AI) · 2022 · arXiv preprint

https://arxiv.org/abs/2211.04325

AI models collapse when trained on recursively generated data

Shumailov, I., et al. · 2024 · Nature

https://www.nature.com/articles/s41586-024-07566-y

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.