--- name: training-data description: "Use when assembling or curating the corpus a fine-tune trains on — turning raw examples into the JSONL shape a trainer expects (instruction, conversational, preference-pair or binary-label), matching the data to the model's chat template, generating synthetic or distilled examples, deduplicating and decontaminating against eval sets, and quality-filtering. NOT cleaning tabular rows, nulls and dtypes (that is `data-cleaning`), NOT building a retrieval corpus of chunks and embeddings (that is `embeddings-search`), NOT running the trainer or picking hyperparameters (that is `finetuning`)." tags: [training-data, fine-tuning-dataset, jsonl, chat-template, preference-data, dpo, kto, synthetic-data, decontamination, dataset-curation] recommends: [finetuning, unsloth, huggingface, data-cleaning] origin: risco --- # training-data — the corpus a fine-tune actually eats You own the **training corpus**: the JSONL of chat turns, instruction triples, or preference pairs that a trainer reads. The deliverable is a validated, deduplicated, decontaminated, license-clean file in the **exact shape the trainer expects**, rendered through the **target model's chat template**. You stop the moment that file loads cleanly and round-trips through `apply_chat_template`. You do not choose LoRA rank or launch the run — that is [`finetuning`](../finetuning/SKILL.md) / [`unsloth`](../unsloth/SKILL.md). **Loud boundary.** This is *LLM training corpora* — messages, instruction triples, preference pairs. It is **not**: - Tabular row cleaning — nulls, dtypes, dedupe of CSV rows, category normalization → [`data-cleaning`](../data-cleaning/SKILL.md). - A *retrieval* corpus — chunking documents and embedding them for search → [`embeddings-search`](../embeddings-search/SKILL.md). - Actually training or serving — hyperparameters, the run, export → [`finetuning`](../finetuning/SKILL.md), [`unsloth`](../unsloth/SKILL.md), [`huggingface`](../huggingface/SKILL.md). **Version reality (verified July 2026 — re-verify, these move monthly).** TRL is on the **v1.x** line (its dataset-formats doc was tagged `v1.8.0` at author time); `transformers` is in the **4.57+** era (mixed text+vision data needs ≥4.57); `datasets` is **4.x** (the `Json()` feature type needs ≥4.7). Pin whatever you install — do not trust these numbers as current. ## 1. The format the trainer expects (pick by trainer, not by taste) The trainer dictates the columns. Get this wrong and TRL either errors or, worse, trains on a mangled string. Two axes: **format** (`standard` = plain strings vs `conversational` = `messages` lists) and **type** (the task). One JSON object per line = JSONL. | Trainer | Dataset type | Required keys | | --- | --- | --- | | `SFTTrainer` | language-modeling **or** prompt-completion | `messages` / `text`, or `prompt`+`completion` | | `DPOTrainer`, `ORPOTrainer`, `CPOTrainer` | preference (explicit prompt recommended) | `prompt`, `chosen`, `rejected` | | `KTOTrainer`, `BCOTrainer` | unpaired preference (binary label) | `prompt`, `completion`, `label` | | `RewardTrainer` | preference (implicit prompt) | `chosen`, `rejected` | | `GRPOTrainer`, `RLOOTrainer`, `PPOTrainer` | prompt-only | `prompt` | Tiny JSONL of each (conversational values are **lists of `{role, content}`**; `label` is a JSON boolean): ```jsonl # Alpaca instruction (standard) — classic; NOT a native TRL type, see below {"instruction": "Classify the sentiment.", "input": "The battery dies in an hour.", "output": "negative"} # Conversational messages (SFT) — the default for chat fine-tunes {"messages": [{"role": "system", "content": "You are a terse support agent."}, {"role": "user", "content": "My order never arrived."}, {"role": "assistant", "content": "Sorry about that — what is your order number?"}]} # Preference pair (DPO) — chosen beats rejected for the same prompt {"prompt": [{"role": "user", "content": "Define a hash map in one sentence."}], "chosen": [{"role": "assistant", "content": "A hash map stores key-value pairs and finds a value by hashing its key to a bucket, giving average O(1) lookup."}], "rejected": [{"role": "assistant", "content": "It's a fast dictionary thing."}]} # KTO / unpaired preference — one completion + a good/bad boolean label {"prompt": [{"role": "user", "content": "Define a hash map in one sentence."}], "completion": [{"role": "assistant", "content": "It's a fast dictionary thing."}], "label": false} ``` **Alpaca is not a native TRL type.** `{instruction, input, output}` is the Stanford-Alpaca convention, still common in Unsloth notebooks, but TRL trains on `text`/`messages`/`prompt`+ `completion`. You must either (a) map it into `messages` (instruction+input → user, output → assistant), or (b) render it into a single `text` string via a prompt template — **and append the EOS token yourself**, or the model never learns to stop (the #1 Unsloth-Alpaca bug). Prefer (a) `messages` for chat models. Full field matrix, tool-calling (`tools` column) and vision (`images`) extras, and every type→type conversion live in `references/formats.md`. ## 2. Chat templates — the silent run-wrecker A chat template is a **Jinja** string stored in the tokenizer (in `tokenizer_config.json` under `chat_template`, or a standalone `chat_template.jinja` in newer tokenizers). It maps a `messages` list to the exact token string the model was trained on — special tokens (`<|im_start|>`, `[INST]`, `<|start_header_id|>`, …) and all. You render it, you never hand-type it: ```python from transformers import AutoTokenizer tok = AutoTokenizer.from_pretrained("") # the model you will fine-tune # TRAINING: no trailing generation prompt — the assistant turn is already in the data text = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=False) # INFERENCE: add_generation_prompt=True appends the assistant turn-start so the model continues prompt = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True) ``` Three ways this silently destroys a run — **no error, just a worse model**: - **Hand-formatting the tokens.** Writing `<|im_start|>user\n…` strings yourself and getting one token, one newline, or the BOS wrong. Train-time string ≠ inference-time string → the model learns a distribution it is never served. Always render via `apply_chat_template`. - **Using the wrong model's template.** The template must be the one of the model you are fine-tuning. Copy Llama's template onto a Qwen fine-tune and every example is subtly malformed. - **A base model with no template at all.** Base (non-instruct) checkpoints often ship `chat_template = None`. `apply_chat_template` then raises — you must **choose and attach** a template (e.g. ChatML) and use that same one at inference forever after. Also decide **loss masking**: for chat SFT you usually train only on the assistant tokens (`completion_only_loss` / assistant-only masking in SFTTrainer, or a completion-only collator), so the model is not penalized for "predicting" the user's words. TRL applies the template for you when the dataset is conversational — let it, rather than pre-flattening to `text`. ## 3. Synthetic data & distillation Not enough real examples? Generate them. Two workhorses: **Self-Instruct** (seed a few hand-written examples, prompt a strong model to produce more, filter) and **Evol-Instruct** (iteratively mutate prompts to be harder/deeper). Wrap them in a pipeline framework rather than ad-hoc loops (see §7). **Licensing trap — read before you distill.** Generating your training data from *another model's outputs* ("distillation") is a **terms-of-service question, not just a quality one**. Some providers' terms restrict using their outputs to train competing models; some open-weight licenses carry naming/derivative obligations (e.g. Llama-derived data/models may inherit naming requirements). Never assert a model's license from memory — check the specific model card and provider ToS at author time (licenses change). If in doubt, distill from an openly-licensed-for-this-use model, and record the provenance per example. ## 4. Dedup + decontamination (skip these and your numbers lie) - **Dedup.** Exact dedup is trivial (hash the text). Real corpora need **near-dup** removal: **MinHash + LSH** (Jaccard similarity over shingles) catches templated/boilerplate repeats that inflate a few patterns. Dupes waste compute and bias the model toward whatever is over-represented. - **Decontamination — the one people forget.** Remove any training example that overlaps your **eval / benchmark test sets** (n-gram overlap, e.g. long-n-gram match against MMLU, GSM8K, your own held-out set). If test items leak into training, your eval score is **inflated** and meaningless — you measured memorization, not capability. Decontaminate *against every metric you will report*, including your private eval. Code for both in `references/synthesis-dedup-quality.md`. ## 5. Quality filtering — a few thousand clean beats a noisy dump **LIMA** (*Less Is More for Alignment*, arXiv **2305.11206**) is the anchor: ~1,000 carefully curated examples produced a strong instruction-follower — for **alignment/style** SFT, quality and diversity dominate raw volume. (This is about teaching *behavior/format*, not injecting a lot of new *knowledge* — a broad knowledge shift still wants scale.) Cheap, high-leverage filters, applied before you spend GPU hours: - **Length/format**: drop empty or truncated turns, runaway-length outliers, malformed JSON, wrong-role sequences (two `assistant` turns in a row, missing final assistant turn for SFT). - **Dedup + decontam** from §4. - **Diversity**: cluster/embed and prune near-identical intents so the set is not 80% one task. - **Model/heuristic scoring**: rate helpfulness/correctness (a reward model or an LLM judge) and keep the top slice — but audit the judge, LLM-as-judge has its own biases. ## 6. Licensing — two separate questions 1. **The dataset's own license** — what *you* release the JSONL under, and whether you *can* release it (aggregating others' data does not launder their licenses). 2. **Source-usage restrictions** — the terms on where each example *came from*: scraped-site ToS, the license of any base dataset you built on, and the model-output ToS from §3. These bind even if you never publish. Keep a provenance column so an audit can trace every row. State the license *class* and point at the source; never freeze a license as bare fact. ## 7. Tooling - **distilabel** (Argilla, now under Hugging Face) — the go-to synthetic-data / AI-feedback pipeline framework: composable `Step`/`Task` graphs (`TextGeneration`, `UltraFeedback`, `EvolInstruct`), serializable to YAML/JSON, outputs a `Distiset` you push to the Hub. v1.x. - **Argilla** — human-in-the-loop annotation/review UI to label and vet examples. - **HF `datasets`** — load/`map`/`filter`/`push_to_hub`; the substrate everything else speaks. - **Lilac** — dataset exploration/clustering for quality triage. **[verify — the open-source repo was archived (read-only) around July 2025 after the Databricks acquisition]**; treat as unmaintained OSS and confirm before depending on it. ## Worked lifecycle (build → validate → dedup → decontaminate → format → push) ```python from datasets import load_dataset from transformers import AutoTokenizer ds = load_dataset("json", data_files="raw.jsonl", split="train") tok = AutoTokenizer.from_pretrained("") # 1. VALIDATE shape + render every row through the template (catches template errors NOW, # not after 3 GPU-hours). A base model with chat_template=None raises here — attach one. def render(ex): return {"text": tok.apply_chat_template(ex["messages"], tokenize=False, add_generation_prompt=False)} ds = ds.filter(lambda ex: isinstance(ex.get("messages"), list) and ex["messages"] and ex["messages"][-1]["role"] == "assistant") # SFT: must end on assistant ds = ds.map(render) # 2. DEDUP (near-dup) and 3. DECONTAMINATE against your eval set — see references for MinHash # + n-gram code; both are one filter pass each. # 4. PUSH with a data card recording license + provenance. ds.push_to_hub("me/support-sft", private=True) ``` Deep code — MinHash/LSH dedup, n-gram decontamination, a distilabel Self-Instruct pipeline, and the full conversion matrix — is in `references/`. ## Guardrails / gotchas - **Wrong format for the trainer** = hard error or silent garbage. Match the table in §1 to your trainer before generating a single row. - **Hand-typed chat tokens** train a distribution you never serve. Render via `apply_chat_template`. - **No EOS in Alpaca-`text` formatting** → the model never stops. Append it. - **Skipped decontamination** → inflated eval; you measured leakage. Non-negotiable. - **Distilling model outputs** can violate ToS. Provenance + license check first. - **Quantity worship** — a noisy 500k dump loses to a curated few-thousand for alignment (LIMA). - `label` in KTO/unpaired data is a JSON boolean (`true`/`false`), not the strings `"true"`/`"1"`. ## Related skills - [`finetuning`](../finetuning/SKILL.md) — consumes this corpus: chooses SFT vs DPO vs KTO, LoRA/QLoRA, hyperparameters, runs trl/peft. You hand it the file; it trains. - [`unsloth`](../unsloth/SKILL.md) — one fast single-GPU training backend + GGUF export; its notebooks expect exactly the Alpaca/`messages` shapes you produce here. - [`huggingface`](../huggingface/SKILL.md) — the Hub you `push_to_hub` the dataset to, model cards, and hosted/routed inference of the *result*. - [`data-cleaning`](../data-cleaning/SKILL.md) — upstream when your raw source is dirty *tabular* rows; it hands you clean rows, you turn rows into training examples. ## Checklist - [ ] Format matches the target **trainer** (§1 table); one JSON object per line. - [ ] Every row renders through the **target model's** `apply_chat_template` without error. - [ ] SFT rows end on an `assistant` turn; preference rows have distinct `chosen`/`rejected`; KTO `label` is a boolean. - [ ] Loss masking / EOS handling decided (assistant-only loss; EOS appended if flattening to `text`). - [ ] Near-duplicates removed (MinHash/LSH); exact dupes gone. - [ ] **Decontaminated** against every eval/benchmark you will report. - [ ] Quality-filtered (length/format/diversity/score) — curated over bulk. - [ ] Dataset license set **and** source-usage/model-output ToS checked; provenance recorded. - [ ] Data card written; pushed (private first).