soup/examples
Alpamys d75797cc3e docs(examples): make every command and promise in examples/ true
examples/README.md led with `soup train --config examples/configs/sft_basic.yaml`
and "Takes ~2-3 minutes on a consumer GPU". The command failed at validation,
and the fixture is 10 rows, so no training would have happened either way. That
timing was never measured; no timing claim replaces it.

Every command in the file was re-run against the installed CLI. Broken ones:

- `soup export output_sft_basic/ ...`  -> requires -m/--model, not positional
- `soup merge output_sft_basic/ ...`   -> requires -a/--adapter, not positional
- `soup data convert ... --from alpaca` -> no --from flag; source is auto-detected
- `soup data filter --input X`          -> takes a positional path
- `soup data score ... --output Y`      -> no --output; it prints a scorecard
- `soup data generate --provider ...`   -> --prompt is required and was missing
- `soup data demo --list`               -> no --list; bare `soup data demo` lists

Same three bugs were in synthetic_workflow.md and are fixed there too, so no
file in this directory documents a command that does not run.

The `soup data inspect` sample output was invented -- it claimed 50 entries for
a 10-row file and showed a row ("Identify the odd one out") that is not in it.
Replaced with the real output. Both config templates at the bottom of the file
taught the old flat schema, which is how a reader would have written a config
that fails to parse; both now show the current nesting.

The README is now split by what a file actually promises, which was the whole
problem: it presented a config with no data as if it were runnable.

  Runnable examples -- parse and run as-is on the bundled fixtures. Stated
    plainly: 5-10 rows, a smoke test, produces nothing useful.
  Templates -- valid configs where you supply the data. vision_llama lives
    here, and says why there is no fixture.

The Runnable table carries a VRAM column because "runnable" is hardware-
relative: the five TinyLlama configs are verified to clear the pre-flight on a
4 GB card, while dpo_example (~13 GB) and dpo_chat (~22 GB) cannot -- their
weights alone are 4.0 and 7.0 GB. Those numbers are what `soup train` predicts.

New examples/data/README.md, because Simon Willison read the folder as a
starting corpus and nothing in it said otherwise. First line says these are
format examples and test fixtures; a table gives the real row counts (10 / 5 /
8 / 5, recounted); then where to get real data, and roughly how much is needed
-- hundreds of rows for a format or style, thousands for a task the model
half-knows, and RAG rather than fine-tuning for new facts. No claim about how
volume scales with model size: we have not measured that.
2026-08-05 02:36:19 +05:00
..
configs fix(examples): migrate example configs to the current schema 2026-08-05 02:35:53 +05:00
data docs(examples): make every command and promise in examples/ true 2026-08-05 02:36:19 +05:00
reward_hacking fix(train): reward-hack mitigation review fixes (v0.71.26) 2026-07-01 16:38:00 +05:00
README.md docs(examples): make every command and promise in examples/ true 2026-08-05 02:36:19 +05:00
synthetic_workflow.md docs(examples): make every command and promise in examples/ true 2026-08-05 02:36:19 +05:00
synthetic_workflow.yaml feat(v0.53.9): Live Dashboard + UX + Bench + Standalone CLIs 2026-05-14 04:28:19 +05:00

README.md

Soup Examples

Configuration examples and sample datasets.

Two kinds of files live here, and they promise different things:

  • Runnable examples — parse and run as-is against the bundled fixtures in data/. They exist to prove your setup works end-to-end. The fixtures are 510 rows, so these runs finish quickly and produce nothing useful — they are a smoke test, not training. Point data.train at real data for that.
  • Templates — valid configs where you supply the data. They will not run until you do.

See data/README.md for what the fixtures are and where to get real data.


Runnable examples

Config Task Base model Fixture Needs
configs/sft_basic.yaml sft TinyLlama-1.1B-Chat alpaca_tiny.jsonl (10 rows) 4 GB
configs/grpo_reasoning.yaml grpo TinyLlama-1.1B-Chat reasoning_math.jsonl (5 rows) 4 GB
configs/rlhf_step1_sft.yaml sft TinyLlama-1.1B-Chat alpaca_tiny.jsonl (10 rows) 4 GB
configs/rlhf_step2_reward.yaml reward_model TinyLlama-1.1B-Chat chat_preferences.jsonl (5 rows) 4 GB
configs/rlhf_step3_ppo.yaml ppo TinyLlama-1.1B-Chat alpaca_tiny.jsonl (10 rows) 4 GB
configs/dpo_example.yaml dpo Llama-3.1-8B-Instruct dpo_sample.jsonl (8 rows) ~13 GB
configs/dpo_chat.yaml dpo Llama-2-7b-chat chat_preferences.jsonl (5 rows) ~22 GB

