Fine-tune Doctor (v0.71.27)
Most fine-tunes don't fail loudly. They fail silently: the model never stops generating, the assistant turns were never actually trained, or your DPO run quietly learns "longer = better" instead of the preference you meant. v0.71.27 "Fine-tune Doctor" is a pure-CPU, zero-GPU pre-flight that catches these before a single training step.
We have not found these checks in Unsloth, Axolotl or LLaMA-Factory. Without them you find out after the GPU hour.
soup data doctor — 8 chat-template checks
soup data doctor chats.jsonl --model meta-llama/Llama-3.1-8BIt renders your data through the model's real tokenizer and chat template, then runs eight checks:
| # | Check | Catches |
|---|---|---|
| 1 | chat_template present | Tokenizer with no chat template at all |
| 2 | template_render | A template that throws on your rows |
| 3 | generation markers | Missing {% generation %} spans (needed for response-only masking) |
| 4 | eos_in_labels | The #1 "model never stops generating" bug — every assistant turn's trained span must actually contain an EOS/EOT token (checked on every turn, not just the last) |
| 5 | bos_duplication | Template and tokenizer both prepending BOS |
| 6 | system_role | Mistral-style templates that reject a leading system turn |
| 7 | unknown_roles | Roles the template doesn't understand |
| 8 | truncation_risk | p95 rendered length vs max_length |
The verdict uses the same OK / MINOR / MAJOR taxonomy as soup diagnose: exit 0 on OK/MINOR, exit 2 on MAJOR, so it drops straight into CI.
--max-length (default 2048) is the length the truncation_risk check compares against, so pass the data.max_length you train with; it also truncates the --show-mask rows. The check is OK when the p95 rendered length is within it, MAJOR when at least 20% of the sampled rows are longer, and MINOR otherwise. --sample (default 200, at most 20000, otherwise exit 1) is how many rows the checks run on, spaced evenly across the file rather than taken from the top.
See the mask, don't guess it
soup data doctor chats.jsonl --model meta-llama/Llama-3.1-8B --show-mask 3--show-mask N prints N sample rows with every token coloured trained vs masked, rendered through the real collator path (answer-only, per-message train-field, or RAFT span-mask), not a reimplementation. An assistant-mask bug becomes visible instantly. The flags --train-on-responses-only and --train-on-messages-with-train-field pick the exact masking strategy soup train would use, so what you see is what you'll train.
Dataset-derived strings are stripped of C0 control characters before hitting your terminal (Rich's markup escape doesn't neutralise raw ESC bytes); the --output JSON is unaffected.
soup data lint — the preference-data linter
soup data lint prefs.jsonl # word-count length bias
soup data lint prefs.jsonl --model Qwen/Qwen2.5-7B # exact token-length biasFor dpo / orpo / simpo / ipo / bco / kto data it flags:
length_bias— chosen systematically longer than rejected (the #1 silent DPO degradation), reported as a Cohen's d effect size so you know how bad it is, not just that it exists.label_imbalance— KTO desirable:undesirable ratio out of balance.near_duplicates— MinHash/LSH near-dupes (reuses thesoup data dedupkernel).identical_pairs— chosen == rejected, i.e. zero preference signal.prompt_leak— the prompt echoed verbatim inside the completion.
--sample sets how many rows the linter checks (default 2000, at most 50000, otherwise exit 1), spaced evenly across the file.
Numbers
Validated live against the real HuggingFaceTB/SmolLM2-135M-Instruct tokenizer; the smoke pass found and fixed two genuine bugs. Part of the v0.71 release line, which closed at 16,529 tests across 319 files.
See also
- soup diagnose — the post-training report card whose OK/MINOR/MAJOR taxonomy the doctor mirrors.
- Pre-flight & tooling —
soup plan/apply,soup tunability, hardware-fit, the rest of the "catch it before GPU" surface. - MCP server —
data_doctoris one of the tools exposed to your coding agent.
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.