Hate Speech Detection β Multilingual Sequential Transfer Learning
GloVe Embeddings + Bidirectional LSTM (BiLSTM)
What is this project about?
This project builds a system that can automatically detect hate speech in text written in three languages:
- English β standard English text
- Hindi β Hindi text (transliterated or native script)
- Hinglish β a mix of Hindi and English (very common in Indian social media)
The core question we are trying to answer is:
Does the order in which you teach a model different languages matter for how well it performs?
For example β is a model that learns English first, then Hindi, then Hinglish better or worse than one that learns Hinglish first?
The Dataset
| Property | Value |
|---|---|
| Total samples | 29,505 |
| English samples | 14,994 (50.8%) |
| Hindi samples | 9,738 (33.0%) |
| Hinglish samples | 4,774 (16.2%) |
| Hate speech (label=1) | 13,707 (46.5%) |
| Non-hate speech (label=0) | 15,799 (53.5%) |
The dataset was split into three parts:
- Training set β 17,704 samples (used to teach the model)
- Validation set β 2,950 samples (used to monitor learning during training)
- Test set β 8,852 samples (used only at the end to measure real performance)
The Model β What is GloVe + BiLSTM?
Think of the model like a two-part reading machine:
Part 1: GloVe Embeddings (the dictionary)
Before the model can understand words, it needs to know what words mean relative to each other. GloVe (Global Vectors) is a pre-trained lookup table of 300,000+ English words, where each word is represented as a list of 300 numbers that capture its meaning. Words with similar meanings end up with similar numbers.
- We used
glove.6B.300d.txtβ 6 billion word training corpus, 300 dimensions - The embedding layer is frozen (not updated during training) β we keep GloVe's knowledge as-is and only train the layers on top
Part 2: Bidirectional LSTM (the reader)
An LSTM (Long Short-Term Memory) is a type of neural network designed to read sequences β like sentences β and remember what it read. Bidirectional means it reads the sentence both forwards and backwards, so it understands context from both directions.
Input sentence
β
GloVe Embeddings (300d, frozen)
β
BiLSTM (128 units, reads leftβright AND rightβleft)
β
Dropout (50% β randomly switches off neurons to prevent overfitting)
β
Dense layer (64 neurons, ReLU activation)
β
Output (1 neuron, Sigmoid β gives a probability 0 to 1)
β
> 0.5 = Hate Speech, β€ 0.5 = Not Hate Speech
The Training Strategy β What is Transfer Learning?
Transfer learning means the model carries what it learned from one task into the next. Like a student who already knows French β learning Spanish is easier because both share Latin roots.
In our case, we train the model on one language, and instead of starting fresh for the next language, we keep all the weights (knowledge) from the previous training. The model continues learning from where it left off.
The Bug We Fixed
The original code was creating a brand new model for every language β resetting all the weights each time. That is not transfer learning, it's just training three separate models. We fixed this by building the model once and sequentially fine-tuning it.
# WRONG β model reset every loop iteration
for lang in languages:
model = Sequential() # β new model = no transfer learning
model.fit(...)
# CORRECT β model built once, weights carry forward
model = build_model() # β built once
for lang in languages:
model.fit(...) # β continues learning from previous language
Plan B β The Experiment
We ran all 6 possible orderings of the three languages, each followed by a final training round on the complete shuffled dataset:
| # | Strategy |
|---|---|
| 1 | English β Hindi β Hinglish β Full |
| 2 | English β Hinglish β Hindi β Full |
| 3 | Hindi β English β Hinglish β Full |
| 4 | Hindi β Hinglish β English β Full |
| 5 | Hinglish β English β Hindi β Full |
| 6 | Hinglish β Hindi β English β Full |
For each strategy, training happens in 4 phases. After each phase, we immediately evaluate the model on that specific language's test data and record all metrics. This tells us how well the model performs at each stage of the learning journey.
Phase 1: Train on Language A β Test on Language A test set β Record metrics + plots
Phase 2: Train on Language B β Test on Language B test set β Record metrics + plots
Phase 3: Train on Language C β Test on Language C test set β Record metrics + plots
Phase 4: Train on Full data β Test on Full test set β Record metrics + plots
Each phase used 8 epochs with batch size 32 (64 for the full phase).
Metrics β What do we measure?
| Metric | What it means in plain English |
|---|---|
| Accuracy | Out of all predictions, how many were correct? |
| Balanced Accuracy | Accuracy adjusted for class imbalance (more fair) |
| Precision | Of everything the model flagged as hate speech, how much actually was? |
| Recall | Of all actual hate speech, how much did the model catch? |
| Specificity | Of all non-hate speech, how much did the model correctly ignore? |
| F1 Score | Balance between Precision and Recall (harmonic mean) |
| ROC-AUC | Overall ability to distinguish hate from non-hate (1.0 = perfect) |
Results Summary
Full results are in output/results_tables/all_strategies_results.csv. Key highlights:
English phase performance across strategies (best language)
| Strategy | Accuracy | F1 | ROC-AUC |
|---|---|---|---|
| English β Hindi β Hinglish β Full | 0.7701 | 0.7696 | 0.8504 |
| English β Hinglish β Hindi β Full | 0.7721 | 0.7743 | 0.8525 |
| Hindi β English β Hinglish β Full | 0.7780 | 0.7830 | 0.8549 |
| Hindi β Hinglish β English β Full | 0.7780 | 0.7816 | 0.8563 |
| Hinglish β English β Hindi β Full | 0.7716 | 0.7829 | 0.8484 |
| Hinglish β Hindi β English β Full | 0.7765 | 0.7811 | 0.8534 |
Full dataset phase (final performance)
| Strategy | Accuracy | F1 | ROC-AUC |
|---|---|---|---|
| English β Hindi β Hinglish β Full | 0.6796 | 0.5923 | 0.7599 |
| English β Hinglish β Hindi β Full | 0.6813 | 0.6244 | 0.7535 |
| Hindi β English β Hinglish β Full | 0.6854 | 0.6419 | 0.7528 |
| Hindi β Hinglish β English β Full | 0.6865 | 0.6364 | 0.7507 |
| Hinglish β English β Hindi β Full | 0.6778 | 0.6285 | 0.7521 |
| Hinglish β Hindi β English β Full | 0.6845 | 0.6301 | 0.7548 |
Key observations
- English consistently achieves the highest accuracy (~77%) regardless of when it is trained β likely because GloVe embeddings are English-centric
- Hindi is the hardest language β accuracy hovers around 55β59% across all strategies
- Hinglish sits in the middle (~66β70%) which makes sense as it borrows heavily from English
- Strategies that train Hindi first (
Hindi β English β Hinglish) tend to recover better in later phases, suggesting the model benefits from tackling the hardest language early - The Full phase shows consistent ~68% accuracy across all strategies, suggesting the final shuffled training normalises the differences introduced by ordering
Plots by Strategy
Strategy 1: English β Hindi β Hinglish β Full
Strategy 2: English β Hinglish β Hindi β Full
Strategy 3: Hindi β English β Hinglish β Full
Strategy 4: Hindi β Hinglish β English β Full
Strategy 5: Hinglish β English β Hindi β Full
Strategy 6: Hinglish β Hindi β English β Full
Output Files
output/
βββ dataset_splits/
β βββ train.csv # 17,704 training samples
β βββ val.csv # 2,950 validation samples
β βββ test.csv # 8,852 test samples
β
βββ results_tables/
β βββ all_strategies_results.csv # All 24 rows (6 strategies Γ 4 phases)
β βββ english_to_hindi_to_hinglish_results.csv
β βββ english_to_hinglish_to_hindi_results.csv
β βββ hindi_to_english_to_hinglish_results.csv
β βββ hindi_to_hinglish_to_english_results.csv
β βββ hinglish_to_english_to_hindi_results.csv
β βββ hinglish_to_hindi_to_english_results.csv
β
βββ figures/
βββ language_distribution.png # Pie chart of dataset languages
β
βββ english_to_hindi_to_hinglish/ # One folder per strategy
β βββ *_[english]_curves.png # Train/Val accuracy + loss
β βββ *_[english]_cm.png # Confusion matrix
β βββ *_[english]_roc.png # ROC curve
β βββ *_[english]_pr.png # Precision-Recall curve
β βββ *_[english]_f1.png # F1 vs Threshold curve
β βββ *_[hindi]_curves.png
β βββ *_[hindi]_cm.png ...
β βββ *_[hinglish]_curves.png
β βββ *_[hinglish]_cm.png ...
β βββ *_[Full]_curves.png
β βββ *_[Full]_cm.png ...
β
βββ english_to_hinglish_to_hindi/
βββ hindi_to_english_to_hinglish/
βββ hindi_to_hinglish_to_english/
βββ hinglish_to_english_to_hindi/
βββ hinglish_to_hindi_to_english/
How to Run
Requirements
pip install tensorflow scikit-learn pandas seaborn matplotlib
You also need GloVe embeddings (glove.6B.300d.txt) placed at /root/glove.6B.300d.txt:
wget http://nlp.stanford.edu/data/glove.6B.zip && unzip glove.6B.zip
Run
python main.py
Training was performed on an NVIDIA H200 GPU (Vast.ai) β total runtime approximately 15β20 minutes for all 6 strategies.
Project Structure
SASC/
βββ main.py # Full training + evaluation pipeline
βββ dataset.csv # Raw dataset (29,505 samples)
βββ README.md # This file
βββ output/ # All results, figures, and model checkpoints
























































































































