{
  "type": "new-runtime-knowledge-guide",
  "version": 1,
  "generated_at": "2026-07-23",
  "volume": 4,
  "slug": "llm-finetuning",
  "title": "Fine-Tuning Strategies",
  "description": "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.",
  "track": {
    "slug": "prompting-and-adaptation",
    "title": "Prompting & Adaptation",
    "route": "https://newruntime.com/learn/tracks/prompting-and-adaptation/",
    "position": 1
  },
  "counts": {
    "sections": 8,
    "cards": 27
  },
  "routes": {
    "html": "https://newruntime.com/learn/llm-finetuning/",
    "json": "https://newruntime.com/learn/llm-finetuning.json"
  },
  "sections": [
    {
      "number": "01",
      "title": "The main question is whether to fantune or not",
      "intro": "",
      "cards": [
        {
          "number": "01",
          "title": "RAG vs Fine-tuning vs Prompting — decision tree",
          "tag": "decision",
          "description": "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?",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "text",
              "value": "Problem: The model gives incorrect answers\n │\n ├── The model does not know the current facts / company data\n │ └──→ RAG (add knowledge, leave weight alone)\n │\n ├── The model does not understand the task the first time, long instructions are needed\n │ └──→ Prompt engineering + few-shot (try first)\n │\n ├── The model does not produce the desired format/style/tone consistently\n │ └──→ SFT fine-tuning (train with examples of the correct format)\n │\n ├── The model does not know how to do a specific task (domain reasoning)\n │ └──→ SFT + domain data (train on a task)\n │\n ├── Model too expensive/slow for production\n │ └──→ Distillation (small model repeats large one)\n │\n └── Model is toxic / ignores rules / does not follow policies\n         └──→ DPO / RLHF (alignment)"
            }
          ]
        },
        {
          "number": "02",
          "title": "When RAG is better than fine tuning - 6 signs",
          "tag": "decision",
          "description": "RAG is about knowledge. Fine-tuning is about behavior and skills. If the problem is knowledge, RAG is cheaper, faster and updated without retraining.",
          "blocks": [
            {
              "kind": "code",
              "label": "RAG wins when",
              "language": "text",
              "value": "✓ Data is updated frequently\n  → re-indexing is cheaper than retraining\n\n✓ You need a link to the source (citation)\n  → RAG gives attribution out of the box\n\n✓ Large corpus of specific facts\n  → the model does not remember facts well\n\n✓ No GPU or training data\n  → RAG works with API models\n\n✓ Different clients with different knowledge bases\n  → one index per client, one model\n\n✓ Need transparency/audit\n  → sources are always visible"
            }
          ]
        },
        {
          "number": "03",
          "title": "When fine tuning is necessary - 6 signs",
          "tag": "decision",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Fine-tuning is necessary when",
              "language": "sql",
              "value": "✓ Need a specific style/tone consistently\n  → “write as a lawyer for our company”\n\n✓ The task requires domain reasoning\n  → medical diagnostics, industrial calculations\n\n✓ We need to remove the long few-shot from the prompt\n  → saving tokens = reducing cost\n\n✓ The problem cannot be solved by prompting at all\n  → specific output format, rare language\n\n✓ Need a small fast model (latency SLA)\n  → GPT-4 distillation → 7B model\n\n✓ Data is confidential and cannot be sent to the API\n  → self-hosted fine-tuned model"
            }
          ]
        },
        {
          "number": "04",
          "title": "RAG + Fine-tuning - not OR, but AND",
          "tag": "decision",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Combined architecture",
              "language": "sql",
              "value": "fine-tuned model:\n  ✓ knows the company's output format\n  ✓ understands domain terminology\n  ✓ knows how to reason in the right style\n  ✗ does not know specific facts of clients\n\n+ RAG on top:\n  ✓ current data\n  ✓ specific facts from the database\n  ✓ links to sources\n\n→ the result is better than each one separately"
            },
            {
              "kind": "list",
              "label": "Combo examples",
              "items": [
                "medical assistant: SFT on clinical reasoning + RAG on patient history",
                "seller assistant: SFT on reporting format + RAG on WB/Ozon data"
              ]
            }
          ]
        }
      ]
    },
    {
      "number": "02",
      "title": "Supervised Fine-Tuning (SFT)",
      "intro": "",
      "cards": [
        {
          "number": "05",
          "title": "SFT - what's going on under the hood",
          "tag": "SFT",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "sql",
              "value": "Pretraining SFT Result\n──────────────────────────── ────────────────────────────\nBase model Fine-tuned model\n  p(token | context) → updated to → stable\n  trained on examples {input, output} required format\n  the entire Internet from your dataset and style\n\nLoss:\n  L = -Σ log p(output_token_i | input, output_tokens_# cross-entropy only on output tokens, not on input\n  # input is masked → the model only learns to respond\n\nChat template (important!):\n  <|user|> {input} <|assistant|> {output} <|end|>\n  # each model has its own format - use it exactly"
            },
            {
              "kind": "list",
              "label": "When is SFT enough?",
              "items": [
                "need a specific output format",
                "domain-specific task with examples",
                "remove long few-shot from prompt",
                "need 500–5000 high-quality examples"
              ]
            }
          ]
        },
        {
          "number": "06",
          "title": "Instruction Tuning - SFT for following instructions",
          "tag": "SFT",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "instruction tuning data format",
              "language": "text",
              "value": "{\n  \"instruction\": \"Translate to English\",\n  \"input\": \"Hi, how are you?\",\n  \"output\": \"Hello, how are you?\"\n}\n# thousands of such examples for different tasks\n# → the model learns to follow any instruction\n\nKey: variety of tasks is more important than volume\n  1000 different instructions > 10000 of the same type"
            }
          ]
        },
        {
          "number": "07",
          "title": "Catastrophic Forgetting is the main danger of SFT",
          "tag": "SFT",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "How to prevent",
              "language": "text",
              "value": "✓ Low learning rate\n  1e-5 – 3e-5 for full fine-tuning\n  # don't break what already worked\n\n✓ Small dataset → LoRA instead of full FT\n  # update minimum parameters\n\n✓ Replay: mix with general-purpose data\n  # 10–20% of the original data in the dataset\n\n✓ Early stopping by validation loss\n  # do not retrain to zero\n\n✗ Many epochs on a small dataset\n  # → retraining, loss of general abilities"
            }
          ]
        }
      ]
    },
    {
      "number": "03",
      "title": "LoRA & Parameter-Efficient Fine-Tuning",
      "intro": "",
      "cards": [
        {
          "number": "08",
          "title": "LoRA - Low-Rank Adaptation, atomic",
          "tag": "LoRA",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "sql",
              "value": "Regular layer: W (d×d matrix, frozen)\nLoRA adds: ΔW = A × B\n  where A: d×r, B: r×d, r ≪ d (rank)\n\nLayer output: h = W x + ΔW x = W x + (A B) x\n\nExample for 7B model:\n  Full FT: 7,000,000,000 parameters are updated\n  LoRA r=16: 4,000,000 parameters updated → 0.06%\n\nAfter training - merge back to W:\nW_new = W + A B ← no overhead in inference\nor store A, B separately → swap adapters for different tasks"
            },
            {
              "kind": "list",
              "label": "Parameter rank (r) - how to choose",
              "items": [
                "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"
              ]
            }
          ]
        },
        {
          "number": "09",
          "title": "QLoRA - fine tuning on a consumer GPU",
          "tag": "QLoRA",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Memory Requirements",
              "language": "text",
              "value": "Model Full FT LoRA QLoRA\n───────────────────── ─────────────────────\n7B parameters 28 GB 14 GB 6 GB ← RTX 3090\n13B parameters 52 GB 26 GB 10 GB ← RTX 4090\n34B parameters 136 GB 68 GB 22 GB ← A100 40G\n70B parameters 280 GB 140 GB 48 GB ← 2×A100\n\nQLoRA quality loss vs LoRA: ~1-2% on most tasks"
            }
          ]
        },
        {
          "number": "10",
          "title": "Other PEFT methods - DoRA, IA³, Prefix Tuning",
          "tag": "PEFT",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Alternatives to LoRA",
              "language": "text",
              "value": "DoRA (Weight-Decomposed LoRA)\n  separates magnitude and direction updates\n  → slightly better than LoRA with the same rank\n\nIA³ (Infused Adapter by Inhibiting and Amplifying)\n  scales activations, does not add matrices\n  → even fewer parameters than LoRA\n\nPrefix Tuning / Prompt Tuning\n  adds trainees \"soft tokens\" to the input\n  → does not change the weight at all, few parameters\n  → performs worse than LoRA on complex tasks\n\nIn practice: LoRA/QLoRA → default choice"
            }
          ]
        },
        {
          "number": "11",
          "title": "LoRA Adapters - swap without retraining",
          "tag": "LoRA",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Multi-adapter serving",
              "language": "text",
              "value": "base_model = load(\"Llama-3.1-8B\") # 1 time, 8GB\n\nadapter_legal = load_lora(\"legal_v2\") # 50MB\nadapter_medical = load_lora(\"medical_v1\") # 50MB\nadapter_seller = load_lora(\"wb_seller\") # 50MB\n\n# at runtime on request:\nmodel.set_adapter(route_to_adapter(query))\noutput = model.generate(query)\n\n# LoRAX, vLLM, S-LoRA - servers with support"
            }
          ]
        }
      ]
    },
    {
      "number": "04",
      "title": "Alignment — RLHF, DPO, ORPO",
      "intro": "",
      "cards": [
        {
          "number": "12",
          "title": "RLHF — Reinforcement Learning from Human Feedback",
          "tag": "alignment",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "sql",
              "value": "Stage 1: SFT (Supervised Fine-Tuning)\n  base_model + demos from people → SFT model\n\nStage 2: Reward Model Training\n  people rank pairs of answers: A > B\n  trains Reward Model to predict human preferences\n  reward(prompt, response) → scalar score\n\nStage 3: RL with PPO (Proximal Policy Optimization)\n  SFT model = policy (what we train)\n  Reward Model = environment (gives a reward)\n  + KL-penalty vs original SFT model (don’t go far)\n  L = reward(response) - β·KL(policy || SFT_ref)\n\nRLHF problem: difficult, unstable, requires many GPUs\n→ DPO solves this more elegantly"
            }
          ]
        },
        {
          "number": "13",
          "title": "DPO - Direct Preference Optimization, atomic",
          "tag": "alignment",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "text",
              "value": "Data: triples (prompt, chosen_response, rejected_response)\n\nRLHF: prompt → [RM, PPO, KL, instability...] → aligned model\nDPO: prompt + chosen + rejected → one gradient step → aligned model\n\nDPO Loss (simplified):\nL = -log σ(β log[π(chosen)/π_ref(chosen)]\n         - β log[π(rejected)/π_ref(rejected)])\n\nMeaning: increase the probability of chosen, reduce the probability of rejected\n       relative to reference model (original SFT)\n\nWhy DPO wins in practice:\n  ✓ No Reward Model (one model instead of three)\n  ✓ Stable training (supervised loss)\n  ✓ Fewer GPUs, easier to implement\n  ✓ Comparable quality to RLHF"
            },
            {
              "kind": "list",
              "label": "Data for DPO",
              "items": [
                "UltraFeedback, Anthropic HH-RLHF",
                "or generate: GPT-4 → chosen, bad model → rejected"
              ]
            }
          ]
        },
        {
          "number": "14",
          "title": "ORPO - one pass instead of two",
          "tag": "alignment",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Pipeline comparison",
              "language": "sql",
              "value": "RLHF: pretraining → SFT → RM → PPO # 4 stages\nDPO: pretraining → SFT → DPO # 3 stages\nORPO: pretraining → ORPO # 2 stages\n\nORPO Loss:\nL = L_SFT + λ L_OR\nwhere L_OR = log odds ratio(chosen vs rejected)\n\nPractice: DPO - standard, ORPO - if there is no SFT checkpoint"
            }
          ]
        },
        {
          "number": "15",
          "title": "Constitutional AI / RLAIF",
          "tag": "alignment",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Pipeline RLAIF",
              "language": "python",
              "value": "# Instead of people:\nfor prompt in dataset:\n    response_A = model.generate(prompt)\n    response_B = model.generate(prompt)\n    preference = judge_llm(prompt, A, B)\n    # \"A is better because...\"\n    pairs.append((prompt, A, B, preference))\n\n# Next is the standard DPO on these pairs\ntrain_dpo(model, pairs)"
            },
            {
              "kind": "list",
              "label": "Applicable",
              "items": [
                "no budget for markers",
                "you need a large dataset of preferences"
              ]
            }
          ]
        }
      ]
    },
    {
      "number": "05",
      "title": "Distillation - small model as big",
      "intro": "",
      "cards": [
        {
          "number": "16",
          "title": "Knowledge Distillation - atomic",
          "tag": "distillation",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "text",
              "value": "Teacher: GPT-4 / Claude Opus ← expensive, slow, API-only\nStudent: Llama-3.1-8B ← cheap, fast, self-hosted\n\nClassic distillation (Hinton 2015):\n  Loss = α CE(student_logits, labels) # hard labels\n       + (1-α) · KL(student || teacher) · T² # soft labels\n  # T = temperature: the higher, the “softer” the teacher distribution\n  # soft labels carry more information than one-hot\n\nFor LLM tasks - data distillation (simpler, works well):\n1. Run teacher on N prompts → generate answers\n2. SFT student on these pairs (prompt → teacher_answer)\n   # teacher student learns to be like without access to logits"
            },
            {
              "kind": "list",
              "label": "Applicable",
              "items": [
                "reduce cost by 10–50x",
                "latency < 100ms requires a small model",
                "self-hosted without API dependency"
              ]
            }
          ]
        },
        {
          "number": "17",
          "title": "Specialize & Distill - practical pattern",
          "tag": "distillation",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Practical pipeline",
              "language": "python",
              "value": "# 1. Collect or generate task prompts\nprompts = domain_prompts + synthetic_generated(N=5000)\n\n#2. Teacher generates answers (expensive, one time)\ndataset = [(p, gpt4(p)) for p in prompts]\n\n#3. SFT of a small model on this data\nstudent = finetune(\"Llama-3.1-8B\", dataset, epochs=3)\n\n#4. Eval: compare quality vs cost\n# Result: quality ~85% teacher, cost 1/30"
            }
          ]
        },
        {
          "number": "18",
          "title": "Reasoning Distillation - chain-of-thought distillation",
          "tag": "distillation",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Scheme",
              "language": "text",
              "value": "teacher: o1 / DeepSeek-R1 / QwQ\n→ generates: <think>...long argument...</think> response\n\ndataset: (prompt, <think>reasoning</think> + answer)\n\nstudent: Llama/Qwen 7–14B\n→ SFT on full traces with reasoning\n\nresult: DeepSeek-R1-Distill-Qwen-7B\n  ≈ 70% quality o1 at 1/100 cost"
            }
          ]
        }
      ]
    },
    {
      "number": "06",
      "title": "Data is the bottleneck of all fine tuning",
      "intro": "",
      "cards": [
        {
          "number": "19",
          "title": "How much data is needed - practical numbers",
          "tag": "data",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "text",
              "value": "Objective Minimum Good Excellent\n──────────────────────────────── ────────────────────────────────\nOutput style/format 100–200 500 1000+\nClassification (4–10 classes) 200–500 1000 5000+\nEntity extraction 500 2000 10000+\nSpecific domain QA 500 2000 5000+\nInstructions following 1000 5000 50000+\nDPO alignment 500 pairs 2000 pairs 10000+ pairs\nDistillation of a narrow task 1000 5000 20000+\n\nThe main rule: 500 high-quality > 10,000 noisy"
            }
          ]
        },
        {
          "number": "20",
          "title": "Synthetic Data Generation - dataset scaling",
          "tag": "data",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Self-Instruct pipeline",
              "language": "python",
              "value": "# 1. Seed: 20-30 real quality examples\nseed_examples = human_curated_examples\n\n#2. LLM generates new instructions\nnew_instructions = GPT4(f\"\"\"\n    Here are examples of tasks: {seed_examples}\n    Generate 20 new similar but different problems.\n\"\"\")\n\n#3. LLM responds to generated instructions\ndataset = [(instr, GPT4(instr)) for instr in new_instructions]\n\n#4. Filtering: deduplication + quality filter\nfiltered = [x for x in dataset if quality_score(x) > 0.7]"
            }
          ]
        },
        {
          "number": "21",
          "title": "Data Quality - what spoils a dataset",
          "tag": "data",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Common data problems",
              "language": "text",
              "value": "Inconsistency\n  There are different correct answers to the same question\n  → the model cannot learn the pattern\n\nDuplication\n  one example 100 times → the model retrains it\n  → deduplicate by embedding similarity\n\nLeaked response prompt\n  output contains instruction parts\n  → mask instruction correctly\n\nInvalid chat template\n  <|user|> and <|assistant|> tokens are mixed up\n  → the model learns the wrong roles\n\n✓ Verification: manually review 100 random examples"
            }
          ]
        },
        {
          "number": "22",
          "title": "Data Curation Pipeline - from raw materials to dataset",
          "tag": "data",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Pipeline",
              "language": "text",
              "value": "raw_data\n → collect logs, databases, synthetics, expert examples\n → clean remove noise, special characters, artifacts\n → deduplicate MinHash / embedding similarity\n → filter LLM-quality-score > threshold\n → model-specific format chat template\n → split train 90% / val 5% / test 5%\n → version git + DVC / HuggingFace Datasets\n → audit manual check of 100 examples"
            }
          ]
        }
      ]
    },
    {
      "number": "07",
      "title": "Infrastructure and tools",
      "intro": "",
      "cards": [
        {
          "number": "23",
          "title": "Fine-tuning tools - map",
          "tag": "infrastructure",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Diagram",
              "language": "text",
              "value": "Level Tool Control Convenience Cost\n─────────────────────────────────── ───────────────────────────────────\nLow-level HF Transformers maximum minimum GPU in fact\n                   PEFT library\n                   TRL (SFT/DPO)\n\nHigh-level Axolotl high high GPU in fact\n                   LLaMA-Factory ← I recommend for starting\n                   Unsloth ← 2x faster, less VRAM\n\nManaged Together.ai FT low maximum $$/hour\n                   OpenAI FT API ← GPT-3.5/4o-mini only\n                   Modal + Axolotl medium high serverless GPU\n\nEval during FT W&B / Langfuse log loss, eval metrics"
            }
          ]
        },
        {
          "number": "24",
          "title": "Hyperparameters - what really matters",
          "tag": "infrastructure",
          "description": "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.",
          "blocks": [
            {
              "kind": "code",
              "label": "Starting values",
              "language": "text",
              "value": "learning_rate: 2e-4 #LoRA; 1e-5 for full FT\nlr_scheduler: cosine with warmup\nwarmup_ratio: 0.05 # 5% steps to warm up\nepochs: 1–3 # rarely need more than 3\nbatch_size: per_device=2, grad_accum=8 # effective=16\nmax_seq_length: 2048 # per task\n\nLoRA specific:\n  r: 16# rank\n  alpha: 32 # = 2×r usually\n  target_modules: [\"q_proj\",\"v_proj\",\"k_proj\",\"o_proj\"]\n  dropout: 0.05"
            }
          ]
        },
        {
          "number": "25",
          "title": "Eval during and after fine tuning",
          "tag": "infrastructure",
          "description": "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?).",
          "blocks": [
            {
              "kind": "code",
              "label": "Checklist ratings",
              "language": "text",
              "value": "During training:\n  ✓ is train_loss decreasing?\n  ✓ val_loss is not growing? (if growing → overfitting)\n  ✓ Is grad_norm stable? (spike → lr too high)\n\nAfter training:\n  ✓ target_metric on test set vs baseline\n  ✓ general benchmarks have not fallen?\n     (MT-Bench, MMLU, HumanEval)\n  ✓ human evaluation 50 examples\n  ✓ compare vs prompted GPT-4 on the same task"
            }
          ]
        }
      ]
    },
    {
      "number": "08",
      "title": "Final strategy map",
      "intro": "",
      "cards": [
        {
          "number": "26",
          "title": "Comparison of all approaches",
          "tag": "comparison",
          "description": "Summary table for quick navigation through strategies.",
          "blocks": []
        },
        {
          "number": "27",
          "title": "Rule of three questions",
          "tag": "decision",
          "description": "Before any fine tuning project, answer three questions. If there’s even one “no,” go back a step.",
          "blocks": [
            {
              "kind": "code",
              "label": "Checklist before start",
              "language": "text",
              "value": "1. Have you exhausted your prompting?\n   Have you tried few-shot, CoT, persona, chain?\n   No → prompting first, it's free\n\n2. Do you have data and metrics?\n   Minimum 200 quality examples?\n   A clear metric by which to measure improvement?\n   No → first collect data and define a metric\n\n3. Is the problem in behavior, not knowledge?\n   If you add the correct data to the prompt → does everything work?\n   Yes → use RAG, not fine tuning\n\nAll three yes? FineTun.\nStart with LoRA on 7-8B models.\nCompare with prompted GPT-4 on your task."
            }
          ]
        }
      ]
    }
  ]
}
