IsmatS commited on
Commit
09e8ec4
·
1 Parent(s): 1e27951
Files changed (1) hide show
  1. models/README.md +269 -0
models/README.md ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Azerbaijani Named Entity Recognition (NER) with XLM-RoBERTa
2
+
3
+ This project fine-tunes a custom NER model for Azerbaijani text using the multilingual XLM-RoBERTa model. This notebook and its supporting files enable extracting named entities like **persons**, **locations**, **organizations**, and **dates** from Azerbaijani text.
4
+
5
+ ### Notebook Source
6
+ This notebook was created in Google Colab and can be accessed [here](https://colab.research.google.com/drive/1EYYZa7dya2RjTZXHSJ4pzIOgzqR8lmSk).
7
+
8
+ ## Setup Instructions
9
+
10
+ 1. **Install Required Libraries**:
11
+ The following packages are necessary for running this notebook:
12
+ ```bash
13
+ pip install transformers datasets seqeval huggingface_hub
14
+ ```
15
+
16
+ 2. **Hugging Face Hub Authentication**:
17
+ Set up Hugging Face Hub authentication to save and manage your trained models:
18
+ ```python
19
+ from huggingface_hub import login
20
+ login(token="YOUR_HUGGINGFACE_TOKEN")
21
+ ```
22
+ Replace `YOUR_HUGGINGFACE_TOKEN` with your Hugging Face token.
23
+
24
+ 3. **Disable Unnecessary Warnings**:
25
+ For a cleaner output, some warnings are disabled:
26
+ ```python
27
+ import os
28
+ import warnings
29
+
30
+ os.environ["WANDB_DISABLED"] = "true"
31
+ warnings.filterwarnings("ignore")
32
+ ```
33
+
34
+ ## Detailed Code Walkthrough
35
+
36
+ ### 1. **Data Loading and Preprocessing**
37
+
38
+ #### Loading the Azerbaijani NER Dataset
39
+ The dataset for Azerbaijani NER is loaded from the Hugging Face Hub:
40
+ ```python
41
+ from datasets import load_dataset
42
+
43
+ dataset = load_dataset("LocalDoc/azerbaijani-ner-dataset")
44
+ print(dataset)
45
+ ```
46
+ This dataset contains Azerbaijani texts labeled with NER tags.
47
+
48
+ #### Preprocessing Tokens and NER Tags
49
+ To ensure compatibility, the tokens and NER tags are processed using the `ast` module:
50
+ ```python
51
+ import ast
52
+
53
+ def preprocess_example(example):
54
+ try:
55
+ example["tokens"] = ast.literal_eval(example["tokens"])
56
+ example["ner_tags"] = list(map(int, ast.literal_eval(example["ner_tags"])))
57
+ except (ValueError, SyntaxError) as e:
58
+ print(f"Skipping malformed example: {example['index']} due to error: {e}")
59
+ example["tokens"] = []
60
+ example["ner_tags"] = []
61
+ return example
62
+
63
+ dataset = dataset.map(preprocess_example)
64
+ ```
65
+ This function checks each example for format correctness, converting strings to lists of tokens and tags.
66
+
67
+ ### 2. **Tokenization and Label Alignment**
68
+
69
+ #### Initializing the Tokenizer
70
+ The `AutoTokenizer` class is used to initialize the XLM-RoBERTa tokenizer:
71
+ ```python
72
+ from transformers import AutoTokenizer
73
+
74
+ tokenizer = AutoTokenizer.from_pretrained("xlm-roberta-base")
75
+ ```
76
+
77
+ #### Tokenization and Label Alignment
78
+ Each token is aligned with its label using a custom function:
79
+ ```python
80
+ def tokenize_and_align_labels(example):
81
+ tokenized_inputs = tokenizer(
82
+ example["tokens"],
83
+ truncation=True,
84
+ is_split_into_words=True,
85
+ padding="max_length",
86
+ max_length=128,
87
+ )
88
+ labels = []
89
+ word_ids = tokenized_inputs.word_ids()
90
+ previous_word_idx = None
91
+ for word_idx in word_ids:
92
+ if word_idx is None:
93
+ labels.append(-100)
94
+ elif word_idx != previous_word_idx:
95
+ labels.append(example["ner_tags"][word_idx] if word_idx < len(example["ner_tags"]) else -100)
96
+ else:
97
+ labels.append(-100)
98
+ previous_word_idx = word_idx
99
+ tokenized_inputs["labels"] = labels
100
+ return tokenized_inputs
101
+
102
+ tokenized_datasets = dataset.map(tokenize_and_align_labels, batched=False)
103
+ ```
104
+ Tokens and labels are aligned, with `-100` used to ignore sub-tokens created during tokenization.
105
+
106
+ ### 3. **Dataset Split for Training and Validation**
107
+ The dataset is split into training and validation sets:
108
+ ```python
109
+ tokenized_datasets = tokenized_datasets["train"].train_test_split(test_size=0.1)
110
+ ```
111
+ This ensures a 90-10 split, maintaining a consistent setup for training and testing.
112
+
113
+ ### 4. **Define Labels and Model Components**
114
+
115
+ #### Define Label List
116
+ The NER tags are set up as BIO-tagging (Begin, Inside, Outside):
117
+ ```python
118
+ label_list = [
119
+ "O", "B-PERSON", "I-PERSON", "B-LOCATION", "I-LOCATION",
120
+ "B-ORGANISATION", "I-ORGANISATION", "B-DATE", "I-DATE",
121
+ "B-TIME", "I-TIME", "B-MONEY", "I-MONEY", "B-PERCENTAGE",
122
+ "I-PERCENTAGE", "B-FACILITY", "I-FACILITY", "B-PRODUCT",
123
+ "I-PRODUCT", "B-EVENT", "I-EVENT", "B-ART", "I-ART",
124
+ "B-LAW", "I-LAW", "B-LANGUAGE", "I-LANGUAGE", "B-GPE",
125
+ "I-GPE", "B-NORP", "I-NORP", "B-ORDINAL", "I-ORDINAL",
126
+ "B-CARDINAL", "I-CARDINAL", "B-DISEASE", "I-DISEASE",
127
+ "B-CONTACT", "I-CONTACT", "B-ADAGE", "I-ADAGE",
128
+ "B-QUANTITY", "I-QUANTITY", "B-MISCELLANEOUS", "I-MISCELLANEOUS",
129
+ "B-POSITION", "I-POSITION", "B-PROJECT", "I-PROJECT"
130
+ ]
131
+ ```
132
+
133
+ #### Initialize Model and Data Collator
134
+ The model and data collator are set up for token classification:
135
+ ```python
136
+ from transformers import AutoModelForTokenClassification, DataCollatorForTokenClassification
137
+
138
+ model = AutoModelForTokenClassification.from_pretrained(
139
+ "xlm-roberta-base",
140
+ num_labels=len(label_list)
141
+ )
142
+
143
+ data_collator = DataCollatorForTokenClassification(tokenizer)
144
+ ```
145
+
146
+ ### 5. **Define Evaluation Metrics**
147
+
148
+ The model’s performance is evaluated based on precision, recall, and F1 score:
149
+ ```python
150
+ import numpy as np
151
+ from seqeval.metrics import precision_score, recall_score, f1_score, classification_report
152
+
153
+ def compute_metrics(p):
154
+ predictions, labels = p
155
+ predictions = np.argmax(predictions, axis=2)
156
+ true_labels = [[label_list[l] for l in label if l != -100] for label in labels]
157
+ true_predictions = [
158
+ [label_list[p] for (p, l) in zip(prediction, label) if l != -100]
159
+ for prediction, label in zip(predictions, labels)
160
+ ]
161
+ return {
162
+ "precision": precision_score(true_labels, true_predictions),
163
+ "recall": recall_score(true_labels, true_predictions),
164
+ "f1": f1_score(true_labels, true_predictions),
165
+ }
166
+ ```
167
+
168
+ ### 6. **Training Setup and Execution**
169
+
170
+ #### Set Training Parameters
171
+ The `TrainingArguments` define configurations for model training:
172
+ ```python
173
+ from transformers import TrainingArguments
174
+
175
+ training_args = TrainingArguments(
176
+ output_dir="./results",
177
+ evaluation_strategy="epoch",
178
+ save_strategy="epoch",
179
+ learning_rate=1e-5,
180
+ per_device_train_batch_size=64,
181
+ per_device_eval_batch_size=64,
182
+ num_train_epochs=8,
183
+ weight_decay=0.01,
184
+ fp16=True,
185
+ logging_dir='./logs',
186
+ save_total_limit=2,
187
+ load_best_model_at_end=True,
188
+ metric_for_best_model="f1",
189
+ report_to="none"
190
+ )
191
+ ```
192
+
193
+ #### Initialize Trainer and Train the Model
194
+ The `Trainer` class handles training and evaluation:
195
+ ```python
196
+ from transformers import Trainer, EarlyStoppingCallback
197
+
198
+ trainer = Trainer(
199
+ model=model,
200
+ args=training_args,
201
+ train_dataset=tokenized_datasets["train"],
202
+ eval_dataset=tokenized_datasets["test"],
203
+ tokenizer=tokenizer,
204
+ data_collator=data_collator,
205
+ compute_metrics=compute_metrics,
206
+ callbacks=[EarlyStoppingCallback(early_stopping_patience=2)]
207
+ )
208
+
209
+ training_metrics = trainer.train()
210
+ eval_results = trainer.evaluate()
211
+ print(eval_results)
212
+ ```
213
+
214
+ ### 7. **Save the Trained Model**
215
+
216
+ After training, save the model and tokenizer for later use:
217
+ ```python
218
+ save_directory = "./XLM-RoBERTa"
219
+ model.save_pretrained(save_directory)
220
+ tokenizer.save_pretrained(save_directory)
221
+ ```
222
+
223
+ ### 8. **Inference with the NER Pipeline**
224
+
225
+ #### Initialize the NER Pipeline
226
+ The pipeline provides a high-level API for NER:
227
+ ```python
228
+ from transformers import pipeline
229
+ import torch
230
+
231
+ device = 0 if torch.cuda.is_available() else -1
232
+ nlp_ner = pipeline("ner", model=model, tokenizer=tokenizer, aggregation_strategy="simple", device=device)
233
+ ```
234
+
235
+ #### Custom Evaluation Function
236
+ The `evaluate_model` function allows testing on custom sentences:
237
+ ```python
238
+ label_mapping = {f"LABEL_{i}": label for i, label in enumerate(label_list) if label != "O"}
239
+
240
+ def evaluate_model(test_texts, true_labels):
241
+ predictions = []
242
+ for i, text in enumerate(test_texts):
243
+ pred_entities = nlp_ner(text)
244
+ pred_labels = [label_mapping.get(entity["entity_group"], "O
245
+
246
+ ") for entity in pred_entities if entity["entity_group"] in label_mapping]
247
+ if len(pred_labels) != len(true_labels[i]):
248
+ print(f"Warning: Inconsistent number of entities in sample {i+1}. Adjusting predicted entities.")
249
+ pred_labels = pred_labels[:len(true_labels[i])]
250
+ predictions.append(pred_labels)
251
+ if all(len(true) == len(pred) for true, pred in zip(true_labels, predictions)):
252
+ precision = precision_score(true_labels, predictions)
253
+ recall = recall_score(true_labels, predictions)
254
+ f1 = f1_score(true_labels, predictions)
255
+ print("Precision:", precision)
256
+ print("Recall:", recall)
257
+ print("F1-Score:", f1)
258
+ print(classification_report(true_labels, predictions))
259
+ else:
260
+ print("Error: Could not align all samples correctly for evaluation.")
261
+ ```
262
+
263
+ #### Test on a Sample Sentence
264
+ An example test with expected output labels:
265
+ ```python
266
+ test_texts = ["Shahla Khuduyeva və Pasha Sığorta şirkəti haqqında məlumat."]
267
+ true_labels = [["B-PERSON", "B-ORGANISATION"]]
268
+ evaluate_model(test_texts, true_labels)
269
+ ```