Soup 的定位很直接:Fine-tune LLMs from one YAML. Layer streaming trains an 8B model on a 4 GB laptop GPU. 它同时解决两个层面的痛点——一是把动辄几百行的训练样板代码收敛成一份声明式配置,二是用“层流式”(layer streaming)把权重从显存里赶出去,只让当前计算所需的那几层临时进场。它真正想做的事,是让硬件受限的个人开发者也能把微调流程完整跑通,而不是只做推理演示。
graph TD
A[soup.yaml 配置文件] --> B[配置解析与校验]
B --> C[模型加载与 4-bit 量化]
C --> D[分层权重池<br/>常驻 CPU 内存]
D --> E[层流式调度器]
E -->|"前向预取当前层"| F[GPU 计算窗口<br/>4 GB 显存预算]
F -->|"计算完毕释放显存"| D
F --> G[LoRA 适配器与优化器状态]
G --> H[梯度累积与参数更新]
H --> I[检查点保存与权重合并]
Soup turns the pain of LLM fine-tuning into a simple workflow. One config, one command, done.
pip install "soup-cli[train]" # add [train] to fine-tune; bare `soup-cli` is the light CLI
soup init --template chat
soup train
Fine-tune an 8B model on a 4 GB laptop GPU. Layer streaming keeps the frozen base out of
VRAM and feeds it to the GPU one decoder layer at a time. Measured on an RTX 3050 Laptop 4 GB:
Llama-3.1-8B-Instruct + NF4 at 119.6 tok/s at 952 MHz, 3.32 GB peak (pre-repair) — bit-exact
against a normal resident run, and reproduced independently on an H100 at 113.00 tok/s in the same
3.32 GB. (Both figures were measured on v0.72.2, before the v0.73.0 correctness repair that cost
−4.8% at 32B. The post-repair run, on another RTX 3050 Laptop 4 GB (@umran666, #1103), reads
208.6 tok/s at 1935–1957 MHz in a 2.40 GB peak. That is 59% of its same-session GEMM ceiling
against 68%: about 14% slower per unit clock, so the raw 1.74x gain is the clock, not a speedup.
Large-layer streaming also changed the memory pattern between the two rows, so even the fraction
is not like-for-like — the record.) Opt-in (stream_layers: true)
and still BETA —
how it works ·
all measurements · paper ·
check it yourself on a free Colab T4 (caps the process to
4 GB, then asserts a streamed model is bit-identical to a normal one)
Llama-3.1-8B-Instruct + NF4, LoRA, batch 1, seq 512 on an RTX 3050 Laptop 4 GB — 3.32 GB peak, 119.6 tok/s at 952 MHz (pre-repair, v0.72.2; post-#331: 208.6 tok/s at 1935 MHz in 2.40 GB, not directly comparable, @umran666, #1103). Full video (90s)
Why Soup?
Training LLMs is still painful. Even experienced teams spend 30-50% of their time fighting
infrastructure instead of improving models. Soup fixes that.
Zero SSH. Never SSH into a broken GPU box again.
One config. A simple YAML file is all you need.
Auto everything. Batch size, GPU detection, quantization — handled.
Works locally. Train on your own GPU with QLoRA. No cloud required.
What’s New
v0.77.2 — a cut of main after v0.77.1: 159 pull requests, 153 of them from 30 people outside
the maintainer. Most of it is fixes. It also adds features and two rules that can refuse what
v0.77.1 accepted, so read the
v0.77.2 release notes before
upgrading a server or a task: sft config. Coming from 0.76.x, run soup doctor --config soup.yaml
first and read the v0.77.0 release notes.
soup profile --model <id> answers “will it fit?” without a soup.yaml. It prices the run
from the model’s config.json, shaped by --seq, --batch, --method, --lora-r,
--optimizer and --gradient-checkpointing; on Apple Silicon it compares with Metal’s working
set. soup plan and soup apply take --minillm-on-policy.
More training on Apple Silicon.task: preference with preference_loss: dpo, orpo or
simpo runs the native MLX trainer, MLX GRPO trains on 4-bit mlx-community bases, and MLX
Adafactor follows the configured learning rate and schedule.
Two new DPO recipes,qwen3.5-0.8b-dpo and qwen3.5-27b-dpo.
Closer VRAM estimates. The optimizer step is its own phase, a PRM step is charged the logits
of one position, a sharded FSDP or ZeRO run is priced per card, a stream_loss_chunk step its
last layer’s recompute, and Unsloth’s LoRA targets as its loader picks them.
Fewer silent overwrites and empty results. More commands refuse an --output that names an
input (soup data ingest, persona-mix, generate and others); soup ship --adapter refuses an
adapter that changes nothing; soup distill-prompt, soup data evolve, gen-magpie and
filter --perplexity fail instead of writing an empty or unfiltered file.
Preference and RL fixes.data.max_length holds again for SimPO and KTO, PPO checkpoints its
policy when asked (and no longer crashes under 4-bit and 8-bit), and soup merge loads the base
commit the adapter was trained on.
Text shown as typed. Dozens of commands print paths, names and messages with brackets and
:name: text kept and terminal control characters removed.
Behaviour changes to know.soup serve --tool-auth-token must be 16 to 128 characters of
A-Z, a-z, 0-9, _ and - (exit 2 otherwise). task: sft refuses reasoning_effort,
train_on_eot, use_flash_attn and use_liger on the vision, audio, MLX, Unsloth, RAFT and
pre-tokenised paths that never applied them. Scripts from soup completions need regenerating.
soup data from-traces --signal thumbs_up, MLX Adafactor, soup merge and the VRAM pre-flight can
give a different result than on v0.77.1.
Use pip rather than pipx if you also want to import soup_cli from your own
code, since pipx deliberately isolates the application from everything else.
The full extras table (fast, mlx, serve, eval, ui, vision, audio, …) lives in
docs/models.md.
error: externally-managed-environment? That is
PEP 668, not a Soup problem. Debian 12,
Ubuntu 23.04 and later stop pip from writing into the system Python, because
apt manages those files too. pipx and uv tool sidestep it by giving Soup
its own environment, which is why they are listed first above. python3 -m venv .venv && source .venv/bin/activate then plain pip works just as well.
Double quotes, not single."soup-cli[train]" is the only spelling that works in every
shell — cmd.exe, PowerShell, bash and zsh. If you copied 'soup-cli[train]' from an older
tutorial and pip rejected it, that is the reason:
why, and the exact error.
soup init, soup data …, and the other data/inspection commands work on the light install.
Fine-tuning (soup train) needs the [train] extra.
2. Create a config
soup init # interactive wizard
soup init --template chat # or start from a template
config/schema.py is the single source of truth for every field. Advanced data, training,
and PEFT options are documented under Documentation.
Unknown config keys are rejected since v0.75. A key no model declares — a typo
like quantizaton, or a field that only exists on a newer Soup — used to validate
clean and be discarded, so the run proceeded with the setting simply not applied.
v0.74 reported it at load with the field you probably meant; from v0.75 the same
config fails to load, so fix or remove the key rather than relying on it being
ignored. See Unknown config keys.
Documentation
The full feature reference lives in docs/. Start here:
Recommended model families, the VRAM size guide, the pip extras matrix
Data Formats
Alpaca, ShareGPT, ChatML, preference pairs (DPO / ORPO / SimPO / IPO / KTO), vision, audio,
ASR, plaintext, embedding, RAFT and more — all auto-detected from JSONL, JSON, CSV, Parquet or
TXT, so in most cases you point data.train at a file and nothing else changes. Schemas with a
worked example per format, plus the data pipeline (remote URIs, streaming, sharding,
interleaving, vocab expansion, document ingestion), are in
docs/data.md, with native Sesame CSM audio training documented separately.
Common Commands
soup train --config soup.yaml # train (SFT/DPO/GRPO/PPO/KTO/ORPO/SimPO/IPO/...)
soup infer --model ./output --input prompts.jsonl --output results.jsonl # batch inference
soup chat --model ./output # interactive chat
soup serve --model ./output # OpenAI-compatible API server
soup ui # local browser dashboard
soup merge --adapter ./output # merge LoRA into the base model
soup export --model ./output --format gguf # export for deployment
soup eval benchmark --model ./output # evaluate
soup data inspect ./data/train.jsonl # dataset stats
soup recipes list # 100+ ready-made model recipes
soup autopilot --model <id> --data d.jsonl --goal chat # zero-config
soup doctor # check GPU / deps / environment
Soup works with any text-generation model on the
HuggingFace Hub — if it loads with
AutoModelForCausalLM, it works, zero config changes. Llama 3.x/4, Qwen 2.5/3, Gemma 3, Mistral,
Mixtral, DeepSeek R1/V3, Phi-4, and 100+ others ship as ready-made recipes (soup recipes list).
VRAM
Max model (QLoRA 4-bit)
Example
8 GB
~7B
Llama-3.1-8B, Mistral-7B
16 GB
~14B
Phi-4-14B, Qwen2.5-14B
24 GB
~34B
CodeLlama-34B, Yi-1.5-34B
48 GB
~70B
Llama-3.3-70B
80 GB+
70B+ (full) or MoE
Mixtral-8x22B, DeepSeek-V3
Full model + vision tables and the optional-extras matrix are in docs/models.md.
Docker
Run Soup without installing CUDA or PyTorch locally (image published to GHCR on every release):
docker pull ghcr.io/makazhanalpamys/soup:latest
docker run --gpus all -v $(pwd):/workspace ghcr.io/makazhanalpamys/soup train --config soup.yaml --yes
docker compose up # or build locally
Requirements
Python 3.11, 3.12 or 3.13 (those are the versions CI tests; 3.14+ is not supported yet
because the PyTorch stack has not been validated there)
GPU with CUDA (recommended), Apple Silicon (MPS), or CPU (experimental — very slow)
8 GB+ VRAM for 7B models with QLoRA
All training tasks run on CPU for testing (quantization auto-disabled). Optional extras
(train, all, fast, vision, qat, serve, serve-fast, ui, eval, deepspeed,
liger, mlx, onnx, tensorrt, …) are listed in
docs/models.md.
Troubleshooting
soup doctor # GPU, system resources, dependencies, and version in one place
git clone https://github.com/MakazhanAlpamys/Soup.git
cd Soup
pip install -e ".[dev]"
ruff check src/soup_cli/ tests/ # lint
pytest tests/ -v # unit tests (fast, no GPU)
pytest tests/ -m smoke -v # smoke tests (downloads a tiny model, trains)
pytest tests/ -m gpu --no-cov -v # GPU tests (need a CUDA card; report results, see CONTRIBUTING.md)
pre-commit install # optional: ruff lint+format on commit
See CONTRIBUTING.md for the full workflow and SECURITY.md to
report a vulnerability. Telemetry is strictly opt-in (SOUP_TELEMETRY=1, default off; see Privacy Policy).
Support Soup
Soup is Apache-2.0 and free — and stays that way. It is built and maintained in the open on a
single 4 GB laptop, which is why every performance number in these docs is measured rather than
claimed.
If Soup saved you a training run, starring the repo
helps most, and it costs nothing. If you would like to fund the work directly:
❤️ Donate — one-off, any amount (use
Change amount on the checkout page). Payments are processed by Stripe under the maintainer’s
registered business, MePlay, Inc. — that name, not “Soup”, is what appears on the checkout
page and on your card statement.
Donations buy GPU time for the hardware-gated work — multi-GPU, 8B+ validation, Apple Silicon —
that a single 4 GB laptop cannot reach.
The other way to move exactly those items is hardware itself. They ship behind honest
“requires <hardware>” gates rather than unverified claims, so if you have access to a bigger
box — or GPU credits going unused — running one of the
help wanted
issues and posting the numbers helps as much as funding the GPU time would. Those issues say
exactly what is blocked on hardware today.
Contributors
Built by the community ❤️ — thank you to everyone who has contributed. See
CONTRIBUTORS.md.
Contact
Bugs and feature requests belong in the
issue tracker, questions in
Discussions — both get answered faster
and help the next person with the same problem.
For live chat, setup help, and everything that reads better as a conversation, join the
Discord or the Telegram community.
Anything that should still be findable in six months
belongs in Issues or Discussions — a Discord answer helps one person, an issue helps everyone
who hits the same thing. The Code of Conduct applies there too.
For anything that does not fit in public — security reports (see SECURITY.md),
Code of Conduct matters, or press — email [email protected]. That is the project address
and the right one for anything Soup-related. [email protected] is the maintainer’s
personal address; it reaches the same person and is a fine fallback.
Citing Soup
Layer streaming — training an 8B model on a 4 GB laptop GPU by streaming the frozen base from
host RAM one decoder layer at a time — is described in a preprint, together with the correctness
protocol that verifies a streamed run against a resident one (forward and backward stated
separately, because they are two claims and not one).
Version 3 (13 August 2026) is current. The title and the claim are unchanged — 8B on 4 GB —
and no measured number has changed since v1. What v3 does is withdraw an explanation we had
published, which is also the shortest way to describe what the paper is for:
Retracted in v3: “layer streaming is bound by host-to-device transfer, not by the GPU.”
That was an inference from the H100 replication below, and it had never been measured. We
measured it on 11 August and it is false at the published configuration: deleting every
host-to-device byte buys 1.4%, the compute stream waits on a copy for 0.20% of the
step, and the step runs at 71.3% of that card’s same-session GEMM ceiling. The largest
streaming-specific cost is the per-layer NF4 dequantisation, at 9.8%
(the record). Every measurement stands;
the replication survives in a weaker form — the constraint is common to both machines and is
not the GPU’s compute.
Replication on hardware nothing like the original (added in v2): 119.6 tok/s on the RTX
3050 (at 952 MHz) against a median 113.00 on an H100, at the same 3.32 GB peak. Both pre-date
the #331 repair and are the figures the paper reports. The post-#331 row (@umran666, #1103) is
208.6 tok/s at 1935–1957 MHz in a 2.40 GB peak, 59% against 68% of the same-session GEMM
ceiling: the raw 1.74x gain is the clock, not a speedup, and the memory pattern changed between
the rows, so even the fraction is not like-for-like
(the record).
A silent wrong-gradient defect, found and repaired. On NF4 above ~165 MiB per layer the
forward stayed bit-exact and the loss curve looked healthy while the gradients were wrong. The
cause is named in the upstream library and reported there; the repair is gated against controls
on real 32B and 72B.
Bit-exactness at real model sizes instead of three-layer toys: forward from 0.5B to 72B,
backward at 8B and 14B.
Trained-model quality, measured for the first time, and indistinguishable from a resident run.
A comparison against DeepSpeed — including the result that does not flatter us: eight cards
of ZeRO-3 are slower than one card training resident.
The limitations section rewritten: of v1’s ten items, one closed and four more narrowed,
and seven new ones added.
Cite the version you used. 10.5281/zenodo.21771064 is the concept DOI and always resolves to
the latest version (v3 today); v1 and v2 remain citable at their own version DOIs and are not
edited — the retraction above is a new version precisely so that the record of what we claimed,
and when, stays intact.
The measurement records behind every number in it are in benchmarks/, published
as written — including the failures, the assumptions that turned out wrong, and the numbers that
were measured and then discarded.
@misc{makazhan2026exact,
title = {Exact Layer Streaming: LoRA Fine-Tuning of an 8B Model on a 4 GB Laptop GPU},
author = {Makazhan, Alpamys},
year = {2026},
publisher = {Zenodo},
version = {v3},
doi = {10.5281/zenodo.21918325},
url = {https://doi.org/10.5281/zenodo.21918325}
}
License
Apache-2.0. Copyright 2026 Makazhan Alpamys and the Soup contributors. If you redistribute Soup or a modified copy of it, sections 4 and 6 of the license apply to you: keep LICENSE and NOTICE with every copy, mark the files you changed, and do not use the Soup name beyond saying where the work comes from.
评论