Module 10 of 16
Retrieval-Augmented Generation (RAG)
Current Study Module
GenAI - Fine-Tuning, PEFT & LoRA
Alignment: RLHF & DPO
Module 09 • Model Customization

Fine-Tuning, PEFT & LoRA Adaptation

While prompt engineering and RAG augment the context window, Supervised Fine-Tuning (SFT)and Parameter-Efficient Fine-Tuning (PEFT) internalize behavioral patterns, syntax conventions, and specialized output structures directly into neural network weights.

1. When to Prompt, When to RAG, When to Fine-Tune

StrategyWeight Updates?Primary StrengthsIdeal Production Use Case
Prompt EngineeringNone (Frozen)Instant iteration, zero training cost, high flexibility.Ad-hoc reasoning, general chat, zero-shot task exploration.
RAG SystemsNone (Frozen)Access to dynamic private data, verifiable citations, zero retraining needed.Enterprise search, dynamic company documentation, customer support.
PEFT / LoRA Fine-TuningLow-Rank Adapters (<1% params)Teaches consistent syntax, custom tone, compact prompts, specialized jargon.Structured JSON output formatting, specialized domain coding, instruction following.
Full Fine-TuningAll 100% ParametersMaximum domain plasticity, deep knowledge embedding.Training specialized biomedical, legal, or regional language foundation models.

2. The Memory Bottleneck of Full Fine-Tuning

Why can't we simply fine-tune all parameters of a 7B or 70B model with standard backpropagation? The problem is the explosive GPU memory overhead of the AdamW optimizer states:

GPU Memory Arithmetic for a 7-Billion Parameter Model (FP16):
  • Model Weights (FP16): 7B × 2 bytes = 14 GB
  • Gradients (FP16): 7B × 2 bytes = 14 GB
  • AdamW Optimizer States (FP32): 7B × 4 bytes (momentum) + 7B × 4 bytes (variance) = 56 GB
  • Activations & KV-Caches: ~10–20 GB depending on batch size and sequence length
  • Total Required VRAM: >94 GB (requires multiple enterprise A100/H100 80GB GPUs just for a small 7B model!).

3. Low-Rank Adaptation (LoRA): Mathematical Formulation

Introduced by Hu et al. (Microsoft, 2021), LoRA hypothesizes that the weight updates ΔWduring task adaptation have a very low "intrinsic dimension" or rank r.

LoRA Weight Decomposition:
W = W_0 + ΔW = W_0 + (α / r) · ( B · A )
Where W_0 ∈ ℝ^(d × k) is frozen, A ∈ ℝ^(r × k) is initialized with Gaussian noise, and B ∈ ℝ^(d × r) is initialized to zero.
Rank Decomposition

If d = 4096, a dense linear layer contains 4096×4096 = 16.7M weights. With LoRA rank r = 16, A and B contain only (4096×16) + (16×4096) = 131k weights—a 99.2% reduction in trainable parameters!

Zero Inference Latency

When deploying to production, the learned update matrix ΔW = (α/r) · BA is simply added directly back into the original weights W_0. Inference executes at standard baseline speed with zero extra FLOPs.

Hot-Swappable Adapters

Because adapter files are tiny (10MB–50MB), a single base model instance in GPU VRAM can dynamically serve hundreds of custom tenant adapters on the fly without reloading the foundation weights.

4. QLoRA: Fine-Tuning 70B Models on Consumer GPUs

Developed by Dettmers et al. (UW, 2023), QLoRA pushed parameter-efficiency to the extreme by quantizing the frozen base model down to 4 bits while backpropagating gradients through FP16 LoRA adapters:

1. NormalFloat 4 (NF4)

An information-theoretically optimal quantile quantization for normally distributed neural network weights, preserving higher precision than standard 4-bit integers.

2. Double Quantization

Quantizes the quantization constants themselves, reducing memory consumption from 0.5 bits per parameter down to 0.127 bits per parameter.

3. Paged Optimizers

Leverages CUDA Unified Memory to automatically page optimizer states to CPU RAM during memory-intensive sequence spikes, preventing CUDA OOM crashes.

5. Production Code: Fine-Tuning with Hugging Face PEFT & TRL

The following production training script fine-tunes Llama 3 using QLoRA and Hugging Face SFTTrainer:

import torch
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer

model_id = "meta-llama/Meta-Llama-3-8B-Instruct"

# 1. 4-bit NF4 Quantization Configuration
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True
)

tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,
    device_map="auto"
)
model = prepare_model_for_kbit_training(model)

# 2. LoRA Adapter Configuration
peft_config = LoraConfig(
    r=16,                           # LoRA Rank
    lora_alpha=32,                  # Scaling factor (alpha / r = 2.0)
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()  # Shows < 1% trainable parameters!

# 3. Training Arguments
training_args = TrainingArguments(
    output_dir="./llama3-lora-finetuned",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    lr_scheduler_type="cosine",
    warmup_ratio=0.03,
    logging_steps=10,
    max_steps=100,
    fp16=False,
    bf16=True,
    optim="paged_adamw_8bit"
)

# 4. SFTTrainer Execution
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset["train"],
    peft_config=peft_config,
    dataset_text_field="text",
    max_seq_length=2048,
    tokenizer=tokenizer,
    args=training_args
)

trainer.train()
model.save_pretrained("./final_lora_adapter")
print("LoRA adapter trained and saved successfully.")
Module Key Takeaways
  • Full parameter fine-tuning is cost-prohibitive due to AdamW optimizer memory footprints (4x model weight size).
  • LoRA freezes base weights and decomposes delta updates into low-rank matrices W = W_0 + (α/r)BA.
  • QLoRA combines 4-bit NF4 quantization, double quantization, and paged optimizers to enable fine-tuning on consumer-grade GPUs.
  • LoRA adapters can be merged directly into base weights to ensure zero latency overhead during production inference.

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools