File size: 9,202 Bytes
e6c2e77
2965f7e
e6c2e77
 
 
 
2965f7e
e6c2e77
2965f7e
 
 
e6c2e77
2965f7e
 
 
e6c2e77
2965f7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
591a846
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2965f7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
---
library_name: transformers
tags:
- unsloth
---

# Finetuned Gemma 4 based Hate Detection in Arabic MultiModal Memes

The rise of social media and online communication platforms has led to the spread of Arabic memes as a key form of digital expression. 
While these contents can be humorous and informative, they are also increasingly being used to spread offensive language and hate speech.
Consequently, there is a growing demand for precise analysis of content in Arabic memes. 

This work used Gemma 4 with its vision capability to effectively identify hate content within Arabic memes.
The evaluation is conducted using a dataset of Arabic memes proposed in the ArabicNLP ArGuard 2026 challenge. 
The results underscore the capacity of ***unsloth/gemma-4-E4B-it fine-tuned with Arabic memes***, to deliver the superior performance. 


The proposed solutions offer a more nuanced understanding of memes for accurate and efficient Arabic content moderation systems.
 

# Examples of Arabic Memes from ArabicNLP ArGuard 2026 challenge

# Examples

| | | |
|:-------------------------:|:-------------------------:|:-------------------------:|
|<img width="500"  height="500" src="https://cdn-uploads.huggingface.co/production/uploads/656ee240c5ac4733e9ccdd0e/Id-NC6vel4bY5rqj8DKSg.png"> |<img width="500" height="500" src="https://cdn-uploads.huggingface.co/production/uploads/656ee240c5ac4733e9ccdd0e/kMkq_AqwbeUcuOvh_FjwG.png"> |  
|<img width="500"  height="500" src="https://cdn-uploads.huggingface.co/production/uploads/656ee240c5ac4733e9ccdd0e/7QUCyWPS6drmJJfG3FXBy.png"> |<img width="500" height="500" src="https://cdn-uploads.huggingface.co/production/uploads/656ee240c5ac4733e9ccdd0e/auyA0tmV4uQ6d19uNLRoz.png"> |
|<img width="500"  height="500" src="https://cdn-uploads.huggingface.co/production/uploads/656ee240c5ac4733e9ccdd0e/1qCrsho84Ds8C_xYV4M2z.png"> |<img width="500" height="500" src="https://cdn-uploads.huggingface.co/production/uploads/656ee240c5ac4733e9ccdd0e/Kuy_hqLY-rK07qJrY_l_W.png"> |



# Finetuned Gemma 4 Embedding Model with mean pooling

``` python


import os
import torch

# 1. Create a dummy pass-through decorator to replace torch.compile
def dummy_compile(fn=None, *args, **kwargs):
    if fn is None:
        return lambda x: x
    return fn

# 2. Patch torch.compile BEFORE unsloth imports
torch.compile = dummy_compile
os.environ["UNSLOTH_FUSED_FORWARD"] = "0"
os.environ["UNSLOTH_DISABLE_AUTO_UPDATES"] = "1"

# 3. Import Unsloth safely now
from unsloth import FastVisionModel

print("SUCCESS: Unsloth loaded smoothly without compiler errors!")


import numpy as np
import torch
import torch._dynamo
from tqdm import tqdm  # Progress bar library
from unsloth import FastVisionModel


from datasets import load_dataset

instruction = "classify meme into Hateful or Not"

def convert_to_conversation(sample):
    
    
    lis=[]
    lis.append({"type": "text", "text": sample["text"]})
    lis.append({"type": "image", "image": sample["image"]})
            
            
    conversation = [
        {
            "role": "system",
            "content": instruction,
        },
        {
            "role": "user",
            "content": lis,
        },
        {"role": "assistant", "content": [{"type": "text", "text": sample["label"]}]},
    ]
    return {"messages": conversation}
pass

dataset = load_dataset("QCRI/ArGuard-Task1",  split="train")

converted_dataset = [convert_to_conversation(sample) for sample in dataset]


# 2. Load your fine-tuned model and processor
model_path = "NYUAD-ComNets/Gemma4_meme_classification"
model, processor = FastVisionModel.from_pretrained(
    model_path,  device_map = {"": 0},
    load_in_4bit = True,token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
FastVisionModel.for_inference(model)

# Instruction context
instruction = "classify meme into Hateful or Not"

all_embeddings = []
labels_list = []  

num_iterations = len(converted_dataset)

print(f"Starting embedding extraction for {num_iterations} items...")

for idx in tqdm(range(num_iterations), desc="Extracting Embeddings"):
    try:
        sample = converted_dataset[idx]
        
        # Pull text, image, and ground-truth label
        sample_text = sample["messages"][1]["content"][0]["text"]
        sample_image = sample["messages"][1]["content"][1]["image"]
        sample_label = sample["messages"][2]["content"][0]["text"] # From training format

        # Setup multimodal conversation payload
        conversation = [
            {"role": "system", "content": instruction},
            {"role": "user", "content": [{"type": "text", "text": sample_text}, {"type": "image", "image": sample_image}]},
        ]

        # 4. Process inputs normally
        templated_text = processor.apply_chat_template(conversation, tokenize=False)
        inputs = processor(text=templated_text, images=sample_image, return_tensors="pt").to("cuda")

        # 5. Forward Pass
        with torch.no_grad():
            with torch.autocast(device_type="cuda", dtype=torch.bfloat16):
                outputs = model(**inputs, output_hidden_states=True, return_dict=True)

        # 6. Extract final layer and attention mask
        last_hidden_states = outputs.hidden_states[-1]  # [batch_size, seq_len, hidden_dim]
        attention_mask = inputs["attention_mask"]       # [batch_size, seq_len]

        # 7. Masked Mean Pooling (Ignores padding tokens entirely)
        input_mask_expanded = attention_mask.unsqueeze(-1).expand(last_hidden_states.size()).float()
        sum_embeddings = torch.sum(last_hidden_states * input_mask_expanded, dim=1)
        sum_mask = torch.clamp(input_mask_expanded.sum(dim=1), min=1e-9)
        
        all_embedding = (sum_embeddings / sum_mask).squeeze(0).float()
        
        all_embeddings.append(all_embedding.cpu().numpy())


        labels_list.append(sample_label)

    except Exception as e:
        print(f"\nSkipping row {idx} due to an error: {e}")
        continue


embedding_matrix = np.vstack(all_embeddings)

print("Final Concatenated Array Shape:", embedding_matrix.shape)

np.save("train_gemma4_mean_embeddings.npy", embedding_matrix)

```



