Fine-Tuning Language Models ๐Ÿ”ง

Class 10Age 14โ€“15Lesson 5 of 12๐Ÿ†“ Free
Student in Kolkata fine-tuning BERT on Indian e-commerce reviews, Hugging Face Trainer output shown on laptop screen
Watch first - 2-3 minutes

Class 10 Lesson 5 - Fine-Tuning Language Models

No sign-in needed - English narration - Safe for all school ages

Meet Rahul โ€” Class 10, Kolkata

Rahul's family runs a small handicrafts shop on an Indian e-commerce platform. They receive hundreds of product reviews in Hinglish (Hindi-English mix) โ€” but manually reading all of them to understand customer sentiment wastes hours every week. He wanted an AI to classify each review as positive, neutral, or negative automatically.

He tried using a ready-made sentiment model from Hugging Face โ€” but it was trained on English movie reviews and completely missed sarcasm common in Hinglish ("Arey bahut badiya tha, item waste ho gaya" โ€” "Oh very great, the item turned out to be waste"). He needed to fine-tune a model on actual Indian e-commerce language.

Three Approaches
Prompting vs Fine-Tuning vs Training from Scratch
๐Ÿ’ฌ
Prompting
โœ… No training, instant, flexible
โŒ Unreliable for consistent output, costs API money, can't deploy offline
๐Ÿ”ง
Fine-Tuning
โœ… Accurate, consistent, can run offline, customised for your domain
โŒ Needs labelled data (few hundred+), takes hours in Colab
๐Ÿ—๏ธ
Training from Scratch
โœ… Full control
โŒ Needs billions of tokens, months of GPU time, not for students

For most real-world NLP problems, fine-tuning is the sweet spot. You get the benefit of a model pre-trained on billions of words, adapted to your specific task in hours.

Hugging Face Ecosystem
The Tools You Need
IndicBERT: A BERT model pre-trained on 12 Indian languages including Hindi, Bengali, Tamil, Telugu, Kannada, Malayalam, Gujarati, Punjabi, Marathi, Urdu, Assamese, and Odia. Available at ai4bharat/indic-bert on Hugging Face Hub โ€” ideal for Indian NLP projects.
Full Code
Fine-Tune BERT for Sentiment Classification
# Fine-Tune BERT for Sentiment Analysis โ€” Google Colab
!pip install transformers datasets evaluate -q

import numpy as np
from datasets import Dataset, DatasetDict
from transformers import (AutoTokenizer, AutoModelForSequenceClassification,
                          TrainingArguments, Trainer)
import evaluate

# โ”€โ”€ Step 1: Prepare a small labelled dataset โ”€โ”€
# Real data: label Indian e-commerce reviews 0=negative 1=neutral 2=positive
# Here we use a minimal demo set โ€” in your project, collect 300โ€“1000 reviews
train_data = {
    "text": [
        "Product quality is excellent, very happy with purchase!",
        "Delivery was very fast and packaging was great",
        "Average product, nothing special but works fine",
        "Totally waste of money, stopped working in 2 days",
        "Bahut achha hai, bilkul sahi quality",           # Hindi
        "Kaam nahi karta, paise doob gaye",               # Hindi
        "Okay okay product, theek hai for this price",    # Hinglish
        "Amazing value, will definitely buy again",
        "Product is decent, delivery was late though",
        "Complete fraud, never buying from this seller",
        "Superb build quality, highly recommend",
        "Not as described in photos, disappointing"
    ],
    "label": [2, 2, 1, 0, 2, 0, 1, 2, 1, 0, 2, 0]
}
test_data = {
    "text": [
        "Mast product hai yaar, full paisa vasool",        # Hinglish
        "Bakwaas quality, return kar diya",                # Hinglish
        "It's okay, average experience overall"
    ],
    "label": [2, 0, 1]
}

train_dataset = Dataset.from_dict(train_data)
test_dataset  = Dataset.from_dict(test_data)
dataset = DatasetDict({"train": train_dataset, "test": test_dataset})
print(dataset)

# โ”€โ”€ Step 2: Load tokenizer โ”€โ”€
# Use IndicBERT for Indian language text, or bert-base-multilingual-cased
MODEL_NAME = "ai4bharat/indic-bert"
# MODEL_NAME = "bert-base-multilingual-cased"  # fallback if above is slow

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)

def tokenize(examples):
    return tokenizer(examples["text"], padding="max_length",
                     truncation=True, max_length=128)

tokenized = dataset.map(tokenize, batched=True)
print("Sample tokens:", tokenized["train"][0].keys())

# โ”€โ”€ Step 3: Load model with classification head โ”€โ”€
NUM_LABELS = 3  # negative / neutral / positive
model = AutoModelForSequenceClassification.from_pretrained(
    MODEL_NAME, num_labels=NUM_LABELS
)

# โ”€โ”€ Step 4: Set up evaluation metric โ”€โ”€
accuracy_metric = evaluate.load("accuracy")

