A fun little experiment comparing different approaches to detect hate speech in Bahasa Indonesia. Just trying out a few combos and seeing what sticks.
Basically, I wanted to see how these things compare against each other:
| Split | Size |
|---|---|
| Train | ~12k samples |
| Test | ~3k samples |
Labels used: 0 = Non_HS and 1 = HS (hate speech).
Dataset source: Indonesian hate speech superset
Light preprocessing — minimal cleaning, keeping things as natural as possible:
Heavy preprocessing — more aggressive, almost "traditional NLP" style:
| Model | Preprocessing | Accuracy | Macro F1 | HS F1 |
|---|---|---|---|---|
| IndoBERT (fine-tune) | Light | 0.8988 | 0.8966 | 0.8816 |
| IndoBERT (fine-tune) | Heavy | 0.8762 | 0.8729 | 0.8527 |
| SVM + IndoBERT Embedding | Light | 0.8266 | 0.8214 | 0.7910 |
| SVM + IndoBERT Embedding | Heavy | 0.8116 | 0.8056 | 0.7714 |
| XLM-RoBERTa | Light | 0.8845 | 0.8814 | 0.8624 |
*XLM-RoBERTa was trained with a smaller batch size + gradient accumulation because my GPU ran out of memory. So the result might not be perfectly comparable.
1. IndoBERT wins
Fine-tuning IndoBERT with light preprocessing gave the best numbers overall. Not super surprising — it was pretrained specifically on Indonesian text, so it naturally picks up on local language patterns, slang, and context better than multilingual models.
2. Heavy preprocessing actually hurts transformers
Normally in classic NLP, more cleaning helps. But transformers really depend on context. Stripping out stopwords and stemming words removes a lot of subtle signals the model would've used. Less is more here.
3. SVM + embeddings is solid, but not a replacement
Using IndoBERT just as an embedding extractor and throwing an classic SVM on top still got decent results (~82% accuracy). It's a lighter approach and could work well in minimum-resource setups — but you do lose a few percent in performance compared to full fine-tuning.
4. Multilingual models are close
XLM-RoBERTa performed really well! But it still fell slightly short of IndoBERT. Makes sense — when a model is trained on 100+ languages, it can't go as deep on any single one.
Fine-tune IndoBERT with light preprocessing.
1. Clone the repo
git clone https://github.com/your-repo/indo-hate-speech-classification
cd indo-hate-speech-classification
2. Set up a Python environment
python -m venv .venv
source .venv/bin/activate
3. Install dependencies
pip install -r requirements.txt
Main libraries used: transformers, datasets, torch, scikit-learn, pandas
4. Start training
python app/train.py
Trained artifacts will be saved to:
artifacts/model/artifacts/svm/svm.joblibWant to swap models? Just change the model constant in
app/train.pyand you're good to go.
4. Run prediction CLI
python app/prediction_cli.py
Run this to if you're curious your sentence counts as hate speech or not. It loads the saved model and lets you type a sentence to test it out.
Nothing crazy — this should run fine on any mid-range gaming PC with a decent GPU.
A few things I want to try when I get the time:
MIT — do whatever you want with it. :D
2 commits
Python
100.0%
A fun little experiment comparing different approaches to detect hate speech in Bahasa Indonesia. Just trying out a few combos and seeing what sticks.
Basically, I wanted to see how these things compare against each other:
| Split | Size |
|---|---|
| Train | ~12k samples |
| Test | ~3k samples |
Labels used: 0 = Non_HS and 1 = HS (hate speech).
Dataset source: Indonesian hate speech superset
Light preprocessing — minimal cleaning, keeping things as natural as possible:
Heavy preprocessing — more aggressive, almost "traditional NLP" style:
| Model | Preprocessing | Accuracy | Macro F1 | HS F1 |
|---|---|---|---|---|
| IndoBERT (fine-tune) | Light | 0.8988 | 0.8966 | 0.8816 |
| IndoBERT (fine-tune) | Heavy | 0.8762 | 0.8729 | 0.8527 |
| SVM + IndoBERT Embedding | Light | 0.8266 | 0.8214 | 0.7910 |
| SVM + IndoBERT Embedding | Heavy | 0.8116 | 0.8056 | 0.7714 |
| XLM-RoBERTa | Light | 0.8845 | 0.8814 | 0.8624 |
*XLM-RoBERTa was trained with a smaller batch size + gradient accumulation because my GPU ran out of memory. So the result might not be perfectly comparable.
1. IndoBERT wins
Fine-tuning IndoBERT with light preprocessing gave the best numbers overall. Not super surprising — it was pretrained specifically on Indonesian text, so it naturally picks up on local language patterns, slang, and context better than multilingual models.
2. Heavy preprocessing actually hurts transformers
Normally in classic NLP, more cleaning helps. But transformers really depend on context. Stripping out stopwords and stemming words removes a lot of subtle signals the model would've used. Less is more here.
3. SVM + embeddings is solid, but not a replacement
Using IndoBERT just as an embedding extractor and throwing an classic SVM on top still got decent results (~82% accuracy). It's a lighter approach and could work well in minimum-resource setups — but you do lose a few percent in performance compared to full fine-tuning.
4. Multilingual models are close
XLM-RoBERTa performed really well! But it still fell slightly short of IndoBERT. Makes sense — when a model is trained on 100+ languages, it can't go as deep on any single one.
Fine-tune IndoBERT with light preprocessing.
1. Clone the repo
git clone https://github.com/your-repo/indo-hate-speech-classification
cd indo-hate-speech-classification
2. Set up a Python environment
python -m venv .venv
source .venv/bin/activate
3. Install dependencies
pip install -r requirements.txt
Main libraries used: transformers, datasets, torch, scikit-learn, pandas
4. Start training
python app/train.py
Trained artifacts will be saved to:
artifacts/model/artifacts/svm/svm.joblibWant to swap models? Just change the model constant in
app/train.pyand you're good to go.
4. Run prediction CLI
python app/prediction_cli.py
Run this to if you're curious your sentence counts as hate speech or not. It loads the saved model and lets you type a sentence to test it out.
Nothing crazy — this should run fine on any mid-range gaming PC with a decent GPU.
A few things I want to try when I get the time:
MIT — do whatever you want with it. :D
2 commits
Python
100.0%