# Finetuned Gemma 4 for Inference

``` python

import pandas as pd
import torch

from datasets import load_dataset
dataset = load_dataset("QCRI/ArGuard-Task1")

instruction = "Classify meme into Hateful or not"

def convert_to_conversation(sample):
    conversation = [
        {
            "role": "user",
            "content": [
                {"type": "text", "text": instruction},
                {"type": "text", "text": sample["text"]},
                {"type": "image", "image": sample["image"]},
            ],
        },
        {"role": "assistant", "content": [{"type": "text", "text": sample["label"]}]},
    ]
    return {"messages": conversation}
pass

converted_dataset_dev = [convert_to_conversation(sample) for sample in dataset['dev']]

from unsloth import FastVisionModel

model, processor = FastVisionModel.from_pretrained(
    model_name = "NYUAD-ComNets/Gemma4_meme_classification", # Load clean base
    load_in_4bit = True,
)

FastVisionModel.for_inference(model)

lis=[]
pred=[]

for k in range(len(converted_dataset_dev)):

        sample=converted_dataset_dev[k]['messages'][0]['content']
        
        messages = [
            {
                "role": "user",
                "content": [
                     {"type": "text", "text": sample[0]['text']},
                    {
                        "type": "text",
                        "text": sample[1]['text'],
                    },
                    {
                        "type": "image",
                        "image":sample[2]['image'].convert("RGB")
                    },
                ],
            },
        ]
        input_text = processor.apply_chat_template(messages, add_generation_prompt = True)
        inputs = processor(
            sample[2]['image'].convert("RGB"),
            input_text,
            add_special_tokens = False,
            return_tensors = "pt",
        ).to("cuda")
        
        from transformers import TextStreamer
        
        text_streamer = TextStreamer(processor.tokenizer, skip_prompt = True)
        result = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 4,
                           use_cache = True, temperature = 0.1, top_p = 0.95, top_k = 64)

        lab=dataset['dev'][k]['label']
    
        clean_result = result[result != 258880]
        res=processor.tokenizer.decode(clean_result, skip_special_tokens=True).split("model\n")[-1].strip()
        lis.append(lab)
        pred.append(res)
        d=pd.DataFrame({'lab':lis,'pred':pred})
        print(sum(d.lab==d.pred))

```


We used Low-Rank Adaptation (LoRA) as the Parameter-Efficient Fine-Tuning (PEFT) method for fine-tuning utilizing the unsloth framework.


# BibTeX entry and citation info

```
@misc{aldahoul,
      title={NYUAD at ArGuard Shared Task: Multimodal Embedding Models for
Detecting Arabic Hateful Memes and Unsafe Prompts}, 
      author={Nouar AlDahoul and Yasir Zaki},
      year={2026},
      eprint={},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={}, 
}


```