How Fine-tuning Works

By Syncfusion®, Inc. · Last updated

Weights, loss, epochs, learning rate, validation sets, overfitting and LoRA, explained for developers with no machine learning background.

How Fine-tuning Works

The JSON ticket team has its evidence: prompting plateaued at 80%. Now they will fine-tune.

But nobody on the team has trained a model before. The training tool asks for a learning rate, a number of epochs and a LoRA rank. They do not know what any of these mean.

This lesson explains them without the maths. Start with one single training step.

That is all training is: guess, measure how wrong the guess was, nudge the numbers a little, and repeat.

Simple lesson: a model learns by many tiny corrections, not by reading rules.

A Real-World Example

Think about learning to throw darts.

You throw. You miss to the left. Next time you aim a little to the right. You do this hundreds of times, and slowly your arm learns.

If you correct too much after each throw, you swing from far left to far right and never settle. If you correct too little, you take forever to improve.

If you practise on only three darts at one board, you get great at that board and nothing else.

Those three problems have names in training: the learning rate, epochs, and overfitting.

Simple lesson: practise often, correct a little at a time, and test on a board you did not practise on.

What You Will Learn

In this lesson, you will learn:

  1. What weights, a training step and loss are.
  2. What an epoch and the learning rate do.
  3. Why you keep a validation set, and how to spot overfitting.
  4. How LoRA trains a tiny add-on instead of the whole model.
  5. How to read the three numbers every training tool asks for.

Before you start

  • No maths or machine learning background is needed.
  • Open the Words you need boxes when a word is new. They open by themselves if you told the course you have never trained a model.
  • The Fine-tune Lab's Live fine-tune tab trains a real tiny model. You will break it on purpose in this lesson.

TL;DR

Weights = the numbers inside a model. Training changes them.

Loss = one number for how wrong the model's guesses are. Training tries to make it smaller.

Epoch = one pass over all the training examples.

Learning rate = how big each nudge to the weights is.

Validation set = examples kept out of training, used to check that the model learned the pattern and did not just memorise.

LoRA = freeze the big model and train two small matrices beside it.

One Training Step

Weights and loss

  • A model is a very long list of numbers called weights. A small open model has billions of them.
  • When the model reads your message, it uses its weights to give every possible next word a chance, like 22% for "cancel" and 31% for "refund".
  • Loss turns "how wrong was that" into one number. If the right word got a high chance, the loss is small. If it got a low chance, the loss is big.

The loss for one example is minus the logarithm of the chance the model gave the right word. You do not need to know logarithms. You only need the pattern:

Loss for one guess

// Loss for one example = -log(chance the model gave the right word).
function loss(chanceOfRightWord: number): number {
  return -Math.log(chanceOfRightWord);
}

for (const p of [0.22, 0.41, 0.88, 0.99]) {
  console.log(`right word at ${Math.round(p * 100)}% -> loss ${loss(p).toFixed(2)}`);
}

Loss for one guess

// Loss for one example = -log(chance the model gave the right word).
double Loss(double chanceOfRightWord) => -Math.Log(chanceOfRightWord);

foreach (var p in new[] { 0.22, 0.41, 0.88, 0.99 })
{
    Console.WriteLine($"right word at {Math.Round(p * 100, MidpointRounding.AwayFromZero)}% -> loss {Loss(p):F2}");
}

Expected output:

right word at 22% -> loss 1.51
right word at 41% -> loss 0.89
right word at 88% -> loss 0.13
right word at 99% -> loss 0.01

A 22% chance gives a loss of 1.51. A 99% chance gives 0.01. Training pushes the right word's chance up, so the loss goes down.

Simple lesson: lower loss means the model gives the right answer more chance.

Epochs and the Learning Rate

Epochs, batches and the learning rate

  • The model does not learn from one example at a time. It looks at a small group, called a batch, then nudges its weights.
  • One epoch = one pass over every training example. Two or three epochs is common for a fine-tune.
  • The learning rate is the size of each nudge. A typical LoRA learning rate is around 0.0001 to 0.0002 (written 1e-4 to 2e-4).

The learning rate matters a lot. Here is a model with just one number to learn. The right answer is 3.

Learning one number with three learning rates

// Learning one number: find w so that w * x matches y.
// The right answer is w = 3. Each step nudges w against the error.
const data: [number, number][] = [[1, 3], [2, 6], [3, 9]];

function train(learningRate: number, steps: number): string {
  let w = 0;
  for (let s = 0; s < steps; s++) {
    let grad = 0;
    for (const [x, y] of data) grad += 2 * (w * x - y) * x;
    w -= learningRate * (grad / data.length);
  }
  return w.toFixed(3);
}

console.log("lr 0.01, 20 steps:", train(0.01, 20));
console.log("lr 0.1,  20 steps:", train(0.1, 20));
console.log("lr 0.3,  20 steps:", train(0.3, 20));

Learning one number with three learning rates

// Learning one number: find w so that w * x matches y.
// The right answer is w = 3. Each step nudges w against the error.
(double X, double Y)[] data = [(1, 3), (2, 6), (3, 9)];

string Train(double learningRate, int steps)
{
    double w = 0;
    for (var s = 0; s < steps; s++)
    {
        double grad = 0;
        foreach (var (x, y) in data) grad += 2 * (w * x - y) * x;
        w -= learningRate * (grad / data.Length);
    }
    return w.ToString("F3");
}

Console.WriteLine($"lr 0.01, 20 steps: {Train(0.01, 20)}");
Console.WriteLine($"lr 0.1,  20 steps: {Train(0.1, 20)}");
Console.WriteLine($"lr 0.3,  20 steps: {Train(0.3, 20)}");

Expected output:

