Multi-GPU Mastery
Soup v0.27.0 turns multi-GPU training from a research paper into a CLI flag. --gpus detects the topology and re-launches under accelerate, ZeRO++ lands quantized weights and grads, FSDP2 can opt into torch.compile, and a pipeline-parallelism setting is validated but not yet executed (see below).
One-flag launch
soup train --gpus auto
soup train --gpus 8--gpus resolves the GPU count (an integer or auto) and detects the interconnect (NVLink vs PCIe). With more than one GPU it then re-launches the same soup train command under accelerate launch --num_processes N, carrying your flags with it. It does not pick a sharding strategy for you: choose one with --deepspeed or --fsdp (or in the config). Pass --no-reexec to print the accelerate launch command instead of running it; Soup then exits 1 so a script does not carry on as if training had started.
The exit code after a launch is the launcher's, on every platform (v0.76.0). On Linux and macOS Soup replaces its own process with accelerate, so the code your shell or CI sees is the launcher's. On Windows, through v0.75.2, the same call returned immediately: in a check with a stand-in launcher that ran for five seconds and exited 7, soup train --gpus 2 still exited 0 after about three seconds, the launcher kept running in the background, and its exit code was lost. Since v0.76.0 Soup waits for the launcher on Windows and exits with its code, and an OSError while launching exits 1 with a --no-reexec hint. This is from the call site (commands/train.py), and upstream's own end-to-end test uses a stand-in accelerate; a real Windows multi-GPU run was not exercised here. If a script gated on soup train --gpus N on Windows ever passed while training was still running, that was this.
Multi-node launch
soup train takes four flags for training across several machines (v0.76.0). Run the same command on each node, changing only --node-rank. For two machines with eight GPUs each:
# On rank 0 (replace 10.0.0.10 with its reachable private hostname or IP)
soup train --config soup.yaml --gpus 8 --nodes 2 --node-rank 0 --master-addr 10.0.0.10 --master-port 29500
# On rank 1
soup train --config soup.yaml --gpus 8 --nodes 2 --node-rank 1 --master-addr 10.0.0.10 --master-port 29500| Flag | Meaning |
|---|---|
--nodes N | Number of machines, 1 to 256, default 1. Every node must use the same --gpus |
--node-rank R | This machine's rank, 0 to N-1, default 0. Ranks must be distinct |
--master-addr | Rank 0's hostname or IP, reachable from every node. Required when --nodes is above 1. An IPv4 or IPv6 literal or a hostname: the port goes in --master-port, so head:29500 is refused |
--master-port | Coordinator port, 1 to 65535, default 29500 |
--gpus is the number of GPUs per node: the two commands above pass --num_processes 16 --num_machines 2 to Accelerate and start eight workers on each machine. --gpus auto detects the local count, so use it only when every node has the same number of visible GPUs. --nodes above 1 requires --gpus, and cannot be combined with --cloud or --find-lr; the rank, address and port flags are refused with --nodes 1. Soup uses static rendezvous and does not provision machines, copy files or run the command on other nodes: install the same Soup and training dependencies on every node and make the model, config and data available at the paths each command uses. All nodes need network access to rank 0's coordinator port and to the peer connections NCCL uses; opening only the coordinator port may not be enough.
Every launch-setting mistake is caught before anything loads and exits 1 with Invalid distributed launch: .... One message is easy to misread: a malformed --master-addr (for example head:29500) prints --master-addr is required and must be a hostname or IP address, the same text as a missing one. Checked with --dry-run --gpus 4 --nodes 2 --node-rank 1 --master-addr 10.0.0.10 on a machine with no GPU: the valid command printed accelerate launch --num_processes 8 --multi_gpu --num_machines 2 --machine_rank 1 ... and Config valid. Ready to train! (exit 0, without probing the other nodes); --master-addr head:29500, no --master-addr, --node-rank 2 with --nodes 2, and --node-rank 1 with --nodes 1 each exited 1. --no-reexec prints the same command without --dry-run and exits 1, as for any multi-GPU launch.
Multi-node launches default to NCCL_IB_DISABLE=0, which allows InfiniBand; on a TCP-only cluster set NCCL_IB_DISABLE=1 on every node before launching. Existing NCCL settings are preserved, and Soup prints that default as a note. No two-node run was possible here: the validation and the printed launch command are tested, a live multi-node launch was not.
ZeRO++
base: meta-llama/Llama-3.1-70B
task: sft
data:
train: ./data/train.jsonl
training:
quantization: 4bit
lora:
r: 16
alpha: 32soup train --gpus 8 --deepspeed zero++
# aliases: zero_ppZeRO++ cuts inter-GPU communication by quantizing the broadcasted weights and gradients. Integer fields (sub_group_size, stage3_max_live_parameters, stage3_max_reuse_distance) are written as int(1e9) so DeepSpeed's strict JSON validator accepts them.
FSDP2 + torch.compile
training:
use_fsdp2_compile: truesoup train --gpus 4 --fsdp full_shardThe validator requires an FSDP preset, CUDA, backend=transformers, and torch>=2.2 + accelerate>=0.27. DeepSpeed + torch.compile is explicitly rejected — the two own their own compile paths and mixing them produces a cryptic runtime crash.
Pipeline parallelism
training:
parallelism: pipeline
pipeline_stages: 4The validator requires pipeline_stages >= 2, CUDA, and gpu_count >= pipeline_stages. pipeline_stages is bounded [1, 16].
Validation only. At v0.76.0 parallelism: pipeline is checked and then the run executes data-parallel: soup train prints a yellow "Pipeline parallelism (deferred execution)" panel saying the config is validated and the trainer runs in data-parallel mode. No pipeline stages are executed, so setting it does not split the model across GPUs.
Task coverage of --fsdp and --deepspeed widened in v0.76.0 (#1204). The prm and moe_lora_routing wrappers stored --fsdp and never passed it to their trainer arguments, and the online_dpo wrapper did the same with both --fsdp and --deepspeed, so the flags had no effect on the trainer for those tasks. They now reach the trainer on all three; if you launched one of them under --gpus N expecting sharding, you did not get it.
DeepSpeed-MII backend
soup serve --backend mii --model ./outputRegistered in v0.27.0, live since v0.33.0. A misconfigured --backend mii always exits non-zero (never silently accepts).
v0.74.0 repaired the prompt and the finish reason. Until then this backend hand-rolled a System:/User:/Assistant: prompt and hardcoded finish_reason to stop, so a served model saw a format it was never trained on and a client could not tell a truncated answer from a completed one. It now applies the model's own chat template through the shared builder and reports the engine's real finish reason. Behaviour is unchanged for a model that ships no chat template. That is the third backend to have carried this same pair, after vLLM in v0.73.0 and SGLang in v0.74.0.
Multi-GPU recipes
llama3-70b-fsdp2— 70B SFT on 8×A100 via FSDP2 + compileqwen3-32b-zeropp— Qwen 3 32B SFT via DeepSpeed ZeRO++deepseek-v3-pipeline— DeepSeek V3 SFT scaffold (the pipeline setting is validated; training runs data-parallel)
soup recipes use llama3-70b-fsdp2
soup train --gpus 8 --fsdp full_shardSharding is a launch flag, not a recipe key. The llama3-70b-fsdp2 recipe sets use_fsdp2_compile: true, and soup train refuses that (exit 1, "use_fsdp2_compile requires FSDP to be enabled") unless --fsdp is passed, so soup train --gpus 8 alone fails. The ZeRO++ recipe takes --deepspeed zero++ in the same position. See Before you run one.
Security & guardrails
--gpusrejectsbool, negatives, zero, non-digits, and values aboveMAX_GPU_COUNT=128--gpus autoon a CPU-only host prints an explicit yellow warning instead of silently single-processing- The
accelerate launchargv is built viashlex.quoteso copy-pasted commands can't inject via a crafted config path - NCCL env hints are applied via
os.environ.setdefault— user / launcher overrides always win - Rich markup on
--configpaths is escaped before embedding in advice panels
See also
- Training speed & memory — Cut CE, FP8, activation offloading
- Backends — transformers / unsloth / MLX
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.