Training 70B Models on Consumer Hardware (If You're Willing to Wait)
What if the constraint "must load model to train it" was assumed rather than required?
Training a 70-billion parameter language model requires approximately 782 GB of memory when using the Adam optimizer. Weights, momentum, variance, gradients. The hardware to do this costs around $100,000: eight A100 GPUs at 80 GB each, high-speed interconnects, the whole enterprise setup.
Or you could do it with ~8 GB of system RAM, a modest GPU for compute, and patience.
The GPU VRAM holds the active layer during forward/backward passes. The system RAM holds the OS page cache for memory-mapped files. The SSD holds everything else. Total system: a gaming PC.
I've been working on a technique I'm calling frozen incremental training. Simple once you see it. I haven't found prior work that treats disk as the authoritative model state while preserving full-weight updates.
The Assumption Everyone Makes
Here's the standard gradient descent update, the formula at the heart of every neural network training loop:
W_new = W_old - learning_rate × gradient
Look at it carefully. To compute W_new, you need W_old loaded in memory. This is why training requires holding the entire model in RAM. Every framework, every paper, every implementation assumes this.
But watch what happens when we rewrite the same operation differently:
W += (-learning_rate × gradient)
Mathematically identical. Same result. Different implementation.
The insight: An additive accumulation to a memory-mapped file doesn't require holding the full model in RAM. At the OS level, mmap updates still fault pages into RAM via the page cache. The win is bounded residency, not zero reads. You only need enough RAM for the active layer's working set.
The weights live on disk. You compute the gradient for one layer. You add the update directly to the disk-backed storage. The full model is never resident in memory.
How It Works
The architecture:
+------------------------------------------------------------------+
| SYSTEM RAM (~8 GB) |
| |
| +-----------------+ +-----------------+ +-----------------+ |
| | Layer N Weights | | Layer N Grads | | Activations | |
| | (~3.5 GB) | | (~3.5 GB) | | (streamed) | |
| +--------+--------+ +--------+--------+ +--------+--------+ |
| | | | |
| load compute stream |
| | | | |
+------------|--------------------|--------------------|------------+
| | |
| +=delta | |
v v v
+------------------------------------------------------------------+
| NVMe SSD (~800 GB) |
| |
| +-----------------------------------------------------------+ |
| | FROZEN STORAGE (memory-mapped files) | |
| | | |
| | +---------+ +---------+ +---------+ +---------+ | |
| | | Layer 0 | | Layer 1 | | Layer 2 | ... | Layer 79| | |
| | | W,M,V | | W,M,V | | W,M,V | | W,M,V | | |
| | +---------+ +---------+ +---------+ +---------+ | |
| | | |
| | + activation_cache.bin (temporary, streamed) | |
| +-----------------------------------------------------------+ |
+------------------------------------------------------------------+
Training flow:
1. Load Layer N weights from frozen storage into RAM
2. Forward pass, stream activations to disk
3. Backward pass, compute gradients
4. frozen_W[:] += delta (write-through to mmap)
5. mmap.flush()
6. Free Layer N from RAM, load Layer N+1
Storage
Three memory-mapped files per layer:
- W: Model weights (initialized randomly, updated incrementally)
- M: Adam first moment / momentum (initialized to zeros)
- V: Adam second moment / variance (initialized to zeros)
For a 70B model, this is ~782 GB of files. They sit on an SSD. Cold storage. Not RAM.
Training Loop
For each layer, sequentially:
- Load this layer's weights into RAM (~3.5 GB for a 70B model)
- Forward pass through this layer, stream activations to temporary disk storage
- Backward pass, compute gradients (reload activations from disk)
- Load M and V for this layer from disk
- Compute Adam update, tracking global timestep t
- Add delta directly to frozen W:
frozen_W[:] += delta - Flush M and V updates to disk
- Free this layer from RAM, move to next
Peak RAM: one layer's weights plus one layer's gradient plus activations. For a 70B model with ~80 layers, that's roughly 6-7 GB. Not 782 GB.
The Math
For the skeptical (as you should be), here's the Adam update rewritten for frozen storage:
# Traditional Adam (requires W, M, V in memory)
m = β₁ × m + (1 - β₁) × gradient
v = β₂ × v + (1 - β₂) × gradient²
m_hat = m / (1 - β₁^t) # t = global timestep (scalar, incremented each batch)
v_hat = v / (1 - β₂^t)
W = W - lr × m_hat / (√v_hat + ε)
# Frozen incremental (on disk, updated via memmap)
frozen_m[:] = β₁ × frozen_m + (1 - β₁) × gradient
frozen_v[:] = β₂ × frozen_v + (1 - β₂) × gradient²
m_hat = frozen_m / (1 - β₁^t) # t tracked globally, persisted to disk
v_hat = frozen_v / (1 - β₂^t)
delta = -lr × m_hat / (√v_hat + ε)
frozen_W[:] += delta # Additive accumulation, write-through to file
Same update rule per parameter. Same convergence behavior, with bounded deviations in bias correction under sequential updates. The timestep t is a single scalar tracked globally and persisted alongside the model state. If training resumes from checkpoint, t picks up where it left off. (Note: if using progressive layer locking, per-layer timesteps would preserve exact Adam semantics. The global t approach means bias correction becomes approximate for locked layers.)
Verification
I ran three verification tests:
Test 1: Mathematical Equivalence
Traditional: W = [1.0, 2.0, 3.0] → [0.985, 1.970, 2.955]
Frozen: W = [1.0, 2.0, 3.0] → [0.985, 1.970, 2.955]
✓ Results identical to floating-point precision
Test 2: Memory-Mapped Persistence
Write 1: arr[:] = [1.0, 2.0] → mmap.flush() → close
Write 2: arr[:] += [0.5, 0.3] → mmap.flush() → close
Read: arr[:] = [1.5, 2.3]
✓ Values accumulate correctly across file handles
The explicit flush() ensures data integrity. The OS writes dirty pages to disk before we close the handle. Without it, you're at the mercy of the kernel's write-back timing.
Safety note: If the process crashes between the += and flush(), the model state can corrupt. Production implementations should checkpoint the global timestep and use epoch-level snapshots. For fine-tuning runs measured in hours, this is manageable. For week-long training, you want atomic writes or shadow copies.
Test 3: Training Convergence
Epoch 1: Loss 1.3381
Epoch 2: Loss 1.0878 ↓ 19%
Epoch 3: Loss 1.0259 ↓ 6%
Epoch 4: Loss 0.9866 ↓ 4%
Epoch 5: Loss 0.9573 ↓ 3%
✓ Loss decreases consistently
The model trains. Weights update. Loss goes down. The full model is never resident. (These tests were run on a small transformer under 100M params to validate mechanics, not throughput. 7B+ scale testing is ongoing.)
What About Existing Techniques?
There's a lot of work on memory-efficient training. Here's how this approach differs:
Earlier out-of-core and disk-offload approaches treat disk as overflow. This treats disk as the authoritative state and never materializes a full in-memory model.
| Technique | Approach | Still Requires |
|---|---|---|
| Gradient Checkpointing | Trade compute for memory during backprop | Full model loaded |
| Model Parallelism | Split model across GPUs | Multiple GPUs |
| ZeRO (DeepSpeed) | Partition optimizer states across GPUs | Multiple GPUs |
| CPU Offloading | Swap to CPU RAM during training | Eventually loads full model |
| LoRA | Train small adapter matrices only | Not full model training |
| Frozen Incremental | Additive accumulation to frozen storage | Single GPU + SSD |
The key difference: the full model is never resident in memory. Not partitioned across GPUs. Not swapped to CPU. The weights live on disk, and updates are accumulated directly to that frozen storage via the OS page cache as a sliding window.
ZeRO and CPU offloading still use the traditional W_new = W_old - lr × grad formulation. They just move tensors around to fit them in available memory. Frozen incremental training reformulates the operation itself.
Progressive Layer Locking
Once training happens layer-by-layer with frozen storage, you can lock layers that have converged.
Epoch 5: Loss 0.9573
→ layer_0 gradient magnitude below threshold
→ Lock layer_0 (skip gradient computation)
Epoch 6: Loss 0.9356 ↓ (layer_0 frozen, still converging)
Epoch 7: Loss 0.9296 ↓
Locked layers become immutable. No gradient computation, no updates, no I/O for that layer. Compute redirects to layers still learning.
The slow speed becomes a feature. Since we're processing layers individually anyway, we gain granular visibility into per-layer convergence. You can inspect, lock, and even rollback individual layers. Traditional batch training doesn't offer this introspection easily.
This is transfer learning without reloading the base model. The frozen layers stay on disk, untouched, while you fine-tune the upper layers with full weight updates (not adapter matrices).
The Numbers
| Metric | Traditional (70B) | Frozen Incremental (70B) |
|---|---|---|
| Memory Required | 782 GB (GPU/CPU) | ~8 GB system RAM + SSD |
| Hardware | 8× A100 (80GB) | 1× consumer GPU + NVMe |
| Estimated Cost | ~$100,000 | ~$1,500 |
| Time per Step | ~seconds | ~minutes |
| Memory Reduction | 1× (baseline) | ~100× |
The disk requirement is the same (782 GB of model state). But disk is cheap. A 2TB NVMe SSD costs $150. The tradeoff: what takes hours on a cluster takes weeks or months on consumer hardware. For fine-tuning, that might be acceptable. For pretraining from scratch, probably not.
Why Hasn't Anyone Done This?
I've asked myself this question repeatedly. The math is trivial. Memory-mapped files are a 50-year-old operating system feature. Here's my working hypothesis:
Economic Incentives
- GPU vendors benefit from high memory requirements driving hardware sales
- Cloud providers benefit from expensive training compute bills
- Research labs have cluster access; no pressure to optimize for consumer hardware
Conceptual Barriers
- The mental model is "gradient descent requires loading weights"
- Memory-mapped files are seen as I/O optimization, not training primitives
- Optimizer states (M, V) are always assumed to be "hot" in memory
The Obviousness Gap
It seems obvious in retrospect. Additive accumulation is mathematically equivalent to assignment. Memmap files exist in every OS. Layer-by-layer processing is standard. Variants of disk-offload training exist (ZeRO-Offload, etc.), but they generally treat disk as overflow rather than primary state.
The difference: treating the SSD as primary storage rather than overflow. Accepting the patience tradeoff as a feature rather than a bug.
The constraint was assumed, not derived. Once you question it, the solution is obvious.
Limitations
To be clear about what this approach doesn't solve:
The I/O Bottleneck (The Elephant)
This is the big one. Let's do the math honestly:
- A 70B model (FP32) is ~280 GB of weights alone
- One training step requires reading the whole model (forward), then reading it again plus optimizer states (backward)
- Total I/O per step: ~1 TB of data movement
- NVMe Gen4 speed: ~7 GB/s sequential (best case)
- Time per step: ~142 seconds
The ~7 GB/s assumes sequential access. If the mmap files fragment on disk, performance tanks to random I/O speeds (~100 MB/s). Pre-allocating contiguous files with fallocate before training is critical. Compare this to A100 HBM2 bandwidth (~2000 GB/s). Traditional training is orders of magnitude faster per step.
The tradeoff is space for time. This makes training possible on consumer hardware, not fast. For full pretraining on large datasets, you're looking at months or years. For fine-tuning (fewer epochs, smaller datasets), it becomes a viable "patience" strategy.
Other Considerations
- Activations: Must also stream to disk to stay within RAM constraints. This is arguably the bigger bottleneck than weight I/O. Backward pass latency explodes with random access patterns, and prefetching becomes difficult. Batch size and sequence length collapse to near-minimum values.
- Mixed precision: Current analysis assumes fp32. fp16/bf16 would halve storage and I/O requirements, making this more practical.
- SSD endurance: Constant write-through to mmap will exhaust the TBW (Total Bytes Written) rating of consumer NVMe drives faster than standard use. Enterprise-grade or high-endurance drives recommended for sustained runs.
- OS hints: Default page replacement (LRU) doesn't know you're traversing tensors sequentially. Use
madvise(MADV_SEQUENTIAL)on mmap regions to enable aggressive read-ahead and prevent cache thrashing. - Full-scale validation: The math is verified on small models. 7B → 70B scale testing is ongoing.
- System RAM vs VRAM: The OS file cache for mmap uses system RAM, not GPU VRAM. A "gaming PC" with 32 GB system RAM and 8 GB VRAM is the target configuration. The GPU handles compute; system RAM handles the memory-map window.
The Broader Pattern
This fits into the same research program as Veriduct and OIS: questioning assumptions that security and ML systems take for granted.
- Veriduct: Files don't have inherent format. The loader assigns it.
- OIS: Malicious bytes don't have to exist. Coordinates into signed code suffice.
- Frozen incremental training: Models don't have to be fully resident. Bounded RAM via page cache sliding window works.
Each challenges a foundational assumption by asking: is this constraint necessary, or just conventional?
The interpreter defines meaning. The bytes have none inherently.
For neural networks, the "interpreter" is the training loop. And the training loop doesn't actually require what we assumed it did.
What This Means
This doesn't make consumer hardware competitive with A100 clusters for speed. It makes training possible where it was previously impossible.
The practical applications are narrower than "train GPT-5 on your laptop":
- Fine-tuning: Adapting a pretrained 70B model to a specific domain with a small dataset. Fewer epochs, acceptable wall-clock time.
- Research exploration: Testing architectural changes on large models without cloud budget. Slow, but possible.
- Edge cases: Situations where you have more patience than money, or where data can't leave local hardware.
It's not "training frontier models is now free." It's "training frontier models is now possible without institutional resources, if you're willing to wait."
That's a different world than the marketing pitch. But it's still a world that didn't exist before.