Seven of the eight configs in examples/configs/ did not parse. They were
written against a pre-nesting schema and stayed that way through several
schema changes, so `soup train --config examples/configs/sft_basic.yaml` --
the first command examples/README.md tells you to run -- failed validation
with "base: Field required; data -> train: Field required".
model: -> base:
data.path: -> data.train:
max_seq_length: -> data.max_length
quantization: -> training.quantization ("null" -> "none", int8 -> 8bit)
lora_r/alpha/... -> training.lora.{r,alpha,dropout,target_modules}
num_epochs -> training.epochs
learning_rate -> training.lr
lr_scheduler_type -> training.scheduler
output_dir: -> output:
Dropped keys with no schema equivalent: seed, eval_steps, eval_strategy,
save_strategy, load_best_model_at_end.
Three correctness fixes beyond the mechanical migration:
- dpo_chat / rlhf_step2_reward declared `format: sharegpt`, but
chat_preferences.jsonl is prompt/chosen/rejected -- detect_format() calls
it dpo, and a reward model needs the pair shape. Now `format: dpo`.
- target_modules listed `out_proj`, which no Llama has (it is `o_proj`), so
PEFT would have raised on the two configs using it.
- vision_llama pointed at examples/data/vision_dataset.jsonl and
examples/data/images/, neither of which has ever existed in this repo. It
is now marked a TEMPLATE in its first line, with placeholder paths and the
reason there is no fixture: we do not commit image files. Its base model id
was `llama-vision-13b`, which is not a real repo id; now
meta-llama/Llama-3.2-11B-Vision-Instruct, matching the vision template.
batch_size and max_length on the five TinyLlama configs were leftovers that
made them unrunnable rather than tuned choices: batch_size 16 against a
10-row fixture never forms a single batch, and max_length 2048 against a
longest-row of ~233 tokens only inflated the activation budget. The VRAM
pre-flight refused all five on a 4 GB card. Now batch_size 4 / max_length
512, with the reason written above the line so the number does not drift
back anonymously. Verified: all five clear `soup train --dry-run` on a 4 GB
card and report their data as valid. dpo_example is unchanged (its values
are pinned by tests/test_dpo_example.py).
All 8 configs now pass load_config_from_string.
Every printed and documented `pip install 'soup-cli[extra]'` was bash / zsh /
PowerShell syntax and failed on Windows cmd.exe:
ERROR: Invalid requirement: "'soup-cli[train]'": Expected package name at
the start of dependency specifier
cmd.exe has no single-quote quoting, so it passes the quotes to pip verbatim
and pip rejects the requirement. Nothing in Soup can fix that once the command
is typed -- pip and the shell own it, and Soup is not installed yet when the
README line runs -- so the fix is the spelling we print.
Migrated 147 sites across 67 files to `pip install "soup-cli[extra]"`:
- 64 in src/ (Rich console hints + plain ImportError text)
- 57 in README.md + docs/
- 22 in src/soup_cli/templates/*.yaml + examples/configs/*.yaml
- 3 in examples/README.md
Double quotes are the only spelling valid in every shell (cmd, PowerShell,
bash, zsh), which is why the repo already used `pip install -e ".[dev]"`.
Measured on Windows: single quotes fail ONLY on cmd; double quotes pass
everywhere; bare passes on Windows but zsh globs `[extra]` and fails.
Method note (the PR #247 class): the hints sit INSIDE double-quoted Python
string literals, so a blind ' -> " sed produces SyntaxError. A tokenize-based
rewriter escaped `\"` in DQUOTE tokens and left bare `"` in TRIPLE / COMMENT
tokens; every touched .py was compile-checked. The full suite (not ruff, not
compile-check) caught two rewriter blind spots: the real YAML templates under
src/soup_cli/templates/ (byte-identical drift test) and examples/README.md.
A regression test (tests/test_v07137.py) scans the package and every docs code
block for the single-quoted form; prose may still name it so a reader from an
older tutorial recognises the error.
Also bundles #315 (@Sanjays2402): eval-gate benchmark tasks now run via
ForgettingDetector instead of a helper that never existed. Closes#310.
Test count: 16283 -> 16288 (+4 in tests/test_v07137.py).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a working DPO (Direct Preference Optimization) example using the
current Pydantic config schema with Llama 3.1 8B Instruct and QLoRA.
- examples/configs/dpo_example.yaml: DPO config with all core training
and LoRA parameters, plus commented-out advanced options
- examples/data/dpo_sample.jsonl: 8 preference pairs in DPO format
with ShareGPT-style message lists for chosen/rejected
- tests/test_dpo_example.py: 7 tests validating config loading, field
values, data format detection, and data validation
- examples/README.md: document the new DPO with QLoRA example