The layer streaming paper
The mechanism behind training an 8B model on a 4 GB laptop GPU is written up as a preprint, together with the correctness protocol that verifies a streamed run is bit-exact against a resident one. This page is the short version, plus everything you need to cite it.
Exact Layer Streaming: LoRA Fine-Tuning of an 8B Model on a 4 GB Laptop GPU (v3). Makazhan, A. (2026). Zenodo. 10.5281/zenodo.21918325. Preprint, CC-BY-4.0.
Version 3 is current, published 13 August 2026. The title and the claim are unchanged, still 8B on 4 GB, and no measured number has changed since v1. What version 2 added is a session on hardware the project does not own; what version 3 does is retract one explanation version 2 gave for it.
Two DOIs, and they are not interchangeable:
| DOI | What it points at | Use it when |
|---|---|---|
| 10.5281/zenodo.21771064 | the concept DOI, always the newest version, v3 today | you mean "the paper" and want the reference to follow it forward |
| 10.5281/zenodo.21918325 | v3 specifically | you are citing a version you actually read |
Cite the version you used. v1 was not withdrawn and stays citable at its own version DOI; nothing in it was retracted, and the section below says exactly what changed.
What it reports
Two results, both on one machine: an RTX 3050 Laptop with 4 GB of VRAM, 16.9 GB of host RAM, running Windows 11.
- Llama-3.1-8B-Instruct in NF4 at 119.6 tok/s, 3.32 GB peak, 100% SM occupancy.
- Qwen2.5-3B with an un-quantized bf16 base at 143 tok/s in 2.15 GB, a configuration that raises CUDA out of memory when the same model is trained resident on the same card.
Both are configurations whose weights alone exceed the card. Measured overhead against resident training is 1.43x, at 0.5B, the only size on that machine that admits a valid resident baseline at all.
The paper is deliberate about what that does not beat. Layer streaming on a small card is well established for inference, and AirLLM's own documentation says layer sharding is not compatible with gradient propagation. The published fine-tuning result for this hardware class is 1.3B, reached by LSP-Offload (arXiv:2406.10181) by compressing the optimisation into a learned sparse subspace rather than by streaming the base. The systems that do stream weights during training are evaluated on an H200 with 1.5 TB of host memory, an RTX 4090 with 256 GB, or a cluster. The unserved combination, and the one the paper addresses, is streamed training on a small card.
What version 2 adds
The paper roughly doubled, from about 9,000 words to about 19,800, and every addition comes from the same source: three borrowed days on an 8x H100 box, which was the first hardware other than the original laptop this work had ever run on.
- Replication on hardware nothing like the original. 119.6 tok/s on the RTX 3050 against a median of 113.00 on an H100, at the same 3.32 GB peak. The server card is if anything slightly slower. Version 2 offered an explanation for that and version 3 retracts it; the measurement itself is unaffected.
- A silent wrong-gradient defect, found and repaired. On NF4 above roughly 165 MB per decoder 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 the method: eight cards of ZeRO-3 are slower than one card training resident.
- The limitations section rewritten: of v1's ten items, one is closed and four more are narrowed, and seven new ones are added.
The last line is the one worth pausing on. A revision that only closed limitations would be a marketing document. This one closed one, narrowed four and opened seven, because measuring at a real size is how you find out what you did not know you were assuming.
What version 3 adds
Version 3 is current, published 13 August 2026. The title and the claim are unchanged, still 8B on 4 GB, and no measured number changed. It exists to retract one explanation version 2 gave.
Version 2 read the H100 replication, a server card coming back no faster than the laptop, as evidence that layer streaming is bound by host-to-device transfer rather than by the GPU. It was an inference, and it had never been measured. On 11 August 2026 it was measured on the original laptop and is false at the published configuration: four ablation arms interleaved in one process at a pinned clock show that removing all host-to-device traffic, 6.864 GB per step, buys 1.44%, removing the NF4 dequantisation buys 9.80%, and removing both leaves 88.7% of the step standing. The compute stream is blocked on a copy for 8.4 ms of a 4190 ms step, and the step runs at 71.3% of that card's same-session, shape-matched GEMM ceiling. The claim is true below roughly 128 tokens per step, where the fixed transfer volume dominates, and the published configuration is not there.
What survives is the measurement itself, and it is untouched: a card with roughly two orders of magnitude more compute came back no faster than the laptop. The constraint is common to both machines and is not the compute the datacenter card adds. Beyond that we no longer offer an explanation for why: the one we offered was measured and refuted, and a second guess would be the same mistake in a new sentence. The H100's own bottleneck was never instrumented and no claim is made about it.
Two things about how it was published are worth copying rather than admiring. The retraction is a new version of the paper rather than an edit to the old one, because a claim that reached readers cannot be unpublished by changing a file. And every occurrence in the measurement records is annotated in place rather than deleted: in a folder whose premise is publishing the record as written, a silent deletion costs more credibility than the error does. The record is probe-v0.73.0-what-bounds-streaming.md.
The result it defends hardest is not the throughput
In a streamed trainer the natural failure is silent. If the autograd graph is severed at the base weights, the upper layers still train, the loss still descends, and the run looks healthy. A throughput number taken before correctness is established measures nothing.
So the central check is bit-exactness against a resident reference of the same numerics: resident NF4 for a streamed NF4 run, never resident bf16, because quantisation error is wide enough to hide a real defect inside it. Against a matched reference the expected answer is 0.0, so anything else is a bug by construction.
That discipline paid for itself. It caught a PEFT dispatch path that selected a different LoRA implementation on a meta-device skeleton and produced a 0.94 maximum logit divergence with byte-identical weights and byte-identical adapters: no exception, no warning, and a loss curve that looked entirely healthy. Nothing short of bit-exactness would have surfaced it.
The protocol itself, on SmolLM2-135M in bf16 with LoRA r=16 on q_proj and v_proj:
| Check | Threshold | Measured |
|---|---|---|
| Streamed vs resident logits, max abs diff | < 1e-3 | 0.0, bit-exact |
| LoRA gradient at layer 0 | non-zero | 9.50e-01, 30 of 30 layers non-zero |
| 100-step loss curve vs resident | within noise | max relative difference 0.0 |
| Same seed twice | identical | 0.0 |
| With pinned-host boundary offload | < 2% relative | 4.83e-3 |
| Two buffers vs three | identical | 0.0 |
Bit-exactness was then re-verified across nine model_type families in both bf16 and NF4, 14 of 14 comparisons at a maximum absolute logit difference of 0.000e+00. Two rows carry more weight than the others. phi3 fuses Q, K and V into a single qkv_proj, so the projection names a Llama-shaped implementation would look for do not exist at all, and it is bit-exact anyway, which is the strongest evidence that layer detection walks the real module tree rather than a naming assumption. And gemma3 is deliberately refused while gemma3_text is accepted, with the accept and the refuse asserted together so the refusal cannot decay into a spelling accident.
The protocol runs on CPU and is part of the project's test suite rather than a one-off experiment, so a regression fails CI instead of reaching a user.
Three findings that have nothing to do with streaming
These are the parts most likely to be useful even if you never enable layer streaming.
- The cross-entropy logits term costs 14 bytes per element, not 6. A first-principles budget counts the bf16 logits plus an fp32 upcast. The measured figure is 14, because the loss holds the bf16 logits, the fp32 upcast, an fp32 log-softmax and an fp32 gradient live at the same time. That is a 2.33x under-prediction on a term that dominates: at batch 8 the logits tensor was over a hundred times the size of the entire layer buffer pool. Anyone budgeting VRAM for a large-vocabulary model from first principles will make the same mistake.
- Windows and WDDM do not raise out of memory, they spill. One row of the fitting grid allocated 9.27 GB on a 4.29 GB card and completed without an exception. The methodological consequence is blunt: on this platform, "it did not crash" is not evidence that a configuration fits. It also cost a discarded baseline, a resident run whose reported peak turned out to be the driver paging into host memory.
- Gradient accumulation is per-token I/O-neutral. The received wisdom, the paper's own earlier draft included, is that accumulation multiplies I/O linearly because every micro-batch re-reads the model. True per optimizer step, and misleading per token, which is the unit that sets wall-clock time: layer reads per 1000 tokens held constant at 175.78 across accumulation 1, 2 and 4. The real cost is opportunity cost, measured at 2.52x at an equal effective batch of 4, which is why the tool prints "raise batch size until the pre-flight refuses, then accumulate" rather than the standard low-VRAM advice of keeping batch at 1.
A fourth, smaller one, aimed at anyone quoting a fraction of peak on a consumer GPU: a ceiling is only comparable to a throughput measured in the same session. Repeating one GEMM six times inside a single session was stable to under 1%, while the same card varied by about 13% between sessions at the same reported clock. Any fraction-of-ceiling figure has to state the SM clock it was taken at.
What it does not claim
The limitations section is long on purpose, and it is the reason to trust the rest.
- 8B is the largest size measured. No 14B or larger claim is supported by any number in the paper.
- The 3B bf16 figure is a lower bound. That machine could not page-lock a 5.55 GB store, so the run fell back to a pageable one, which makes the host-to-device copy synchronous. The occupancy drop from 96.8% to 79.3% is that cost, measured rather than estimated.
- Windows and WDDM throughout. The numbers are systematically pessimistic against Linux, and there is no Linux measurement.
- One card, and architecture coverage verified at small scale. The nine-family gate used tiny from-config checkpoints rather than downloaded ones, deliberately, because the risk being tested is a naming property and not a size property. The throughput results are Qwen2.5 and Llama only.
- Bit-exactness is verified at 135M, not at 8B. At 8B it is impossible on that machine by construction: it needs a resident reference, which cannot exist for a model that does not fit. The paper names this as the most useful missing experiment in it. That experiment has since been run on borrowed hardware, and the section below says what it returned.
- n = 1. Every throughput row is a single run of 50 measured steps after 10 warm-up, on a working laptop that was not otherwise idle, and no variance is reported. The one exception is the accumulation comparison, repeated in an interleaved order precisely because a monotonic clock drift would otherwise have manufactured the result.
- The RAM-versus-disk performance gap is unmeasured and no figure is claimed for it. Correctness of the disk tier is established; relative speed is not.
The experiment it named as missing is now in the paper
The limitation above is the one worth acting on, and in August 2026 a borrowed 8x H100 box made it possible. It was open in v1 and it is closed in v2, which is the largest single reason the revision exists. Those cards can hold a resident 8B, 14B, 32B and even 72B, so the comparison the paper could not make on a 4 GB laptop was finally made against real checkpoints instead of 3-layer fixtures. The full record is its own page; three things from it bear directly on the paper.
No measured number from v1 changes, and nothing in it is invalidated. Its headline configuration sits at 105 MB per decoder layer, comfortably below the boundary the exercise found, and its gradients survive a 50-backward soak against a resident NF4 reference at exactly 0.0. Its throughput claim reproduces on completely different hardware, a different operating system and a much newer software stack: 119.6 tok/s in 3.32 GB there, against a median of 113.00 tok/s in the same 3.32 GB peak on an H100.
The exactness claim is strengthened, and the two halves are strengthened by different amounts. The forward is exact against matched resident references at 8B, 14B, 32B and 72B. The backward is exact at 8B and 14B, which is at and below the paper's own scope, and above that it was wrong until it was repaired. So "verified at 72B" is a forward statement and only a forward statement. The paper asserts nothing at 72B, so nothing in it depends on the distinction, but any future revision that reaches past 14B has to carry it explicitly rather than saying "bit-exact" and leaving a reader to decide which half was meant. Two expert readers already read it the other way.
One thing that stays open across every version so far. The repair changed the code path the headline was measured on. At real training shapes the arithmetic is unchanged, and the measured cost at 32B is 4.8%, but nobody has re-run the 8B laptop configuration on the repaired code, and a server card cannot stand in for a 4 GB laptop, which the H100 replication showed by coming back no faster rather than faster. Treat 119.6 tok/s as a pre-repair figure until someone re-runs it on that card. It is one of the seven limitations v2 adds rather than something v2 quietly resolved.
The records behind it
Every number comes from measurement logs published verbatim in the benchmarks directory. They are the working gate records kept while each item was built, not a summary assembled afterwards, so they carry the failures, the assumptions that turned out wrong and the numbers that were measured and then discarded, in the order those things happened. Read a file from its top rather than lifting a passage out of the middle: a passage may be one the same page later corrects.
Reproducing the headline row
The implementation shipped in Soup v0.72.3 under Apache-2.0. Two keys below are load-bearing, and omitting them is a silent divergence rather than an error: gradient_accumulation_steps (the shipped default is 4, and at batch 1 that measures roughly 2.5x lower throughput) and, for the un-quantized run, quantization (the shipped default is 4bit).
base: meta-llama/Llama-3.1-8B-Instruct
task: sft
data:
train: data.jsonl
max_length: 512
training:
stream_layers: true
stream_source: ram
stream_buffers: 2
quantization: 4bit
batch_size: 1
gradient_accumulation_steps: 1 # load-bearing: the shipped default is 4
optimizer: paged_adamw_8bit
lora:
r: 16
target_modules: [q_proj, v_proj]Omitting the lora block is not equivalent either: it defaults to r=64 with automatic target selection rather than the r=16 on q_proj and v_proj that produced these numbers. The run also needs free host RAM of at least the store size divided by 0.7, about 5.1 GB for the 8B NF4 store, and the pre-flight refuses below that rather than thrashing.
Cite it
@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}
}See also
- Layer streaming — the mechanism as it ships today, the measured numbers, and the full refusal table.
- Scaling a streaming run — architectures, batch versus gradient accumulation, the VRAM pre-flight, resume and the disk tier.
- Preference losses over streaming — DPO, ORPO, SimPO and KTO against a streamed base, which came after v1 was written and are still outside what the paper measures.
- Validation on hardware we do not own — the resident reference at 8B, 14B, 32B and 72B in full, which v1 named as its most useful missing experiment and v2 carries.
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.