Installation
Install the required libraries. We'll use HuggingFace transformers, PEFT (for LoRA), TRL (for training), and bitsandbytes (for 4-bit quantization):
pip3 install transformers peft trl bitsandbytes datasets torch
Step 1: Load model in 4-bit + configure LoRA
Load your base model with QLoRA (4-bit quantization) and configure LoRA adapters:
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig, get_peft_model
model_id = "mistralai/Mistral-7B-Instruct-v0.2"
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=bnb_config,
device_map="auto",
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
tokenizer.pad_token = tokenizer.eos_token
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 4,194,304 || all params: 3,756,154,880 || trainable%: 0.1117
What this does: Loads Mistral 7B in 4-bit (uses ~6GB VRAM), applies LoRA to the query and value projection layers with rank 16. The output shows how many parameters are trainable (0.1117% = ~4M params instead of 3.7B).
Step 2: Prepare dataset
Load your JSONL training data using the datasets library:
from datasets import load_dataset
dataset = load_dataset("json", data_files={"train": "dataset.jsonl"})
print(dataset)
The dataset should have a "messages" column with chat format (system/user/assistant roles).
Step 3: Configure training & train
Set up SFTTrainer with training arguments and start training:
from datasets import load_dataset
from trl import SFTTrainer, SFTConfig
dataset = load_dataset("json", data_files={"train": "dataset.jsonl"})
training_args = SFTConfig(
output_dir="./fine_tuned_model",
max_steps=200,
per_device_train_batch_size=2,
gradient_accumulation_steps=4,
learning_rate=2e-4,
warmup_steps=20,
logging_steps=10,
save_steps=100,
fp16=True,
max_seq_length=1024,
dataset_text_field="messages",
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
tokenizer=tokenizer,
)
trainer.train()
trainer.save_model("./fine_tuned_model/adapter")
print("Training complete. Adapter saved.")
Key parameters:
- max_steps=200: Train for 200 gradient steps (~15 minutes on RTX 4090)
- per_device_train_batch_size=2: Batch size 2 per GPU (memory efficient)
- gradient_accumulation_steps=4: Effective batch size = 2 × 4 = 8
- learning_rate=2e-4: Standard for fine-tuning
- fp16=True: Use half precision (faster, less VRAM)
- max_seq_length=1024: Max tokens per example
Step 4: Save adapter weights
The SFTTrainer automatically saves checkpoints. The adapter weights (tiny files, ~20MB each) are stored separately from the base model. On training completion, load and use:
from peft import AutoPeftModelForCausalLM
# Load the checkpoint
model = AutoPeftModelForCausalLM.from_pretrained(
"./fine_tuned_model", # this directory contains the adapter weights
device_map="auto",
)
# Merge if needed (for deployment)
model = model.merge_and_unload()
model.save_pretrained("./merged_model")
Understanding training behavior
Loss curves
You'll see training loss decrease over steps. A good sign. Eval loss should decrease too (if you have an eval set). If eval loss increases while training loss decreases, you're overfitting.
Overfitting signals
Training loss ↓ but eval loss ↑. Model memorized training data but doesn't generalize. Solution: reduce max_steps, increase learning_rate, or add more training data.
When to stop training
Training often completes in 2–4 hours. Stop when eval loss plateaus (hasn't improved in 10+ steps). SFT Trainer has early stopping; set eval_strategy="steps" and eval_steps to enable it.
Cloud GPU options
Google Colab (Free)
T4 GPU (free) or A100 (paid). Good for learning. Disconnects after 12 hours.
Modal (~$0.20–0.50/hour)
Simple API, auto-scaling, good for short jobs. Easy to get started.
RunPod (~$0.20–0.50/hour)
Fast GPU rental, templates for fine-tuning. Good for quick prototyping.
Lambda Labs (~$0.50–2/hour)
Reliable, multiple GPU options. Good for serious work.
Typical training time and cost
Training Llama 7B with 500 examples (200 steps) on an RTX 4090: ~15 minutes, free (your hardware). On cloud with A100: ~10 minutes, $0.25–0.50. Full fine-tuning on same hardware would cost 10x more and take 10x longer.
Training tips from practitioners
Experienced practitioners follow a consistent pattern: start with a small subset of data (50-100 examples), train for a short run (50 steps), and manually inspect outputs. This quick iteration loop catches data formatting issues, chat template mismatches, and obvious quality problems before you commit to a full training run. A 50-step run on an RTX 4090 takes under two minutes and can save hours of debugging later.
Learning rate is the most sensitive hyperparameter. The default 2e-4 works for most LoRA fine-tunes, but if you see training loss oscillating wildly, drop to 1e-4. If loss barely moves after 50 steps, increase to 5e-4. Gradient accumulation is your friend when GPU memory is tight — instead of increasing batch size (which requires more VRAM), accumulate gradients over multiple smaller batches. An effective batch size of 8-16 is typically optimal for instruction fine-tuning. For projects that require gathering training data from web sources, combining this training pipeline with Firecrawl's RAG integration creates an end-to-end system from data collection to model deployment.
LoRA Training FAQ
How do I fine-tune with LoRA in Python?
Install the transformers and peft libraries, load a base model, configure LoraConfig with your target modules and rank, then train using SFTTrainer from the trl library.
What GPU do I need for LoRA fine-tuning?
A single GPU with 16GB VRAM (like an RTX 4080 or T4) handles 7B models with LoRA. With QLoRA, you can use GPUs with as little as 6GB VRAM.
What are good cloud GPU options for fine-tuning?
Google Colab Pro offers T4 and A100 GPUs. Lambda Labs, RunPod, and Vast.ai offer on-demand A100s for $1-2 per hour. AWS and GCP have more enterprise options.
How long does LoRA training take?
Training a 7B model on 1,000 examples with LoRA typically takes 30 minutes to 1 hour on a single A100. On a T4, expect 2-4 hours for the same job.
How do I know when training is done?
Monitor training loss and validation loss. Stop when validation loss stops decreasing for several steps. Most LoRA fine-tunes converge in 1-3 epochs.
Related tutorials
Continue learning with our evaluation tutorial and deployment guide.