The five TinyLlama configs are verified to clear the pre-flight on a 4 GB card. The two larger-base configs cannot — their weights alone are 4.0 GB and 7.0 GB — so the "Needs" column is what soup train predicts for them, margin included.

Run any of them:

soup train --config examples/configs/sft_basic.yaml

Validate a config without training:

soup train --config examples/configs/sft_basic.yaml --dry-run

Gated models (Llama-2, Llama-3.1) need Hugging Face access and a login first: huggingface-cli login. The TinyLlama configs need neither.

soup train estimates peak VRAM before it loads anything and refuses to start a run it predicts won't fit, printing the breakdown and what to change. The TinyLlama configs are sized for a small card (batch_size: 4, max_length: 512) — on a bigger one you can raise both.

Basic SFT

sft_basic.yaml — instruction tuning with LoRA (r=16) on alpaca-format rows. The smallest complete config in the repo; a good base to copy.

Preference alignment (DPO)

dpo_chat.yaml and dpo_example.yaml both train on prompt / chosen / rejected pairs. dpo_example.yaml adds QLoRA (quantization: 4bit) for memory-efficient training on a larger base, and dpo_beta: 0.1 sets how hard the KL penalty pulls back toward the reference model.

Reasoning (GRPO)

grpo_reasoning.yaml generates num_generations: 4 completions per prompt and scores them with the built-in accuracy reward. See docs/training.md for custom reward functions.

Full RLHF pipeline

Three configs, run in order — step 3 reads the reward model that step 2 writes:

soup train --config examples/configs/rlhf_step1_sft.yaml
soup train --config examples/configs/rlhf_step2_reward.yaml
soup train --config examples/configs/rlhf_step3_ppo.yaml

Templates

Valid configs that need your data before they run.

Vision

configs/vision_llama.yaml — LLaMA-3.2-11B-Vision on image + conversation pairs in LLaVA format. There is no vision fixture in this repo because we do not commit image files, so data.train and data.image_dir are placeholders. Replace both, then:

soup train --config examples/configs/vision_llama.yaml

Built-in templates

soup init writes a starter soup.yaml you fill in with your own data:

soup init --template kto     # unpaired preference (thumbs up/down labels)
soup init --template orpo    # reference-free alignment
soup init --template simpo   # length-normalized preference
soup init --template ipo     # regularized preference (squared hinge)
soup init --template pretrain    # continued pre-training on raw text
soup init --template moe         # Mixture-of-Experts (Qwen3, Mixtral, DeepSeek V3)
soup init --template longcontext # RoPE scaling for 128k+ context
soup init --template embedding   # sentence embeddings (BGE, E5, GTE)
soup init --template vision      # vision-language
soup init --template audio       # audio/speech — needs pip install "soup-cli[audio]"
soup train

Full list: soup init --help. Available templates are audio, bco, chat, code, embedding, eu-ai-act, hipaa, ipo, kto, longcontext, medical, moe, orpo, pretrain, reasoning, rlhf, simpo, soc2, sr-11-7, tool-calling, vision.


Synthetic-data workflow

Generate training data from a local LLM, filter and score it, then train on the result. Walkthrough in synthetic_workflow.md; the config it trains with is synthetic_workflow.yaml (a template — it reads ./synth_clean.jsonl, which the workflow produces).

Reward-hacking mitigation demo

reward_hacking/rewards.py provides synthetic reward functions for the closed-loop mitigation feature (soup train --reward-hack-mitigation): a gameable length_hack_reward / sentinel_reward proxy decoupled from a held-out true_score. Point a GRPO config's training.reward_fn at a .py that re-exports one as reward_fn, enable reward_hack_detector: info_rm + reward_hack_mitigation: kl_control, and watch mitigation_log.jsonl under the run's output dir. See docs/training.md.


Dataset formats

Soup auto-detects and normalizes:

  • Alpaca: instruction, input, output
  • ShareGPT: conversations with from/value
  • ChatML: OpenAI-style messages with role/content
  • DPO/ORPO/SimPO/IPO: prompt + chosen + rejected
  • KTO: prompt + completion + label
  • LLaVA / ShareGPT4V: image + conversations
  • Plaintext: raw .txt or JSONL with a text field (pre-training)
  • Audio: audio path + messages

Inspect a dataset

