Project: a tuned model
Lesson 6 of 6
6Project: a tuned model
The big pictureIn this project you tune a small model on one Arabic task and prove with a number that it beat the best that prompting alone can do, or discover that it did not, which is also a valid result. The fair comparison is against the prompt with examples, not against a poor prompt.
What the picture shows: The baseline is the middle bar, the prompt with eight examples, not the weak first one. The tuned model beat it with an interval entirely above zero, but lost ten points on the general set, and that goes into the report with the decision.
Map of this part
The concepts in order, click any one to jump to it:
Two ways into the same idea
You pick one specific Arabic task, like classifying customer complaints, and tune a small model on it. Then you prove with numbers that it beats simply writing good instructions for an untuned model. If it does not, that too is an important result you write down honestly.
Cleaned, split JSONL data, a LoRA run with recorded settings, and a comparison on a fixed test set against the best prompt with a few examples. The report states accuracy, cost, inference time and a forgetting check.
Before You Start
📋Tuning data
You know how to build a clean file with a grouped split and a frozen test set.
📏Did it actually improve
You know the confidence interval for a difference, and the general set for forgetting.
The Core Idea
In this project you tune a small model on one Arabic task, and prove with a number whether it beat the best prompting can do. You choose the task, build the data, run the tuning, then fill in the results table.
1Choosing the task
Pick a narrow task whose answers can be checked automatically, with enough volume to justify tuning or a clear reason to need a small model.
Look at the picture: three tasks that suit a first project, and one to avoid because evaluating it is much harder.
2The data and the frozen test
You need 500 to 2,000 clean examples, a written labelling guide, and a grouped split. And the test set is frozen before any training.
Look at the picture: each step from the data lesson, in order, before you run any training.
3The tuning run
The run is LoRA on a small open model, with the settings recorded in the folder name, and the checkpoint at the lowest validation loss.
It needs a GPU and pip install transformers peft trl datasets, so it is here for reading. A model of half a billion to 1.5 billion parameters is enough for a classification task, and trains in under an hour on a mid-range or free card.
from datasets import load_dataset
from peft import LoraConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
from trl import SFTConfig, SFTTrainer
BASE = "Qwen/Qwen2.5-0.5B-Instruct"
tok = AutoTokenizer.from_pretrained(BASE)
model = AutoModelForCausalLM.from_pretrained(BASE, torch_dtype="bfloat16")
data = load_dataset("json", data_files={"train": "train.jsonl", "val": "val.jsonl"})
peft = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05, target_modules="all-linear", task_type="CAUSAL_LM")
args = SFTConfig(
output_dir="runs/r16-lr2e-4-ep2",
per_device_train_batch_size=4, gradient_accumulation_steps=8,
learning_rate=2e-4, num_train_epochs=2, bf16=True,
eval_strategy="steps", eval_steps=50, save_steps=50, load_best_model_at_end=True,
completion_only_loss=True, # learn the assistant's answer, not the user's message
)
trainer = SFTTrainer(model=model, args=args, train_dataset=data["train"], eval_dataset=data["val"],
processing_class=tok, peft_config=peft)
trainer.train()
trainer.save_model("runs/r16-lr2e-4-ep2/best")
completion_only_loss=True puts the loss on the assistant's answer only, so the model does not spend capacity learning to rewrite user messages. After training, run the tuned model and the original with both prompts on the frozen test set and the general set, and fill the table with the same code as above.
4The results table
The table compares three systems on the same frozen questions: the prompt alone, the prompt with examples, and the tuned model. The fair comparison is against the prompt with examples, not a poor prompt.
Three systems on the same 300 frozen questions, plus a general set of 100 questions to detect forgetting. The numbers here are generated for illustration; in your project they come from a real run of each system.
import numpy as np
rng = np.random.default_rng(7)
# per-question results on a frozen set of 300 (1 = correct); in your project these come from real runs
task = {"prompt only": rng.random(300) < 0.62,
"prompt + 8 examples": rng.random(300) < 0.74,
"LoRA tuned": rng.random(300) < 0.86}
general = {"prompt only": rng.random(100) < 0.80, # 100 unrelated questions: forgetting check
"prompt + 8 examples": rng.random(100) < 0.80,
"LoRA tuned": rng.random(100) < 0.74}
def interval(a, b, n=2000):
idx = rng.integers(0, len(a), (n, len(a)))
d = b[idx].mean(1) - a[idx].mean(1)
return np.percentile(d, [2.5, 97.5])
base = task["prompt + 8 examples"]
print(f"{'system':22} {'task':>6} {'vs few-shot (95%)':>22} {'general':>8}")
for name in task:
if task[name] is base:
cell = "baseline"
else:
lo, hi = interval(base, task[name])
cell = f"[{lo:+.1%}, {hi:+.1%}]"
print(f"{name:22} {task[name].mean():6.1%} {cell:>22} {general[name].mean():8.0%}")
The baseline is the prompt with eight examples, not the poor prompt. The tuned model beat it with an interval entirely above zero, so the improvement is real. But it lost 10 points on the general set. If the model will serve this task alone, that is acceptable and goes in the report. If it will serve others, rerun mixing in general examples.
Look at the picture: this is the table's other column, the general set. The tuned model won on the task, but lost here. Both numbers go into the recommendation.
How It Works, Step by Step: how to run the project from task to recommendation
Pick a narrow Arabic task with automatically checkable answers, and freeze a test set of at least 200 questions.
Measure the prompt alone and the prompt with examples on the test set and the general set before any training.
Train LoRA on a small model with logged settings, and take the checkpoint at the lowest validation loss.
Fill the three-system table with the interval against the prompt with examples, and write the recommendation with its numbers.
Worked example
Pick a narrow task with checkable answers: classifying messages into categories, extracting fields from text into JSON, or converting dialect to standard Arabic with clear criteria. Avoid open tasks like creative writing, since evaluating them is much harder for a first project.
Try it without code
Myth vs Reality
| Myth | Reality |
|---|---|
| If the tuned model beats the prompt alone, tuning is worth it. | The fair comparison is with the best cheap alternative, the prompt with examples. A gap against a weak prompt inflates the benefit. |
| A project where tuning did not win is a failed project. | A "do not tune" result with numbers and reasons is a valid result, and saves the team maintaining a model it does not need. |
| The model should learn the whole conversation. | completion_only_loss=True puts the loss on the assistant's answer only, so capacity is not spent learning to write users' messages. |
Try it yourself
The tuned model beats the prompt alone by 25 points, and the prompt with examples by one point with an interval including zero. What do you recommend?
The 25 points are against a weak baseline. Against the real alternative there is no proven difference, so the decision comes down to cost and latency, written with their numbers.
What does completion_only_loss=True do?
Your goal is for the model to learn how to answer, not how to write users' questions. A loss on the answer alone focuses learning where you want it.
Quick review cards
Check Your Understanding
Why is the baseline "the prompt with eight examples" rather than "the prompt alone"?
Because the real question is whether tuning is worth its cost against the best cheap alternative, and examples in the prompt are a cheap alternative that helps a lot. Comparing the tuned model with a poor prompt inflates its benefit and leads to the wrong decision.
The tuned model lost ten points on the general set. When do you accept that, and when not?
Accept it if the model will serve this task alone, and write it in the report. If it will serve other tasks, rerun with general examples mixed in.
Resources for this lesson
Grouped by type. Start with the official docs for precision, or an article or video for the explanation.
Done with this lesson?
Sign in to save your progress.