Multimodal hate speech detection on MMHS150K using CLIP image features, Twitter-RoBERTa, and gated cross-modal attention fusion. Addresses the documented failure mode where naive multimodal fusion underperforms text-only baselines. PyTorch · HuggingFace · LoRA · Streamlit.
0
stars
11
commits
Jupyter Notebook
primary language
May 18, 2026
updated
Parameter-efficient multimodal hate speech detection on MMHS150K with per-sample interpretability.
HateFusion is a gated cross-modal attention architecture that fuses CLIP ViT-B/16 (image), Twitter-RoBERTa (text), and a 9-dimensional structured-feature branch under PEFT LoRA constraints. It targets the documented failure mode in Gomez et al. 2019 where naive multimodal fusion underperforms text-only baselines on MMHS150K, and was developed through a systematic 11-notebook ablation spanning four fusion strategies × two LoRA capacities × two entropy weights × four IW-attention variants. The headline finding is a clean negative result: the ~ 0.74 AUC ceiling under PEFT is information-theoretically over-determined across 10+ runs, and the project's named contribution — context-conditioned identity-weighted cross-attention — is shown via bias-off ablation to contribute essentially zero to final predictions. The architectural plumbing introduced alongside the bias term (per-branch LayerNorm + centered VADER modulation) is what carries what modest gains exist over the gated baseline.
Matched-methodology test-set results across the four MVP 4 variants plus the bias-off ablation, all evaluated on lowercase preprocessing (n = 10,000 test samples / n_t2_valid = 8,411). 95 % bootstrap CIs from 1,000 resamples (seed 42). Source: outputs/diagnostic/mvp4_corrected_comparison.md.
| Variant | Test AUC [95 % CI] | F1m [95 % CI] | FPR | T2 NotHate F1 [95 % CI] | Gate (t / i / s, H) |
|---|---|---|---|---|---|
| MVP 4-lower (gated baseline) | 0.7358 [0.7253, 0.7456] | 0.6867 [0.6772, 0.6956] | 0.2921 | 0.2692 [0.2559, 0.2829] | 0.450 / 0.062 / 0.489, H = 0.845 |
| MVP 4-IW (NB 09) | 0.7359 [0.7258, 0.7459] | 0.6876 [0.6780, 0.6965] | 0.2857 | 0.3378 [0.3237, 0.3528] | 0.374 / 0.299 / 0.327, H = 1.073 |
| MVP 4-IW-CC (NB 09b) | 0.7340 [0.7241, 0.7437] | 0.6882 [0.6790, 0.6971] | 0.2981 | 0.5154 [0.5011, 0.5287] | 1.000 / 0.000 / 0.000, H = 0.000 |
| MVP 4-IW-CC-S (NB 09c) | 0.7359 [0.7256, 0.7458] | 0.6889 [0.6797, 0.6979] | 0.3011 | 0.5791 [0.5663, 0.5930] | 0.467 / 0.219 / 0.315, H = 1.029 |
| IW-CC-S-bias-off (λ_id = 0) | 0.7359 [0.7256, 0.7458] | 0.6888 [0.6796, 0.6979] | 0.3013 | 0.5789 [0.5661, 0.5930] | 0.467 / 0.219 / 0.315, H = 1.029 |

