66from more_itertools import flatten
77import torch
88from torch .utils .data import Dataset
9- from datasets import Dataset as HGDataset
9+ from datasets import Dataset as HFDataset , DatasetDict as HFDatasetDict
1010from datasets import Sequence , ClassLabel
1111from transformers import (
1212 AutoModelForTokenClassification ,
@@ -92,7 +92,7 @@ def __init__(
9292 assert all (
9393 [len (cm ) == len (elt ) for elt , cm in zip (self .elements , context_mask )]
9494 )
95- self ._context_mask = context_mask or [[1 ] * len (elt ) for elt in self .elements ]
95+ self ._context_mask = context_mask or [[0 ] * len (elt ) for elt in self .elements ]
9696
9797 self .tokenizer = tokenizer
9898
@@ -213,8 +213,10 @@ def load_conll2002_bio(
213213 tags = []
214214 for line in raw_data .split ("\n " ):
215215 line = line .strip ("\n " )
216- if re .fullmatch (r"\s*" , line ) or (
217- not max_sent_len is None and len (sent_tokens ) >= max_sent_len
216+ if (
217+ re .fullmatch (r"\s*" , line ) # ignore empty lines
218+ or re .fullmatch (r"# [^:]+: .*" , line ) # ignore Novelties style metadata
219+ or (not max_sent_len is None and len (sent_tokens ) >= max_sent_len )
218220 ):
219221 if len (sent_tokens ) == 0 :
220222 continue
@@ -224,29 +226,36 @@ def load_conll2002_bio(
224226 token , tag = line .split (separator )
225227 sent_tokens .append (token )
226228 tags .append (tag_conversion_map .get (tag , tag ))
229+ if len (sent_tokens ) != 0 :
230+ sents .append (sent_tokens )
227231
228232 tokens = list (flatten (sents ))
229233 entities = ner_entities (tokens , tags )
230234
231235 return sents , list (flatten (sents )), entities
232236
233237
234- def hgdataset_from_conll2002 (
238+ def hfdataset_from_conll2002 (
235239 path : str ,
236240 tag_conversion_map : Optional [Dict [str , str ]] = None ,
237241 separator : str = "\t " ,
238242 max_sent_len : Optional [int ] = None ,
243+ labels : Optional [list [str ]] = None ,
239244 ** kwargs ,
240- ) -> HGDataset :
245+ ) -> HFDataset :
241246 """Load a CoNLL-2002 file as a Huggingface Dataset.
242247
243248 :param path: passed to :func:`.load_conll2002_bio`
244249 :param tag_conversion_map: passed to :func:`load_conll2002_bio`
245250 :param separator: passed to :func:`load_conll2002_bio`
246251 :param max_sent_len: passed to :func:`load_conll2002_bio`
252+ :param labels: the list of all possible labels. If ``None``, will
253+ automatically be assigned to the sorted list of possible tags
254+ found in the input file.
247255 :param kwargs: additional kwargs for :func:`open`
248256
249- :return: a :class:`datasets.Dataset` with features 'tokens' and 'labels'.
257+ :return: a :class:`datasets.Dataset` with features 'tokens' and
258+ 'labels'.
250259 """
251260 sentences , tokens , entities = load_conll2002_bio (
252261 path , tag_conversion_map , separator , max_sent_len , ** kwargs
@@ -268,13 +277,21 @@ def hgdataset_from_conll2002(
268277 for sent_start , sent_end in zip (sent_starts , sent_ends )
269278 ]
270279
271- dataset = HGDataset .from_dict ({"tokens" : sentences , "labels" : sent_tags })
272- dataset = dataset . cast_column (
273- " labels" , Sequence ( ClassLabel ( names = sorted (set (tags )) ))
274- )
280+ dataset = HFDataset .from_dict ({"tokens" : sentences , "labels" : sent_tags })
281+ if labels is None :
282+ labels = sorted (set (tags ))
283+ dataset = dataset . cast_column ( "labels" , Sequence ( ClassLabel ( names = labels )) )
275284 return dataset
276285
277286
287+ def hgdataset_from_conll2002 (** kwargs ) -> HFDataset :
288+ """
289+ Deprecated function that only exists for retrocompatibility, you
290+ should call :func:`.hfdataset_from_conll2002` instead.
291+ """
292+ return hfdataset_from_conll2002 (** kwargs )
293+
294+
278295def _tokenize_and_align_labels (
279296 examples , tokenizer : PreTrainedTokenizerFast , label_all_tokens : bool = True
280297):
@@ -315,37 +332,49 @@ def _tokenize_and_align_labels(
315332
316333
317334def train_ner_model (
318- hg_id : str ,
319- dataset : HGDataset ,
335+ hf_id : str ,
336+ dataset : Union [ HFDataset , HFDatasetDict ] ,
320337 targs : TrainingArguments ,
338+ train_split : str = "train" ,
339+ valid_split : str = "valid" ,
340+ trainer_class : type [Trainer ] = Trainer ,
321341) -> PreTrainedModel :
342+ """Train a NER model on the given dataset.
343+
344+ :param hf_id: huggingface ID of the model to train
345+ :param dataset: huggingface dataset on which to train. The
346+ 'labels' column is assumed to contain NER labels.
347+ :param TrainingArguments: training arguments for the huggingface
348+ trainer.
349+ :param train_split: split of the dataset used for train.
350+ :param valid_split: split of the dataset used for validation.
351+ :param trainer_class: trainer class to use. Can be used to
352+ override the default huggingface trainer.
353+ """
322354 from transformers import DataCollatorForTokenClassification
323355
324356 # BERT tokenizer splits tokens into subtokens. The
325357 # tokenize_and_align_labels function correctly aligns labels and
326358 # subtokens.
327- tokenizer = AutoTokenizer .from_pretrained (hg_id )
359+ tokenizer = AutoTokenizer .from_pretrained (hf_id )
328360 dataset = dataset .map (
329361 ft .partial (_tokenize_and_align_labels , tokenizer = tokenizer ), batched = True
330362 )
331- dataset = dataset .train_test_split (test_size = 0.1 )
332363
333- label_lst = dataset ["train" ].features ["labels" ].feature .names
364+ label_lst = dataset [train_split ].features ["labels" ].feature .names
334365 model = AutoModelForTokenClassification .from_pretrained (
335- hg_id ,
366+ hf_id ,
336367 num_labels = len (label_lst ),
337368 id2label = {i : label for i , label in enumerate (label_lst )},
338369 label2id = {label : i for i , label in enumerate (label_lst )},
339370 )
340371
341- trainer = Trainer (
372+ trainer = trainer_class (
342373 model ,
343374 targs ,
344- train_dataset = dataset ["train" ],
345- eval_dataset = dataset ["test" ],
346- # data_collator=DataCollatorForTokenClassificationWithBatchEncoding(tokenizer),
375+ train_dataset = dataset [train_split ],
376+ eval_dataset = dataset [valid_split ],
347377 data_collator = DataCollatorForTokenClassification (tokenizer ),
348- tokenizer = tokenizer ,
349378 )
350379 trainer .train ()
351380
0 commit comments