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.
No competitor — Unsloth, Axolotl, LLaMA-Factory — ships any of these checks. They let 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 the
soup 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 release line that took the suite to 16,001 tests across 313 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.