Skip to content
Free & Open Source

Stop tuning.Start training.Soup writes the config for you

The whole post-training stack in one CLI. Soup checks your data before the run, writes the config and gives every finished run a SHIP or DON'T-SHIP verdict. When the model is bigger than the card, it streams the frozen base one layer at a time and quantizes it to 4-bit (BETA), so Llama-3.1-8B fine-tunes on a 4 GB GPU.

23 methods · 173 recipes · 17 quant formats · MLX on Apple Silicon

Three commands to a first run

  1. Install

    pip install "soup-cli[train]"

    Python 3.11 to 3.13. On Apple Silicon, install soup-cli[mlx] instead.

  2. Write a config

    soup init --template chat
    Using template: chat
    Config saved to soup.yaml

    A Llama-3.1-8B chat fine-tune, loaded on the GPU in 4-bit. Point data.train at your JSONL, or start from a recipe below. On a card too small for that, such as a 4 GB laptop GPU, stream the base instead (BETA).

  3. Train

    soup train --config soup.yaml
    Start training? [Y/n]: y
    …
    Training started!
Soup CLI on Product Hunt
Apache-2.0 LicensePython 3.11 to 3.13No vendor lock-in

Integrates with your entire ML stack

HuggingFaceHuggingFace
OllamaOllama
vLLMvLLM
DeepSpeedDeepSpeed
UnslothUnsloth
ONNXONNX
NVIDIA TensorRTNVIDIA TensorRT
W&BW&B
SGLangSGLang
FlashAttentionFlashAttention
HuggingFaceHuggingFace
OllamaOllama
vLLMvLLM
DeepSpeedDeepSpeed
UnslothUnsloth
ONNXONNX
NVIDIA TensorRTNVIDIA TensorRT
W&BW&B
SGLangSGLang
FlashAttentionFlashAttention
soup migrate

Already using another tool? Bring your config.

soup migrate converts a LLaMA-Factory, Axolotl or Unsloth config into soup.yaml, and flags what it could not carry over, like a dataset registry name that still needs a real file path.

LLaMA-Factory
LLaMA-Factory
Auto-converted to Soup
Axolotl
Axolotl
Auto-converted to Soup
Unsloth
Unsloth
Auto-converted to Soup

One run, on a real LLaMA-Factory config

soup migrate
$ soup migrate --from llamafactory llama3_lora_sft.yaml --yes
Migration Warnings
  ! Dataset 'alpaca_en' is a LLaMA-Factory dataset registry name. You need to provide the actual file path in data.train.
  ! Original template: llama3 (auto-detected in Soup)
# (the generated soup.yaml prints here, shown in full below)
Resolved: task=sft, quantization=4bit, lora.r=64
✓ Config written to soup.yaml
Next: soup train --config soup.yaml
Before: LLaMA-Factory config
llama3_lora_sft.yaml
model_name_or_path: meta-llama/Llama-3.1-8B
stage: sft
finetuning_type: lora
lora_rank: 64
lora_alpha: 16
lora_dropout: 0.05
lora_target: all
dataset: alpaca_en
template: llama3
cutoff_len: 2048
per_device_train_batch_size: 4
gradient_accumulation_steps: 4
num_train_epochs: 3
learning_rate: 2.0e-5
lr_scheduler_type: cosine
warmup_ratio: 0.1
quantization_bit: 4
output_dir: ./saves/llama3-lora
Soup config (from soup migrate)
soup.yaml
base: meta-llama/Llama-3.1-8B
task: sft
data:
  train: ./alpaca_en.jsonl
  format: auto
  max_length: 2048
  val_split: 0.0
training:
  epochs: 3
  lr: 2.0e-05
  batch_size: 4
  gradient_accumulation_steps: 4
  scheduler: cosine
  warmup_ratio: 0.1
  quantization: 4bit
  lora:
    r: 64
    alpha: 16
    dropout: 0.05
    target_modules: all-linear
output: ./saves/llama3-lora

Batch size, scheduler, warmup, the validation split and the LoRA settings carry over, and lora_target: all becomes all-linear. A LLaMA-Factory dataset name such as alpaca_en still needs its real file path in data.train, and the migrator says so.

v0.77.2

The whole loop: decide, train, ship, operate, secure

Most tools stop at "hit train and hope." Curate the data, train text or speech without erasing the old task, then give every finished run one SHIP or DON'T-SHIP verdict you can commit next to the weights that produced it.

v0.77.2 flagship · Layer streaming · BETA

Fine-tune Llama-3.1-8B on a 4 GB laptop GPU. Align on the same card.

Never load the frozen base at all. Soup keeps it in CPU RAM or on NVMe and copies it into VRAM one decoder layer at a time, so peak VRAM is bounded by one layer, not by the model. Quantizing that streamed base to NF4 shrinks it about fourfold.

  • Llama-3.1-8B at 119.6 tok/s in 3.32 GB on a 4 GB RTX 3050 Laptop.Measured on v0.72.2 at 952 MHz, before the NF4 gradient repair; a post-repair row from another RTX 3050 Laptop, taken at a different clock, is recorded, and the two are not directly comparable.
  • DPO, ORPO, SimPO and KTO stream too. The reference model is the same base with its adapters switched off, so it needs no second copy of the model. It is not free in time (1.52x the layer reads), and no tok/s is claimed for a preference loss because none was measured.
  • Eleven architectures, from Llama and Qwen to the DeepSeek-V3 MoE family, and a pre-flight that refuses a run that will not fit. BETA: transformers, text, plain LoRA; 8B is the largest size measured on this card.

Upgrading from an older release? A run that finished may still be wrong. Run soup doctor --config soup.yaml first, then check what to re-run, release by release.

