FAQ
General
What models does Soup support?
Any HuggingFace-compatible model. Popular choices include Llama, Mistral, Qwen, Phi, and Gemma families. Vision models (LLaMA-3.2-Vision, Qwen2-VL) and audio models (Qwen2-Audio) are also supported.
Do I need a GPU?
A CUDA-compatible GPU is strongly recommended, and 4-bit quantization is what makes a small card usable. As a QLoRA rule of thumb: 8 GB reaches about 7B, 16 GB about 14B, 24 GB about 34B, 48 GB about 70B, and 80 GB and up covers 70B QLoRA with headroom or a MoE. Full fine-tuning is a different budget: in our H100 measurement an 8B full fine-tune did not fit on one 80 GB card even at batch 1 (see LISA). For a card too small for that rule of thumb, layer streaming changes the arithmetic entirely: it bounds peak VRAM by one decoder layer rather than by the model, which is how an 8B trains on a 4 GB card.
How is Soup different from other fine-tuning tools?
Soup is CLI-first and opinionated. One command to train, one YAML to configure. It wraps best practices (Unsloth, FlashAttention, optimal hyperparameters) so you don't have to research them. 23 training methods (text / vision / audio / ASR / TTS / classifier / distill / preference / MoLE routing / online DPO), 17 quantization formats, multimodal support, full pipeline from training to deployment. Plus, you can migrate from LLaMA-Factory, Axolotl, or Unsloth in one command.
What version is current?
Soup CLI v0.76.0, tagged 12 October 2026, with no codename: upstream titled it with a sentence, "settings Soup accepted and never applied now stop the load", and that sentence is the release. 490 pull requests were merged between 12 September, the day v0.75.0 shipped, and the tag, and 418 of them came from 80 people outside the maintainer. What they found is settings that Soup validated, documented and accepted and then read nowhere on the path they claimed to configure, so a soup.yaml could ask for one thing and train another. This release refuses a long list of those settings at load, warns about 29 more and names v0.77 as the release that will refuse them, evaluates the validation split Soup held out and never used (on the tasks that still hold one out), and applies the grpo_beta KL penalty to every GRPO variant. It also adds soup adapters check, soup bench train, soup data clean, soup recipes verify and soup rewind, Sigstore keyless signing, multi-node soup train, and a layer-streaming disk tier that reads on a background thread and can stripe across NVMe drives. A config that loaded on v0.75 can stop loading: run soup doctor --config soup.yaml before you train, and the exit codes of the gate commands moved to 0 / 2 / 3, so a CI step that tests for exit 1 as "the gate failed" now passes a failing gate. There is no new security advisory in it, and the supported line for security fixes is 0.76.x. Before it, v0.75.2, tagged 1 October 2026, a security patch with one change in it: the outbound endpoint checks (soup data generate --api-base, the vLLM provider, judge URLs, eval-gate suites, soup ship --judge-model, training.online_dpo_judge and the Web UI chat proxy) now refuse a private, link-local or reserved IP address on https as well as http. It fixes advisory GHSA-9f49-hqpf-c849, rated medium, reported by an outside contributor and written by the maintainer alone, and there is nothing to re-run and nothing to rotate: a config that names a private, link-local or reserved IP address now fails loudly and should name a hostname. Before it, v0.75.1, tagged 21 September 2026, a security and correctness backport (the v0.75.0 tree plus 25 cherry-picks, also written entirely by the maintainer) that carries advisory GHSA-63h4-gvp4-r26g, rated high and covering eight issues, with three credentials to rotate, and four fixes that mean something you already ran was lost, deleted or left billing. The one to check first: a layer-streamed adapter saved on peft 0.21 or newer holds zero tensors and cannot be recovered. Before it, v0.75.0, tagged 12 September 2026, which also had no codename: upstream titled it with a sentence, "MLX honours its config; unknown config keys refuse the load", and that sentence is the release. The headline is still that you can fine-tune Llama-3.1-8B on a 4 GB laptop GPU, and since v0.72.4 align on the same card. All 60 of v0.75.0's pull requests came from outside the maintainer, by 22 people, and what they found is training settings that backend: mlx validated, documented, accepted and read by nothing (upstream counts six options; its fix entries name eight settings), so the same config trained a different recipe on Apple Silicon than on a CUDA box. The same release makes an unknown config key refuse the load rather than warn, records validation loss for the first time on any backend (since corrected in v0.76.0: that held for the MLX backend, and the transformers backend evaluated no validation split at all until v0.76.0, #1223 and #1313), and raises the torch floor to 2.6.0, which closes the known limitation v0.74.0 published. Before it, v0.74.0, tagged 4 September 2026, where 116 of 120 merged pull requests came from somebody other than the maintainer, by 25 people, and what they found is that a LoRA run's frozen base, the one part that never receives an optimizer step, was being materialised at twice its checkpoint's precision on every supervised path and in twelve more trainers: measured on an H100 with Llama-3.1-8B and LoRA, peak memory falls from 48,241 MiB to 18,658 MiB, 2.59x on an unchanged config. It also moved the stack to Transformers 5.16.1, TRL 0.29 and PEFT 0.20, repaired the free notebook tier a second time, took layer streaming to a tenth architecture, and gave soup mcp serve bearer-gated sse and http transports. Before it, the v0.73 line: v0.73.1 fixed the free notebook tier, where bf16 was assumed on every CUDA card in fourteen places, and caught the streaming VRAM pre-flight under-predicting at long sequence; v0.73.2 stopped the SHIP verdict ranking by the wrong thing and added soup ship --noise-floor; and v0.73.3 was the first release the maintainer did not write, all 24 of its pull requests coming from other people, who found four flags the schema validated, the docs described and nothing read. Underneath them, v0.73.0 is the release that took the method to hardware this project does not own: three borrowed days on an 8x H100 box, which confirmed it against a real resident reference up to 72B and found a silent gradient defect above 32B in NF4 that is repaired here. Set training.stream_layers: true and the frozen base is never loaded resident; it streams from CPU RAM one decoder layer at a time into a small pool of VRAM buffers while only the LoRA adapters stay resident, so peak VRAM is bounded by one layer instead of the whole model. Add quantization: 4bit (v0.72.2) and that RAM store shrinks about fourfold, which is what puts 8B within reach of a card that cannot hold a quarter of it. Measured on a 4 GB RTX 3050 Laptop at batch 1: Llama-3.1-8B at 119.6 tok/s in 3.32 GB (measured on v0.72.2, before the NF4 gradient repair; a post-repair row on another RTX 3050 Laptop at a different clock is recorded in v0.76.0 and the two are not comparable, see the measured numbers), Qwen2.5-3B at 264.2 tok/s in 1.76 GB, and on the bf16 path 3B at 143.1 tok/s in 2.15 GB, 1.5B at 525.0 tok/s and 0.5B at 978.6 tok/s. The honest cost is 1.43x slower than resident (measured at 0.5B), a streamed NF4 run is bit-exact against a resident NF4 run and that is a CI test rather than a one-off, and it ships BETA. Nothing above 8B has been measured on that 4 GB card, so there is no 14B claim for it; the larger sizes were measured on the borrowed H100 box instead.
v0.72.3 is the breadth release, and it is what turns streaming from a demonstration into something you can plan a run on. Nine architectures streamed instead of three after it (Llama, Qwen, Mistral, Gemma, Phi; v0.74.0 later took it to ten), with the six new families each verified bit-exact against the same checkpoint loaded resident under both bf16 and NF4, though no throughput was measured for them so none is claimed. Batches above 1 and gradient accumulation both work, and at the same effective batch raising batch_size measured about 2.52x faster than accumulating. A pre-flight now predicts peak VRAM and refuses a run that will not fit, which matters because streaming bounds the weights but not the logits: on a 151,936-token vocabulary at batch 8 the logits tensor alone measured 8.71 GB, 146x the whole layer-buffer pool. --resume and --hf-resume work. And an NVMe disk overflow tier takes a base too large even for RAM, holding nothing resident, bit-exact against the RAM tier, with its speed deliberately left unmeasured at that release. Since v0.76.0 the disk tier reads on a background thread through direct I/O and can stripe across NVMe drives (SOUP_LAYER_STREAM_STRIPE_DIRS). On one RTX 5070 Laptop 8 GB with a synthetic 70B-shaped NF4 store of 36 GB (random weights), a cold step took 110.5 s on the previous synchronous reader and 16.2 to 17.3 s on the direct-I/O reader; across two NVMe drives a 17.4 s step fell to 9.97 s. A sustained-load probe measured 1.28x and 1.41x in two rounds and reached no formal verdict. A store that fits RAM is still faster on the RAM tier, which stream_source: auto picks. The disk tier has the caveats.
v0.72.4 opened it to the preference losses. dpo, orpo, simpo and kto run against a streamed base now, so alignment stops being the step that forces a bigger card. DPO's reference model is the same streamed base with its adapters switched off, not a second copy: on a 365M-parameter synthetic fixture, streamed DPO peaked at 0.914x the streamed SFT peak with a byte-identical RAM store, and the control that forced a real second instance moved the peak by 730.44 MB against 730.44 MB of weights, exactly one copy. All four are bit-exact against a resident run of the same loss. Read that 0.914x as "no second copy" rather than as a saving, and note the cost that is not free: DPO reads the layer stack 1.52x as often per step. KTO is not reference-free however it is usually described, and it needs batch_size of 2 or more. No throughput figure is claimed for any preference loss, because none was measured. What remains scoped: task in sft, dpo, orpo, simpo, kto, transformers, text, plain LoRA. GRPO and PPO are permanently excluded, not pending. The measurement records behind all of it are published in full, and the work has a preprint: 10.5281/zenodo.21771064.
v0.72.0 also made soup adapters arithmetic exact across mixed ranks instead of refusing them, and added --rank N.
v0.72.1 is an out-of-band correctness release, and it matters if you already used streaming: an adapter saved by a v0.72.0 streamed run is inert outside the streaming path, because its keys carried an extra .inner. segment and PEFT reports missing keys as a warning rather than an error, so soup merge, soup serve and soup chat all silently returned the untuned base. The training was correct and the bit-exactness results stand; only the saved file was wrong. Re-run that adapter. The same release also closed a hole where --hf-resume slipped around the --resume guard; both were then refused until v0.72.3 fixed the load side and unblocked them.
Underneath it, the v0.71 line is two stories plus a run of capstones: v0.71.0 split the install (pip install soup-cli is now a light, PyTorch-free CLI; pip install "soup-cli[train]" adds the training stack) and raised the floor to Python 3.10+, and v0.71.1 → v0.71.14 wired the entire schema-first roadmap live — the reward-hack / echo-trap detectors, ULD + MiniLLM distillation, mid-epoch RL checkpoints, soup iterative-dpo, RAFT span-mask training + soup ra-dit, CAA/ITI/RepE steering, ROME/MEMIT/AlphaEdit edits + GRACE, NPO/SimNPO/RMU unlearning, the SAE / sleeper / truth / harm / interference probes, the live eval / advise / tunability / diagnose runners, the soup build dbt-DAG materialiser, the Magpie generator, the soup compile / distill-prompt / compile-tools / local-rl train prompt family, VeRA/VB-LoRA multi-tenant serving, MoLE routing, FSDP shard consolidation, and serve-side KV-cache typing now all run end-to-end. Genuinely new in v0.71: ed25519 adapter/attestation signing with supply-chain merge gates, codecarbon energy/CO2 tracking, PDF Annex XI/XII docs, Soup Can v3 attestations, and a local audit log. v0.71.15 → v0.71.23 then closed the stub tail and added native Spectrum targeted training (soup spectrum scan + training.unfrozen_parameters), serve-time MoLE (soup serve --mole), soup agent eval --sandbox, soup train --cloud modal, GPT-2 + Mixtral knowledge editing, and live TTS and MoE-quant trainers (plus a BitNet trainer wrapper that does not run: Modality II has the detail). v0.71.24 grew the recipe catalog from 116 to 133 with 17 new SFT recipes for the 2026 open-weight families (Qwen 3.5 / 3.6, DeepSeek-V4, GLM-5.1, Kimi K2.5 / K2.6, MiniMax M3, Mistral Large 3 (that recipe was removed in v0.76.0)), v0.71.25 added soup ship, the one-command SHIP / DON'T-SHIP verdict, v0.71.26 closed the RL loop with reward-hacking auto-mitigation (the trainer self-corrects mid-run instead of only halting; soup train --help still describes these flags as GRPO/PPO, but since v0.76.0 task: ppo refuses reward_hack_detector, reward_hack_mitigation and echo_trap_enabled (#1514) because its trainer cannot feed them, so only GRPO takes them), plus a new qwen2.5-coder-7b-sft recipe (catalog 133 → 134). v0.71.27 "Fine-tune Doctor" added a pure-CPU pre-flight — soup data doctor (8 chat-template checks incl. the "never stops generating" EOS bug) and soup data lint (DPO length-bias as a Cohen's d effect size) — v0.71.28 shipped the soup mcp serve MCP server so any coding agent (Claude Code, Cursor, Cline, Continue) can drive Soup over stdio, v0.71.29 added soup shrink, one-command depth pruning with an optional distill-heal and a SHIP / DON'T-SHIP perplexity verdict, v0.71.30 let a Process Reward Model drive GRPO (PRM-guided GRPO), v0.71.31 shipped the judge-in-the-loop suite (Online DPO, best-of-N & Evol-Instruct, plus a pairwise judge win-rate for soup ship), v0.71.32 added ASR fine-tuning (task: asr fine-tunes Whisper on your own audio, soup infer --task asr reports WER/CER, whisper-tiny/base train on a 4 GB GPU), v0.71.33 shipped soup draft (train and, above all, measure a speculative-decoding draft: the measured verdict on our own validated pair was that it does not pay off, so the speedup pitch was withdrawn rather than shipped), v0.71.34 added adapter algebra (soup adapters arithmetic "coder + 0.5*math - toxic") and LISA (full fine-tune quality without a full fine-tune), and v0.71.35 shipped the compliance pack: regulation-shaped soup init --template hipaa|soc2|eu-ai-act|sr-11-7 configs, soup card model-card autogen from a registry entry, a soup ci init PR gate (validate to expect to ship, exit 2 blocks the merge; since v0.76.0 exit 2 blocks it in each of the three steps, and any other non-zero such as a usage error, 3, also fails the job and is labelled as a configuration error), and GGUF export validated end-to-end on Windows for the first time. v0.71.36 "Data Moat II" added a semantic layer over your training data (soup data dedup --semantic, soup data topics) plus two tools for what a fine-tune forgets and leaks (soup data canary, soup train --replay), and v0.71.37 made every pip install "soup-cli[extra]" hint work on Windows cmd.exe and fixed eval-gate benchmark tasks. The v0.71 line closed with the eval-gate wedge: v0.71.38 gave the soup ship regression leg real teeth (answer-extraction scoring over seven bundled offline suites instead of substring-matched trivia), v0.71.39 closed the evidence loop (soup ship --emit-evidence + a committed ShipConfig + --push owner/repo#N, provenance-bound so the gate is CI for weights on every PR), and v0.71.40 + v0.71.41 shipped Reward Forge (soup reward synth auto-generates a deterministic reward verifier from your gold outputs and refuses a degenerate one, soup reward stress attacks a verifier with empty, padded, repetitive and sentinel-spam junk to prove it cannot be gamed). Counts at the current release (v0.76.0): 875 test files, 23 training tasks, 20 data formats (that count includes auto), 17 quantization formats, 170 recipes, 21 built-in templates. Apache-2.0 license since v0.29.0. Check with soup version --full.
Will my v0.75 soup.yaml still load?
Not necessarily. v0.76.0 refuses, at load, settings that Soup accepted on v0.75 and never applied (three of them, use_longlora, ebft_variant and quantization_aware: true, were applied wrongly): dozens of combinations that loaded on v0.75 are now refused, each with a message that names the field and what to change (unknown keys have refused the load since v0.75.0). Run soup doctor --config soup.yaml after you upgrade and before you train. A refusal prints the error and Config could not be loaded (see above). and exits 2; a missing file also exits 2, and warnings alone exit 0. Unknown keys are reported together, but doctor stops at the first cross-field refusal, so fix that setting and run it again until it prints no error.
Among the settings now refused: training.quantization_aware: true (it never ran quantization-aware training), training.use_longlora: true, any non-null training.ebft_variant, every non-null training.gdpo_variant, training.rope_scaling_type on a task that does not apply it, training.freeze_layers and freeze_ratio outside the text sft and tts path on the transformers backend, training.auto_mixed_precision outside sft and tts, backend: unsloth on seven further tasks, a Sesame CSM text-to-speech config, quantization: bitnet_1.58 for training, a relora_steps config that does not also set quantization: none, task: kto with batch_size: 1, and the optimizer names that transformers 5 rejects (adam_mini, adamw_apex_fused, ao_adamw_fp8, ao_adamw_4bit, ao_adamw_8bit, badam, came_pytorch and dion everywhere; muon and adamw_hf off the MLX backend). Deleting a refused key is the fix. Three of the refused keys, training.use_longlora, training.ebft_variant and training.quantization_aware: true, were applied wrongly rather than ignored, so a run that finished on v0.75 with one of them did not do what its config said: see the Re-run this table.
Twenty-nine further fields are accepted but read by nothing. They only warn, for example Warning: training.lr_groups is accepted but read by nothing; v0.77 will refuse it: the load continues and the exit code is 0, a field is reported only when its value differs from the schema default, and upstream states that v0.77 will refuse them, so delete those keys now. Three deprecated values warn and are ignored as well: data.remove_unused_columns: true, an explicit training.quantization: 4bit or 8bit on a task whose trainer never quantizes, and soup ab --beta. A few other keys, for example training.warmup_auto and training.forgetting_threshold, are not among those 29: the schema accepts them, nothing in v0.76.0 reads them, and upstream names no release for them.
Some behaviour changes even when the config still loads. data.val_split is now evaluated (at the end of each epoch, or every N steps with the new training.eval_steps) and the validation loss is recorded, so runs take a few percent longer; grpo, ppo and online_dpo evaluate by generating, so by default they ignore data.val_split with a note and train on every row. Every non-standard grpo_variant now applies the grpo_beta KL penalty it used to validate and drop, so an existing variant config will not reproduce a prior run. training.loraplus_lr_ratio now applies on every LoRA task, and an FP8 request that cannot run stops the run instead of training in bf16.
Do not read doctor's Config check as an all-clear. Its table covers only four combinations of task, backend and modality (sft on mlx, sft on unsloth, and sft on transformers with vision or with audio); for anything else it prints None of the 0 setting(s) known to be unread ... is switched on in this config., which means "not reviewed". A config that must load on both v0.75 and v0.76.0 needs the refused key removed, not renamed. Settings refused at load groups the refusals with the start of each message and what to change, and lists the staged fields, and Upgrading from v0.75 or earlier has the install side.
What changed in exit codes?
Eleven gate and verdict commands now share one taxonomy: 0 pass, 2 gate failure, regression or drift, 3 usage or input error, and a mistyped flag on one of them is 3. They are soup ship, soup expect, soup data validate, soup data lint, soup eval gate, soup eval quant-check, soup eval against, soup eval behavior, soup eval checklist, soup lock check and soup recipes verify. What moved: a failed soup eval gate is 2 (was 1), soup lock check drift is 2 (was 3), soup expect suite failure is 2 (was 3) and its rejected input is 3 (was 2), and soup data validate exits 3 (was 1) for a missing file, an unknown or undetectable format and a bad --min-valid-fraction. soup eval behavior (with neither --evidence nor --base-model) and soup eval checklist without the --evidence flag exit 3 where they used to print a neutral OK report and exit 0, and soup diagnose has a new NOT_RUN verdict that exits 3.
The silent-pass risk: a CI step that tests for exit 1 as "the gate failed" now passes a failing gate. The other commands keep their own schemes, and a mistyped flag on those is still 2, but a few individual codes moved as well (soup plugins install now exits 2, soup eval benchmark exits 1 when nothing was measured, soup doctor exits 1 for an installed package beyond its declared ceiling, soup attest emit --sign sigstore exits 2 without the extra): the table has them all. Exit codes lists every command, and what moved in v0.76.0 has the before-and-after table.
Is there a paper?
Yes. Layer streaming is written up as a preprint on Zenodo, CC-BY-4.0, cited by a concept DOI so a revision never strands a reference:
Exact Layer Streaming: LoRA Fine-Tuning of an 8B Model on a 4 GB Laptop GPU. Makazhan, A. (2026). Zenodo. 10.5281/zenodo.21771064.
The paper page is the short version, with the BibTeX entry. The result it defends hardest is not the throughput but the correctness protocol: a streamed trainer whose autograd graph has been severed still produces a falling loss, so the only meaningful evidence is bit-exactness against a resident reference of the same numerics, resident NF4 for a streamed NF4 run and never resident bf16. That discipline caught a dispatch path producing a 0.94 logit divergence with byte-identical weights and adapters, no crash and a healthy-looking loss curve. It is not on arXiv, so cite the Zenodo DOI above rather than an arXiv identifier.
Can I migrate from LLaMA-Factory / Axolotl / Unsloth?
Yes: soup migrate --from llamafactory config.yaml converts your existing config automatically. Supports LLaMA-Factory YAML, Axolotl YAML, and Unsloth Jupyter notebooks. Use --dry-run to preview without writing.
Are there ready-made configs?
Yes. Soup ships 170 recipes spanning Llama 3.1/3.2/4 (Scout), Qwen 2.5/3 (incl. the 30B-A3B MoE), the 2026 families (Qwen 3.5/3.6, DeepSeek-V4 Flash/Pro, GLM-5.1, Kimi K2.5/K2.6, MiniMax M3 — v0.71.24, with DPO and GRPO additions for several of them in v0.76.0), QwQ-32B, QVQ-72B, Gemma 3, Mistral, Phi-4, DeepSeek R1/V3 + all 6 R1-Distill sizes, plus v0.51 additions (GPT-OSS 20B/120B, GLM 4.6/5, Kimi K2 / K2-Thinking, MiniMax M2, Granite 4, LFM2, Mistral Small 3 / Medium 3.5, Magistral / Devstral / Ministral, Baichuan 2), vision (Pixtral, Qwen2-VL, InternVL 3.5, LLaVA-Next, MiniCPM-V, Qwen-Image, DeepSeek-OCR, Paddle-OCR-VL), audio (Qwen2-Audio, Whisper-large-v3, Voxtral, SeamlessM4T-v2), ASR fine-tuning (whisper-tiny-asr / whisper-base-asr / whisper-large-v3-asr — v0.71.32), TTS (Orpheus, Llasa, Oute — v0.52; the recipe catalog says which of them run end to end), edge (SmolLM2 135M-1.7B, Phi-3.5-mini, LFM2), domain specialists (BioMistral, Meditron, CodeLlama, Magicoder, Mathstral, MedGemma, EmbeddingGemma), plus v0.62 RAG (raft-llama3-8b, ra-dit-retriever, ra-dit-llama3-8b), MLX-native, and multi-GPU (llama3-70b-fsdp2, qwen3-32b-zeropp, deepseek-v3-pipeline). Six recipes were removed in v0.76.0 (cogito-v2-sft, falcon-e-bitnet-sft, gemma3-9b-sft, mistral-large-3-sft, sesame-csm-tts, spark-tts); soup recipes use on one of those names exits 1 with Recipe not found. Run soup recipes list to browse, soup recipes search llama to filter, soup recipes verify to check that a recipe's LoRA adapter can attach before you download the model, and soup recipes use llama3.1-8b-sft to start training instantly.
How do I report a security problem?
Privately, and not as a public issue or in Discord. Open a GitHub Security Advisory, or email team@trysoup.dev if you cannot use GitHub. Upstream aims to acknowledge within 5 business days, offers credit by name in the release notes rather than a bounty, and ships fixes for the latest release only (0.76.x is the supported line). The full policy, including what is in scope, is under Reporting a vulnerability.
Training
How long does training take?
Depends on model size, dataset size, sequence length and hardware, so no single figure is published here. soup profile --config soup.yaml estimates memory and speed for your own config before you spend GPU hours. With Unsloth backend, 2-5x faster.
Can I resume training from a checkpoint?
Yes: soup train --config soup.yaml --resume auto (latest checkpoint) or --resume ./output/checkpoint-500 (specific checkpoint).
Does Soup support multi-GPU?
Yes. v0.27.0 added soup train --gpus N (it counts the GPUs per node, detects NVLink vs PCIe and re-launches under accelerate; you choose the sharding with --deepspeed or --fsdp; since v0.76.0 it exits with the launcher's exit code on Windows too), ZeRO++ (quantized weights + grads), FSDP2 + torch.compile, a pipeline-parallelism setting (parallelism: pipeline + pipeline_stages, which is validated but not executed at v0.76.0: the run stays data-parallel), and the DeepSpeed-MII serving backend. v0.76.0 added multi-node launches: soup train --gpus 8 --nodes 2 --node-rank 0 --master-addr <rank-0-host> on each machine, with the same --gpus on every node. See Multi-GPU Mastery.
What training methods are available?
23 methods: SFT, DPO, Online DPO (v0.71.31 — on-policy against an LLM judge or a reward model, wraps TRL OnlineDPOTrainer), GRPO, PPO, KTO, ORPO, SimPO, IPO, BCO (v0.40), Pretrain, Embedding, Reward Model, the unified preference dispatcher (v0.40 — set training.preference_loss: dpo|simpo|orpo|ipo|bco to swap loss without renaming the task), PRM (v0.50 Process Reward Model — also usable as the per-step reward inside GRPO via PRM-guided GRPO, v0.71.30), TTS (v0.52 — Orpheus / Llasa / Spark / Oute; tts_family: sesame_csm is refused at load since v0.76.0), ASR (v0.71.32 — Whisper fine-tuning with built-in WER/CER), Classifier / Reranker / Cross-Encoder (v0.52), Distill (v0.52 — kl / forward_kl / reverse_kl / js divergences), Unlearn (v0.61 — NPO / SimNPO / RMU), and MoE LoRA Routing (v0.67 — MoLE per-token gating over 2..64 task adapters). Plus soup edit set (v0.61 — ROME / MEMIT / AlphaEdit) and soup steer train (v0.62 — CAA / ITI / RepE) as inference-time / weight-surgery surfaces.
Can I auto-push checkpoints to HuggingFace during training?
Yes — soup train --push-as user/my-model uploads every save_steps checkpoint to HF Hub as a checkpoint-<N> branch. Pair with --hf-resume to pull the latest branch and keep going after a spot-instance preemption. Set HF_ENDPOINT=https://hf.internal.example.com to target a self-hosted Hub. See HF Hub integration.
Can I train faster on large-vocab models?
Yes — v0.28.0 adds Cut Cross-Entropy (use_cut_ce: true), which avoids materialising the full [seq × vocab] logits tensor. Best on Llama 3 / Qwen 3 (vocab ≥ 128k). Install with pip install "soup-cli[cce]". It only takes effect when that optional package imports: the trainer prints whether it did, and the one measurement on record could not make it engage (see Cut Cross-Entropy). v0.28 also added an FP8 training option, a gradient-checkpointing tier setting and CPU/disk activation offloading, and a kernel auto-composition benchmark. Since v0.76.0 FP8 needs a card of compute capability 8.9 or higher (Ada or newer, not only Hopper) and a request that cannot run stops the run with the reason instead of training on in bf16 (FP8 training); the checkpointing tiers differ from each other on SFT (tiered checkpointing); and kernel_auto_compose: true is refused at load, so choose use_liger or use_flash_attn explicitly. See Training speed & memory.
Which cloud GPU providers work?
Modal and Lambda Cloud: soup train --config soup.yaml --cloud modal or --cloud lambda. Both are plan-only until you add --cloud-submit. --cloud runpod is recognised and refused with exit code 2 (RunPod cloud training is not yet live), and any other value is an Invalid --cloud error. See serverless cloud training.
Data
What data formats are supported?
20 formats (that count includes Auto): Alpaca, ShareGPT, ChatML, DPO, KTO, LLaVA, ShareGPT4V, Plaintext, Embedding, Audio, Tool-calling, Auto, PRM, Pre-tokenized, Input-output, Video, Multimodal (v0.42), RAFT (v0.62 Retrieval-Augmented Fine-Tuning — query + golden_doc + distractors + answer), ASR (v0.71.32 Whisper fine-tuning — {"audio": path, "text": transcript}), and Cross-encoder (v0.76.0, valid only with task: cross_encoder). Format is auto-detected from the first row. Local paths or remote URIs (s3 / gs / az / abfs / oci). Use soup data convert to switch between formats. v0.69 adds soup build (dbt-shaped DAG of dataset transforms with incremental materialisation), soup expect (Great Expectations suite for chat data), and soup data brain-rot (AI-slop detector — refuses to train on clickbait).
How much data do I need?
For SFT, 1K-10K high-quality samples is a good starting point. Quality matters more than quantity. Use soup data filter to check data quality.
Can I generate synthetic data?
Yes: soup data generate --prompt "Create math problems" --count 100. Supports OpenAI, Ollama, Anthropic Claude, vLLM, and custom servers. Includes domain templates (code, conversation, QA, preference, reasoning) and a full quality pipeline.
Deployment
How do I serve my model?
soup serve --model ./output --backend vllm for production. The API is OpenAI-compatible. No backend puts a token check on the generation routes, so a non-loopback bind publishes the model to whoever can reach the port: put an authenticating proxy in front of it. Serving says what the bearer token and the Origin and Host checks cover, which differs by backend.
Can I export to llama.cpp / Ollama?
Yes: soup export --model ./output --format gguf --quant q4_k_m
My model is deployed to Ollama but missing from soup deploy ollama --list
--list only shows Ollama models whose name starts with soup-. A model deployed with --name my-model is in Ollama (ollama list shows it) but not in that listing; deploy it as --name soup-my-model if you want it listed. soup export --deploy ollama already names the model soup-<model-name> unless you pass --deploy-name. See Model export.
What export formats are supported?
Nine: GGUF and GGUF-UD (llama.cpp / Ollama, the second being the Unsloth Dynamic ladder), ONNX (cross-platform), TensorRT-LLM (NVIDIA optimized), AWQ and GPTQ (quantized deployment; both require --calibration-data, GPTQ since v0.74.0 and AWQ since v0.75.0; both are deprecated in v0.76.0 and upstream says they will be removed in v0.77, because AutoAWQ and AutoGPTQ are archived and neither extra installs next to [train], so prefer GGUF, ONNX, TensorRT-LLM, BitNet or tq1_0), BitNet and tq1_0 (1.58-bit), and torchao.
Troubleshooting
How do I see full error messages?
Use soup --verbose <command> for full tracebacks.
How do I check my environment?
Run soup doctor to check Python version, GPU availability (since v0.76.0 with each card's compute capability and architecture, a red warning when your PyTorch build has no code for it, and a precision block for BF16, FP8 and NVFP4), the MLX backend on Apple Silicon, dependency versions, and get fix suggestions. soup doctor --config soup.yaml also loads a config under the current rules; see Installation.
ImportError: DLL load failed while importing _C on Windows
That is PyTorch, not Soup: the installed wheel does not match your CUDA runtime. Reinstall torch from the index for your CUDA version, for example pip install torch --index-url https://download.pytorch.org/whl/cu126. Pick an index that still carries torch 2.6.0 or newer: Soup's [train] extra requires torch>=2.6.0, and the cu121 index stops at 2.5.1.
Every soup command fails with Type not yet supported: int | None
That is an old typer already installed in the environment, not a Soup defect. Soup declares typer>=0.9.0,<0.21.0, but only typer 0.15.4 and newer start on every click that range admits, and pip install -U soup-cli does not upgrade a dependency that already satisfies its range. Fix it with pip install -U "typer>=0.15.4,<0.21". A normal fresh install resolves a current typer and is not affected. See Installation.
soup <command> --help shows ADAPTER TEXT [required] with no description
click 8.5.0 drops the description of every positional argument from --help. Soup declares click>=8.0.0,<8.5 since v0.76.0; on an earlier release, or in an environment where another package forced click 8.5, install click below 8.5 or install Soup in its own environment (pipx does this).
soup version disagrees with pip show soup-cli
You have more than one Python installation and they are not the one you think. Use a virtual environment. This is worth taking seriously rather than ignoring, because the two commands read different things: soup version reads the source that is actually going to run.
My environment used to work and now something is off
soup env check audits your installed packages against the version bounds Soup itself declares and exits 3 when one is violated. That audit needs no lock file, but without one the command otherwise exits 1 (No lock file at soup-env.lock; run soup env lock first). The usual cause is a later pip install of a serving stack into a training environment. soup env fix then prints a reproducible install plan from your lock file.
Where does Soup keep its files, and how do I move them?
Most of it lives under ~/.soup/ (the experiments and registry databases, the audit log, caches), plus a few directories in the folder you run from (.soup-loops/, .soup-crashes/, .soup_hub_cache/). Thirteen SOUP_* environment variables move individual files; nine of them are only honoured if the new path is under your home directory, the working directory or the system temp directory, and an out-of-bounds value is ignored without an error. The other four are used exactly as given. Every soup command, --help included, appends a line to the audit log unless you set SOUP_NO_AUDIT_LOG=1. See Environment variables and state files for the full list.
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.