Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Goal: turn a model that continues text into a model that answers questions.


Why this step matters

Your model from Step 11 predicts what comes next. Ask it a question and it may well reply with more questions, because that is what it saw in the data.

Supervised fine-tuning (SFT) fixes this. You show it thousands of examples of the pattern “someone asks, someone answers well”, and it learns the shape of that pattern.


What you do

1. Get instruction data in Sanskrit

This is the hard part. Options, roughly best to worst:

Written by native speakers and scholars. Expensive, slow, and by far the best.

Translated from English instruction datasets. Cheap. But translated instructions produce a model that sounds translated — the phrasing, the assumptions, and the register are all wrong.

Generated by a large model. Cheapest. Check the licence, and check the quality by hand on a sample. Generating question-and-answer pairs from your own corpus works better than generating them from nothing, because the content is grounded in real text.

Mix them. But note: a few thousand genuinely excellent examples beat a hundred thousand mediocre ones. This is not a slogan, it has been measured repeatedly.

Task types worth including for Sanskrit:

2. Choose a chat template and never change it

The chat template is the special markup that says where the user’s turn starts and the assistant’s turn starts.

If you train with one template and serve with a different one, the model breaks in confusing ways that look like a quality problem rather than a formatting problem.

This is one of the most common bugs in the whole field.

3. Mask the loss on the prompt

Train the model only on the answers, not on the questions. You do not want it learning to generate user questions.

4. Choose full fine-tuning, LoRA, or QLoRA

Here the advice differs from Step 11, and the reason matters:

Step 11 already gave the model the Sanskrit knowledge. This step is teaching behaviour. So LoRA is a good choice here, and full fine-tuning would be a good choice there.

5. Do the same for Urdu

Use a separate adapter so you can compare, and so you can serve either one from the same base model.


Where people usually get stuck

The chat template mismatch.

Print your fully formatted training example, character by character, including every special token. Then print what your serving code produces. Compare them.

They must be identical. Not similar. Identical.


You are ready to move on when

Your model answers a Sanskrit question with a Sanskrit answer, in the right format, without wandering off into unrelated text.



🧑‍💻 Runnable code for this step

Instruction tuning (SFT) changes the shape of your data from raw text to pairs. Keeping prompt and completion separate is what lets the trainer score the answer only, not the parroted question:

# one line of sanskrit_sft.jsonl
{"prompt": "Translate this Sanskrit line into English:\nअहिंसा परमो धर्मः।",
 "completion": "Non-violence is the highest virtue."}
from trl import SFTTrainer, SFTConfig
from peft import LoraConfig

cfg = SFTConfig(output_dir="./adapter", num_train_epochs=3,
                per_device_train_batch_size=2, gradient_accumulation_steps=8,
                learning_rate=2e-4, max_length=1024,
                completion_only_loss=True,     # ← score the answer, not the question
                bf16=True, report_to="none")

trainer = SFTTrainer(model=model, args=cfg, train_dataset=ds,
                     peft_config=LoraConfig(r=16, lora_alpha=32,
                                            task_type="CAUSAL_LM",
                                            target_modules="all-linear"),
                     processing_class=tokenizer)
trainer.train()