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.

01

The main question is whether to fantune or not

4 cards
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?

Diagramtext
Problem: 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.

RAG wins whentext
✓ 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 visible
03decisionWhen 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.

Fine-tuning is necessary whensql
✓ 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 model
04decisionRAG + 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.

Combined architecturesql
fine-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 separately

Combo examples

  • medical assistant: SFT on clinical reasoning + RAG on patient history
  • seller assistant: SFT on reporting format + RAG on WB/Ozon data
02

Supervised Fine-Tuning (SFT)

3 cards
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.

Diagramsql
Pretraining 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 exactly

When 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.

instruction tuning data formattext
{
  "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 type
07SFTCatastrophic 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.

How to preventtext
✓ 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 abilities
03

LoRA & Parameter-Efficient Fine-Tuning

4 cards
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.

Parameter workbenchKeep the base frozen. Train a narrow update.

Change rank to see the trainable adapter grow.

Base parameters
16,777,216
Trainable adapter
Trainable share

The example uses one 4096 × 4096 projection. Real models attach adapters to multiple selected projections and layers.
Diagramsql
Regular 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 tasks

Parameter 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.

Memory Requirementstext
Model 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 tasks
10PEFTOther 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.

Alternatives to LoRAtext
DoRA (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 choice
11LoRALoRA 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.

Multi-adapter servingtext
base_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 support
04

Alignment — RLHF, DPO, ORPO

4 cards
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.

Diagramsql
Stage 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 elegantly
13alignmentDPO - 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.

Diagramtext
Data: 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 RLHF

Data 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.

Pipeline comparisonsql
RLHF: 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 checkpoint
15alignmentConstitutional 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.

Pipeline RLAIFpython
# 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
05

Distillation - small model as big

3 cards
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.

Diagramtext
Teacher: 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 logits

Applicable

  • 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.

Practical pipelinepython
# 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/30
18distillationReasoning 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.

Schemetext
teacher: 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 cost
06

Data is the bottleneck of all fine tuning

4 cards
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.

Diagramtext
Objective 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 noisy
20dataSynthetic 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.

Self-Instruct pipelinepython
# 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.

Common data problemstext
Inconsistency
  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 examples
22dataData 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.

Pipelinetext
raw_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 examples
07

Infrastructure and tools

3 cards
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.

Diagramtext
Level 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 metrics
24infrastructureHyperparameters - 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.

Starting valuestext
learning_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.05
25infrastructureEval 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?).

Checklist ratingstext
During 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 task
08

Final strategy map

2 cards
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.

Checklist before starttext
1. 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.