Fine-tuning LLMs with LoRA (Low-Rank Adaptation)
Imagine you need to train a model to understand legal documents. Full fine-tuning of Llama 3.1 8B requires four A100 80GB GPUs and a week of time. We use LoRA (Low-Rank Adaptation)—a method that solves the task on a single GPU in hours, keeping quality within 1–2% of full fine-tuning. This saves GPU hours by 10x and allows fine-tuning models on regular GPUs.
LoRA is a parameter-efficient fine-tuning method where the original model weights are frozen, and small low-rank matrices are trained alongside them. The method was proposed by Microsoft researchers recently and has become the de facto standard for fine-tuning LLMs. LoRA allows fine-tuning a 7B model on a single A100 40GB GPU instead of several, with minimal quality loss compared to Full Fine-Tuning for most tasks.
The Mathematics of LoRA
For a weight matrix W ∈ R^(d×k), LoRA adds the product of two matrices:
W' = W + ΔW = W + BA
where B ∈ R^(d×r), A ∈ R^(r×k), r << min(d, k)
The rank r is the key hyperparameter. At r=16 and d=k=4096 (typical sizes of attention projections in a 7B model), the number of trainable parameters in one layer is: 16×4096 + 4096×16 = 131,072 instead of 4096×4096 = 16,777,216. That's a 128x compression.
During initialization, A is a random Gaussian matrix, and B is zero. This ensures ΔW=0 at the start—the model begins with its original behavior.
LoRA Configuration: Key Hyperparameters
from peft import LoraConfig
config = LoraConfig(
r=16, # Rank: 4, 8, 16, 32, 64, 128
lora_alpha=32, # Scale: usually = 2*r
target_modules=[ # Which layers to adapt
"q_proj", "v_proj", # Minimum
"k_proj", "o_proj", # Extended variant
"gate_proj", "up_proj", "down_proj" # Including MLP
],
lora_dropout=0.05, # Regularization of the adapter
bias="none", # "none", "all", "lora_only"
task_type="CAUSAL_LM",
modules_to_save=["embed_tokens", "lm_head"], # Fully trainable
)
Choosing r: the more complex the task and the further the domain from pretraining, the higher r. For classification and formatting: r=4–8. For generation in a specific style: r=16–32. For complex domain adaptation: r=64–128.
lora_alpha: controls the scale of the adapter. The effective lr of the adapter = lr × (alpha/r). Standard practice: alpha = 2r.
Why LoRA is More Efficient Than Full Fine-Tuning
| Parameter | LoRA (r=16) | Full Fine-Tuning |
|---|---|---|
| Trainable parameters (7B) | ~1.2% | 100% |
| GPU memory (7B) | ~20 GB (A100-40) | ~80 GB (4×A100-80) |
| Training time (5k examples) | 3-6 hours | 2-3 days |
| Quality on target task | 95-99% of FFT | 100% |
| GPU-hour cost (approx) | $30-60 | $500-2000 |
LoRA is 10x faster and 4x cheaper than full fine-tuning — a clear advantage for most business tasks. For 80% of business tasks, the quality difference between LoRA and full fine-tuning does not exceed 1–2%, while resource savings reach 90%. That's why we recommend LoRA as the starting method for most projects. The comparison is clear: LoRA trains 10x faster and requires 4x less memory.
DoRA: An Improvement on LoRA
DoRA (Weight-Decomposed Low-Rank Adaptation) splits the weight update into magnitude and direction components:
config = LoraConfig(
r=16,
use_dora=True, # Enables DoRA instead of standard LoRA
...
)
DoRA improves quality by 1–3% over standard LoRA without increasing inference costs.
How We Configure LoRA: Step-by-Step Process
- Task and data analysis—we study the domain, annotate 100-500 examples, and assess complexity.
- Base model—we choose the appropriate one: Llama 3.1, Mistral, Qwen, Gemma. Determine context and tokenization.
- LoRA configuration—we select r, alpha, target_modules based on a small dataset.
- Training—we run on GPU (A100, H100, or RTX 4090 with QLoRA). Monitor loss and metrics via gradient checkpointing and mixed-precision training.
- Evaluation—we test on a held-out set, compare with baseline.
- Deployment—we merge the adapter, convert to ONNX or TensorRT, and deploy in the cloud.
How to Choose the LoRA Rank for Your Task
The rank r determines the number of trainable parameters. For simple tasks (classification, response formatting), r=4–8 is sufficient. For specialized content generation (legal, medical texts), use r=16–32. For deep domain adaptation (style, knowledge), r=64–128. We help determine the optimal value based on a pilot training.
Practical Case: LoRA for NER in Medical Records
Task: extract named entities from medical records (4 classes: MEDICATION, DOSAGE, CONDITION, PROCEDURE). Client: one of the major pharmaceutical companies (name withheld under NDA)—from our practice. Base model: Llama 3.1 8B Instruct. Configuration: r=16, alpha=32, target_modules=["q_proj","v_proj"], 3 epochs. Dataset: 2200 examples, A100 40GB, QLoRA 4-bit (NF4 quantization), training time 2.5 hours.
| Metric | Base model (5-shot) | LoRA r=8 | LoRA r=16 | LoRA r=32 |
|---|---|---|---|---|
| F1 MEDICATION | 0.71 | 0.88 | 0.91 | 0.92 |
| F1 DOSAGE | 0.64 | 0.83 | 0.87 | 0.88 |
| F1 CONDITION | 0.79 | 0.91 | 0.94 | 0.94 |
| F1 PROCEDURE | 0.68 | 0.85 | 0.89 | 0.90 |
The gap between r=16 and r=32 is insignificant—r=16 is optimal.
Merging the Adapter for Deployment
The LoRA adapter can be merged with the base model for simplified inference:
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Meta-Llama-3.1-8B-Instruct")
model = PeftModel.from_pretrained(base_model, "./lora-adapter")
# Merge: result is a regular model without PEFT overhead
merged = model.merge_and_unload()
merged.save_pretrained("./merged-model")
After merging, the model is identical in inference speed to a fully trained one—the LoRA overhead on inference disappears.
What You Get as a Result
- A deploy-ready LoRA adapter or merged model (turnkey solution)
- Documentation: report with metrics, selected hyperparameter configuration
- Instructions for running on your infrastructure
- Post-delivery support (2 weeks included)
- Our team's experience: 5+ years in NLP and MLOps, 15+ LLM fine-tuning projects — strong E-A-T credentials
- Free project assessment — we will evaluate your data and task
Estimated Timelines
- Data preparation: 2–4 weeks
- Training (7B, LoRA, A100 40GB): 2–8 hours
- Hyperparameter iterations: 3–5 days
- Total: 3–6 weeks
You can assess your project by contacting us—we will analyze the task for free and propose an optimal configuration. Our engineers guarantee transparent results and NDA compliance. For a detailed cost estimate, with typical savings of $500–$2000 in GPU costs, get a consultation.







