Issue with processing custom dataset for Named Entity Recognition

I have an issue processing my dataset for training my NER model using Transformers.
The dataset is a set of French medical text files and annotations files. For each text file containing paragraphs, its corresponding annotation file contains the different tags with the position of the entity in the text.

For example, the text file contains:
Le cas présenté concerne un homme âgé de 61 ans (71 kg, 172 cm, soit un indice de masse corporelle de 23,9 kg/m²) admissible à une transplantation pulmonaire en raison d’une insuffisance respiratoire chronique terminale sur emphysème post-tabagique, sous oxygénothérapie continue (1 L/min) et ventilation non invasive nocturne. Il présente, comme principaux antécédents, une dyslipidémie, une hypertension artérielle et un tabagisme sevré estimé à 21 paquets-années (facteurs de risque cardiovasculaires). Le bilan préopératoire a révélé une hypertension artérielle pulmonaire essentiellement postcapillaire conduisant à l’ajout du périndopril (2 mg par jour) et du furosémide (40 mg par jour). La mise en évidence d’un Elispot (enzyme-linked immunospot) positif pour la tuberculose a motivé l’introduction d’un traitement prophylactique par l’association rifampicine-isoniazide (600-300 mg par jour) pour une durée de trois mois.
Deux mois après le bilan préopératoire, le patient a bénéficié d’une transplantation mono-pulmonaire gauche sans dysfonction primaire du greffon5,6. Le donneur et le receveur présentaient tous deux un statut sérologique positif pour cytomegalovirus (CMV) et Epstein Barr Virus (EBV). Une sérologie positive de la toxoplasmose a été mise en évidence uniquement chez le receveur. Le traitement immunosuppresseur d’induction associait la méthylprednisolone (500 mg à jour 0 et 375 mg à jour +1 post-transplantation) et le basiliximab, anticorps monoclonal dirigé contre l’interleukine-2 (20 mg à jour 0 et jour +4 posttransplantation). À partir de jour +2 post-transplantation, l’immunosuppression a été maintenue par une trithérapie par voie orale comprenant le tacrolimus à une posologie initiale de 5 mg par jour, le mofétil mycophénolate (MMF) 2000 mg par jour et la prednisone 20 mg par jour. Les traitements associés sont présentés dans le tableau I.
L’évolution est marquée par la survenue, au jour +5 posttransplantation, d’une dégradation respiratoire sur œdème pulmonaire gauche de reperfusion, avec possible participation cardiogénique. Le rejet aigu de grade III, évoqué par la présence d’infiltrats lymphocytaires aux biopsies transbronchiques, a été confirmé par l’anatomopathologie.

While the annotation file contains:
T1 genre 28 33 homme
T2 age 41 47 61 ans
A1 genre T1 masculin
T3 origine 127 326 une transplantation pulmonaire en raison d’une insuffisance respiratoire chronique terminale sur emphysème post-tabagique, sous oxygénothérapie continue (1 L/min) et ventilation non invasive nocturne
T4 issue 1962 2104 une dégradation respiratoire sur œdème pulmonaire gauche de reperfusion, avec possible participation cardiogénique. Le rejet aigu de grade III
A2 issue T4 détérioration

My issue is about how to process the data, mainly the annotation in order to make it usable by Transformers.

Hi ! Feel free to take a look at the .map() of the datasets library to process your dataset. To be used by transformers, you dataset must follow the NER task template, which requires having the following columns:

  • tokens: a list of tokens (usually at word level since we’re doing NER, so you can just split by space in your case) of type string
  • ner_tags: a list of labels, usually in IOB format, of type ClassLabel, of the same length that tokens

You can find an example of a dataset ready for NER by loading CoNLL2003:

from datasets import load_dataset

ds = load_dataset("conll2003")

I managed to preprocess the data, can you please take a look in this notebook. Here is a link to the data.

I have used the .map() of the datasets library.

def map_func(x, y):
  return {'input_ids': x['input_ids'], 'attention_mask': x['attention_mask'], 'labels':y}

train_dataset = train_dataset.map(map_func)
validation_dataset = validation_dataset.map(map_func)
test_dataset = test_dataset.map(map_func)

The thing is that with this format, first the data is accepted in the training phase, but not in the test phase, I get the following error:

