When to Fine-Tune
Fine-tuning is NOT always the answer. Try these first:
- ●Prompt engineering — Can you get better results with a better prompt?
- ●RAG — Can you add relevant context?
- ●Fine-tuning — Only when you need specific behavior, style, or domain knowledge.
Full Fine-Tuning vs LoRA
- ●Full fine-tuning: Update all parameters. Expensive, needs lots of data.
- ●LoRA (Low-Rank Adaptation): Update a small subset of parameters. Cheap, fast, almost as good.
python
class="text-purple-400 font-medium">from peft class="text-purple-400 font-medium">import LoraConfig, get_peft_model
class="text-purple-400 font-medium">from transformers class="text-purple-400 font-medium">import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(class="text-emerald-class="text-amber-300">400">"meta-llama/Llama-class="text-amber-300">2-7b")
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># LoRA config
lora_config = LoraConfig(
r=class="text-amber-300">16, class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Rank
lora_alpha=class="text-amber-300">32, class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Scaling factor
target_modules=[class="text-emerald-class="text-amber-300">400">"q_proj", class="text-emerald-class="text-amber-300">400">"v_proj", class="text-emerald-class="text-amber-300">400">"k_proj", class="text-emerald-class="text-amber-300">400">"o_proj"],
lora_dropout=class="text-amber-300">0.05,
bias=class="text-emerald-class="text-amber-300">400">"none",
task_type=class="text-emerald-class="text-amber-300">400">"CAUSAL_LM"
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># trainable params: class="text-amber-300">4,class="text-amber-300">194,class="text-amber-300">304 || all params: class="text-amber-300">6,class="text-amber-300">742,class="text-amber-300">609,class="text-amber-300">920 || class="text-amber-300">0.06%Dataset Preparation
python
class="text-purple-400 font-medium">from datasets class="text-purple-400 font-medium">import Dataset
class=class="text-emerald-class="text-amber-300">400">"text-gray-class="text-amber-300">500 italic"># Format your data as instruction-response pairs
data = {
class="text-emerald-class="text-amber-300">400">"instruction": [
class="text-emerald-class="text-amber-300">400">"Summarize this text:",
class="text-emerald-class="text-amber-300">400">"Translate to French:",
class="text-emerald-class="text-amber-300">400">"Fix this code:"
],
class="text-emerald-class="text-amber-300">400">"input": [
class="text-emerald-class="text-amber-300">400">"Long text here...",
class="text-emerald-class="text-amber-300">400">"Hello, how are you?",
class="text-emerald-class="text-amber-300">400">"class="text-purple-400 font-medium">def add(a b): return a+b"
],
class="text-emerald-class="text-amber-300">400">"output": [
class="text-emerald-class="text-amber-300">400">"Summary here...",
class="text-emerald-class="text-amber-300">400">"Bonjour, comment allez-vous?",
class="text-emerald-class="text-amber-300">400">"class="text-purple-400 font-medium">def add(a, b): return a + b"
]
}
dataset = Dataset.from_dict(data)
class="text-purple-400 font-medium">def format_prompt(example):
return class="text-emerald-class="text-amber-300">400">f""class="text-emerald-class="text-amber-300">400">"class="text-gray-class="text-amber-300">500 italicclass="text-emerald-class="text-amber-300">400">">### Instruction:
{example[class="text-emerald-class="text-amber-300">400">'instruction']}
class="text-gray-class="text-amber-300">500 italicclass="text-emerald-class="text-amber-300">400">">### Input:
{example[class="text-emerald-class="text-amber-300">400">'input']}
class="text-gray-class="text-amber-300">500 italicclass="text-emerald-class="text-amber-300">400">">### Response:
{example[class="text-emerald-class="text-amber-300">400">'output']}"class="text-emerald-class="text-amber-300">400">""
dataset = dataset.map(lambda x: {class="text-emerald-class="text-amber-300">400">"text": format_prompt(x)})Training with Hugging Face
python
class="text-purple-400 font-medium">from transformers class="text-purple-400 font-medium">import TrainingArguments, Trainer
training_args = TrainingArguments(
output_dir=class="text-emerald-class="text-amber-300">400">"./results",
num_train_epochs=class="text-amber-300">3,
per_device_train_batch_size=class="text-amber-300">4,
gradient_accumulation_steps=class="text-amber-300">4,
learning_rate=2e-class="text-amber-300">4,
weight_decay=class="text-amber-300">0.01,
warmup_steps=class="text-amber-300">100,
logging_steps=class="text-amber-300">10,
save_steps=class="text-amber-300">500,
fp16=True,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=dataset,
tokenizer=tokenizer,
)
trainer.train()Key Takeaways
- ●Always try prompt engineering and RAG before fine-tuning
- ●LoRA makes fine-tuning accessible on consumer GPUs
- ●Quality data matters more than quantity — 1000 good examples beat 10,000 bad ones
- ●Use
fp16=Trueand gradient accumulation to train on limited VRAM