File size: 4,589 Bytes
a24fd1f
 
 
 
 
 
 
047e1d3
 
a24fd1f
047e1d3
 
 
 
 
 
 
 
a24fd1f
 
 
047e1d3
a24fd1f
047e1d3
 
a24fd1f
 
 
 
 
 
4fc952c
 
 
a24fd1f
 
 
e552f33
047e1d3
4fc952c
a24fd1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4fc952c
 
 
 
 
 
 
 
 
 
 
 
 
a24fd1f
047e1d3
a24fd1f
4fc952c
 
 
 
 
 
 
 
 
 
 
 
a24fd1f
0cff5cc
a24fd1f
047e1d3
 
 
 
a24fd1f
 
 
 
 
 
 
 
 
 
 
047e1d3
 
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
---
license: mit
language:
- ar
pipeline_tag: text-generation
tags:
- Arabic_Dialectal_Lemmatization
---

# Gulf-S2S-lemmatizer

# Model Description

The model is developed for Arabic dialect lemmatization, focusing on Gulf (GLF) Arabic. It follows a sequence-to-sequence formulation of lemmatization, where the model generates the lemma of a given word knowing 2 words before and 2 words after the current word rather than treating lemmas as fixed classification labels.

The model is evaluated using lemma accuracy as the main metric, with an additional normalized lemma accuracy metric that accounts for orthographic and diacritic variation. The full methodology, training setup, hyperparameters, and evaluation results are described in our paper [“Lemmatizing Dialectal Arabic with Sequence-to-Sequence Models”](https://aclanthology.org/2025.arabicnlp-main.10/)


# Standalone Usage



The model can also be used independently without the full lemmatization workflow on the GitHub repository (https://github.com/CAMeL-Lab/seq2seq-arabic-dialect-lemmatization). In this case, the input should contain the target word surrounded by the special token `<target>`, with up to two words before and two words after the target word.


```python
import re
import math
import pandas as pd
import torch
from tqdm import tqdm
from tqdm.auto import tqdm
tqdm.pandas()

from transformers import T5Tokenizer, T5ForConditionalGeneration

DIALECT_MODELS = {
    "glf": "CAMeL-Lab/GLF-S2S-lemmatizer",
}

def load_model(s2s_dialect: str):
    model_name = DIALECT_MODELS[s2s_dialect]
    tokenizer = T5Tokenizer.from_pretrained(model_name, use_fast=True, legacy=False)
    model = T5ForConditionalGeneration.from_pretrained(model_name)
    tokenizer.add_special_tokens({"additional_special_tokens": ["<target>"]})
    model.resize_token_embeddings(len(tokenizer))
    return tokenizer, model

def predict(tokenizer, model, texts: list[str], device=None, batch_size: int = 16) -> list[str]:
    if device is None:
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model.to(device).eval()
    all_preds = []
    total_batches = math.ceil(len(texts) / batch_size)
    for i in tqdm(range(0, len(texts), batch_size), total=total_batches, desc="Predicting"):
        batch = texts[i:i + batch_size]
        enc = tokenizer(
            batch,
            return_tensors="pt",
            padding=True,
            truncation=True,
            max_length=64
        )
        enc = {k: v.to(device) for k, v in enc.items()}
        with torch.no_grad():
            out = model.generate(
                **enc,
                max_length=50,
                num_beams=1,
                do_sample=False
            )
        all_preds.extend(tokenizer.batch_decode(out, skip_special_tokens=True))
    return all_preds

def get_context_window_fast(sentence_index, word_index, window_size=2):
    words, indices = sentence_lookup[sentence_index]
    target_pos = indices.index(word_index)

    start_idx = max(0, target_pos - window_size)
    end_idx = min(len(words), target_pos + window_size + 1)
    context_words = words[start_idx:end_idx][:]
    target_word_idx = target_pos - start_idx
    context_words[target_word_idx] = f"<target>{context_words[target_word_idx]}<target>"

    return f"lemmatize: {' '.join(context_words)}"


# df should contain an input_text column with the target word marked using <target>
# Example input: "أنا أبي <target>أروح<target> البيت الحين"

# Sort df by sentence_index and word_index
df = df.sort_values(by=["sentence_index", "word_index"])

# Build a lookup dict: {sentence_index: (words_list, indices_list)}
sentence_lookup = {
    sid: (group['word'].astype(str).tolist(), group['word_index'].tolist())
    for sid, group in df.sort_values('word_index').groupby('sentence_index')
}

df['input_text'] = df.progress_apply(
    lambda row: get_context_window_fast(row['sentence_index'], row['word_index']), axis=1
)

tokenizer, model = load_model("glf")
df["predicted_lex"] = predict(tokenizer, model, df["input_text"].tolist())
```

## 📖 Citation

If you use this model in your research, please cite the following paper:

```bibtex
@inproceedings{saeed-habash-2025-lemmatizing,
    title = {Lemmatizing Dialectal Arabic with Sequence-to-Sequence Models},
    author = {Saeed, Mostafa and Habash, Nizar},
    booktitle = {Proceedings of the Third Arabic Natural Language Processing Conference},
    year = {2025},
    address = {Suzhou, China},
    url = {https://aclanthology.org/2025.arabicnlp-main.10/}
}
```