Fine-Tuning, and When Not ToLesson 60 of 84

Contents

Fine-Tuning, and When Not To

Lesson 60 of 84. Sign in to keep your place.

Module 7 · Fine-tuning beyond a chat model

Fine-tuning a classifier properly

9 min read

The setup

Module one argued that a fixed set of labels wants an encoder rather than a generative model. This is how that is done.

Python
from transformers import AutoModelForSequenceClassification, AutoTokenizer

MODEL = "answerdotai/ModernBERT-base"     # 149M; or microsoft/deberta-v3-base
tok = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL, num_labels=6, id2label=ID2LABEL, label2id=LABEL2ID)

Pass id2label and label2id. They are saved in the config, which means the model that comes back off disk in six months says what its outputs mean. Without them you have a tensor of six numbers and a note in somebody’s head.

Full fine-tuning at this size costs about 6 GB of GPU memory at a learning rate of 2e-5 for 3 to 5 epochs. No adapters, no quantisation; the model is small enough that all the machinery from earlier modules is unnecessary.

Class imbalance, which you will have

Real label distributions are not uniform. A six-way routing task might be 62% one class and 3% another. Trained naively, the model learns to predict the majority class and scores 62% accuracy while being useless.

Three treatments, in order of preference:

Weighted loss. Weight each class inversely to its frequency. One override:

Python
weights = torch.tensor(len(y) / (n_classes * np.bincount(y)), dtype=torch.float)
loss = F.cross_entropy(logits, labels, weight=weights.to(logits.device))

Threshold adjustment after training. Train normally, then move the decision boundary per class using a validation set. Often better than reweighting, because it separates “what does the model believe” from “what do we do about it”, and lets you change the second without retraining.

Resampling. Oversample the minority or undersample the majority. Simple, and oversampling duplicates examples, which invites memorisation of your rarest and most precious class.

Measure with macro F1, not accuracy

Accuracy is dominated by the majority class and will tell you a useless model is a good one. Macro-averaged F1 weights every class equally, so the 3% class counts as much as the 62% one.

Print the per-class report, always:

Python
from sklearn.metrics import classification_report, confusion_matrix
print(classification_report(y_true, y_pred, target_names=LABELS, digits=3))
print(confusion_matrix(y_true, y_pred))

Read the confusion matrix rather than the summary line. It tells you which classes are being confused with which, and that is almost always actionable: two labels that the model mixes up are usually two labels your annotators mixed up, which is a taxonomy problem rather than a model problem.

Multi-label is a different loss

If an item can carry several labels at once, the labels are not mutually exclusive and softmax is wrong. Use independent sigmoids:

Python
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL, num_labels=12, problem_type="multi_label_classification")

That problem_type switches the loss to binary cross-entropy per label. Then tune a threshold per label on validation data: a single global 0.5 is rarely right when label frequencies differ by an order of magnitude.

Calibration, if you will route on confidence

A common and sensible design is to use the classifier for confident cases and fall back to an expensive model for the rest. That rule depends on the confidence meaning something.

Fine-tuned classifiers are typically overconfident: predictions cluster near 0 and 1, and those at 0.9 are right less often than 90% of the time. Check it by binning held-out predictions by confidence and comparing each bin’s mean confidence with its accuracy. Temperature scaling (one scalar fitted on validation data, dividing the logits) corrects most of the gap in about ten lines.

Knowing when you have enough data

Plot the learning curve. Train on 25%, 50%, 75% and 100% of your labels and plot macro F1 against training size.

  • Still climbing steeply at 100%: more labels is your best investment.
  • Flattening: more labels will not help much; better labels, better features or a different taxonomy might.

This takes four short runs on a 150M model (under an hour on free hardware) and it answers the question teams usually argue about instead: whether to spend the next week labelling.

Where the encoder stops being right

Be honest about the boundary. An encoder classifier needs labels, cannot take a new class without retraining, and degrades silently when your inputs drift. If your label set changes monthly, or you have fewer than a few hundred examples per class, prompting a general model is the better tool despite costing more per call.

Every lesson here is open. Your progress is recorded once you pass the Running Models Yourself exam.

Check your understanding

A six-class router reports 89% accuracy. The confusion matrix shows the rarest class, 3% of the data, is never predicted at all. Why did accuracy miss this?

Pick the one you would defend. Your answer stays private.

Next lesson · 9 minFine-tuning a speech model

Stuck on something?Ask Rafael, your AI tutor

How to cite: Addaly (2026) ‘Fine-tuning a classifier properly’, in Fine-Tuning, and When Not To. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/fine-tuning/fine-tuning-a-classifier (Accessed: 13 October 2026).