HeshamHaroon commited on
Commit
4b4c26b
·
verified ·
1 Parent(s): 7e48269

Upload Arabic Semantic Highlighter model

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ARABIC SEMANTIC HIGHLIGHTER MODEL LICENSE
2
+ Non-Commercial Use Only
3
+
4
+ Copyright (c) 2026 Hesham Haroon
5
+ All rights reserved.
6
+
7
+ 1. DEFINITIONS
8
+
9
+ "Model" refers to the Arabic Semantic Highlighter model, including all weights,
10
+ configurations, tokenizer files, and associated documentation.
11
+
12
+ "Commercial Use" means any use intended for or directed toward commercial
13
+ advantage or monetary compensation, including but not limited to:
14
+ - Using the Model in products or services sold for profit
15
+ - Using the Model to provide paid services to third parties
16
+ - Using the Model in applications that generate revenue
17
+ - Incorporating the Model into proprietary software for sale
18
+
19
+ "Non-Commercial Use" means use for research, education, personal projects,
20
+ or other purposes not primarily intended for commercial advantage.
21
+
22
+ 2. GRANT OF LICENSE
23
+
24
+ Subject to the terms of this License, the copyright holder grants you a
25
+ worldwide, royalty-free, non-exclusive license to:
26
+
27
+ a) Use the Model for Non-Commercial purposes
28
+ b) Modify and create derivative works for Non-Commercial purposes
29
+ c) Distribute the Model or derivative works for Non-Commercial purposes
30
+ d) Use the Model for academic research and publication
31
+
32
+ 3. RESTRICTIONS
33
+
34
+ You may NOT:
35
+
36
+ a) Use the Model for any Commercial purpose without prior written permission
37
+ b) Sell, lease, or rent the Model or any derivative works
38
+ c) Use the Model in any product or service offered for monetary compensation
39
+ d) Remove or alter any copyright notices or this License
40
+ e) Use the Model in ways that violate applicable laws or regulations
41
+ f) Use the Model to generate harmful, misleading, or illegal content
42
+
43
+ 4. ATTRIBUTION
44
+
45
+ Any use of the Model must include appropriate attribution to the original
46
+ author. When publishing research or other works that use this Model, please
47
+ cite as specified in the README.md file.
48
+
49
+ 5. COMMERCIAL LICENSING
50
+
51
+ For Commercial Use licensing inquiries, please contact the copyright holder
52
+ to negotiate terms. Commercial licenses may be available on a case-by-case basis.
53
+
54
+ 6. NO WARRANTY
55
+
56
+ THE MODEL IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
57
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
58
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
59
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
60
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
61
+ OUT OF OR IN CONNECTION WITH THE MODEL OR THE USE OR OTHER DEALINGS IN THE
62
+ MODEL.
63
+
64
+ 7. TERMINATION
65
+
66
+ This License automatically terminates if you violate any of its terms.
67
+ Upon termination, you must cease all use of the Model and destroy any copies
68
+ in your possession.
69
+
70
+ 8. GOVERNING LAW
71
+
72
+ This License shall be governed by and construed in accordance with
73
+ international copyright law.
74
+
75
+ ---
76
+
77
+ For questions about this license or to request Commercial Use permissions,
78
+ please contact: [Your Contact Information]
79
+
80
+ Last updated: 2026
README.md ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Arabic Semantic Highlighter
2
+
3
+ A sentence-level semantic highlighting model for Arabic text, designed for RAG (Retrieval-Augmented Generation) systems.
4
+
5
+ ## Model Description
6
+
7
+ This model identifies and highlights sentences in Arabic text that are relevant to a given query. It was fine-tuned on the [HeshamHaroon/arabic-semantic-relevance](https://huggingface.co/datasets/HeshamHaroon/arabic-semantic-relevance) dataset using span annotations.
8
+
9
+ ### Model Details
10
+
11
+ - **Base Model:** BAAI/bge-reranker-base
12
+ - **Task:** Sentence-level semantic relevance classification
13
+ - **Language:** Arabic (العربية)
14
+ - **Training Data:** ~66,000 query-sentence pairs extracted from span annotations
15
+
16
+ ### Performance Metrics
17
+
18
+ | Metric | Score |
19
+ |--------|-------|
20
+ | Accuracy | 93.13% |
21
+ | F1 Score | 94.58% |
22
+ | Precision | 94.85% |
23
+ | Recall | 94.30% |
24
+ | AUC-ROC | 98.24% |
25
+
26
+ ## Usage
27
+
28
+ ```python
29
+ import torch
30
+ import numpy as np
31
+ import re
32
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer
33
+
34
+ class ArabicSemanticHighlighter:
35
+ def __init__(self, model_path):
36
+ self.model = AutoModelForSequenceClassification.from_pretrained(
37
+ model_path,
38
+ num_labels=1,
39
+ )
40
+ self.tokenizer = AutoTokenizer.from_pretrained(model_path)
41
+ self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
42
+ self.model.to(self.device)
43
+ self.model.eval()
44
+
45
+ def _split_sentences(self, text, language="ar"):
46
+ if language == "ar":
47
+ sentences = re.split(r'[.؟!。\n]', text)
48
+ else:
49
+ sentences = re.split(r'[.?!\n]', text)
50
+ return [s.strip() for s in sentences if s.strip() and len(s.strip()) > 5]
51
+
52
+ def _score_sentence(self, question, sentence):
53
+ inputs = self.tokenizer(
54
+ question, sentence,
55
+ truncation=True,
56
+ max_length=256,
57
+ padding='max_length',
58
+ return_tensors='pt'
59
+ ).to(self.device)
60
+
61
+ with torch.no_grad():
62
+ logit = self.model(**inputs).logits.squeeze().item()
63
+ return 1 / (1 + np.exp(-logit))
64
+
65
+ def process(self, question, context, threshold=0.5, language="auto", return_sentence_metrics=False):
66
+ """
67
+ Highlight relevant sentences in context based on the question.
68
+
69
+ Args:
70
+ question: Query string
71
+ context: Text to search for relevant sentences
72
+ threshold: Minimum probability for relevance (default: 0.5)
73
+ language: "ar", "en", or "auto"
74
+ return_sentence_metrics: Include probability scores
75
+
76
+ Returns:
77
+ dict with highlighted_sentences, all_sentences, and optionally sentence_probabilities
78
+ """
79
+ if language == "auto":
80
+ arabic_chars = len(re.findall(r'[\u0600-\u06FF]', context))
81
+ language = "ar" if arabic_chars > len(context) * 0.3 else "en"
82
+
83
+ sentences = self._split_sentences(context, language)
84
+ probabilities = []
85
+ highlighted = []
86
+
87
+ for sentence in sentences:
88
+ prob = self._score_sentence(question, sentence)
89
+ probabilities.append(prob)
90
+ if prob >= threshold:
91
+ highlighted.append(sentence)
92
+
93
+ result = {
94
+ "highlighted_sentences": highlighted,
95
+ "all_sentences": sentences,
96
+ }
97
+
98
+ if return_sentence_metrics:
99
+ result["sentence_probabilities"] = probabilities
100
+
101
+ return result
102
+
103
+ # Load model
104
+ highlighter = ArabicSemanticHighlighter("path/to/model")
105
+
106
+ # Example usage
107
+ question = "ما هي فوائد الذكاء الاصطناعي في التعليم؟"
108
+ context = """الذكاء الاصطناعي يحدث ثورة في قطاع التعليم.
109
+ يساعد الذكاء الاصطناعي المعلمين في تخصيص المحتوى التعليمي لكل طالب.
110
+ الطقس اليوم مشمس ودافئ."""
111
+
112
+ result = highlighter.process(
113
+ question=question,
114
+ context=context,
115
+ threshold=0.5,
116
+ return_sentence_metrics=True
117
+ )
118
+
119
+ print("Highlighted sentences:", result["highlighted_sentences"])
120
+ # Output: Relevant sentences about AI in education (excludes weather sentence)
121
+ ```
122
+
123
+ ## Training Details
124
+
125
+ - **Epochs:** 3
126
+ - **Batch Size:** 8
127
+ - **Learning Rate:** 2e-5
128
+ - **Max Sequence Length:** 256
129
+ - **Gradient Accumulation Steps:** 4
130
+ - **Optimizer:** AdamW with weight decay 0.01
131
+ - **Training Time:** ~73 minutes on NVIDIA RTX 5060
132
+
133
+ ## Use Cases
134
+
135
+ - **RAG Systems:** Highlight relevant passages for LLM context
136
+ - **Search Results:** Show users which parts of documents match their query
137
+ - **Document QA:** Identify answer-containing sentences
138
+ - **Content Filtering:** Extract relevant information from long documents
139
+
140
+ ## Limitations
141
+
142
+ - Optimized for Arabic text; may work on other languages but not tested
143
+ - Best performance on sentences 10-200 characters in length
144
+ - Requires GPU for efficient inference on large documents
145
+
146
+ ## Citation
147
+
148
+ If you use this model, please cite:
149
+
150
+ ```bibtex
151
+ @misc{arabic-semantic-highlighter,
152
+ author = {Hesham Haroon},
153
+ title = {Arabic Semantic Highlighter},
154
+ year = {2026},
155
+ publisher = {HuggingFace},
156
+ howpublished = {\url{https://huggingface.co/HeshamHaroon/arabic-semantic-highlighter}}
157
+ }
158
+ ```
159
+
160
+ ## License
161
+
162
+ This model is released under a **Non-Commercial License**. See [LICENSE](LICENSE) for details.
config.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "XLMRobertaForSequenceClassification"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.1,
6
+ "bos_token_id": 0,
7
+ "classifier_dropout": null,
8
+ "dtype": "float32",
9
+ "eos_token_id": 2,
10
+ "hidden_act": "gelu",
11
+ "hidden_dropout_prob": 0.1,
12
+ "hidden_size": 768,
13
+ "id2label": {
14
+ "0": "LABEL_0"
15
+ },
16
+ "initializer_range": 0.02,
17
+ "intermediate_size": 3072,
18
+ "label2id": {
19
+ "LABEL_0": 0
20
+ },
21
+ "layer_norm_eps": 1e-05,
22
+ "max_position_embeddings": 514,
23
+ "model_type": "xlm-roberta",
24
+ "num_attention_heads": 12,
25
+ "num_hidden_layers": 12,
26
+ "output_past": true,
27
+ "pad_token_id": 1,
28
+ "position_embedding_type": "absolute",
29
+ "transformers_version": "4.57.3",
30
+ "type_vocab_size": 1,
31
+ "use_cache": true,
32
+ "vocab_size": 250002
33
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0cfd398375f844acca5a5d5470a7358fbfc0bb3c711a0f05d11b810cb31757e5
3
+ size 1112201932
modeling_highlighter.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import torch
3
+ import numpy as np
4
+ import re
5
+ from transformers import AutoModelForSequenceClassification, AutoTokenizer, PreTrainedModel, PretrainedConfig
6
+
7
+ class SemanticHighlighterConfig(PretrainedConfig):
8
+ model_type = "semantic_highlighter"
9
+
10
+ def __init__(self, base_model_name="BAAI/bge-reranker-base", **kwargs):
11
+ super().__init__(**kwargs)
12
+ self.base_model_name = base_model_name
13
+
14
+ class SemanticHighlighter(PreTrainedModel):
15
+ """Arabic Semantic Highlighter - highlights relevant sentences given a query."""
16
+
17
+ config_class = SemanticHighlighterConfig
18
+
19
+ def __init__(self, config):
20
+ super().__init__(config)
21
+ self.model = AutoModelForSequenceClassification.from_pretrained(
22
+ config._name_or_path,
23
+ num_labels=1,
24
+ ignore_mismatched_sizes=True
25
+ )
26
+ self.tokenizer = AutoTokenizer.from_pretrained(config._name_or_path)
27
+ self.device_type = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
28
+
29
+ def forward(self, input_ids, attention_mask=None, labels=None):
30
+ return self.model(input_ids=input_ids, attention_mask=attention_mask, labels=labels)
31
+
32
+ def _split_sentences(self, text, language="ar"):
33
+ """Split text into sentences."""
34
+ if language == "ar":
35
+ sentences = re.split(r'[.؟!。\n]', text)
36
+ else:
37
+ sentences = re.split(r'[.?!\n]', text)
38
+ return [s.strip() for s in sentences if s.strip() and len(s.strip()) > 5]
39
+
40
+ def _score_sentence(self, question, sentence):
41
+ """Score a single sentence against the question."""
42
+ inputs = self.tokenizer(
43
+ question, sentence,
44
+ truncation=True,
45
+ max_length=256,
46
+ padding='max_length',
47
+ return_tensors='pt'
48
+ ).to(self.device_type)
49
+
50
+ with torch.no_grad():
51
+ logit = self.model(**inputs).logits.squeeze().item()
52
+ return 1 / (1 + np.exp(-logit))
53
+
54
+ def process(self, question, context, threshold=0.5, language="auto", return_sentence_metrics=False):
55
+ """
56
+ Process question and context to highlight relevant sentences.
57
+
58
+ Args:
59
+ question: The query/question string
60
+ context: The context text to search for relevant sentences
61
+ threshold: Minimum probability to consider a sentence relevant (default: 0.5)
62
+ language: Language of the text ("ar", "en", or "auto" for detection)
63
+ return_sentence_metrics: If True, include sentence probabilities in output
64
+
65
+ Returns:
66
+ dict with keys:
67
+ - highlighted_sentences: List of sentences above threshold
68
+ - all_sentences: All sentences in the context
69
+ - sentence_probabilities: (if return_sentence_metrics=True) probability scores
70
+ """
71
+ self.model.to(self.device_type)
72
+ self.model.eval()
73
+
74
+ # Auto-detect language
75
+ if language == "auto":
76
+ arabic_chars = len(re.findall(r'[\u0600-\u06FF]', context))
77
+ language = "ar" if arabic_chars > len(context) * 0.3 else "en"
78
+
79
+ # Split into sentences
80
+ sentences = self._split_sentences(context, language)
81
+
82
+ # Score each sentence
83
+ probabilities = []
84
+ highlighted = []
85
+
86
+ for sentence in sentences:
87
+ prob = self._score_sentence(question, sentence)
88
+ probabilities.append(prob)
89
+ if prob >= threshold:
90
+ highlighted.append(sentence)
91
+
92
+ result = {
93
+ "highlighted_sentences": highlighted,
94
+ "all_sentences": sentences,
95
+ }
96
+
97
+ if return_sentence_metrics:
98
+ result["sentence_probabilities"] = probabilities
99
+
100
+ return result
sentencepiece.bpe.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cfc8146abe2a0488e9e2a0c56de7952f7c11ab059eca145a0a727afce0db2865
3
+ size 5069051
special_tokens_map.json ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<s>",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "cls_token": {
10
+ "content": "<s>",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "eos_token": {
17
+ "content": "</s>",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "mask_token": {
24
+ "content": "<mask>",
25
+ "lstrip": true,
26
+ "normalized": true,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ },
30
+ "pad_token": {
31
+ "content": "<pad>",
32
+ "lstrip": false,
33
+ "normalized": false,
34
+ "rstrip": false,
35
+ "single_word": false
36
+ },
37
+ "sep_token": {
38
+ "content": "</s>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false
43
+ },
44
+ "unk_token": {
45
+ "content": "<unk>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false
50
+ }
51
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:14917dd757b81bc44d4af6b028367351702656670c1954e055dabdfcf21593cf
3
+ size 17082798
tokenizer_config.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "<s>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "1": {
12
+ "content": "<pad>",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "2": {
20
+ "content": "</s>",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "3": {
28
+ "content": "<unk>",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "250001": {
36
+ "content": "<mask>",
37
+ "lstrip": true,
38
+ "normalized": true,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "bos_token": "<s>",
45
+ "clean_up_tokenization_spaces": true,
46
+ "cls_token": "<s>",
47
+ "eos_token": "</s>",
48
+ "extra_special_tokens": {},
49
+ "mask_token": "<mask>",
50
+ "model_max_length": 512,
51
+ "pad_token": "<pad>",
52
+ "sep_token": "</s>",
53
+ "sp_model_kwargs": {},
54
+ "tokenizer_class": "XLMRobertaTokenizer",
55
+ "unk_token": "<unk>"
56
+ }
training_args.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be0ad0c4baf7bbfafb4f0e5edee081009ea9f8611c7d422822c0245787f41b62
3
+ size 5777
training_info.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_name": "BAAI/bge-reranker-base",
3
+ "dataset": "HeshamHaroon/arabic-semantic-relevance",
4
+ "task": "sentence-level-highlighting",
5
+ "epochs": 3,
6
+ "batch_size": 8,
7
+ "learning_rate": 2e-05,
8
+ "train_sentences": 88110,
9
+ "test_results": {
10
+ "eval_loss": 0.2000904530286789,
11
+ "eval_accuracy": 0.9313270046455262,
12
+ "eval_f1": 0.9457562220804084,
13
+ "eval_precision": 0.94848,
14
+ "eval_recall": 0.9430480432707604,
15
+ "eval_auc": 0.9823959128165132,
16
+ "eval_runtime": 14.9552,
17
+ "eval_samples_per_second": 331.055,
18
+ "eval_steps_per_second": 20.729,
19
+ "epoch": 3.0
20
+ },
21
+ "completed_at": "2026-01-13T14:39:05.018353"
22
+ }