{"course":{"slug":"fine-tuning","title":"Fine-Tuning, and When Not To","url":"https://addaly.com/learn/fine-tuning","level":"advanced","track":"deep"},"lesson":{"slug":"the-dataset","title":"The Dataset Decides Everything","url":"https://addaly.com/learn/fine-tuning/the-dataset","position":28,"of":84,"minutes":11,"answer":"Your model learns your dataset's whole distribution, including the habits you never meant to teach.","keyIdea":"Your model learns your dataset's whole distribution, including the habits you never meant to teach."},"body":{"format":"markdown","text":"## Build the test set before the training set\n\nDo this first, before you write a single training example.\n\nTake 100-300 real inputs from real traffic. Not invented ones: invented inputs are always cleaner, shorter and more polite than what people actually send. Write or approve the ideal output for each. Freeze the file. Never train on it. Split it in half: a dev half you look at while iterating, and a test half you open exactly twice, once at the start to record the base model's score and once at the end.\n\nTeams that skip this cannot answer the only question that matters at the end, which is whether the work helped. They ship on vibes, and vibes favour whatever they just spent a week building.\n\n## Then write twenty by hand\n\nYourself. Not generated, not delegated. You will discover that the task you thought was well defined has four cases you had never decided, and that two of your \"obviously correct\" outputs contradict each other. Better to find that now than inside a 4,000-row dataset where the contradiction is trained in.\n\nThose twenty become the style guide for everything that follows.\n\n## The model learns the whole distribution\n\nIncluding the parts you were not thinking about.\n\n- If 30% of your answers open with \"Certainly,\" the tuned model opens with \"Certainly.\"\n- If your answers average 400 words because you wrote them carefully, it will write 400 words in reply to a yes-or-no question.\n- If every input is a well-formed question, it will handle a typo-ridden fragment badly.\n- If no example says \"I don't know,\" it will never say it.\n\nSo vary the **inputs** hard (length, register, typos, ambiguity, off-topic, hostile, and the other languages you serve) and keep the **outputs** consistent in the ways you care about. Include the hard cases, the refusals, the ones where the right answer is a clarifying question. A dataset of easy cases produces a model that is confident on hard ones.\n\n## Deduplicate\n\nNear-duplicates inflate your evaluation and waste training. Exact dedup on normalised text takes a minute:\n\n```python\nimport json, hashlib\nseen, out = set(), []\nfor line in open(\"train.jsonl\"):\n    row = json.loads(line)\n    text = row[\"messages\"][0][\"content\"]\n    key = hashlib.sha1(\" \".join(text.split()).lower().encode()).hexdigest()\n    if key not in seen:\n        seen.add(key)\n        out.append(row)\nprint(len(out))\n```\n\nThen check the same way for overlap between train and test. If a test input also appears in training, your score is fiction.\n\n## Synthetic data\n\nGenerating training data by prompting a stronger model is normal, effective, and widely done. Two conditions. Check the provider's terms, because several forbid using outputs to train competing models. And understand what you are buying: the stronger model's style, its mistakes and its blind spots, transferred faithfully. Have a human read and fix a sample. A 500-example set you have actually read beats a 5,000-example set nobody has.\n\nNever draw the test set from the same generator. It would measure agreement with the generator, not quality.\n\n## How many examples\n\nHonest ranges, assuming clean data and LoRA on a competent instruct base:\n\n- **50-200**: tone, register, format, output schema. This works better than people expect, and it is where most teams should stop.\n- **500-2,000**: a narrow task with real accuracy gains: routing, extraction, structured summarisation in your house form.\n- **5,000-50,000**: a new behaviour, or wide domain coverage. Expect weeks of data work.\n\nLIMA is the paper everyone cites for \"a thousand examples is enough.\" Read what it measured: human preference for helpfulness and style, starting from a strong 65B base. It is real evidence about style. It is not evidence that a thousand examples teaches a task that requires being right.\n\n## Find your own number with an ablation\n\nDo not guess. Train on 25%, 50% and 100% of your data with everything else fixed, and score each on the dev set.\n\n- Still climbing at 100%? More of the same data will help.\n- Flat between 50% and 100%? More of the same will not. You need *different* data (harder cases, different input styles) or the bottleneck is somewhere else entirely.\n\nThree small runs cost a few dollars and replace an argument that would otherwise last a month.\n\n## One aside worth the whole lesson\n\nIf your task is classification over a fixed label set and you have 5,000 or more labelled examples, fine-tune a small encoder model (the BERT family, 100-400M parameters) before you fine-tune an LLM. It is often more accurate, it serves on a CPU for a fraction of the cost, and it trains in twenty minutes. The unfashionable answer is frequently the right one.\n\n> Figure: How many examples, by what you are teaching. Layers, top to bottom: 50 to 200 examples (Tone, register, format, an output schema. This works better than people expect, and it is where most teams should stop.); 500 to 2,000 (A narrow task with real accuracy gains: routing, extraction, structured summarising in your house form.); 5,000 to 50,000 (A genuinely new behaviour, or wide domain coverage. Expect weeks of data work, not a weekend.). LIMA is the paper cited for \"a thousand is enough\". It measured human preference for helpfulness and style from a strong 65B base: real evidence about style, and not evidence that a thousand examples teaches a task that requires being right."},"check":{"question":"You generated 4,000 training examples by prompting a strong model, held out 400 of them, and scored 92%. In production the model is clearly worse than that number suggests. What is the most likely explanation?","options":[{"text":"The model overfit; train for fewer epochs.","correct":false,"tempting":"A large train-test gap is the classic overfitting signature, but here the held-out score is high too: both sets are simply the wrong distribution."},{"text":"4,000 examples is too few for this task; generate 40,000.","correct":false,"tempting":"More data is the reflex, but forty thousand examples from the same generator produce the same mismatch and roughly the same 92%."},{"text":"The base model was contaminated with the evaluation data during pretraining.","correct":false,"tempting":"Contamination is a real problem for public benchmarks, but this set is private and freshly generated; the gap is distributional, not memorised."},{"text":"The held-out set came from the same generated pool, so it measures agreement with the generator on generator-shaped inputs rather than performance on real ones.","correct":true}]},"prev":{"slug":"training-on-a-small-budget","title":"Training on a free or nearly free budget","url":"https://addaly.com/learn/fine-tuning/training-on-a-small-budget"},"next":{"slug":"where-the-data-comes-from","title":"Where the data legitimately comes from","url":"https://addaly.com/learn/fine-tuning/where-the-data-comes-from"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'The Dataset Decides Everything', in Fine-Tuning, and When Not To. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/fine-tuning/the-dataset (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"The Dataset Decides Everything","courseTitle":"Fine-Tuning, and When Not To","module":{"index":4,"slug":"building-the-dataset","title":"Building the dataset"},"answer":null,"keyIdea":"Your model learns your dataset’s whole distribution, including the habits you never meant to teach.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure 4.1","figure":{"type":"stack","title":"How many examples, by what you are teaching","layers":[{"label":"50 to 200 examples","detail":"Tone, register, format, an output schema. This works better than people expect, and it is where most teams should stop."},{"label":"500 to 2,000","detail":"A narrow task with real accuracy gains: routing, extraction, structured summarising in your house form."},{"label":"5,000 to 50,000","detail":"A genuinely new behaviour, or wide domain coverage. Expect weeks of data work, not a weekend."}],"caption":"LIMA is the paper cited for “a thousand is enough”. It measured human preference for helpfulness and style from a strong 65B base: real evidence about style, and not evidence that a thousand examples teaches a task that requires being right."},"alt":"Figure: How many examples, by what you are teaching. Layers, top to bottom: 50 to 200 examples (Tone, register, format, an output schema. This works better than people expect, and it is where most teams should stop.); 500 to 2,000 (A narrow task with real accuracy gains: routing, extraction, structured summarising in your house form.); 5,000 to 50,000 (A genuinely new behaviour, or wide domain coverage. Expect weeks of data work, not a weekend.). LIMA is the paper cited for “a thousand is enough”. It measured human preference for helpfulness and style from a strong 65B base: real evidence about style, and not evidence that a thousand examples teaches a task that requires being right."}},"blocks":[{"t":"h2","id":"build-the-test-set-before-the-training-set","runs":[{"text":"Build the test set before the training set"}]},{"t":"p","runs":[{"text":"Do this first, before you write a single training example."}]},{"t":"p","runs":[{"text":"Take 100-300 real inputs from real traffic. Not invented ones: invented inputs are always cleaner, shorter and more polite than what people actually send. Write or approve the ideal output for each. Freeze the file. Never train on it. Split it in half: a dev half you look at while iterating, and a test half you open exactly twice, once at the start to record the base model’s score and once at the end."}]},{"t":"p","runs":[{"text":"Teams that skip this cannot answer the only question that matters at the end, which is whether the work helped. They ship on vibes, and vibes favour whatever they just spent a week building."}]},{"t":"h2","id":"then-write-twenty-by-hand","runs":[{"text":"Then write twenty by hand"}]},{"t":"p","runs":[{"text":"Yourself. Not generated, not delegated. You will discover that the task you thought was well defined has four cases you had never decided, and that two of your “obviously correct” outputs contradict each other. Better to find that now than inside a 4,000-row dataset where the contradiction is trained in."}]},{"t":"p","runs":[{"text":"Those twenty become the style guide for everything that follows."}]},{"t":"h2","id":"the-model-learns-the-whole-distribution","runs":[{"text":"The model learns the whole distribution"}]},{"t":"p","runs":[{"text":"Including the parts you were not thinking about."}]},{"t":"ul","items":[[{"text":"If 30% of your answers open with “Certainly,” the tuned model opens with “Certainly.”"}],[{"text":"If your answers average 400 words because you wrote them carefully, it will write 400 words in reply to a yes-or-no question."}],[{"text":"If every input is a well-formed question, it will handle a typo-ridden fragment badly."}],[{"text":"If no example says “I don’t know,” it will never say it."}]]},{"t":"p","runs":[{"text":"So vary the "},{"text":"inputs","b":true},{"text":" hard (length, register, typos, ambiguity, off-topic, hostile, and the other languages you serve) and keep the "},{"text":"outputs","b":true},{"text":" consistent in the ways you care about. Include the hard cases, the refusals, the ones where the right answer is a clarifying question. A dataset of easy cases produces a model that is confident on hard ones."}]},{"t":"h2","id":"deduplicate","runs":[{"text":"Deduplicate"}]},{"t":"p","runs":[{"text":"Near-duplicates inflate your evaluation and waste training. Exact dedup on normalised text takes a minute:"}]},{"t":"code","lang":"python","label":"Python","text":"import json, hashlib\nseen, out = set(), []\nfor line in open(\"train.jsonl\"):\n    row = json.loads(line)\n    text = row[\"messages\"][0][\"content\"]\n    key = hashlib.sha1(\" \".join(text.split()).lower().encode()).hexdigest()\n    if key not in seen:\n        seen.add(key)\n        out.append(row)\nprint(len(out))"},{"t":"p","runs":[{"text":"Then check the same way for overlap between train and test. If a test input also appears in training, your score is fiction."}]},{"t":"h2","id":"synthetic-data","runs":[{"text":"Synthetic data"}]},{"t":"p","runs":[{"text":"Generating training data by prompting a stronger model is normal, effective, and widely done. Two conditions. Check the provider’s terms, because several forbid using outputs to train competing models. And understand what you are buying: the stronger model’s style, its mistakes and its blind spots, transferred faithfully. Have a human read and fix a sample. A 500-example set you have actually read beats a 5,000-example set nobody has."}]},{"t":"p","runs":[{"text":"Never draw the test set from the same generator. It would measure agreement with the generator, not quality."}]},{"t":"h2","id":"how-many-examples","runs":[{"text":"How many examples"}]},{"t":"p","runs":[{"text":"Honest ranges, assuming clean data and LoRA on a competent instruct base:"}]},{"t":"ul","items":[[{"text":"50-200","b":true},{"text":": tone, register, format, output schema. This works better than people expect, and it is where most teams should stop."}],[{"text":"500-2,000","b":true},{"text":": a narrow task with real accuracy gains: routing, extraction, structured summarisation in your house form."}],[{"text":"5,000-50,000","b":true},{"text":": a new behaviour, or wide domain coverage. Expect weeks of data work."}]]},{"t":"p","runs":[{"text":"LIMA is the paper everyone cites for “a thousand examples is enough.” Read what it measured: human preference for helpfulness and style, starting from a strong 65B base. It is real evidence about style. It is not evidence that a thousand examples teaches a task that requires being right."}]},{"t":"h2","id":"find-your-own-number-with-an-ablation","runs":[{"text":"Find your own number with an ablation"}]},{"t":"p","runs":[{"text":"Do not guess. Train on 25%, 50% and 100% of your data with everything else fixed, and score each on the dev set."}]},{"t":"ul","items":[[{"text":"Still climbing at 100%? More of the same data will help."}],[{"text":"Flat between 50% and 100%? More of the same will not. You need "},{"text":"different","i":true},{"text":" data (harder cases, different input styles) or the bottleneck is somewhere else entirely."}]]},{"t":"p","runs":[{"text":"Three small runs cost a few dollars and replace an argument that would otherwise last a month."}]},{"t":"h2","id":"one-aside-worth-the-whole-lesson","runs":[{"text":"One aside worth the whole lesson"}]},{"t":"p","runs":[{"text":"If your task is classification over a fixed label set and you have 5,000 or more labelled examples, fine-tune a small encoder model (the BERT family, 100-400M parameters) before you fine-tune an LLM. It is often more accurate, it serves on a CPU for a fraction of the cost, and it trains in twenty minutes. The unfashionable answer is frequently the right one."}]}],"check":{"question":[{"text":"You generated 4,000 training examples by prompting a strong model, held out 400 of them, and scored 92%. In production the model is clearly worse than that number suggests. What is the most likely explanation?"}],"options":[{"text":[{"text":"The model overfit; train for fewer epochs."}],"correct":false,"tempting":[{"text":"A large train-test gap is the classic overfitting signature, but here the held-out score is high too: both sets are simply the wrong distribution."}]},{"text":[{"text":"4,000 examples is too few for this task; generate 40,000."}],"correct":false,"tempting":[{"text":"More data is the reflex, but forty thousand examples from the same generator produce the same mismatch and roughly the same 92%."}]},{"text":[{"text":"The base model was contaminated with the evaluation data during pretraining."}],"correct":false,"tempting":[{"text":"Contamination is a real problem for public benchmarks, but this set is private and freshly generated; the gap is distributional, not memorised."}]},{"text":[{"text":"The held-out set came from the same generated pool, so it measures agreement with the generator on generator-shaped inputs rather than performance on real ones."}],"correct":true,"tempting":null}],"order":[1,0,2,3],"why":null},"prev":{"slug":"training-on-a-small-budget","title":"Training on a free or nearly free budget","minutes":10},"next":{"slug":"where-the-data-comes-from","title":"Where the data legitimately comes from","minutes":9}}}