SigLIP2-Base Fusion Model for Multi-Modal Hate Speech Detection
PyTorch
Transformers
License
Dataset
A PyTorch-based multi-modal (image + text) hateful content classification model using SigLIP2 encoder with late fusion architecture, trained on the MMHS150K dataset for detecting hate speech in social media memes and posts.
🎯 Model Description
This model implements a late fusion architecture with gated attention mechanism for detecting hateful content in social media memes and posts. It combines visual and textual features using Google's SigLIP2 (Base-Patch16-224) as the backbone encoder.
The model performs multi-label classification across 5 hate speech categories, making it capable of detecting multiple types of hate in a single post (e.g., content that is both racist and sexist).
🏗️ Architecture
┌─────────────┐ ┌─────────────┐
│ Image │ │ Text │
│ Encoder │ │ Encoder │
│ (SigLIP2) │ │ (SigLIP2) │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Projection │ │ Projection │
│ (Linear) │ │ (Linear) │
└──────┬──────┘ └──────┬──────┘
│ │
└─────────┬─────────┘
│
▼
┌─────────────┐
│ Gated Fusion│◄── Modality presence flags
│ Module │ (handles missing modalities)
└──────┬──────┘
│
▼
┌───────────────────────┐
│ Interaction Features │
│ • Fused embedding │
│ • Text embedding │
│ • Visual embedding │
│ • |text - visual| │
│ • text ⊙ visual │
└───────────┬───────────┘
│
▼
┌─────────────┐
│Classification│
│ Head (MLP) │
│ → 5 classes │
└─────────────┘
🔑 Key Features
Feature Description Backbone google/siglip2-base-patch16-224 - Pre-trained SigLIP2 modelFusion Dimension 512 Max Text Length 64 tokens Multi-label Output 5 hate speech categories Gated Attention Modality-aware fusion with learnable gates Interaction Features Rich feature interactions (concatenation, element-wise product, absolute difference) Missing Modality Handling Can handle text-only or image-only inputs
🏷️ Output Classes
Index Class Description Dataset Prevalence 0 Racist Racist content targeting race/ethnicity 32.6% 1 Sexist Sexist content targeting gender 12.0% 2 Homophobe Homophobic content targeting sexual orientation 7.6% 3 Religion Religion-based hate speech 1.5% 4 OtherHate Other types of hate speech 15.6%
📊 Evaluation Results
Test Set Performance
Metric Score F1 Macro 0.507 F1 Micro 0.610 ROC-AUC Macro 0.774 Test Loss 1.530 Throughput 236.3 samples/sec
Per-Class Performance (Validation Set)
Class Precision Recall F1-Score Support Racist 0.534 0.874 0.663 1,994 Sexist 0.620 0.585 0.602 875 Homophobe 0.818 0.632 0.713 612 Religion 0.118 0.140 0.128 129 OtherHate 0.479 0.707 0.571 1,195 Micro Avg 0.541 0.729 0.621 4,805 Macro Avg 0.514 0.588 0.535 4,805
⚙️ Optimized Thresholds
The model uses per-class calibrated thresholds for optimal performance (instead of default 0.5):
Class Threshold Racist 0.30 Sexist 0.75 Homophobe 0.85 Religion 0.20 OtherHate 0.55
📈 Model Comparison
Model F1 Macro F1 Micro ROC-AUC Throughput CLIP Fusion 0.566 0.635 0.783 381.5 CLIP MTL 0.569 0.644 0.783 390.9 SigLIP Fusion (this model) 0.507 0.610 0.774 236.3 CLIP Fusion (Weighted Sampling) 0.557 0.636 0.772 266.4 CLIP Fusion (Bigger Batch) 0.515 0.517 0.804 400.9
🎓 Training Data
MMHS150K Dataset
The model was trained on the MMHS150K (Multi-Modal Hate Speech) dataset, a large-scale multi-modal hate speech dataset collected from Twitter containing 150,000 tweet-image pairs annotated for hate speech detection.
Attribute Value Source Twitter Total Samples ~150,000 Modalities Image + Text Annotation Multi-label (5 hate categories) Language English
Dataset Splits
Split Samples Train ~112,500 Validation ~15,000 Test ~22,500
Dataset Reference
Paper:
"Exploring Hate Speech Detection in Multimodal Publications" (WACV 2020)
Authors: Raul Gomez, Jaume Gibert, Lluis Gomez, Dimosthenis Karatzas
🔧 Training Procedure
Training Configuration
1 # Model Configuration
2 backend : siglip
3 head : fusion
4 encoder_name : google/siglip2 - base - patch16 - 224
5 fusion_dim : 512
6 max_text_length : 64
7 freeze_text : false
8 freeze_image : false
9
10 # Training Configuration
11 num_train_epochs : 6
12 per_device_train_batch_size : 32
13 per_device_eval_batch_size : 64
14 gradient_accumulation_steps : 2
15
16 # Learning Rates (Differential)
17 lr_encoder : 1.0e-5
18 lr_head : 5.0e-4
19
20 # Regularization
21 weight_decay : 0.02
22 max_grad_norm : 1.0
23
24 # Scheduler
25 warmup_ratio : 0.05
26 lr_scheduler_type : cosine
27
28 # Loss
29 loss_type : bce
30 use_logit_adjustment : false
31
32 # Precision
33 precision : fp16
34
35 # Data Augmentation
36 augment : true
37 aug_scale_min : 0.8
38 aug_scale_max : 1.0
39 horizontal_flip : true
40 color_jitter : true
41
42 # Early Stopping
43 early_stopping_patience : 3
44 metric_for_best_model : roc_macro
Training Highlights
Differential Learning Rates : Encoder (1e-5) vs Classification Head (5e-4)
Mixed Precision : FP16 training for efficiency
Data Augmentation : Random scaling, horizontal flip, color jitter
Threshold Calibration : Per-class threshold optimization on validation set
Early Stopping : Patience of 3 epochs based on ROC-AUC macro
Best Checkpoint : Selected based on validation ROC-AUC macro score
Computational Resources
Training Time : ~6 epochs
Best Checkpoint : Step 30,000
Hardware : GPU with FP16 support
🚀 How to Use
Installation
1 # Clone the training repository
2 git clone https://github.com/amirhossein-yousefi/multimodal-content-moderation.git
3 cd multimodal-content-moderation
4
5 # Create virtual environment
6 python -m venv venv
7 source venv/bin/activate # On Windows: venv\Scripts\activate
8
9 # Install dependencies
10 pip install -r requirements.txt
11 pip install -e .
Quick Inference with trust_remote_code
1 from transformers import AutoModel , AutoProcessor
2 from PIL import Image
3 import torch
4
5 # Load model with trust_remote_code
6 model = AutoModel . from_pretrained (
7 "Amirhossein75/siglip2-base-mmhs150k-fusion" ,
8 trust_remote_code = True
9 )
10 processor = AutoProcessor . from_pretrained ( "google/siglip2-base-patch16-224" )
11
12 # Prepare inputs
13 image = Image . open ( "path/to/image.jpg" )
14 text = "sample text from the meme"
15
16 inputs = processor (
17 text = [ text ] ,
18 images = [ image ] ,
19 return_tensors = "pt" ,
20 padding = True ,
21 truncation = True
22 )
23
24 # Inference
25 model . eval ( )
26 with torch . no_grad ( ) :
27 outputs = model ( ** inputs )
28 probabilities = torch . sigmoid ( outputs [ "logits" ] )
29
30 # Apply optimized thresholds
31 thresholds = torch . tensor ( [ 0.30 , 0.75 , 0.85 , 0.20 , 0.55 ] )
32 predictions = ( probabilities > thresholds ) . int ( )
33
34 class_names = [ "racist" , "sexist" , "homophobe" , "religion" , "otherhate" ]
35 for i , name in enumerate ( class_names ) :
36 print ( f" { name } : { bool ( predictions [ 0 , i ] ) } (prob: { probabilities [ 0 , i ] : .3f } )" )
Using the predict() Method
1 from transformers import AutoModel , AutoProcessor
2 from PIL import Image
3 import torch
4
5 # Load model
6 model = AutoModel . from_pretrained (
7 "Amirhossein75/siglip2-base-mmhs150k-fusion" ,
8 trust_remote_code = True
9 )
10 processor = AutoProcessor . from_pretrained ( "google/siglip2-base-patch16-224" )
11
12 # Prepare inputs
13 image = Image . open ( "path/to/image.jpg" )
14 text = "sample text from the meme"
15
16 inputs = processor (
17 text = [ text ] ,
18 images = [ image ] ,
19 return_tensors = "pt" ,
20 padding = True ,
21 truncation = True
22 )
23
24 # Use built-in predict method with calibrated thresholds
25 result = model . predict ( ** inputs )
26
27 print ( result )
28 # {'predictions': {'racist': False, 'sexist': True, 'homophobe': False, 'religion': False, 'otherhate': False},
29 # 'probabilities': {'racist': 0.12, 'sexist': 0.78, ...}}
Batch Inference
1 import torch
2 from PIL import Image
3 from transformers import AutoModel , AutoProcessor
4
5 # Load model
6 model = AutoModel . from_pretrained (
7 "Amirhossein75/siglip2-base-mmhs150k-fusion" ,
8 trust_remote_code = True
9 )
10 processor = AutoProcessor . from_pretrained ( "google/siglip2-base-patch16-224" )
11
12 # Prepare batch
13 images = [ Image . open ( "image1.jpg" ) , Image . open ( "image2.jpg" ) ]
14 texts = [ "text for image 1" , "text for image 2" ]
15
16 inputs = processor (
17 text = texts ,
18 images = images ,
19 return_tensors = "pt" ,
20 padding = True ,
21 truncation = True
22 )
23
24 # Inference
25 with torch . no_grad ( ) :
26 outputs = model ( ** inputs )
27 probabilities = torch . sigmoid ( outputs [ "logits" ] )
28
29 # Apply optimized thresholds
30 thresholds = torch . tensor ( [ 0.30 , 0.75 , 0.85 , 0.20 , 0.55 ] )
31 predictions = ( probabilities > thresholds ) . int ( )
Using with Hugging Face Pipeline (Custom)
1 from huggingface_hub import hf_hub_download
2 import json
3
4 # Download config
5 config_path = hf_hub_download (
6 repo_id = "Amirhossein75/siglip2-base-mmhs150k-fusion" ,
7 filename = "inference_config.json"
8 )
9
10 with open ( config_path ) as f :
11 config = json . load ( f )
12
13 print ( f"Classes: { config [ 'class_names' ] } " )
14 print ( f"Thresholds: { config [ 'thresholds' ] } " )
📁 Model Files
File Description model.safetensorsModel weights in safetensors format config.jsonModel architecture configuration modeling_siglip_fusion.pyCustom model class for trust_remote_code inference_config.jsonInference settings with thresholds and class names label_map.jsonLabel name mapping test_metrics.jsonTest set evaluation metrics val_report.jsonDetailed validation classification report
☁️ AWS SageMaker Deployment
This model is compatible with AWS SageMaker for cloud deployment:
1 from sagemaker . pytorch import PyTorchModel
2 from sagemaker . serializers import JSONSerializer
3 from sagemaker . deserializers import JSONDeserializer
4
5 model = PyTorchModel (
6 model_data = "s3://your-bucket/model.tar.gz" ,
7 role = role ,
8 entry_point = 'inference.py' ,
9 source_dir = 'sagemaker' ,
10 framework_version = '2.1.0' ,
11 py_version = 'py310' ,
12 )
13
14 predictor = model . deploy (
15 instance_type = 'ml.g4dn.xlarge' ,
16 initial_instance_count = 1 ,
17 )
18
19 # Make prediction
20 import base64
21 with open ( 'image.jpg' , 'rb' ) as f :
22 image_b64 = base64 . b64encode ( f . read ( ) ) . decode ( 'utf-8' )
23
24 response = predictor . predict ( {
25 'instances' : [ {
26 'text' : 'Sample text content' ,
27 'image_base64' : image_b64 ,
28 } ]
29 } )
See the
SageMaker documentation for full deployment guide.
⚠️ Intended Uses & Limitations
✅ Intended Uses
Content moderation for social media platforms
Detecting hateful memes and posts
Research in multi-modal hate speech detection
Building content safety systems
Pre-filtering potentially harmful content for human review
⚠️ Limitations
Limitation Description Language Trained only on English content Domain Twitter-specific; may not generalize to other platforms Class Imbalance Lower performance on rare categories (Religion: F1=0.128) Cultural Context May miss culturally-specific hate speech Sarcasm/Irony May struggle with subtle or ironic hateful content Image-only Hate Text encoder is important; purely visual hate may be missed
❌ Out-of-Scope Uses
NOT for making final moderation decisions without human review
NOT suitable for legal or compliance purposes without additional validation
NOT for censorship or suppression of legitimate speech
NOT for targeting or profiling individuals
🛡️ Ethical Considerations
This model should be used as a tool to assist human moderators, not replace them
False positives may incorrectly flag legitimate content
False negatives may miss harmful content
Regular evaluation and bias auditing is recommended
Consider the cultural and contextual factors in deployment
📝 Citation
If you use this model, please cite:
1 @misc{yousefi2024multimodal,
2 title={Multi-Modal Hateful Content Classification with SigLIP2 Fusion},
3 author={Yousefi, Amirhossein},
4 year={2024},
5 publisher={Hugging Face},
6 url={https://huggingface.co/Amirhossein75/siglip2-base-mmhs150k-fusion}
7 }
Dataset Citation
1 @inproceedings{gomez2020exploring,
2 title={Exploring Hate Speech Detection in Multimodal Publications},
3 author={Gomez, Raul and Gibert, Jaume and Gomez, Lluis and Karatzas, Dimosthenis},
4 booktitle={Proceedings of the IEEE/CVF Winter Conference on Applications of Computer Vision (WACV)},
5 pages={1470--1478},
6 year={2020}
7 }
SigLIP Citation
1 @article{zhai2023sigmoid,
2 title={Sigmoid Loss for Language Image Pre-Training},
3 author={Zhai, Xiaohua and Mustafa, Basil and Kolesnikov, Alexander and Beyer, Lucas},
4 journal={arXiv preprint arXiv:2303.15343},
5 year={2023}
6 }
🔗 Links
📄 License
This project is licensed under the MIT License - see the
LICENSE file for details.
🤝 Contributing
Contributions are welcome! Please see the
GitHub repository for contribution guidelines.