from datasets import load_metric
import numpy as np

metric = load_metric("seqeval")

def evaluate(model, dataset, ner_labels):
  all_predictions = []
  all_labels = []
  for batch in dataset:
    logits = model.predict(batch)["logits"]
    labels = batch["labels"]
    predictions = np.argmax(logits, axis = -1)
    for prediction, label in zip(predictions, labels):
      for predicted_idx, label_idx in zip(prediction, label):
        if label_idx == -100:
          continue
        all_predictions.append(ner_labels[predicted_idx])
        all_labels.append(ner_labels[label_idx])
  return metric.compute(predictions=[all_predictions], references=[all_labels])

results = evaluate(model, test_dataset, ner_labels=list(model.config.id2label.values()))
results
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-40-d7e10156347b> in <module>()
     31   return metric.compute(predictions=[all_predictions], references=[all_labels])
     32 
---> 33 results = evaluate(model, test_dataset, ner_labels=list(model.config.id2label.values()))

2 frames
/usr/local/lib/python3.7/dist-packages/tensorflow/python/framework/func_graph.py in autograph_handler(*args, **kwargs)
   1127           except Exception as e:  # pylint:disable=broad-except
   1128             if hasattr(e, "ag_error_metadata"):
-> 1129               raise e.ag_error_metadata.to_exception(e)
   1130             else:
   1131               raise

ValueError: in user code:

    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1621, in predict_function  *
        return step_function(self, iterator)
    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1611, in step_function  **
        outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1604, in run_step  **
        outputs = model.predict_step(data)
    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1572, in predict_step
        return self(x, training=False)
    File "/usr/local/lib/python3.7/dist-packages/keras/utils/traceback_utils.py", line 67, in error_handler
        raise e.with_traceback(filtered_tb) from None

    ValueError: Exception encountered when calling layer "tf_camembert_for_token_classification" (type TFCamembertForTokenClassification).
    
    in user code:
    
        File "/usr/local/lib/python3.7/dist-packages/transformers/models/roberta/modeling_tf_roberta.py", line 1681, in call  *
            outputs = self.roberta(
        File "/usr/local/lib/python3.7/dist-packages/keras/utils/traceback_utils.py", line 67, in error_handler  **
            raise e.with_traceback(filtered_tb) from None
    
        ValueError: Exception encountered when calling layer "roberta" (type TFRobertaMainLayer).
        
        in user code:
        
            File "/usr/local/lib/python3.7/dist-packages/transformers/models/roberta/modeling_tf_roberta.py", line 660, in call  *
                batch_size, seq_length = input_shape
        
            ValueError: not enough values to unpack (expected 2, got 1)
        
        
        Call arguments received:
          • input_ids=tf.Tensor(shape=(32,), dtype=int32)
          • attention_mask=tf.Tensor(shape=(32,), dtype=int32)
          • token_type_ids=None
          • position_ids=None
          • head_mask=None
          • inputs_embeds=None
          • encoder_hidden_states=None
          • encoder_attention_mask=None
          • past_key_values=None
          • use_cache=None
          • output_attentions=False
          • output_hidden_states=False
          • return_dict=True
          • training=False
          • kwargs=<class 'inspect._empty'>
    
    
    Call arguments received:
      • input_ids={'input_ids': 'tf.Tensor(shape=(32,), dtype=int32)', 'attention_mask': 'tf.Tensor(shape=(32,), dtype=int32)', 'labels': 'tf.Tensor(shape=(32,), dtype=int32)'}
      • attention_mask=None
      • token_type_ids=None
      • position_ids=None
      • head_mask=None
      • inputs_embeds=None
      • output_attentions=None
      • output_hidden_states=None
      • return_dict=None
      • labels=None
      • training=False
      • kwargs=<class 'inspect._empty'>

Also, even with the trained model, obtained prediction for a given sentence are bad, I think it’s a tensors shape issue, what do you think, any clues ?

I think this because you are using single examples instead of batches of examples:

batch_size = 8  # or whatever is best in your case
for i in range(0, len(dataset), batch_size):
    batch = dataset[i:i + batch_size]
    ...

Can’t do that because dataset is a MapDataset object. The issue is more than that I guess because as I said, the training gives a model with a poor prediction ability, so I think there is an issue with the current data format I am using.