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.
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.
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.