4.3.4 · D2Pretraining & Fine-Tuning LLMs

Visual walkthrough — Pretraining data curation and cleaning

3,207 words15 min readBack to topic

We are answering one concrete question the whole way:

How do we find document pairs that are almost the same, without comparing every pair to every other pair?


Step 1 — What "the same" even means: shingles

WHAT. We chop each document into overlapping little word-chunks and forget the order — we keep only the set of chunks that appeared.

WHY. Two web pages that differ by a menu item or a date are still 99% the same chunks. A raw string comparison says "different". A set-of-chunks comparison says "almost identical". We want the second notion. Using overlapping windows (not disjoint blocks) means a one-word insertion only damages shingles, not the whole document — the representation is robust to small edits. This is exactly the vocabulary Deduplication and Memorization and MinHash and LSH are built on.

Figure — Pretraining data curation and cleaning

In the figure, the sentence becomes coloured tiles. Each tile is one shingle. Document is the set tile, tile, — order thrown away, duplicates collapsed.


Step 2 — Measuring overlap: Jaccard similarity

WHAT. Count the tiles the two docs share, divide by the total distinct tiles across both.

WHY this ratio and not raw overlap count? A raw count is unfair: two huge documents share many tiles just by being long. Dividing by the union makes the score length-invariant — it always lands in . means identical sets; means no shared tile at all. We declare "near-duplicate" when (the parent used ).

Figure — Pretraining data curation and cleaning

Look at the overlapping circles: the mint lens in the middle is , the whole coloured region is . is literally lens area over total area.


Step 3 — One random ordering, one fingerprint: the minhash

WHAT. Give every tile a random number, then remember only the single smallest number your document owns. That one number is the document's fingerprint.

WHY the minimum? The minimum is a way of picking one specific tile at random out of the whole document — namely the one that happened to win the lowest lottery number. Because the ordering is random, this is a fair random draw from the document's tiles. That fairness is the whole secret, and it powers Step 4.

Figure — Pretraining data curation and cleaning

Each tile gets a random number (butter labels). The coral-circled tile is the winner — the one with the smallest number. Its number is .


Step 4 — The magic equality, seen not memorised

WHAT. The probability that two documents produce the same fingerprint equals their Jaccard similarity — the exact number from Step 2.

WHY — the picture argument. Assume the no-ties property from Step 3 (all lottery numbers distinct, so there is a unique front-runner). Pool all tiles from and line them up by their lottery number, smallest first. Now ask: which tile sits at the very front of the line?

  • The two fingerprints agree exactly when that front tile lives in the shared lens . (If the winning tile is in both sets, both documents claim it as their minimum. If it belongs to only one set, only that document owns it as its minimum, so the fingerprints differ.)
  • The winning tile is a uniformly random member of — every tile was equally likely to draw the lowest number.
  • So the chance the winner sits in the lens is

That is the equality. Nothing more — it is just "probability the random front-runner falls in the shared region." (Ties would blur which tile is the front-runner; Step 8 shows why that never matters in practice.)

Figure — Pretraining data curation and cleaning

The tiles are sorted by lottery number. The front-runner (leftmost) is highlighted; if it is a mint (shared) tile the fingerprints match. Shared tiles form a fraction of the line, so the match happens with probability .


Step 5 — Still : why banding is needed

WHAT. We replaced heavy set-intersection with cheap fingerprint comparison. But we still have to compare each document's fingerprints against every other document's — that is still comparisons. We have not escaped the 16 years.

WHY we need a new idea. We want to compare a document only against a handful of likely candidates, not all . The trick: turn "similar fingerprints" into "landed in the same bucket", so hashing does the matchmaking for us.

Figure — Pretraining data curation and cleaning

The red arrow shows the wall we hit: an grid of comparisons, almost all of them between totally unrelated documents. We need to grey out that whole grid except a thin diagonal band of real candidates.


Step 6 — Bands and rows: the bucketing trick

WHAT. Instead of demanding all fingerprints agree, we ask for a whole band of of them to agree — and we give the document independent chances (one per band) to collide with a partner.

WHY it works. Sharing an entire band of fingerprints is unlikely unless the documents are genuinely similar. So similar docs collide in buckets; dissimilar docs almost never do. We only ever compute exact for docs that already share a bucket — a tiny fraction of all pairs. That is how we escape .

Figure — Pretraining data curation and cleaning

The fingerprint column (lavender) is sliced into bands. Band 2 of doc and doc hash to the same bucket (coral), so the pair is flagged as a candidate — even though we never looked at their other bands.


Step 7 — The S-curve: the tunable wall

WHAT. A formula that says, for any true similarity , how likely the pair survives into the candidate list.

WHY it is an S-curve. For small , is tiny (raising a number below 1 to a power crushes it), so — junk pairs are ignored. As climbs past a threshold, snaps up toward 1 — real duplicates are caught. The steep jump is a wall we can place by choosing and .

Figure — Pretraining data curation and cleaning

Three S-curves for different . The dashed vertical lines are their crossovers . Tune so the wall lands just below your target — dups above are almost surely caught, junk below is almost surely skipped.


Step 8 — Edge and degenerate cases (never leave a gap)


The one-picture summary

Figure — Pretraining data curation and cleaning

The whole pipeline in one frame: text → shingle set → minhash fingerprints → bands → buckets → S-curve gate → candidate pairs → exact check → drop duplicate. Each arrow is one step you just built.

Recall Feynman retelling — say it in plain words

We wanted to find web pages that are almost copies, but comparing every page to every other is impossibly slow. So: chop each page into overlapping word-tiles and forget the order (a page is now a bag of tiles). Overlap of two bags = shared tiles over total tiles — that's Jaccard, a fair 0-to-1 score. Now the trick: give every possible tile a random lottery number (from a huge range, so ties are essentially impossible), and remember only your page's smallest number — one fingerprint. Because the ordering is random and tie-free, two pages get the same fingerprint exactly as often as they share tiles — that's the magic equality. To average out the noise, use hashes built from different seeds; the match fraction estimates with error shrinking like (it's a binomial mean). Then, to avoid all-pairs comparison, glue each band of fingerprints into a string, hash that string into a bucket, and only compare pages that share a bucket. Choosing how many bands versus rows moves a wall on the similarity axis — put the wall just below your duplicate threshold and you catch nearly all real copies while ignoring nearly all junk. Handle empties, identicals, and collisions at the edges, verify every candidate with an exact check, and you can deduplicate a trillion tokens on a normal budget.

Recall Quick self-test

Why divide by the union in Jaccard, not just count shared tiles? ::: Dividing by the union makes the score length-invariant and bounded in ; a raw count unfairly rewards long documents. In one sentence, why does ? ::: Assuming no ties, the smallest-lottery tile of is a uniformly random member, and the fingerprints match exactly when it falls in the shared region, which is a fraction of the union. Where do the hashes come from, and why does have error ? ::: From different seeds of a hash family; the match count is , whose mean-based estimate has standard deviation . What does raising to the power do to the curve? ::: It crushes small toward 0 (creating the flat low part) while leaving near 1 large, producing the S-shape wall. What are the two ways to mis-tune ? ::: too large / too small pushes the wall toward 0 (too many false positives); too small / too large pushes it toward 1 (misses real duplicates). Compute and . ::: (identicals always flagged), (disjoint docs never flagged).


Prerequisites & neighbours: Deduplication and Memorization · MinHash and LSH · Tokenization · Benchmark Contamination · Data Mixture and Domain Weighting · Scaling Laws for LLMs · Fine-Tuning and Instruction Data