Ultra-Low VRAM Matrix-Factorized Optimizer for PyTorch
An OpenBlade Release | Hugging Face: huggingface.co/OpenBlade
Author & Lead Researcher: Jassim Ibrahim Farooqi
Citation / Context: Part of ongoing research and optimizations into extreme-efficiency training architectures and ultra-low-footprint gradient descent methods at OpenBlade.
Modern deep learning is bottlenecked by optimizer memory. In standard FP32 AdamW, training requires storing two states per parameter (the 1st momentum vector
Avalanche is an ultra-low VRAM matrix-factorized optimizer that fundamentally eliminates this bottleneck.
By reformulating second-moment estimation as a Rank-1 marginal factorization (
This represents up to a 99.99% reduction in optimizer memory consumption over standard FP32 AdamW while preserving full FP32 second-moment tracking precision and convergence dynamics.
The table below compares internal optimizer state memory consumption across standard model architectures:
| Model Scale | Parameter Count | Standard FP32 AdamW State ( |
8-bit Adam (bitsandbytes) | Avalanche State | VRAM Reduction |
|---|---|---|---|---|---|
| Small / Edge | 125 Million | ~1.00 GB | ~250 MB | ~1.8 MB | 99.82% |
| Medium / Foundation | 1.12 Billion | ~8.96 GB | ~2.24 GB | ~9.6 MB | 99.89% |
| 7B Base (e.g. LLaMA-7B) | 7.00 Billion | ~56.00 GB | ~14.00 GB | ~24.5 MB | 99.96% |
| 13B Scale | 13.00 Billion | ~104.00 GB | ~26.00 GB | ~42.0 MB | 99.96% |
| 70B Scale | 70.00 Billion | ~560.00 GB | ~140.00 GB | ~78.0 MB | 99.99% |
Key Takeaway: While standard Adam scales linearly with parameter count ($O(M \cdot N)$), Avalanche scales with parameter perimeter ($O(M + N)$). On a 70B parameter model, Avalanche frees over 550 GB of VRAM, allowing massive models to be trained or fine-tuned on drastically fewer GPUs.
For any 2D weight matrix
Avalanche instead maintains two low-dimensional marginal vectors:
-
Row Marginal:
$r \in \mathbb{R}^M$ , where$r_i$ tracks the mean squared gradient across columns:$$r_t = \beta_2 r_{t-1} + (1 - \beta_2) \left( \frac{1}{N} \sum_{j=1}^N G_{ij}^2 \right)$$ -
Column Marginal:
$c \in \mathbb{R}^N$ , where$c_j$ tracks the mean squared gradient across rows:$$c_t = \beta_2 c_{t-1} + (1 - \beta_2) \left( \frac{1}{M} \sum_{i=1}^M G_{ij}^2 \right)$$
During the optimization step, the full variance matrix is reconstructed dynamically via an outer product normalized by the global squared gradient mean
Memory Savings: For a
- Standard Adam:
$4096 \times 4096 = 16,777,216$ elements ($67.1\text{ MB}$ ) - Avalanche:
$4096 + 4096 = 8,192$ elements ($32.8\text{ KB}$ ) - Memory reduction: 99.95% on every single linear layer.
In transformer architectures and modern deep networks, the second moment acts as a per-coordinate adaptive learning rate normalizer. Momentum (first moment
To guarantee training stability in BF16 and FP16 mixed-precision and prevent catastrophic divergence from outlier gradients, Avalanche dynamically computes the root-mean-square norm of the raw update vector
The update is then scaled by
This guarantees that update vectors never exceed an RMS magnitude of 1.0, completely preventing loss spikes without requiring aggressive manual gradient clipping.
For ultra-large matrices (such as vocabulary embeddings with shape fp32_max_elems (default: 4M elements) into bounded row chunks (
- Python 3.8+
- PyTorch 1.13+ (PyTorch 2.0+ recommended)
- CUDA 11.8+ / 12.0+ or ROCm (Fully functional on CPU as well)
Because Avalanche is fully self-contained with zero external dependencies beyond standard PyTorch, you can simply drop optimizer.py directly into your codebase:
cp avalanche/optimizer.py your_project/avalanche.pycd avalanche
pip install .Avalanche inherits directly from PyTorch's torch.optim.Optimizer. It is a 100% drop-in replacement for torch.optim.AdamW:
import torch
import torch.nn as nn
from avalanche import Avalanche
# 1. Define your model
model = nn.Transformer(d_model=1024, nhead=16).cuda()
# 2. Initialize Avalanche (Standard PyTorch interface)
optimizer = Avalanche(
model.parameters(),
lr=1e-4,
betas=(0.0, 0.999),
weight_decay=0.01
)
# 3. Standard training loop
for x, y in dataloader:
optimizer.zero_grad(set_to_none=True)
loss = criterion(model(x), y)
loss.backward()
optimizer.step()You can also pass the nn.Module directly:
optimizer = Avalanche(model, lr=2e-4, weight_decay=0.01)from transformers import Trainer, TrainingArguments
from avalanche import Avalanche
class CustomTrainer(Trainer):
def create_optimizer(self):
self.optimizer = Avalanche(
self.model.parameters(),
lr=self.args.learning_rate,
weight_decay=self.args.weight_decay,
betas=(0.0, 0.999),
)
return self.optimizerAvalanche provides a unified multi-precision architecture where the second-moment state is always factorized to
| Class | Precision Mode | Momentum Memory | Second-Moment Memory | Description |
|---|---|---|---|---|
Avalanche4Bit |
"4bit" |
0.5 B / param |
|
Packed 4-bit nibbles with lossless error-feedback compensation |
Avalanche8Bit |
"8bit" |
1.0 B / param |
|
Block-scaled 8-bit integers with lossless error-feedback compensation |
AvalancheFP16 |
"fp16" |
2.0 B / param |
|
IEEE 754 half-precision float with optional residual compensation |
AvalancheBF16 |
"bf16" |
2.0 B / param |
|
Bfloat16 matching FP32 dynamic range (no underflow/overflow) |
AvalancheFP32 |
"fp32" |
4.0 B / param |
|
Full single-precision velocity with factorized variance |
Avalanche |
"none" ( |
0.0 B / param |
|
Pure zero-momentum; maximum possible memory reduction (99.99%) |
For quantized modes (4bit, 8bit, and fp16), Avalanche uses lossless error feedback:
$$e_t = m_t - \hat{m}t$$
The residual error $e_t$ is stored in compact half-precision (m_residual) and added back to the momentum calculation on the next step:
$$m{t+1} = \beta_1 (\hat{m}t + e_t) + (1 - \beta_1) G{t+1}$$
Because $\sum_{t=1}^T \hat{m}t = \sum{t=1}^T m_t + e_0 - e_T$, no gradient or step magnitude is discarded across training.
from avalanche import (
Avalanche4Bit,
Avalanche8Bit,
AvalancheFP16,
AvalancheBF16,
AvalancheFP32,
Avalanche,
)
# 1. Lossless 4-bit momentum (70% VRAM savings vs FP32 AdamW)
opt = Avalanche4Bit(model.parameters(), lr=1e-4, betas=(0.9, 0.999), lossless=True)
# 2. Lossless 8-bit momentum (55% VRAM savings vs FP32 AdamW)
opt = Avalanche8Bit(model.parameters(), lr=1e-4, betas=(0.9, 0.999), lossless=True)
# 3. Native Bfloat16 momentum (45% VRAM savings vs FP32 AdamW)
opt = AvalancheBF16(model.parameters(), lr=1e-4, betas=(0.9, 0.999))
# 4. Native FP16 momentum
opt = AvalancheFP16(model.parameters(), lr=1e-4, betas=(0.9, 0.999))
# 5. Full FP32 momentum with factorized second moments
opt = AvalancheFP32(model.parameters(), lr=1e-4, betas=(0.9, 0.999))
# Or dynamically through the base class:
opt = Avalanche(model.parameters(), lr=1e-4, betas=(0.9, 0.999), mode="bf16")| Parameter | Type | Default | Description |
|---|---|---|---|
params |
Iterable |
Required | Iterable of parameters or parameter groups. |
lr |
float |
1e-3 |
Learning rate. Recommended: 1e-4 to 3e-4 for pretraining; 1e-5 to 5e-5 for fine-tuning. |
betas |
Tuple[float, float] |
(0.9, 0.999) |
(beta1, beta2). Beta1 controls momentum velocity; Beta2 controls marginal second moments. |
mode |
str |
"auto" |
Precision mode: "4bit", "8bit", "fp16", "bf16", "fp32", "none", or "auto". |
lossless |
bool |
True |
Activates error-feedback residual compensation for quantized modes. |
stochastic_rounding |
bool |
False |
Unbiased stochastic rounding during quantization. |
block_size |
int |
32 |
Block tile size for quantization scaling (32 or 64). |
eps |
float |
1e-30 |
Numerical stability epsilon for division and square root. |
weight_decay |
float |
0.01 |
Decoupled AdamW weight decay coefficient. |
chunk |
int |
16 |
Number of identical-shape tensors batched together in CUDA operations. |
fp32_max_elems |
int |
4194304 |
Threshold (4M elements) above which large 2D tensors use streaming row-chunk updates. |
A self-contained verification benchmark is included in example.py. It instantiates a 360M+ parameter transformer block, executes multiple optimization passes, and prints an exact byte-for-byte memory accounting of the optimizer state:
python avalanche/example.pyExpected output:
============================================================================
βοΈ Avalanche: Ultra-Low VRAM Matrix-Factorized Optimizer
Author: Jassim Ibrahim Farooqi
Citation: Ongoing Research & Optimizations in Extreme-Efficiency Training
============================================================================
[1/4] Instantiating Benchmark Transformer (~360M Parameters)...
Total Parameters : 362,763,264
Model Weights (FP32) : 1383.83 MB
Standard AdamW Memory : 2767.66 MB (2.70 GB)
[2/4] Initializing Avalanche Optimizer...
[3/4] Running 5 Optimization Steps with Synthetic Loss...
Step 1 | Loss: 10.4931
Step 2 | Loss: 6.7421
Step 3 | Loss: 3.9692
Step 4 | Loss: 1.9140
Step 5 | Loss: 0.7471
[4/4] Optimizer Memory Analysis:
----------------------------------------------------------------------------
Standard FP32 AdamW State Footprint : 2767.66 MB (2.70 GB)
Avalanche State Footprint : 2.03 MB
Memory Footprint Reduction : 99.93%
----------------------------------------------------------------------------
β State dict serialization & deserialization verified successfully.
β Avalanche optimizer is ready for deployment across GitHub, Hugging Face, and production.
If you use Avalanche in your research, production systems, or open-source projects, please credit OpenBlade and the author:
@software{openblade2026avalanche,
author = {Jassim Ibrahim Farooqi and OpenBlade},
title = {Avalanche: Ultra-Low VRAM Matrix-Factorized Optimizer for Deep Neural Networks},
year = {2026},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/OpenBladeAI/avalanche}},
url = {https://github.com/OpenBladeAI/avalanche},
note = {An OpenBlade release. Ongoing research and optimizations into extreme-efficiency training architectures.}
}- Official Web Page & Direct Download: https://openblade.org/avalanche (Direct raw script: openblade.org/avalanche/optimizer.py)
- GitHub Organization: https://github.com/OpenBladeAI
- Hugging Face Hub: https://huggingface.co/OpenBlade
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2026 Jassim Ibrahim Farooqi, OpenBlade (https://github.com/OpenBladeAI).