soup data inspect examples/data/alpaca_tiny.jsonl
                   Dataset Stats
┌────────────────────┬────────────────────────────┐
│ Metric             │ Value                      │
├────────────────────┼────────────────────────────┤
│ Total samples      │ 10                         │
│ Columns            │ instruction, input, output │
│ Avg length (chars) │ 180                        │
│ Min length         │ 60                         │
│ Max length         │ 368                        │
│ Empty fields       │ 0                          │
│ Duplicates         │ 0                          │
└────────────────────┴────────────────────────────┘

Convert between formats

The source format is auto-detected; you name the target:

soup data convert examples/data/alpaca_tiny.jsonl \
  --to chatml \
  --output alpaca_as_chatml.jsonl

Directory structure

examples/
  configs/                    # YAML configs
    sft_basic.yaml            # runnable
    dpo_chat.yaml             # runnable
    dpo_example.yaml          # runnable
    grpo_reasoning.yaml       # runnable
    rlhf_step1_sft.yaml       # runnable
    rlhf_step2_reward.yaml    # runnable
    rlhf_step3_ppo.yaml       # runnable
    vision_llama.yaml         # template — bring your own images
  data/                       # format fixtures (see data/README.md)
    alpaca_tiny.jsonl
    chat_preferences.jsonl
    dpo_sample.jsonl
    reasoning_math.jsonl
  reward_hacking/             # synthetic reward fns for the mitigation demo
  synthetic_workflow.md       # synthetic-data walkthrough
  synthetic_workflow.yaml     # template config for that walkthrough

Using your own data

  1. Put your data in one of the supported formats above.
  2. Point the config at it:
data:
  train: /path/to/your/data.jsonl
  format: alpaca   # or sharegpt, chatml, dpo, llava, ... — omit for auto-detect
  1. Train:
soup train --config your_config.yaml

Config shape

Configs are nested: base, task, data, training, output at the top level. config/schema.py is the single source of truth.

Minimal

base: TinyLlama/TinyLlama-1.1B-Chat-v1.0
task: sft

data:
  train: ./your_data.jsonl
  format: alpaca
  max_length: 512

training:
  epochs: 3
  lr: 5e-4
  batch_size: 16
  lora:
    r: 16
    alpha: 32

output: ./output/

More options

base: meta-llama/Llama-2-7b-hf
task: dpo
backend: transformers        # or unsloth, mlx

data:
  train: ./dataset.jsonl
  format: dpo
  max_length: 2048
  val_split: 0.1

training:
  epochs: 2
  lr: 1e-4
  dpo_beta: 0.1
  batch_size: 16             # or "auto" to probe for the largest that fits
  gradient_accumulation_steps: 4
  quantization: 4bit         # 4bit, 8bit, none, gptq, awq, fp8, ...
  scheduler: cosine
  warmup_ratio: 0.1
  gradient_checkpointing: true
  lora:
    r: 64
    alpha: 128
    dropout: 0.05
    target_modules: auto
    # use_dora: true         # Weight-Decomposed LoRA
    # use_rslora: true       # rank-stabilized scaling

output: ./output_advanced/

After training

Batch inference

soup infer --model ./output_sft_basic/ --input prompts.jsonl --output results.jsonl

Merge the LoRA adapter into a full model

soup merge --adapter ./output_sft_basic/ --output ./merged_model/

Export to GGUF

soup export --model ./output_sft_basic/ --format gguf --quant q8_0 --output model.gguf

Requires a built llama.cpp — see docs/serving-and-export.md. soup export --model ... --deploy ollama exports and registers with Ollama in one step.

Monitor with Weights & Biases

pip install wandb
soup train --config your_config.yaml --wandb

Common issues

"CUDA out of memory"

  • Lower training.batch_size, or set it to "auto" to probe for a size that fits
  • Add training.quantization: 4bit
  • Add training.gradient_checkpointing: true
  • Use a smaller base model
  • Or stream the base layer-by-layer: training.stream_layers: true (see docs/training.md)

"Dataset not found"

  • Paths in a config resolve from the directory you run soup in, not from the config's location. Run from the repo root, or use an absolute path.
  • Check the file parses: soup data validate your_data.jsonl

"Model not found on Hugging Face"

  • Check the model id spelling
  • Gated models (Llama, Gemma) need huggingface-cli login and accepted terms

Config validation errors

soup train validates before doing any work. base: Field required or data -> train: Field required means the config uses an old flat layout — see Config shape above for the current nesting.

Learn more

Questions?