Vol. 04 · Prompting & Adaptation
Fine-Tuning Strategies
When to use fine-tuning, and when is RAG or prompting enough? LoRA, QLoRA, SFT, DPO, RLHF, distillation - broken down into focused cards. How to prepare data, how to evaluate the result, how not to waste the GPU.
The main question is whether to fantune or not
01decisionRAG vs Fine-tuning vs Prompting — decision tree
Fine-tuning solves different problems than RAG. They are often confused - and resources are wasted on the wrong things. The key question is: what exactly is not working in the current system?
textProblem: The model gives incorrect answers
│
├── The model does not know the current facts / company data
│ └──→ RAG (add knowledge, leave weight alone)
│
├── The model does not understand the task the first time, long instructions are needed
│ └──→ Prompt engineering + few-shot (try first)
│
├── The model does not produce the desired format/style/tone consistently
│ └──→ SFT fine-tuning (train with examples of the correct format)
│
├── The model does not know how to do a specific task (domain reasoning)
│ └──→ SFT + domain data (train on a task)
│
├── Model too expensive/slow for production
│ └──→ Distillation (small model repeats large one)
│
└── Model is toxic / ignores rules / does not follow policies
└──→ DPO / RLHF (alignment)02decisionWhen RAG is better than fine tuning - 6 signs
RAG is about knowledge. Fine-tuning is about behavior and skills. If the problem is knowledge, RAG is cheaper, faster and updated without retraining.
text✓ Data is updated frequently
→ re-indexing is cheaper than retraining
✓ You need a link to the source (citation)
→ RAG gives attribution out of the box
✓ Large corpus of specific facts
→ the model does not remember facts well
✓ No GPU or training data
→ RAG works with API models
✓ Different clients with different knowledge bases
→ one index per client, one model
✓ Need transparency/audit
→ sources are always visible03decisionWhen fine tuning is necessary - 6 signs
Fine-tuning is justified when the problem is not in knowledge, but in the way the model reasons, responds or behaves - and this cannot be fixed by prompts.
sql✓ Need a specific style/tone consistently
→ “write as a lawyer for our company”
✓ The task requires domain reasoning
→ medical diagnostics, industrial calculations
✓ We need to remove the long few-shot from the prompt
→ saving tokens = reducing cost
✓ The problem cannot be solved by prompting at all
→ specific output format, rare language
✓ Need a small fast model (latency SLA)
→ GPT-4 distillation → 7B model
✓ Data is confidential and cannot be sent to the API
→ self-hosted fine-tuned model04decisionRAG + Fine-tuning - not OR, but AND
The best production systems combine both approaches: fine tuning teaches the model to reason correctly and respond in the right style, RAG provides up-to-date knowledge. These are not competitors - these are different layers.
sqlfine-tuned model:
✓ knows the company's output format
✓ understands domain terminology
✓ knows how to reason in the right style
✗ does not know specific facts of clients
+ RAG on top:
✓ current data
✓ specific facts from the database
✓ links to sources
→ the result is better than each one separatelyCombo examples
- medical assistant: SFT on clinical reasoning + RAG on patient history
- seller assistant: SFT on reporting format + RAG on WB/Ozon data
Supervised Fine-Tuning (SFT)
05SFTSFT - what's going on under the hood
SFT (Supervised Fine-Tuning) - additional training of a pre-trained model on a dataset of pairs (input → output). The model can already do “everything” after pretraining; SFT does not add knowledge - it recalibrates the probability distribution to the desired answer format. This is supervised learning on top of an already trained model.
sqlPretraining SFT Result
──────────────────────────── ────────────────────────────
Base model Fine-tuned model
p(token | context) → updated to → stable
trained on examples {input, output} required format
the entire Internet from your dataset and style
Loss:
L = -Σ log p(output_token_i | input, output_tokens_# cross-entropy only on output tokens, not on input
# input is masked → the model only learns to respond
Chat template (important!):
<|user|> {input} <|assistant|> {output} <|end|>
# each model has its own format - use it exactlyWhen is SFT enough?
- need a specific output format
- domain-specific task with examples
- remove long few-shot from prompt
- need 500–5000 high-quality examples
06SFTInstruction Tuning - SFT for following instructions
Special form of SFT: learning from a large set of varied instructions. This is what turns the base model into a chat model. FLAN, Alpaca, ShareGPT - datasets for instruction tuning.
text{
"instruction": "Translate to English",
"input": "Hi, how are you?",
"output": "Hello, how are you?"
}
# thousands of such examples for different tasks
# → the model learns to follow any instruction
Key: variety of tasks is more important than volume
1000 different instructions > 10000 of the same type07SFTCatastrophic Forgetting is the main danger of SFT
When fine tuning, the model may “forget” the general abilities that were in the base model. It is especially dangerous with a small dataset and a large learning rate. The model does the new task well, but everything else is bad.
text✓ Low learning rate
1e-5 – 3e-5 for full fine-tuning
# don't break what already worked
✓ Small dataset → LoRA instead of full FT
# update minimum parameters
✓ Replay: mix with general-purpose data
# 10–20% of the original data in the dataset
✓ Early stopping by validation loss
# do not retrain to zero
✗ Many epochs on a small dataset
# → retraining, loss of general abilitiesLoRA & Parameter-Efficient Fine-Tuning
08LoRALoRA - Low-Rank Adaptation, atomic
LoRA is the most popular method of effective fine tuning. Idea: do not update all the model weights (billions of parameters), but add small low-rank matrices on top of the key layers. Only they are updated - 0.1–1% of the parameters from the original model.
Change rank to see the trainable adapter grow.
- Base parameters
- 16,777,216
- Trainable adapter
- Trainable share
sqlRegular layer: W (d×d matrix, frozen)
LoRA adds: ΔW = A × B
where A: d×r, B: r×d, r ≪ d (rank)
Layer output: h = W x + ΔW x = W x + (A B) x
Example for 7B model:
Full FT: 7,000,000,000 parameters are updated
LoRA r=16: 4,000,000 parameters updated → 0.06%
After training - merge back to W:
W_new = W + A B ← no overhead in inference
or store A, B separately → swap adapters for different tasksParameter rank (r) - how to choose
- r=4–8: simple tasks, format
- r=16–32: standard, most tasks
- r=64–128: complex domain reasoning
- r higher → more parameters, risk of overfitting
09QLoRAQLoRA - fine tuning on a consumer GPU
QLoRA = LoRA + base model quantization in 4-bit (NF4). The base model is loaded in 4-bit (frozen), LoRA adapters are trained in bf16. Allows fine-tuning 13B on 1× RTX 3090, 70B on 2× A100.
textModel Full FT LoRA QLoRA
───────────────────── ─────────────────────
7B parameters 28 GB 14 GB 6 GB ← RTX 3090
13B parameters 52 GB 26 GB 10 GB ← RTX 4090
34B parameters 136 GB 68 GB 22 GB ← A100 40G
70B parameters 280 GB 140 GB 48 GB ← 2×A100
QLoRA quality loss vs LoRA: ~1-2% on most tasks10PEFTOther PEFT methods - DoRA, IA³, Prefix Tuning
LoRA is not the only PEFT method. Other approaches may be suitable for different problems and constraints. All implemented in the PEFT library from HuggingFace.
textDoRA (Weight-Decomposed LoRA)
separates magnitude and direction updates
→ slightly better than LoRA with the same rank
IA³ (Infused Adapter by Inhibiting and Amplifying)
scales activations, does not add matrices
→ even fewer parameters than LoRA
Prefix Tuning / Prompt Tuning
adds trainees "soft tokens" to the input
→ does not change the weight at all, few parameters
→ performs worse than LoRA on complex tasks
In practice: LoRA/QLoRA → default choice11LoRALoRA Adapters - swap without retraining
LoRA adapters can be stored separately from the base model and loaded dynamically. One basic model + N adapters for N tasks - saving memory, fast switching. These are like plugins for the model.
textbase_model = load("Llama-3.1-8B") # 1 time, 8GB
adapter_legal = load_lora("legal_v2") # 50MB
adapter_medical = load_lora("medical_v1") # 50MB
adapter_seller = load_lora("wb_seller") # 50MB
# at runtime on request:
model.set_adapter(route_to_adapter(query))
output = model.generate(query)
# LoRAX, vLLM, S-LoRA - servers with supportAlignment — RLHF, DPO, ORPO
12alignmentRLHF — Reinforcement Learning from Human Feedback
RLHF is a three-step process that GPT-4, Claude, Gemini are trained on. This is not just “learning from feedback” - it is a complex pipeline with three separate models. It is RLHF that makes models useful and safe.
sqlStage 1: SFT (Supervised Fine-Tuning)
base_model + demos from people → SFT model
Stage 2: Reward Model Training
people rank pairs of answers: A > B
trains Reward Model to predict human preferences
reward(prompt, response) → scalar score
Stage 3: RL with PPO (Proximal Policy Optimization)
SFT model = policy (what we train)
Reward Model = environment (gives a reward)
+ KL-penalty vs original SFT model (don’t go far)
L = reward(response) - β·KL(policy || SFT_ref)
RLHF problem: difficult, unstable, requires many GPUs
→ DPO solves this more elegantly13alignmentDPO - Direct Preference Optimization, atomic
DPO (2023) is a mathematically equivalent solution to RLHF without a separate Reward Model and without RL. Key idea: it turns out that the RL problem can be reformulated as a supervised learning problem directly from preference data. It's elegant mathematics that simplifies everything.
textData: triples (prompt, chosen_response, rejected_response)
RLHF: prompt → [RM, PPO, KL, instability...] → aligned model
DPO: prompt + chosen + rejected → one gradient step → aligned model
DPO Loss (simplified):
L = -log σ(β log[π(chosen)/π_ref(chosen)]
- β log[π(rejected)/π_ref(rejected)])
Meaning: increase the probability of chosen, reduce the probability of rejected
relative to reference model (original SFT)
Why DPO wins in practice:
✓ No Reward Model (one model instead of three)
✓ Stable training (supervised loss)
✓ Fewer GPUs, easier to implement
✓ Comparable quality to RLHFData for DPO
- UltraFeedback, Anthropic HH-RLHF
- or generate: GPT-4 → chosen, bad model → rejected
14alignmentORPO - one pass instead of two
ORPO (Odds Ratio Preference Optimization, 2024) combines SFT and DPO in one step. There is no need to do SFT first, then DPO - learning alignment occurs simultaneously with learning to follow instructions.
sqlRLHF: pretraining → SFT → RM → PPO # 4 stages
DPO: pretraining → SFT → DPO # 3 stages
ORPO: pretraining → ORPO # 2 stages
ORPO Loss:
L = L_SFT + λ L_OR
where L_OR = log odds ratio(chosen vs rejected)
Practice: DPO - standard, ORPO - if there is no SFT checkpoint15alignmentConstitutional AI / RLAIF
Instead of human labelers, the LLM judge generates preference data. RLAIF (RL from AI Feedback, Anthropic) - Reward Model is trained on the estimates of a strong model. More scalable and cheaper than human markup.
python# Instead of people:
for prompt in dataset:
response_A = model.generate(prompt)
response_B = model.generate(prompt)
preference = judge_llm(prompt, A, B)
# "A is better because..."
pairs.append((prompt, A, B, preference))
# Next is the standard DPO on these pairs
train_dpo(model, pairs)Applicable
- no budget for markers
- you need a large dataset of preferences
Distillation - small model as big
16distillationKnowledge Distillation - atomic
Distillation is training a small model (student) to imitate a large one (teacher). Goal: get 80–90% teacher quality with 10x smaller inference size and cost. The basis for production optimization of LLM pipelines.
textTeacher: GPT-4 / Claude Opus ← expensive, slow, API-only
Student: Llama-3.1-8B ← cheap, fast, self-hosted
Classic distillation (Hinton 2015):
Loss = α CE(student_logits, labels) # hard labels
+ (1-α) · KL(student || teacher) · T² # soft labels
# T = temperature: the higher, the “softer” the teacher distribution
# soft labels carry more information than one-hot
For LLM tasks - data distillation (simpler, works well):
1. Run teacher on N prompts → generate answers
2. SFT student on these pairs (prompt → teacher_answer)
# teacher student learns to be like without access to logitsApplicable
- reduce cost by 10–50x
- latency < 100ms requires a small model
- self-hosted without API dependency
17distillationSpecialize & Distill - practical pattern
Not trying to distill “everything” from teacher is ineffective. Distill only a specific task: teacher generates synthetic data for a task, student learns only on it. A small specialized model beats a large general one.
python# 1. Collect or generate task prompts
prompts = domain_prompts + synthetic_generated(N=5000)
#2. Teacher generates answers (expensive, one time)
dataset = [(p, gpt4(p)) for p in prompts]
#3. SFT of a small model on this data
student = finetune("Llama-3.1-8B", dataset, epochs=3)
#4. Eval: compare quality vs cost
# Result: quality ~85% teacher, cost 1/3018distillationReasoning Distillation - chain-of-thought distillation
Distill not only the answer, but also the chain of reasoning teacher. Student learns to reason like a large model. This is the basis of models like DeepSeek-R1-Distill - small models with strong reasoning.
textteacher: o1 / DeepSeek-R1 / QwQ
→ generates: <think>...long argument...</think> response
dataset: (prompt, <think>reasoning</think> + answer)
student: Llama/Qwen 7–14B
→ SFT on full traces with reasoning
result: DeepSeek-R1-Distill-Qwen-7B
≈ 70% quality o1 at 1/100 costData is the bottleneck of all fine tuning
19dataHow much data is needed - practical numbers
The main myth: “fine-tuning requires millions of examples.” The reality is different - a small, high-quality dataset is often better than a large, bad one. Quality >> quantity.
textObjective Minimum Good Excellent
──────────────────────────────── ────────────────────────────────
Output style/format 100–200 500 1000+
Classification (4–10 classes) 200–500 1000 5000+
Entity extraction 500 2000 10000+
Specific domain QA 500 2000 5000+
Instructions following 1000 5000 50000+
DPO alignment 500 pairs 2000 pairs 10000+ pairs
Distillation of a narrow task 1000 5000 20000+
The main rule: 500 high-quality > 10,000 noisy20dataSynthetic Data Generation - dataset scaling
No data - LLM will generate synthetic ones. Self-Instruct, Evol-Instruct, Magpie - patterns for generating training data through strong models. Manual sample verification is required.
python# 1. Seed: 20-30 real quality examples
seed_examples = human_curated_examples
#2. LLM generates new instructions
new_instructions = GPT4(f"""
Here are examples of tasks: {seed_examples}
Generate 20 new similar but different problems.
""")
#3. LLM responds to generated instructions
dataset = [(instr, GPT4(instr)) for instr in new_instructions]
#4. Filtering: deduplication + quality filter
filtered = [x for x in dataset if quality_score(x) > 0.7]21dataData Quality - what spoils a dataset
Bad data is the main reason why fine tuning fails. The model will learn exactly what is in the data—including errors, inconsistencies, and noise. Garbage in - garbage out literally works here.
textInconsistency
There are different correct answers to the same question
→ the model cannot learn the pattern
Duplication
one example 100 times → the model retrains it
→ deduplicate by embedding similarity
Leaked response prompt
output contains instruction parts
→ mask instruction correctly
Invalid chat template
<|user|> and <|assistant|> tokens are mixed up
→ the model learns the wrong roles
✓ Verification: manually review 100 random examples22dataData Curation Pipeline - from raw materials to dataset
Data preparation takes 60–80% of fine tuning time. We need a reproducible pipeline with versioning, otherwise it is impossible to understand what produced the result.
textraw_data
→ collect logs, databases, synthetics, expert examples
→ clean remove noise, special characters, artifacts
→ deduplicate MinHash / embedding similarity
→ filter LLM-quality-score > threshold
→ model-specific format chat template
→ split train 90% / val 5% / test 5%
→ version git + DVC / HuggingFace Datasets
→ audit manual check of 100 examplesInfrastructure and tools
23infrastructureFine-tuning tools - map
The ecosystem of tools is divided into levels: low-level (HF Transformers), high-level (Axolotl, LLaMA-Factory), managed (Modal, Together, OpenAI FT API). The choice comes down to control vs convenience.
textLevel Tool Control Convenience Cost
─────────────────────────────────── ───────────────────────────────────
Low-level HF Transformers maximum minimum GPU in fact
PEFT library
TRL (SFT/DPO)
High-level Axolotl high high GPU in fact
LLaMA-Factory ← I recommend for starting
Unsloth ← 2x faster, less VRAM
Managed Together.ai FT low maximum $$/hour
OpenAI FT API ← GPT-3.5/4o-mini only
Modal + Axolotl medium high serverless GPU
Eval during FT W&B / Langfuse log loss, eval metrics24infrastructureHyperparameters - what really matters
Most hyperparameters are not critical - there are 5 parameters that determine 90% of the result. The rest is fine tuning after the basic launch works.
textlearning_rate: 2e-4 #LoRA; 1e-5 for full FT
lr_scheduler: cosine with warmup
warmup_ratio: 0.05 # 5% steps to warm up
epochs: 1–3 # rarely need more than 3
batch_size: per_device=2, grad_accum=8 # effective=16
max_seq_length: 2048 # per task
LoRA specific:
r: 16# rank
alpha: 32 # = 2×r usually
target_modules: ["q_proj","v_proj","k_proj","o_proj"]
dropout: 0.0525infrastructureEval during and after fine tuning
Fine-tuning without eval is learning blindly. You need to monitor: train/val loss (overfitting?), target metric for holdout (real quality), general abilities (have they degraded?).
textDuring training:
✓ is train_loss decreasing?
✓ val_loss is not growing? (if growing → overfitting)
✓ Is grad_norm stable? (spike → lr too high)
After training:
✓ target_metric on test set vs baseline
✓ general benchmarks have not fallen?
(MT-Bench, MMLU, HumanEval)
✓ human evaluation 50 examples
✓ compare vs prompted GPT-4 on the same taskFinal strategy map
26comparisonComparison of all approaches
Summary table for quick navigation through strategies.
27decisionRule of three questions
Before any fine tuning project, answer three questions. If there’s even one “no,” go back a step.
text1. Have you exhausted your prompting?
Have you tried few-shot, CoT, persona, chain?
No → prompting first, it's free
2. Do you have data and metrics?
Minimum 200 quality examples?
A clear metric by which to measure improvement?
No → first collect data and define a metric
3. Is the problem in behavior, not knowledge?
If you add the correct data to the prompt → does everything work?
Yes → use RAG, not fine tuning
All three yes? FineTun.
Start with LoRA on 7-8B models.
Compare with prompted GPT-4 on your task.No dead end
Keep moving through the map.
Continue in sequence, switch to a related guide, or return to the seven-track learning map.