cardiffnlp/twitter-roberta-base-2022-154m for MMHS150K T1, this ceiling appears information-theoretic, not optimisation-limited.λ_id = 0 at inference) matches the full IW-CC-S to four decimal places on every aggregate metric and disagrees on 1 out of 10,000 test samples (Phase 3 § 6).outputs/diagnostic/nb08_vs_nb10_audit.md.The production architecture is MVP 4-IW-CC-S (NB 09c). Frozen MVP 2 components are shown in [F]; trainable components in [T].
Text input_ids ───► [F] Twitter-RoBERTa + Run-D LoRA (rank 32) ──► text_tokens (B, 128, 768)
└─► text_cls (B, 768)
Image pixel_values ─► [F] CLIP ViT-B/16 + MVP-2 LoRA ─► visual_projection_to_512 (768→512)
└─► image_projection (512→768) ──► img_768 (B, 768)
Struct 9 features ──► [T] Linear(9, 32) + ReLU + Dropout ─────────────────────────────► struct_embed (B, 32)
Cross-attention (image queries text tokens), trainable:
q = img_768.unsqueeze(1) ──► [T] IWCCSMultiheadAttention(num_heads=8) ─────► attn_out (B, 768)
│
logits = (Q@K^T)/√d_k + λ_id · identity_mask
· (1 + α · vader_neg_centered)
│
attended_img = [T] LayerNorm(img_768 + attn_out) (B, 768)
Gate input (per-branch LayerNorm, then concat):
[T] gate_ln_text(text_cls) ── [T] gate_ln_image(attended_img) ── [T] gate_ln_struct(struct_embed)
│
gate_logits ── [T] Linear(1568, 3) ──► softmax ──► gates (B, 3) = [g_text, g_image, g_struct]
Gated fusion in shared 256-d space:
fused = g_text · [T] proj_text(text_cls)
+ g_image · [T] proj_image(attended_img)
+ g_struct · [T] proj_struct(struct_embed) (B, 256)
│
[T] head_t1 (Linear→ReLU→Dropout→Linear) ──► logits_t1 (B, 1) ← binary hate
[T] head_t2 (Linear→ReLU→Dropout→Linear) ──► logits_t2 (B, 6) ← T2 multiclass
The identity-bias term λ_id · identity_mask · (1 + α · vader_neg_centered) was tested but shown via bias-off ablation to contribute negligibly to final predictions (Phase 3 § 6). The architectural improvements (per-branch LayerNorm + centered VADER modulation) are what carry the lift over MVP 4-IW. See Phase 2 § 16c for the architectural progression NB 09 → NB 09b → NB 09c and the post-hoc correction.
HateFusion/
├── notebooks/ 20 executed notebooks (data → modeling → analysis)
├── models/ Trained checkpoints (weights .pt/.safetensors not tracked)
├── data/processed/ Identity lexicon + per-sample analytical parquets
├── outputs/ Charts, tables, diagnostic reports
├── Reports/ Phase 1 / 2 / 3 reports + identity-lexicon docs
└── requirements.txt
Full project documentation lives in the three phase reports:
01_data_loading · 02_eda · 03_structured_features04_roberta_pretrain_kaggle (Twitter-RoBERTa warm-start) · 05d_rank32_lr3e4 (MVP 1 baseline, Run D) · 05_mvp1_rank64 (capacity ablation) · 06_mvp2_naive_fusion · 06_mvp2_rank64 · 07_mvp3_three_branch_fusion · 07_mvp3_rank64 · 08_mvp4_gated_fusion · 08_mvp4_rank64 · 08b_mvp4_entropy_ablation · 08_lower_mvp4_lowercase (auxiliary retrain for matched-methodology) · 09_mvp4_iw_attention · 09b_mvp4_iwcc_attention · 09c_mvp4_iwccs_attention10_per_sample_modality_analysis · 10_lower_per_sample_modality_analysis · 11_bias_analysisEach notebook is self-contained and re-runnable; see the relevant Phase report for findings and decisions locked at each step.
git clone https://github.com/devAbdelrahman-Elgewily/HateFusion.git
cd HateFusion
conda create -n hatefusion python=3.11
conda activate hatefusion
pip install -r requirements.txt
jupyter lab
Notebooks 01 → 11 form the pipeline; each notebook documents its inputs, hparams, and outputs in the first markdown cell.
The smaller text / tabular files (identity lexicon, MMHS150K split definitions, per-sample analytical parquets) are tracked in this repository. The two image datasets — MMHS150K (≈ 6 GB) and Hateful Memes (≈ 3 GB) — must be downloaded separately. See data/README.md for download instructions and the expected directory layout. The Cyberbullying Tweets dataset used for the Twitter-RoBERTa warm-start (NB 04) is downloadable from Kaggle and is not committed.
All experiments use seed 42 throughout (random, numpy, torch, torch.cuda). Official MMHS150K splits are used as-is — train 134,820 / val 4,999 / test 10,000 — for direct comparability with Gomez et al. 2019. Val and test are 50 / 50 hate-balanced by dataset design (Gomez 2019); train follows the natural ~ 22 % hate rate. Bootstrap CIs in all reports use 1,000 resamples with seed 42.
@misc{hatefusion2026,
title = {HateFusion: Multimodal Hate Speech Detection via Gated Cross-Modal Attention on MMHS150K},
author = {Abdelrahman Elgewily},
year = {2026},
url = {https://github.com/devAbdelrahman-Elgewily/HateFusion}
}
@inproceedings{gomez2020exploring,
title = {Exploring Hate Speech Detection in Multimodal Publications},
author = {Gomez, Raul and Gibert, Jaume and Gomez, Lluis and Karatzas, Dimosthenis},
booktitle = {WACV},
year = {2020}
}
@inproceedings{mathew2021hatexplain,
title = {HateXplain: A Benchmark Dataset for Explainable Hate Speech Detection},
author = {Mathew, Binny and Saha, Punyajoy and Yimam, Seid Muhie and Biemann, Chris and Goyal, Pawan and Mukherjee, Animesh},
booktitle = {AAAI},
year = {2021}
}
@inproceedings{hu2022lora,
title = {LoRA: Low-Rank Adaptation of Large Language Models},
author = {Hu, Edward J. and Shen, Yelong and Wallis, Phillip and Allen-Zhu, Zeyuan and Li, Yuanzhi and Wang, Shean and Wang, Lu and Chen, Weizhu},
booktitle = {ICLR},
year = {2022}
}
MIT — see LICENSE for details. Dataset usage is subject to the original dataset licenses; this codebase's MIT license does not grant rights to the underlying data.
11 commits
Jupyter Notebook
99.9%
Multimodal hate speech detection on MMHS150K using CLIP image features, Twitter-RoBERTa, and gated cross-modal attention fusion. Addresses the documented failure mode where naive multimodal fusion underperforms text-only baselines. PyTorch · HuggingFace · LoRA · Streamlit.
0
stars
11
commits
Jupyter Notebook
primary language
May 18, 2026
updated
Parameter-efficient multimodal hate speech detection on MMHS150K with per-sample interpretability.
HateFusion is a gated cross-modal attention architecture that fuses CLIP ViT-B/16 (image), Twitter-RoBERTa (text), and a 9-dimensional structured-feature branch under PEFT LoRA constraints. It targets the documented failure mode in Gomez et al. 2019 where naive multimodal fusion underperforms text-only baselines on MMHS150K, and was developed through a systematic 11-notebook ablation spanning four fusion strategies × two LoRA capacities × two entropy weights × four IW-attention variants. The headline finding is a clean negative result: the ~ 0.74 AUC ceiling under PEFT is information-theoretically over-determined across 10+ runs, and the project's named contribution — context-conditioned identity-weighted cross-attention — is shown via bias-off ablation to contribute essentially zero to final predictions. The architectural plumbing introduced alongside the bias term (per-branch LayerNorm + centered VADER modulation) is what carries what modest gains exist over the gated baseline.
Matched-methodology test-set results across the four MVP 4 variants plus the bias-off ablation, all evaluated on lowercase preprocessing (n = 10,000 test samples / n_t2_valid = 8,411). 95 % bootstrap CIs from 1,000 resamples (seed 42). Source: outputs/diagnostic/mvp4_corrected_comparison.md.
| Variant | Test AUC [95 % CI] | F1m [95 % CI] | FPR | T2 NotHate F1 [95 % CI] | Gate (t / i / s, H) |
|---|---|---|---|---|---|
| MVP 4-lower (gated baseline) | 0.7358 [0.7253, 0.7456] | 0.6867 [0.6772, 0.6956] | 0.2921 | 0.2692 [0.2559, 0.2829] | 0.450 / 0.062 / 0.489, H = 0.845 |
| MVP 4-IW (NB 09) | 0.7359 [0.7258, 0.7459] | 0.6876 [0.6780, 0.6965] | 0.2857 | 0.3378 [0.3237, 0.3528] | 0.374 / 0.299 / 0.327, H = 1.073 |
| MVP 4-IW-CC (NB 09b) | 0.7340 [0.7241, 0.7437] | 0.6882 [0.6790, 0.6971] | 0.2981 | 0.5154 [0.5011, 0.5287] | 1.000 / 0.000 / 0.000, H = 0.000 |
| MVP 4-IW-CC-S (NB 09c) | 0.7359 [0.7256, 0.7458] | 0.6889 [0.6797, 0.6979] | 0.3011 | 0.5791 [0.5663, 0.5930] | 0.467 / 0.219 / 0.315, H = 1.029 |
| IW-CC-S-bias-off (λ_id = 0) | 0.7359 [0.7256, 0.7458] | 0.6888 [0.6796, 0.6979] | 0.3013 | 0.5789 [0.5661, 0.5930] | 0.467 / 0.219 / 0.315, H = 1.029 |

cardiffnlp/twitter-roberta-base-2022-154m for MMHS150K T1, this ceiling appears information-theoretic, not optimisation-limited.λ_id = 0 at inference) matches the full IW-CC-S to four decimal places on every aggregate metric and disagrees on 1 out of 10,000 test samples (Phase 3 § 6).outputs/diagnostic/nb08_vs_nb10_audit.md.The production architecture is MVP 4-IW-CC-S (NB 09c). Frozen MVP 2 components are shown in [F]; trainable components in [T].
Text input_ids ───► [F] Twitter-RoBERTa + Run-D LoRA (rank 32) ──► text_tokens (B, 128, 768)
└─► text_cls (B, 768)
Image pixel_values ─► [F] CLIP ViT-B/16 + MVP-2 LoRA ─► visual_projection_to_512 (768→512)
└─► image_projection (512→768) ──► img_768 (B, 768)
Struct 9 features ──► [T] Linear(9, 32) + ReLU + Dropout ─────────────────────────────► struct_embed (B, 32)
Cross-attention (image queries text tokens), trainable:
q = img_768.unsqueeze(1) ──► [T] IWCCSMultiheadAttention(num_heads=8) ─────► attn_out (B, 768)
│
logits = (Q@K^T)/√d_k + λ_id · identity_mask
· (1 + α · vader_neg_centered)
│
attended_img = [T] LayerNorm(img_768 + attn_out) (B, 768)
Gate input (per-branch LayerNorm, then concat):
[T] gate_ln_text(text_cls) ── [T] gate_ln_image(attended_img) ── [T] gate_ln_struct(struct_embed)
│
gate_logits ── [T] Linear(1568, 3) ──► softmax ──► gates (B, 3) = [g_text, g_image, g_struct]
Gated fusion in shared 256-d space:
fused = g_text · [T] proj_text(text_cls)
+ g_image · [T] proj_image(attended_img)
+ g_struct · [T] proj_struct(struct_embed) (B, 256)
│
[T] head_t1 (Linear→ReLU→Dropout→Linear) ──► logits_t1 (B, 1) ← binary hate
[T] head_t2 (Linear→ReLU→Dropout→Linear) ──► logits_t2 (B, 6) ← T2 multiclass
The identity-bias term λ_id · identity_mask · (1 + α · vader_neg_centered) was tested but shown via bias-off ablation to contribute negligibly to final predictions (Phase 3 § 6). The architectural improvements (per-branch LayerNorm + centered VADER modulation) are what carry the lift over MVP 4-IW. See Phase 2 § 16c for the architectural progression NB 09 → NB 09b → NB 09c and the post-hoc correction.
HateFusion/
├── notebooks/ 20 executed notebooks (data → modeling → analysis)
├── models/ Trained checkpoints (weights .pt/.safetensors not tracked)
├── data/processed/ Identity lexicon + per-sample analytical parquets
├── outputs/ Charts, tables, diagnostic reports
├── Reports/ Phase 1 / 2 / 3 reports + identity-lexicon docs
└── requirements.txt
Full project documentation lives in the three phase reports:
01_data_loading · 02_eda · 03_structured_features04_roberta_pretrain_kaggle (Twitter-RoBERTa warm-start) · 05d_rank32_lr3e4 (MVP 1 baseline, Run D) · 05_mvp1_rank64 (capacity ablation) · 06_mvp2_naive_fusion · 06_mvp2_rank64 · 07_mvp3_three_branch_fusion · 07_mvp3_rank64 · 08_mvp4_gated_fusion · 08_mvp4_rank64 · 08b_mvp4_entropy_ablation · 08_lower_mvp4_lowercase (auxiliary retrain for matched-methodology) · 09_mvp4_iw_attention · 09b_mvp4_iwcc_attention · 09c_mvp4_iwccs_attention10_per_sample_modality_analysis · 10_lower_per_sample_modality_analysis · 11_bias_analysisEach notebook is self-contained and re-runnable; see the relevant Phase report for findings and decisions locked at each step.
git clone https://github.com/devAbdelrahman-Elgewily/HateFusion.git
cd HateFusion
conda create -n hatefusion python=3.11
conda activate hatefusion
pip install -r requirements.txt
jupyter lab
Notebooks 01 → 11 form the pipeline; each notebook documents its inputs, hparams, and outputs in the first markdown cell.
The smaller text / tabular files (identity lexicon, MMHS150K split definitions, per-sample analytical parquets) are tracked in this repository. The two image datasets — MMHS150K (≈ 6 GB) and Hateful Memes (≈ 3 GB) — must be downloaded separately. See data/README.md for download instructions and the expected directory layout. The Cyberbullying Tweets dataset used for the Twitter-RoBERTa warm-start (NB 04) is downloadable from Kaggle and is not committed.
All experiments use seed 42 throughout (random, numpy, torch, torch.cuda). Official MMHS150K splits are used as-is — train 134,820 / val 4,999 / test 10,000 — for direct comparability with Gomez et al. 2019. Val and test are 50 / 50 hate-balanced by dataset design (Gomez 2019); train follows the natural ~ 22 % hate rate. Bootstrap CIs in all reports use 1,000 resamples with seed 42.
@misc{hatefusion2026,
title = {HateFusion: Multimodal Hate Speech Detection via Gated Cross-Modal Attention on MMHS150K},
author = {Abdelrahman Elgewily},
year = {2026},
url = {https://github.com/devAbdelrahman-Elgewily/HateFusion}
}
@inproceedings{gomez2020exploring,
title = {Exploring Hate Speech Detection in Multimodal Publications},
author = {Gomez, Raul and Gibert, Jaume and Gomez, Lluis and Karatzas, Dimosthenis},
booktitle = {WACV},
year = {2020}
}
@inproceedings{mathew2021hatexplain,
title = {HateXplain: A Benchmark Dataset for Explainable Hate Speech Detection},
author = {Mathew, Binny and Saha, Punyajoy and Yimam, Seid Muhie and Biemann, Chris and Goyal, Pawan and Mukherjee, Animesh},
booktitle = {AAAI},
year = {2021}
}
@inproceedings{hu2022lora,
title = {LoRA: Low-Rank Adaptation of Large Language Models},
author = {Hu, Edward J. and Shen, Yelong and Wallis, Phillip and Allen-Zhu, Zeyuan and Li, Yuanzhi and Wang, Shean and Wang, Lu and Chen, Weizhu},
booktitle = {ICLR},
year = {2022}
}
MIT — see LICENSE for details. Dataset usage is subject to the original dataset licenses; this codebase's MIT license does not grant rights to the underlying data.
11 commits
Jupyter Notebook
99.9%