lr 0.01, 20 steps: 2.577
lr 0.1,  20 steps: 3.000
lr 0.3,  20 steps: -382444.086

With 0.01 the nudges are too small: after 20 steps it is still at 2.58. With 0.1 it lands on 3. With 0.3 each nudge overshoots further than the last, and the number flies off to minus several hundred thousand.

A big model behaves the same way. Too high a learning rate makes the loss jump around or explode.

Simple lesson: a learning rate that is too high never settles. One that is too low barely moves.

Train, Validation and Overfitting

Training set, validation set and overfitting

  • The training set is the examples the model learns from.
  • The validation set is a separate group of examples it never trains on. You check the loss on it after every few steps.
  • Overfitting = the model memorises the training examples instead of learning the pattern. Training loss keeps falling, but validation loss starts to rise.

Watch four simulated runs. Each one shows a training loss line and a validation loss line.

The important picture is Run B. Its validation loss is lowest at step 300. After that the model starts memorising. Training for longer makes it worse at new tickets.

A checkpoint is a saved copy of the weights at one step. Good tools save several, so you can keep the best one instead of the last one.

You can make overfitting happen yourself. Train the tiny model on only 4 examples for many epochs.

Simple lesson: trust the validation line, not the training line.

LoRA: a Small Change on the Side

A full fine-tune changes every weight in the model. For a 7-billion-weight model, that needs large GPUs and makes a full copy of the model.

LoRA (Low-Rank Adaptation) does something cheaper. It freezes each big weight matrix and trains two thin matrices beside it, called A and B. Their product is a small correction to the big matrix.

Rank = how thick the two thin matrices are. A higher rank gives the adapter more room to learn.

LoRA keeps the big matrix W frozen. It trains two thin matrices, A and B. Their product is added to W's output.

One 4,096 by 4,096 matrix holds 16,777,216 numbers. A rank 8 adapter for it trains only 65,536 numbers, which is 0.39%.

LoRA size for one matrix

// How many numbers does LoRA train for one weight matrix?
function loraParams(dIn: number, dOut: number, rank: number): number {
  return rank * dIn + rank * dOut; // matrix A (dIn x rank) + matrix B (rank x dOut)
}

const d = 4096;
const full = d * d;
console.log(`full matrix: ${full.toLocaleString("en-US")} numbers`);
for (const r of [4, 8, 16, 64]) {
  const n = loraParams(d, d, r);
  console.log(`rank ${String(r).padStart(2)}: ${n.toLocaleString("en-US")} numbers (${((n / full) * 100).toFixed(2)}%)`);
}

LoRA size for one matrix

// How many numbers does LoRA train for one weight matrix?
int LoraParams(int dIn, int dOut, int rank) => rank * dIn + rank * dOut; // matrix A (dIn x rank) + matrix B (rank x dOut)

var d = 4096;
var full = d * d;
Console.WriteLine($"full matrix: {full:N0} numbers");
foreach (var r in new[] { 4, 8, 16, 64 })
{
    var n = LoraParams(d, d, r);
    Console.WriteLine($"rank {r,2}: {n:N0} numbers ({Math.Round((double)n / full * 100, 2, MidpointRounding.AwayFromZero):F2}%)");
}

Expected output:

full matrix: 16,777,216 numbers
rank  4: 32,768 numbers (0.20%)
rank  8: 65,536 numbers (0.39%)
rank 16: 131,072 numbers (0.78%)
rank 64: 524,288 numbers (3.13%)

QLoRA is LoRA on a base model stored in 4-bit numbers. It uses much less GPU memory, so a 7B or 8B model fits on one 12 to 24 GB GPU.

The three numbers most tools ask for

  • Learning rate: start with the tool's LoRA default (often 1e-4 or 2e-4). Lower it if the loss jumps around.
  • Epochs: start with 2 or 3. Watch validation loss and keep the best checkpoint.
  • LoRA rank: start with 8 or 16. Go higher only if the eval says the adapter cannot learn the task.

What a lead needs to know about training

  • Ask to see the loss curves, training and validation, for every run. A run without a validation line cannot be trusted.
  • Ask which checkpoint was kept and why. "The last one" is not an answer.
  • LoRA should be the default. A full fine-tune needs a written reason.
  • Training runs are cheap. Mistakes are not. A bad learning rate costs an hour of GPU time. Shipping an overfit model costs customers.

Do's and Don'ts

  • Do keep a validation set the model never trains on.
  • Do watch validation loss, and keep the best checkpoint.
  • Do start with LoRA and the tool's default settings.
  • Don't judge a run by training loss alone.
  • Don't raise the learning rate to "train faster" without watching the curves.
  • Don't train for many epochs on a small dataset.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
Watching only training loss"Training loss is near zero, so it learned."Watch validation loss. That shows learning, not memory.You ship an overfit model that fails on new tickets.
Keeping the last checkpoint"More training is always better."Keep the checkpoint with the lowest validation loss.You keep the version after it started memorising.
A very high learning rate"Bigger steps, faster training."Use the tool's default and lower it if loss jumps.The loss jumps around and never settles.
No validation set"All the data should go into training."Hold out a validation set from the start.You cannot see overfitting at all.
Full fine-tune by default"Changing all the weights must be better."Start with LoRA. It trains under 1% of the numbers.Big GPUs, a full model copy and more damage to old skills.

Check Your Understanding

Exercises

What to Remember

  • Training is guess, measure the loss, nudge the weights, repeat.
  • An epoch is one pass over the data. The learning rate is the size of each nudge.
  • Keep a validation set. When its loss rises while training loss falls, the model is overfitting.
  • Keep the best checkpoint, not the last one.
  • LoRA trains two thin matrices beside a frozen model, often under 1% of the numbers.

Next: Dataset Design, what one good training example looks like, and how many of each kind you need.