QLoRA › Memory Savings Analysis

Michael BrenndoerferDecember 4, 20255 min read
Language AI HandbookAll chapters
Part 35 of 67Parameter-Efficient Fine-tuning
Chapter 259QLoRA › Memory Savings Analysis
Reading section 8 of 15 · Memory Savings Analysis · 5 minSection 8 of 15 · 5 min

Book contents

Section 8 of 15 · 5 min read

QLoRA › Memory Savings AnalysisOne section · Sections in this chapter8 / 15 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Let's quantify QLoRA's memory advantages with concrete numbers for different model sizes.

In[20]:
Code
def calculate_memory_breakdown(
    n_params_billions,
    lora_rank=16,
    lora_target_frac=0.02,  # Fraction of params targeted by LoRA
    seq_len=512,
    batch_size=1,
    hidden_dim=None,
):
    """Calculate memory usage for different fine-tuning approaches."""
    n_params = n_params_billions * 1e9

    # Estimate hidden dimension from parameter count (rough approximation)
    if hidden_dim is None:
        hidden_dim = int(np.sqrt(n_params / 100))  # Very rough estimate

    n_lora_params = n_params * lora_target_frac * 2 * lora_rank / hidden_dim

    results = {}

    # Full fine-tuning in FP16
    results["Full FP16"] = {
        "model": n_params * 2,  # FP16 weights
        "gradients": n_params * 2,  # FP16 gradients
        "optimizer": n_params * 8,  # FP32 Adam states
        "total": n_params * 12,
    }

    # LoRA in FP16
    results["LoRA FP16"] = {
        "model": n_params * 2,  # FP16 base weights
        "gradients": n_lora_params * 2,  # FP16 LoRA gradients
        "optimizer": n_lora_params * 8,  # FP32 Adam states for LoRA
        "total": n_params * 2 + n_lora_params * 10,
    }

    # QLoRA
    nf4_bits_per_param = 4 + 0.125  # 4-bit weights + double-quantized scales
    results["QLoRA"] = {
        "model": n_params * nf4_bits_per_param / 8,  # NF4 base weights
        "gradients": n_lora_params * 2,  # BF16 LoRA gradients
        "optimizer": n_lora_params * 8,  # FP32 Adam states for LoRA
        "total": n_params * nf4_bits_per_param / 8 + n_lora_params * 10,
    }

    # Convert to GB
    for method in results:
        for key in results[method]:
            results[method][key] /= 1e9

    return results


# Calculate for different model sizes
model_sizes = [7, 13, 34, 70]
memory_data = {size: calculate_memory_breakdown(size) for size in model_sizes}
Out[21]:
Console
Memory Requirements (GB) - Model Weights + Training State
=================================================================
Model Size   Full FP16       LoRA FP16       QLoRA          
-----------------------------------------------------------------
7B           84.0            14.0            3.6            
13B           156.0           26.0            6.7            
34B           408.0           68.0            17.5           
70B           840.0           140.0           36.1           
=================================================================
Out[22]:
Visualization
Line plot showing memory scaling across model sizes for full fine-tuning, LoRA, and QLoRA.
Memory requirements scale linearly with model size, but at vastly different rates for each approach. QLoRA achieves roughly 4× reduction compared to LoRA FP16, and over 10× reduction compared to full fine-tuning. This enables fine-tuning 70B models on hardware that could previously only handle 7B models.

Let's visualize the memory breakdown for a 70B model:

Out[23]:
Visualization
Stacked bar chart comparing model-weight, gradient, and optimizer-state memory for LoRA FP16 and QLoRA on a 70B model.
Memory breakdown for fine-tuning a 70B parameter model using different approaches. QLoRA achieves approximately 4× reduction in base model memory through 4-bit quantization while keeping trainable components in full precision.

The visualization reveals that for standard LoRA, the base model weights dominate memory usage. QLoRA's 4-bit quantization directly addresses this bottleneck, reducing model memory from 140 GB to approximately 36 GB. The gradient and optimizer state contributions remain small for both methods because only the adapter parameters require these training artifacts.