11import json
22
3+ import evaluate
34import numpy as np
4- from numpy .typing import NDArray
55from datasets import Dataset
6+ from numpy .typing import NDArray
67from transformers import (
7- AutoTokenizer ,
88 AutoModelForTokenClassification ,
9+ AutoTokenizer ,
10+ Trainer ,
911 TrainingArguments ,
10- Trainer
1112)
1213
1314
1415def tokenize_and_align_labels (examples : dict [str , list ]) -> dict [str , list ]:
1516 """Tokenize each sample and align the original token labels
16- to the new subword (tokenized) structure."""
17+ to the new subword (tokenized) structure."""
1718
1819 tokenized_outputs = tokenizer (
1920 examples ["tokens" ],
2021 truncation = True ,
21- is_split_into_words = True , # Important for token-based tasks
22+ is_split_into_words = True , # Important for token-based tasks
2223 return_offsets_mapping = True , # We'll use this if needed
23- padding = "max_length" , # or "longest" / "do_not_pad"
24- max_length = 200 # adjust as needed
24+ padding = "max_length" , # or "longest" / "do_not_pad"
25+ max_length = 200 , # adjust as needed
2526 )
2627
2728 labels_aligned : list [list [int ]] = []
@@ -31,15 +32,13 @@ def tokenize_and_align_labels(examples: dict[str, list]) -> dict[str, list]:
3132 # repeating the label for all subwords of the original token.
3233 word_ids : list [int | None ] = tokenized_outputs .word_ids (batch_index = i )
3334 label_ids : list [int ] = []
34- previous_word_idx : int | None = None
3535
3636 for word_idx in word_ids :
3737 if word_idx is None :
3838 # This is a special token like [CLS], [SEP], or padding
3939 label_ids .append (- 100 )
4040 else :
4141 label_ids .append (label_to_id [labels [word_idx ]])
42- previous_word_idx = word_idx
4342
4443 labels_aligned .append (label_ids )
4544
@@ -52,8 +51,8 @@ def tokenize_and_align_labels(examples: dict[str, list]) -> dict[str, list]:
5251
5352def compute_metrics (eval_pred : tuple [NDArray , NDArray ]) -> dict [str , float ]:
5453 """Compute accuracy at the token level (simple example).
55- You can also compute F1, precision, recall, etc. by ignoring
56- the -100 special tokens."""
54+ You can also compute F1, precision, recall, etc. by ignoring
55+ the -100 special tokens."""
5756 logits : NDArray
5857 labels : NDArray
5958 logits , labels = eval_pred
@@ -62,33 +61,35 @@ def compute_metrics(eval_pred: tuple[NDArray, NDArray]) -> dict[str, float]:
6261 # Flatten ignoring -100
6362 true_predictions : list [int ] = []
6463 true_labels : list [int ] = []
65- for pred , lab in zip (predictions , labels ):
66- for p , l in zip (pred , lab ):
67- if l != - 100 : # skip special tokens
68- true_predictions .append (p )
69- true_labels .append (l )
64+ for pred , lab in zip (predictions , labels , strict = True ):
65+ for _pred , _lab in zip (
66+ pred ,
67+ lab ,
68+ strict = False ,
69+ ):
70+ if _lab != - 100 : # skip special tokens
71+ true_predictions .append (_pred )
72+ true_labels .append (_lab )
7073
7174 results : dict [str , float ] = accuracy_metric .compute (
72- references = true_labels ,
73- predictions = true_predictions
75+ references = true_labels , predictions = true_predictions
7476 )
7577 return {"accuracy" : results ["accuracy" ]}
7678
7779
78- if __name__ == ' __main__' :
79- with open ("sentences.jsonl" , "rt" ) as f :
80+ if __name__ == " __main__" :
81+ with open ("sentences.jsonl" ) as f :
8082 sentences : list [dict ] = [json .loads (line ) for line in f ]
8183
8284 dataset_dict : dict [str , list ] = {
8385 "tokens" : [sentence ["words" ] for sentence in sentences ],
84- "labels" : [sentence ["types" ] for sentence in sentences ]
86+ "labels" : [sentence ["types" ] for sentence in sentences ],
8587 }
8688
8789 full_dataset : Dataset = Dataset .from_dict (dataset_dict )
8890
8991 max_words : int = max ([len (sentence ["words" ]) for sentence in sentences ])
9092
91-
9293 labels : set [str ] = set ()
9394 for sentence in sentences :
9495 labels |= set (sentence ["types" ])
@@ -103,9 +104,10 @@ def compute_metrics(eval_pred: tuple[NDArray, NDArray]) -> dict[str, float]:
103104 print ("Num train samples:" , len (train_dataset ))
104105 print ("Num test samples: " , len (test_dataset ))
105106
106-
107107 model_checkpoint : str = "distilbert-base-multilingual-cased"
108- tokenizer = AutoTokenizer .from_pretrained (model_checkpoint , use_fast = True , add_prefix_space = True )
108+ tokenizer = AutoTokenizer .from_pretrained (
109+ model_checkpoint , use_fast = True , add_prefix_space = True
110+ )
109111
110112 # Apply to train/test datasets
111113 train_dataset = train_dataset .map (tokenize_and_align_labels , batched = True )
@@ -123,7 +125,7 @@ def compute_metrics(eval_pred: tuple[NDArray, NDArray]) -> dict[str, float]:
123125 model_checkpoint ,
124126 num_labels = len (labels ),
125127 id2label = id_to_label ,
126- label2id = label_to_id
128+ label2id = label_to_id ,
127129 )
128130
129131 accuracy_metric = evaluate .load ("accuracy" ) # type: ignore[attr-defined]
@@ -139,7 +141,7 @@ def compute_metrics(eval_pred: tuple[NDArray, NDArray]) -> dict[str, float]:
139141 weight_decay = 0.01 ,
140142 logging_dir = "./logs" ,
141143 logging_steps = 10 ,
142- report_to = "none" # Set to "tensorboard" if you want logs
144+ report_to = "none" , # Set to "tensorboard" if you want logs
143145 )
144146
145147 trainer : Trainer = Trainer (
@@ -148,7 +150,7 @@ def compute_metrics(eval_pred: tuple[NDArray, NDArray]) -> dict[str, float]:
148150 train_dataset = train_dataset ,
149151 eval_dataset = test_dataset ,
150152 processing_class = tokenizer ,
151- compute_metrics = compute_metrics
153+ compute_metrics = compute_metrics ,
152154 )
153155
154156 trainer .train ()
0 commit comments