File size: 7,507 Bytes
ba659db 228ef6a ba659db 228ef6a ba659db 228ef6a | 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 | ---
language:
- so
license: apache-2.0
tags:
- summarization
- headline-generation
- text2text-generation
- somali
- t5
- afriteva
datasets:
- custom
metrics:
- rouge
- sacrebleu
- meteor
- bertscore
pipeline_tag: summarization
---
# Somali Headline Generation (Fine-tuned AfriTeVa v2)
This model generates short, natural Somali news **headlines** from full **article text**. It is a fine-tuned version of [AfriTeVa v2](https://huggingface.co/castorini/afriteva_v2_base), a T5-style sequence-to-sequence model pretrained on African languages, adapted here specifically for Somali headline generation.
## Model Description
- **Base model:** AfriTeVa v2 (T5-style, SentencePiece tokenizer)
- **Task:** Abstractive headline generation (text2text-generation)
- **Language:** Somali (`so`)
- **Input:** A Somali news article (plain text)
- **Output:** A short, cleaned headline summarizing the article
The model was fine-tuned on a dataset of Somali news articles paired with their original headlines, and evaluated using ROUGE, SacreBLEU, METEOR, and BERTScore.
## Intended Uses & Limitations
**Intended uses:**
- Automatic headline suggestion for Somali news articles
- Research on low-resource language summarization/generation
- Educational and non-commercial NLP experimentation
**Limitations:**
- Trained on a specific news domain/style; may not generalize well to other domains (e.g., opinion pieces, social media text)
- May occasionally produce generic or repetitive headlines for very long or unusual articles
- Not intended for use in high-stakes or safety-critical decision-making
- Output quality depends on input article length and clarity; performs best on articles under ~300 tokens (the model's max source length)
## How to Use
### Installation
```bash
pip install transformers torch evaluate sentencepiece
```
### Quick Start
```python
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM, T5Tokenizer
import torch
MODEL_NAME = "your-username/your-model-name" # replace with the actual repo id
# Load tokenizer (SentencePiece preferred; falls back to AutoTokenizer)
try:
tokenizer = T5Tokenizer.from_pretrained(MODEL_NAME, use_fast=False)
except Exception:
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=True)
if tokenizer.pad_token is None and tokenizer.eos_token is not None:
tokenizer.pad_token = tokenizer.eos_token
# Load model
model = AutoModelForSeq2SeqLM.from_pretrained(MODEL_NAME)
model.config.pad_token_id = tokenizer.pad_token_id
model.config.eos_token_id = tokenizer.eos_token_id
if model.config.decoder_start_token_id is None:
model.config.decoder_start_token_id = tokenizer.pad_token_id
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device).eval()
# Prepare input
article = "Halkan geli qoraalka maqaalkaaga Soomaaliga ah..."
input_text = "headline: " + article
inputs = tokenizer(
input_text,
return_tensors="pt",
truncation=True,
max_length=300,
).to(device)
# Generate
with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=30,
min_new_tokens=4,
num_beams=4,
no_repeat_ngram_size=3,
length_penalty=1.3,
repetition_penalty=1.15,
pad_token_id=tokenizer.pad_token_id,
eos_token_id=tokenizer.eos_token_id,
)
headline = tokenizer.decode(output_ids[0], skip_special_tokens=True)
print(headline)
```
### Recommended Post-Processing
Raw model output can sometimes contain trailing boilerplate (e.g., source website names, "akhriso", "daawo", stray URLs). We recommend applying a light cleanup step before displaying the headline to end users:
```python
import re
_DOMAINS = r"(?:com|net|org|so|co|tv|fm|info|news|biz|press)"
_TAIL_WORDS = r"(?:akhriso|daawo|dhegayso|dhegeyso|sawirro?|sawiro?|fiiri|video|maqal|muuqaal)"
def clean_headline(h: str) -> str:
if not isinstance(h, str):
return h
h = h.strip()
h = re.sub(r"https?://\S+", "", h, flags=re.I) # remove URLs
h = re.sub(rf"\b[\w.-]+\.{_DOMAINS}\S*", "", h, flags=re.I) # remove bare domains
h = re.sub(rf"\s*[-–—]\s*\b\w+\.{_DOMAINS}\S*$", "", h, flags=re.I) # trailing "- site.com"
h = re.sub(rf"\s*\b(?:{_TAIL_WORDS})\b\.?\s*$", "", h, flags=re.I) # trailing tail words
if "." in h:
h = h.split(".", 1)[0] # keep first sentence only
h = re.sub(r"\s+([,.;:!?])", r"\1", h) # fix spacing before punctuation
h = re.sub(r"([,.;:!?])([^\s])", r"\1 \2", h) # ensure spacing after punctuation
h = re.sub(r"\s+", " ", h).strip()
# remove a dangling trailing connector/particle
h = re.sub(r"\s+\b(ayaa|ahaa|ka|ku|buu|ayuu|iyo|waxa)\b$", "", h, flags=re.I).strip()
if h and h[-1] not in ".!?":
h += "."
if h:
h = h[0].lower() + h[1:]
return h
headline = clean_headline(headline)
print(headline)
```
### Batch Inference
For generating headlines over a full dataset (e.g., a `test_df` with `article` and `headline` columns):
```python
import pandas as pd
@torch.inference_mode()
def batched_generate(texts, batch_size=16):
preds = []
for i in range(0, len(texts), batch_size):
batch_texts = ["headline: " + t for t in texts[i:i + batch_size]]
enc = tokenizer(
batch_texts,
return_tensors="pt",
padding=True,
truncation=True,
max_length=300,
).to(device)
out = model.generate(
**enc,
max_new_tokens=30,
min_new_tokens=4,
num_beams=4,
no_repeat_ngram_size=3,
length_penalty=1.3,
repetition_penalty=1.15,
pad_token_id=tokenizer.pad_token_id,
eos_token_id=tokenizer.eos_token_id,
)
for seq in out:
text = tokenizer.decode(seq, skip_special_tokens=True)
preds.append(clean_headline(text))
return preds
test_df = pd.read_csv("your_test_set.csv") # columns: ["article", "headline"]
predictions = batched_generate(test_df["article"].astype(str).tolist())
test_df["predicted_headline"] = predictions
test_df.to_csv("predictions.csv", index=False)
```
## Evaluation
The model was evaluated on a held-out test set using the following metrics:
| Metric | Description |
|---|---|
| ROUGE-1 / ROUGE-2 / ROUGE-L / ROUGE-Lsum | N-gram and longest-common-subsequence overlap |
| SacreBLEU | BLEU score with standardized tokenization |
| METEOR | Alignment-based metric accounting for synonyms/stems |
| BERTScore (P/R/F1) | Semantic similarity via `xlm-roberta-large` embeddings |
## Training Details
- **Base checkpoint:** `castorini/afriteva_v2_base`
- **Max source length:** 300 tokens
- **Max target length:** 30 tokens
- **Task prefix:** `"headline: "`
- **Generation strategy:** beam search (`num_beams=4`), with repetition penalty and n-gram blocking to reduce repeated phrases
## Citation
If you use this model, please cite the base AfriTeVa v2 model and, optionally, this fine-tuned checkpoint:
```bibtex
@misc{afriteva_v2,
title = {AfriTeVa V2: African Text-to-Text Transformer},
author = {Oladipo, Akintunde and others},
year = {2023},
url = {https://huggingface.co/castorini/afriteva_v2_base}
}
```
## Acknowledgements
Built on top of [AfriTeVa v2](https://huggingface.co/castorini/afriteva_v2_base) by Castorini, and the Hugging Face `transformers` and `evaluate` libraries. |