soup · DPO over layer streaming
$ cat soup.yamlbase: Qwen/Qwen2.5-3Btask: dpo                  # sft, dpo, orpo, simpo and kto all streamdata:train: ./prefs.jsonlformat: dpomax_length: 512          # a paired loss sends 2x the rows; size it downtraining:stream_layers: true      # base streams from RAM, only the adapter trainsquantization: 4bit       # NF4: ~4x smaller storestream_source: auto      # RAM when it fits, NVMe disk when it does notbatch_size: 1            # kto needs 2 or more; the pre-flight sizes the restlora: { r: 16, target_modules: [q_proj, v_proj] } $ soup train --config soup.yamlLayer streaming is BETA: slower than resident training, but thismodel may not run resident on this card at all. # reference model = this same streamed base, adapters disabled# one set of weights, one RAM store, one buffer pool

Shown on Qwen2.5-3B. The 8B numbers in this card are supervised fine-tuning; no preference-loss run on 8B has been measured on a 4 GB card.

Decide

Train

Ship

Operate

Secure

Most of the above: LLaMA-Factory / Axolotl / Unsloth ✗

Text, preferences, vision, speech: start from a real config

Each file is exactly what its command writes, and each passes soup doctor --config.

Chat SFT

Llama-3.1-8B-Instruct. LoRA on a 4-bit base, alpaca-format rows.

soup.yaml
# Soup template: Chat Assistant# Fine-tune a model for conversational chat base: meta-llama/Llama-3.1-8B-Instructtask: sft# backend: unsloth  # 2-5x faster, pip install "soup-cli[fast]" data:train: ./data/train.jsonlformat: alpacaval_split: 0.1max_length: 2048 training:epochs: 3lr: 2e-5batch_size: autolora:r: 64alpha: 16target_modules: autoquantization: 4bit output: ./output

Preference tuning

Qwen2.5-7B-Instruct. DPO on chosen and rejected answer pairs.

soup.yaml
base: Qwen/Qwen2.5-7B-Instructtask: dpo data:train: ./data/preference_train.jsonlformat: dpomax_length: 2048 training:epochs: 3lr: 5e-6batch_size: autolora:r: 16alpha: 32target_modules: autoquantization: 4bitdpo_beta: 0.1 output: ./output

Vision SFT

Qwen2-VL-7B-Instruct. Images plus conversations, sharegpt4v rows.

soup.yaml
base: Qwen/Qwen2-VL-7B-Instructtask: sftmodality: vision data:train: ./data/vision_train.jsonlformat: sharegpt4vimage_dir: ./data/imagesmax_length: 2048 training:epochs: 3lr: 1e-5batch_size: autolora:r: 16alpha: 32target_modules: autoquantization: 4bit output: ./output

Speech recognition

Whisper tiny. LoRA on q and v; fits a 4 GB GPU.

soup.yaml
base: openai/whisper-tinytask: asr data:train: ./data/train.jsonlformat: asr# Relative audio paths resolve against audio_dir (defaults to the data dir).audio_dir: ./data/audio training:epochs: 3lr: 1e-4batch_size: autoasr_language: enasr_task: transcribeasr_lora: truelora:r: 16alpha: 32target_modules: [q_proj, v_proj]quantization: none output: ./output

Swipe for DPO, vision and speech.

soup recipes list shows all 173. Browse the recipe catalog

Coming soon

Meet Soup Zero.

The full AI workbench built on top of Soup: playground, data, evals, fine-tuning, deploy and monitoring in one desktop app, on your own hardware. The deep layer is live today in the CLI; the workbench around it is what we're building.

Before you install

The rest is in the docs FAQ.

How do I install Soup CLI?

Run pip install "soup-cli[train]" on Python 3.11 to 3.13. pip install soup-cli alone is a light core without PyTorch, for configs and the data tools. Where the system Python refuses pip (PEP 668), use pipx install "soup-cli[train]". On Python 3.10, pip installs v0.76.x instead.

Do I need a big GPU?

Not necessarily. soup init --template chat writes a LoRA run on a 4-bit base, far lighter than a full fine-tune. If the model still does not fit, training.stream_layers: true (BETA) streams the frozen base into VRAM one layer at a time; it is slower, so leave it off when the model fits.

Does it run on a Mac?

Yes, on Apple Silicon through MLX: pip install "soup-cli[mlx]", then set backend: mlx. It trains LoRA adapters for SFT, DPO, ORPO, SimPO, KTO and GRPO (built-in accuracy or format reward; an unquantized base or one pre-quantized to 4 bits), and task: preference with preference_loss dpo, orpo or simpo runs too. Upstream covers the 4-bit and preference paths only with a hosted macOS test job. Other tasks are refused at load.

Does Soup send my data anywhere?

Not unless you set it up to. Training reads your files on your machine; pushing to the Hub, cloud runs, LLM judges and experiment trackers are each something you configure. Telemetry is opt-in with SOUP_TELEMETRY=1, and the shipped release sends nothing even then.

Free forever. Apache-2.0 Licensed.

Your first fine-tuned model is one command away.

Soup picks the method, writes the config, and gives every finished run a SHIP or DON'T-SHIP verdict. Install it, start from a template, and point it at your data.

23 training methods, 173 ready recipes, all offline.

Apache-2.0 licenceNo Soup accountYour GPU or a Mac

Free and Apache-2.0. It stays that way.

Every performance number on this site is measured rather than claimed, most of them on a 4 GB laptop GPU. Donations buy GPU time for what that card cannot reach: multi-GPU, and a card we do not have to give back.

Or help with your own card.

Soup sends nothing about your runs unless you ask it to, so numbers from your card count as much as code: three of the measurement records published in v0.75.0 arrived that way. Open issues and hardware still to test are posted in Soup Tasters, and its app keeps the score.