def compute_metrics(eval_pred):
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return accuracy_metric.compute(predictions=predictions, references=labels)

# โ”€โ”€ Step 5: Configure training โ”€โ”€
training_args = TrainingArguments(
    output_dir="./sentiment_model",
    num_train_epochs=5,
    per_device_train_batch_size=4,
    per_device_eval_batch_size=4,
    warmup_steps=10,
    weight_decay=0.01,
    logging_dir="./logs",
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    report_to="none"              # disable wandb for Colab
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized["train"],
    eval_dataset=tokenized["test"],
    tokenizer=tokenizer,
    compute_metrics=compute_metrics
)

# โ”€โ”€ Step 6: Train โ”€โ”€
trainer.train()

# โ”€โ”€ Step 7: Evaluate โ”€โ”€
results = trainer.evaluate()
print(f"\nTest accuracy: {results['eval_accuracy']:.2%}")

# โ”€โ”€ Step 8: Predict on new text โ”€โ”€
from transformers import pipeline

classifier = pipeline("text-classification", model=model,
                       tokenizer=tokenizer)
id2label = {0: "NEGATIVE", 1: "NEUTRAL", 2: "POSITIVE"}
model.config.id2label = id2label
model.config.label2id = {v: k for k, v in id2label.items()}

samples = [
    "Item bahut zyada pricey hai for such average quality",
    "Absolutely love this product, recommend to everyone!",
    "Not good, not bad, just okay"
]
for s in samples:
    pred = classifier(s)[0]
    print(f"{pred['label']:10s} ({pred['score']:.2%})  โ†’  {s[:50]}")
With a real dataset of 500+ reviews: This pipeline achieves 85โ€“92% accuracy on Indian e-commerce text. The key is collecting diverse Hinglish examples โ€” the model learns from what you label. In Colab with T4 GPU, training takes ~5 minutes.
Where to Find Indian Datasets
Public NLP Datasets for Indian Languages
Rule of thumb: 300 labelled examples per class gives a reasonable baseline. 1,000+ per class gives production-quality performance when fine-tuning BERT/IndicBERT. Collecting good labels beats having more unlabelled data.

๐Ÿงช Check Your Understanding โ€” Lesson 5 Quiz

1. Fine-tuning a language model means:
a) Rebuilding the transformer architecture from scratch for your task
b) Starting from a model pre-trained on large text data and continuing training on your smaller, task-specific labelled dataset
c) Removing the attention layers and replacing them with simpler logic
d) Compressing the model to run faster on mobile devices
2. `AutoModelForSequenceClassification.from_pretrained(MODEL_NAME, num_labels=3)` does what?
a) Downloads only 3 layers of the pre-trained model
b) Loads the full pre-trained model and adds a new classification head with 3 output neurons for your task
c) Creates a new model with 3 attention heads from scratch
d) Trains the model for exactly 3 epochs
3. Why is IndicBERT preferred over bert-base-uncased for Hinglish text classification?
a) IndicBERT was trained on text from 12 Indian languages, so it already understands subword patterns in Hindi, Hinglish and other Indian languages
b) IndicBERT has more parameters and is always more accurate
c) bert-base-uncased cannot process sentences longer than 5 words
d) IndicBERT is faster because it is smaller than BERT
4. In `TrainingArguments`, `weight_decay=0.01` is used to:
a) Reduce the learning rate by 1% each epoch
b) Apply L2 regularisation โ€” adds a small penalty for large weights โ€” helping prevent overfitting on small datasets
c) Prune 1% of the model's weights to make it smaller
d) Decay the batch size over training
5. The Trainer API's `compute_metrics` function is called:
a) After every training step to monitor loss
b) After each evaluation epoch to compute your chosen metrics (e.g., accuracy, F1) on the validation set
c) Only once at the very end of training
d) During tokenisation to check text length
6. `tokenizer(text, padding="max_length", truncation=True, max_length=128)` handles sequences longer than 128 tokens by:
a) Splitting them into multiple examples
b) Truncating them โ€” cutting off text beyond 128 tokens. The model only sees the first 128 tokens of very long inputs.
c) Summarising the text to fit in 128 tokens
d) Raising an error and stopping training
7. `load_best_model_at_end=True` in TrainingArguments means:
a) The model with the lowest training loss is saved
b) After training finishes, the checkpoint with the best evaluation metric is automatically loaded โ€” not necessarily the last epoch's weights
c) The model is only trained until accuracy reaches 100%
d) Training starts from the best model in the Hub
8. For collecting your own labelled sentiment dataset, a good minimum target for a reliable fine-tuned classifier is:
a) 10 examples total
b) 1 million examples per class
c) 300โ€“1,000 labelled examples per class
d) Exactly 50 examples per class
โ† Lesson 4: Transformers Lesson 6: RAG Chatbot โ†’