Views
No views yet
81melody/algerianDeBERTa-realestate-ner (the precision-optimised),This one trades a few precision points for measurably higher recall, especially on neighbourhood names| This model v2 | v1 | |
|---|---|---|
| Val F1 | 0.9780 | 0.9858 |
| Val Precision | 0.9646 | 0.9784 |
| Val Recall | 0.9918 | 0.9933 |
| Avg entities / listing (prod) | 8.45 | 7.84 |
| NEIGHBORHOOD / 100 texts | 72 | 48 |
| Avg entity confidence | 0.903 | 0.931 |



| Architecture | DeBERTa-v2 — 12 layers, hidden=512, 8 heads, 2048 FFN |
| Base model | algerianDeBERTa (pre-trained on Algerian web text) |
| Task | Token classification — 27 BIO labels, 13 entity types |
| Languages | Algerian Darja · Arabizi · French · MSA · Code-switched |
| Domain | Real estate classifieds (sales, rentals, land, villas, apartments) |
| Val F1 | 0.9780 |
| Val Recall | 0.9918 |
| Parameters | ~60M |
| License | Apache 2.0 |
No separate test-set evaluation was run for this version. For test metrics (F1 = 0.9672 on a held-out set of 95 posts) see v1 model card.
pipeline (standard, recommended for short texts)aggregation_strategy="max": for each surface word the subword token with the highest entity-class score wins, then consecutive spans that have the same type are merged automatically1from transformers import pipeline
2
3ner = pipeline(
4 "token-classification",
5 model="81melody/algerianDeBERTa-realestate-ner-v2",
6 aggregation_strategy="max",
7)
8
9
10print(ner("سلام ، خصني اف2 فالعاصمة في ميسوني ولا اودان ولا ديدوش ، في هاد الجويه لي عندو يتوصل معيا في الخاص"))
11
12print(ner("Appartement F4 à vendre Oran centre 120m² 4ème étage acte notarié"))
131result = ner(
2 long_text,
3 truncation=True,
4 max_length=192,
5 stride=64,
6)entity_group, word, score, start, end."cherche" (tokenised as ["cher", "che"]) or prices like "1.700" (tokenised as ["1", ".", "700"]) get truncated mid-word if a trailing subword happens to predict O1from transformers import AutoTokenizer, AutoModelForTokenClassification
2import torch
3import numpy as np
4from typing import List
5
6MODEL_NAME = "81melody/algerianDeBERTa-realestate-ner-v2"
7MAX_SEQ_LEN = 192
8STRIDE = 64
9
10tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
11model = AutoModelForTokenClassification.from_pretrained(MODEL_NAME)
12model.eval()
13device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
14model.to(device)
15
16
17def extract_entities(text: str) -> List[dict]:
18
19 enc = tokenizer(
20 text,
21 return_tensors="pt",
22 max_length=MAX_SEQ_LEN,
23 stride=STRIDE,
24 truncation=True,
25 return_overflowing_tokens=True,
26 return_offsets_mapping=True,
27 padding="max_length",
28 )
29 enc.pop("overflow_to_sample_mapping", None)
30 offsets = enc.pop("offset_mapping")
31
32
33 with torch.no_grad():
34 logits = model(**{k: v.to(device) for k, v in enc.items()}).logits
35 probs = torch.softmax(logits, dim=-1).cpu().numpy()
36 attention = enc["attention_mask"].numpy()
37 off_np = offsets.numpy()
38
39
40 char_probs = {}
41 for c in range(probs.shape[0]):
42 for t in range(off_np.shape[1]):
43 if attention[c, t] == 0:
44 continue
45 cs, ce = int(off_np[c, t, 0]), int(off_np[c, t, 1])
46 if cs == 0 and ce == 0:
47 continue
48 if cs not in char_probs:
49 char_probs[cs] = {"end": ce, "vecs": [probs[c, t]]}
50 else:
51 char_probs[cs]["vecs"].append(probs[c, t])
52
53 if not char_probs:
54 return []
55
56 items = sorted(char_probs.items())
57
58 word_tokens = []
59 w_start, w_info = items[0]
60 w_end = w_info["end"]
61 w_avg_p = np.mean(w_info["vecs"], axis=0)
62
63 for cs, info in items[1:]:
64 if cs == w_end:
65 w_end = info["end"]
66 else:
67 word_tokens.append({"start": w_start, "end": w_end, "avg_p": w_avg_p})
68 w_start = cs
69 w_end = info["end"]
70 w_avg_p = np.mean(info["vecs"], axis=0)
71 word_tokens.append({"start": w_start, "end": w_end, "avg_p": w_avg_p})
72
73 label_map = model.config.id2label
74 entities, current = [], None
75
76 for w in word_tokens:
77 idx = int(np.argmax(w["avg_p"]))
78 label = label_map[idx]
79 score = float(w["avg_p"][idx])
80
81 if label == "O":
82 if current:
83 entities.append(current)
84 current = None
85
86 elif label.startswith("B-"):
87 if current:
88 entities.append(current)
89 current = {
90 "entity": label[2:],
91 "word": text[w["start"]:w["end"]],
92 "score": score,
93 "_sc": [score], "_s": w["start"], "_e": w["end"],
94 }
95
96 elif label.startswith("I-"):
97 etype = label[2:]
98 if current and current["entity"] == etype:
99 current["word"] = text[current["_s"]:w["end"]]
100 current["_e"] = w["end"]
101 current["_sc"].append(score)
102 current["score"] = float(np.mean(current["_sc"]))
103 else:
104 if current:
105 entities.append(current)
106 current = {
107 "entity": etype,
108 "word": text[w["start"]:w["end"]],
109 "score": score,
110 "_sc": [score], "_s": w["start"], "_e": w["end"],
111 }
112
113 if current:
114 entities.append(current)
115
116 return [
117 {"entity": e["entity"], "word": e["word"], "score": round(e["score"], 6)}
118 for e in entities
119 ]
120print(extract_entities('khasni appartement fi bab zouar 200 m2'))
121#[{'entity': 'TRANSACTION', 'word': 'khasni', 'score': 0.703333},
122#{'entity': 'PROPERTY_TYPE', 'word': 'appartement', 'score': 0.973926},
123#{'entity': 'NEIGHBORHOOD', 'word': 'bab zouar', 'score': 0.902971},
124#{'entity': 'SURFACE', 'word': '200 m2', 'score': 0.930045}]
125
126
127
128| Entity | Description | Algerian Examples |
|---|---|---|
PROPERTY_TYPE | Category of asset | شقة · villa · appartement · terrain · carcasse · haouch |
APT_CLASS | Apartment layout | F2 · F3 · F4 · F5 · S+1 · Studio |
TRANSACTION | Listing intent | للبيع · location · louer · خاصني · echange |
WILAYA | Algerian province (all 48) | Alger · Oran · Constantine · 16 · ولاية وهران |
CITY | City / commune | Bab Ezzouar · Sidi Yahia · Ain Benian |
NEIGHBORHOOD | Quarter / district / street | باب الزوار · Hydra · Hai Yasmine · Télemly |
PRICE | Price in DZD, DA, or slang | 8 500 000 da · 12M · 950 000 · 1.5 milliards · 800 U |
SURFACE | Area in m², metres, hectares | 90m² · 120 mètres · 85 متر · 2 hectares |
FLOOR | Floor level | 3ème étage · الطابق الثالث · RDC · R+2 |
PHONE | Contact number (anonymized) | [PHONE] |
AMENITY | Features / utilities | garage · مصعد · piscine · jardin · بيدون |
DOCUMENT | Legal papers | عقد · livret foncier · AADL · acte notarié · timbre |
CONDITION | Property state | neuf · rénové · قديم · semi-fini · en construction |
Val F1 (micro, seqeval): 0.9780
Val Precision (micro): 0.9646
Val Recall (micro): 0.9918Test-set evaluation (strict entity-level seqeval on 95 held-out posts) was performed only on the last epoch (test F1 = 0.9672), This version was not re-evaluated on the test set to avoid data leakage into version selection
| Metric | v2 | v1 |
|---|---|---|
| Avg entities / listing | 8.45 | 7.84 |
| Avg entity confidence | 0.903 | 0.931 |
| Low-conf entities (<0.80) | 3,154 | 1,537 |
| NEIGHBORHOOD / 100 texts | 72.3 | 48.2 |
| SURFACE / 100 texts | 73.1 | 67.3 |
| PRICE / 100 texts | 48.1 | 44.3 |
"Hussein dey", "Bab Ezzouar", "bordj el kiffan") that the more conservative v1 sometimes under-segments1base_model: algerianDeBERTa (DeBERTa-v2)
2architecture: DebertaV2ForTokenClassification
3num_labels: 27 (BIO, 13 entity types)
4saved_at_epoch: 7
5
6
7max_seq_len: 192
8stride: 64
9
10
11optimizer: AdamW
12peak_lr: 2e-5
13llrd_factor: 0.9
14weight_decay: 0.01
15grad_accum_steps: 2
16
17warmup_ratio: 0.1
18schedule: cosine with warmup
19
20
21label_smoothing: 0.05
22class_weighting: inverse-frequency, capped at 10×
23dropout: 0.1m, متر without a number) and single-character fragments (ر, ف) can appear as false-positive WILAYA or FLOOR entities. A confidence threshold of score ≥ 0.75 removes the bulk of these6 000 000) are occasionally split into separate entities rather than merged as one span.| Use case | Notes |
|---|---|
| Location-aware search / matching | Best use case for this version maximises neighbourhood recall |
| Lead enrichment pipelines | Use when missing a location is worse than a noisy one |
| Candidate generation + reranking | Run epoch 7 to cast wide net, rerank with v1 scores |
| Training data generation | Higher recall produces more silver labels for rare location types |
1@misc{himeur2026algeriandeberta_ner_v2,
2 title = {algerianDeBERTa-realestate-ner-v2: Named Entity Recognition
3 for Algerian Real Estate Text in Darja, Arabizi, and French},
4 author = {Himeur, Ayoub},
5 year = {2026},
6 publisher = {Hugging Face},
7 url = {https://huggingface.co/81melody/algerianDeBERTa-realestate-ner-v2},
8 note = {Fine-tuned DeBERTa-v2 on annotated
9 Algerian Facebook real estate posts, 13 entity types}
10}