A lightweight, memory‑efficient fine‑tuning toolkit that projects gradients into a low‑dimensional subspace at adjustable granularity and updates with an Adam‑like optimizer ProjFactor.
What’s new? VLoRP adds a projection granularity hyperparameter
cin addition to the usual rankr, letting you trade memory ↔ performance under a fixed budget$\mathcal{M} = c·r$ . Finer granularity (largerc, smallerr) consistently yields stronger results at the same memory cost, and the method introduces no extra compute beyond a pair of reshape ops.
-
Memory‑efficient: stores projected gradients; total memory
$O(mn + 2ncr + n + m)$ . In experiments, VLoRP used ~24.1GB vs LoRA 28.8GB (budget 256). -
Strong accuracy at fixed budget: the finest‑grained setting
$c=256, r=1$ is consistently among the best under$M=256$ . - Projection choices: Gaussian (normal), Rademacher, or SVD bases all work similarly; normal is slightly better after convergence.
-
Gradient projection with granularity. Reshape each parameter’s gradient matrix
$G ∈ ℝ^{n×m}$ to$\tilde G ∈ ℝ^{nc×(m/c)}$ , project rows with a random matrix$\tilde P ∈ ℝ^{(m/c)×r}$ , store$\tilde G_s=\tilde G\tilde P$ , then project‑back and reshape for the update. Only reshapes are added; compute overhead is unchanged. - Two update schemes, OS > SS. Original‑space (OS) adapts in the full space and tracks Adam closely; subspace (SS) adapts inside the subspace and converges slower when the second moment is used. We propose ProjFactor to approximate OS with far lower memory.
-
Budgeting and performance. Define memory budget
$M=c·r$ . Under the same$M$ , finer granularity generally performs better and can even reduce FLOPs and numeric error. -
Convergence. With SGD, VLoRP attains the standard
$O(1/T)$ rate; with ProjFactor, a Lyapunov (Hamiltonian) argument shows monotone energy decrease toward a stationary point.
Below are minimal templates.
CUDA_VISIBLE_DEVICES=0 torchrun --standalone --nproc_per_node 1 torchrun_main.py \
--model_name llama-2-7b \
--dataset commonsense \
--lr 2e-5 \
--activation_checkpointing \
--batch_size 16 \
--total_batch_size 512 \
--num_training_steps 138 \
--warmup_steps 0 \
--weight_decay 0 \
--grad_clipping 1.0 \
--dtype bfloat16 \
--eval_every 100 \
--update_proj_gap 30 \
--scale 0.25 \
--factor 256 --rank 1 \
--single_gpu \
--optimizer projfactor \
--max_length 1024 \
--wandb_expname llama2-7b-commonsense-VLoRP-c256-r1 from transformers import Trainer
from vlorp.optim import ProjFactor
args = ...
optimizer = ProjFactor(
model,
lr=args.lr,
weight_decay=args.weight_decay,
rank=args.rank,
update_proj_gap=args.update_proj_gap,
scale=args.scale,
factor=args.factor,
scheduler=args.scheduler,
gradient_accumulation=args.gradient_accumulation,
warmup_steps=args.warmup_steps,
num_training_steps=args.num_training_steps,
min_lr_ratio=args.min_lr_ratio,
correct_bias=True,
proj_matrix_dist=args.proj_matrix_dist,
)
scheduler = ...
# ... set up dataloaders and model, then follow standard training loop ...
trainer = Trainer(
...,
optimizers=(optimizer, scheduler)
)Tip: Start with fine granularity (large
c, smallr) for a stronger baseline under the samebudget.
- c (granularity factor): number of vertical slices per gradient row (power‑of‑two recommended). Larger
c⇒ finer granularity. - r (rank): subspace dimension per slice.
-
$\mathcal{M}$ (memory budget): productc*r; in our paper, we compare settings under the same$\mathcal{M}$ . - proj_type:
normal|rademacher|svd(all viable). - optimizer:
projfactor(Adam‑like, memory‑saving).
Notes: exact hyperparameters, warmup steps, and projection refresh frequency are discussed in the paper’s appendix figures/tables.
Under a fixed budget M, finer granularity reduces FLOPs (by a factor proportional to 1/c) and improves numeric stability—useful for bf16/fp16 and long accumulations.
Please refer to table 4 for the meaning of notations in our paper.
Consider a loss function
Theorem 1. Let
where
Theorem 1 confirms that using random projection-based gradient estimation with VLoRP in conjunction with SGD achieves an
To analyze the convergence properties of ProjFactor, we leverage the Hamiltonian descent framework, a powerful tool for understanding the behavior of optimizers in continuous time. This framework allows us to model ProjFactor’s update rule as an ordinary differential equation (ODE), providing insights into its long-term stability and convergence.
The infinitesimal updates of Projfactor is defined as follows:
We use * to denote the above update system.
Notes:
The corresponding Lyapunov function (Hamiltonian) is defined as
Subsequently, we make the following mild assumptions, consistent with prior works in this area, to establish the mathematical foundation for our analysis.
Assumption Assume the functions in system \eqref{eq:projfactor_infinitesimal_appendix} are continuously differentiable, and following conditions hold
- $\frac{d}{dt} \mathcal{H} \left(W_t , \tilde{m}t^s , \tilde{v}^{o}{rt} , \tilde{v}^{o}_{ct}\right) = 0$ implies
$\tilde{G}^s_t=0$ . - For any
$t>0$ , if$G_t\neq 0$ , then$\tilde{G}_t^s \neq 0$ and$\tilde{G}_t^o \neq 0$ . - For any
$t>0$ , $\frac{|\tilde{G}t^o|^2}{|\tilde{v}^o{rt}|}\leq R$.
Theorem 2. Suppose the functions in system * are continuously differentiable. Under above Assumption we have:
- For $\left(W_t, \tilde{m}t^{s}, \tilde{v}{rt}^{o}, \tilde{v}_{ct}^{o}\right)$ satisfying
*,
- Any bounded solution $\left(W_t, \tilde{m}t^{s}, \tilde{v}{rt}^{o}, \tilde{v}_{ct}^{o}\right)_t$ of
*converges to a stationary point of$\mathcal{L}(W)$ as$t\to\infty$ .
If you use this repo, please cite the paper:
@article{vlorp,
title={Memory-Efficient LLM Training by Various-Grained Low-Rank Projection of Gradients},
author={Yezhen Wang, Zhouhao Yang, Brian K Chen, Fanyi Pu, Bo Li, Tianyu Gao, Kenji Kawaguchi},
journal={arXiv preprint arXiv:2505.01744},
year={2025}
}


