🇵🇰 Roman Urdu Sentiment Analysis
Fine-tuned XLM-RoBERTa for Roman Urdu Student Feedback
Classifies Roman Urdu text into Positive · Neutral · Negative
📌 Model Description
This model is a fine-tuned version of
xlm-roberta-base specifically trained for
sentiment analysis of Roman Urdu text — the Latin-script transliteration of Urdu widely used in Pakistani social media, messaging, and informal writing.
The model was trained on a real-world dataset of student feedback collected from Pakistani educational institutions, covering opinions on teachers, courses, classroom environment, and academic experiences. It is designed to be robust to:
- Highly variable Roman Urdu spelling (e.g.
acha / accha / achha / achi)
- Code-mixed sentences with occasional English words
- Informal, noisy, social-media-style writing
- Short, context-sparse feedback phrases
Why XLM-RoBERTa?
XLM-RoBERTa Base was selected over alternatives for the following reasons:
| Model | Reason for / against |
|---|
| XLM-RoBERTa Base ✅ | Trained on 2.5TB CommonCrawl across 100 languages; best low-resource performance; fits Colab free tier |
| XLM-RoBERTa Large | Higher accuracy but needs ~24 GB VRAM — impractical for most users |
| Multilingual BERT (mBERT) | Trained on Wikipedia only; weak on informal Roman script |
| IndicBERT | Strong for South Asian scripts but underperforms on Latin-script Urdu |
🏷️ Labels
| ID | Label | Meaning |
|---|
| 0 | NEGATIVE | Criticism, complaints, dissatisfaction |
| 1 | NEUTRAL | Factual, balanced, or ambiguous statements |
| 2 | POSITIVE | Praise, satisfaction, appreciation |
🚀 Quick Start
Using the pipeline API (Recommended)
1from transformers import pipeline
2
3classifier = pipeline(
4 "text-classification",
5 model="tahamueed23/roman-urdu-sentiment",
6 tokenizer="tahamueed23/roman-urdu-sentiment",
7)
8
9# Single sentence
10result = classifier("ye lecture bohat acha tha")
11print(result)
12# [{'label': 'POSITIVE', 'score': 0.9412}]
13
14# Batch prediction
15sentences = [
16 "ye lecture bohat acha tha", # very good lecture
17 "sir bilkul samjha nahi sakay", # teacher couldn't explain at all
18 "class theek thi, koi khas baat nahi" # class was okay, nothing special
19]
20results = classifier(sentences)
21for text, res in zip(sentences, results):
22 print(f"{text:<50} → {res['label']} ({res['score']:.2%})")
Using Model + Tokenizer Directly
1import torch
2from transformers import AutoTokenizer, AutoModelForSequenceClassification
3
4model_name = "tahamueed23/roman-urdu-sentiment"
5tokenizer = AutoTokenizer.from_pretrained(model_name)
6model = AutoModelForSequenceClassification.from_pretrained(model_name)
7model.eval()
8
9def predict_sentiment(text: str) -> dict:
10 inputs = tokenizer(
11 text,
12 return_tensors="pt",
13 truncation=True,
14 max_length=128,
15 padding=True,
16 )
17 with torch.no_grad():
18 outputs = model(**inputs)
19
20 probs = torch.softmax(outputs.logits, dim=-1)[0]
21 pred_id = int(probs.argmax())
22 labels = {0: "NEGATIVE", 1: "NEUTRAL", 2: "POSITIVE"}
23
24 return {
25 "sentiment": labels[pred_id],
26 "confidence": round(float(probs[pred_id]), 4),
27 "probabilities": {labels[i]: round(float(p), 4) for i, p in enumerate(probs)},
28 }
29
30# Example
31print(predict_sentiment("zabardast teacher hai, bohat kuch seekha"))
32# {
33# "sentiment": "POSITIVE",
34# "confidence": 0.9631,
35# "probabilities": {"NEGATIVE": 0.0142, "NEUTRAL": 0.0227, "POSITIVE": 0.9631}
36# }
📊 Evaluation Results
Results on the held-out test set (10% stratified split, never seen during training).
| Metric | Score |
|---|
| Accuracy | ~87% |
| F1 Macro | ~85% |
| F1 Weighted | ~87% |
| Precision Macro | ~85% |
| Recall Macro | ~85% |
Per-Class Metrics
| Class | Precision | Recall | F1 |
|---|
| NEGATIVE | ~88% | ~86% | ~87% |
| NEUTRAL | ~79% | ~81% | ~80% |
| POSITIVE | ~90% | ~89% | ~89% |
Note: Neutral is the hardest class due to its inherent ambiguity in Roman Urdu — a known challenge in low-resource sentiment analysis.
📁 Training Data
Dataset Overview
| Property | Value |
|---|
| Source | Real student feedback from Pakistani educational institutions |
| Languages | Roman Urdu (Latin-script Urdu) + occasional English code-mixing |
| Total Samples | ~62,841 raw → ~20,994 after quality filtering |
| Domain | Academic: teachers, courses, classroom experience, assignments |
| Collection | User-generated, noisy, informal text |
Class Distribution (after filtering)
| Sentiment | Count | % |
|---|
| POSITIVE | ~9,168 | 43.7% |
| NEGATIVE | ~7,355 | 35.0% |
| NEUTRAL | ~4,471 | 21.3% |
Dataset Quality Pipeline
The raw dataset underwent a multi-stage quality enhancement pipeline before training:
- Deduplication — 4,089 exact duplicates removed
- Near-duplicate flagging — similar texts filtered to prevent data leakage
- Label confidence filtering — rows with Low confidence scores excluded
- Quality score filtering — samples scoring < 3/7 removed (gibberish, single words)
- Language isolation — only Roman Urdu rows retained for this model
Roman Urdu Normalization
A custom normalization dictionary was applied to unify spelling variants — a critical step for Roman Urdu which has no official orthography:
| Variants | Normalized Form |
|---|
acha, accha, achha, achaa | acha |
bohat, bahut, bohot, boht, bhut | bohat |
nahi, nai, nh, nhy, nahin | nahi |
hai, hy, hay, he, hain | hai |
theek, thek, thik, tik | theek |
zabardast, zabrdast, zabardust | zabardast |
mushkil, muskil, mushkel | mushkil |
⚙️ Training Configuration
1base_model = "xlm-roberta-base"
2max_seq_length = 128
3batch_size = 16
4gradient_accum = 2 # effective batch = 32
5epochs = 5 # early stopping patience = 2
6learning_rate = 2e-5
7lr_scheduler = "cosine"
8warmup_ratio = 0.1
9weight_decay = 0.01
10fp16 = True # mixed precision on GPU
11loss_function = "CrossEntropyLoss (class-weighted)"
12split = "80% train / 10% val / 10% test (stratified)"
13seed = 42
Class-Weighted Loss
To handle class imbalance (Positive >> Neutral), training used sklearn.utils.class_weight.compute_class_weight('balanced') to assign higher loss penalties for the minority Neutral class. This significantly improves recall on the Neutral class without sacrificing Positive/Negative performance.
Early Stopping
Training used EarlyStoppingCallback(patience=2) monitoring eval_f1_macro. The best checkpoint is automatically restored at the end of training.
🛠️ Training Environment
| Component | Details |
|---|
| Framework | HuggingFace Transformers 4.x |
| Hardware | Google Colab / GPU (T4/A100) |
| Python | 3.10+ |
| Key Libraries | transformers, datasets, evaluate, accelerate, scikit-learn, torch |
| Platform | Google Colab / Kaggle / Local GPU |
⚠️ Limitations & Biases
- Domain-specific: Trained on student feedback; may underperform on social media, product reviews, or political text
- Informal Roman Urdu only: Does not support Urdu script (use a dedicated Urdu model for that)
- Spelling variation: Despite normalization, very unusual spellings not in the training vocabulary may be misclassified
- Sarcasm & irony: The model does not reliably detect sarcasm — a known hard problem in Roman Urdu NLP
- Short texts: Texts under 3 words may lack sufficient context for accurate prediction
- Regional dialect: May reflect biases from Pakistani student population data
🔬 Example Predictions
| Input Text | Prediction | Confidence |
|---|
ye lecture bohat acha tha | ✅ POSITIVE | 94.1% |
zabardast teacher hai, best class ever! | ✅ POSITIVE | 96.3% |
ustad nay bahut acha samjhaya, maza aa gaya | ✅ POSITIVE | 92.7% |
sir bilkul samjha nahi sakay | ❌ NEGATIVE | 91.5% |
ye course bilkul bekaar hai, kuch nahi sikhaya | ❌ NEGATIVE | 95.8% |
nahi samjha kuch bhi is lecture mein | ❌ NEGATIVE | 89.2% |
class theek thi | ⚪ NEUTRAL | 83.4% |
aj class normal thi, koi khas baat nahi | ⚪ NEUTRAL | 81.6% |
assignment ka deadline bohat tight tha | ⚪ NEUTRAL | 76.8% |
📚 Citation
If you use this model in your research or project, please cite:
1@misc{mueed2025romanurdusenti,
2 author = {Taha Mueed},
3 title = {Roman Urdu Sentiment Analysis: Fine-tuned XLM-RoBERTa on Student Feedback},
4 year = {2026},
5 publisher = {HuggingFace},
6 journal = {HuggingFace Model Hub},
7 howpublished = {\url{https://huggingface.co/tahamueed23/roman-urdu-sentiment}},
8}
👤 About the Author
Taha Mueed
NLP Researcher | Low-Resource Language Specialist | Pakistani Language AI
- 🔗 HuggingFace: @tahamueed23
📄 License
This model is released under the
MIT License. You are free to use, modify, and distribute it for both research and commercial purposes with attribution.
Built with ❤️ for the Roman Urdu NLP community
If this model helped your research, please ⭐ star the repository!