Détection d’expressions de tonalités-sentiments dans un document avec du NER : Partie II — Modélisation
Comment on utilise un NER pour extraire des expressions de tonalités dans nos projets clients
Introduction
Dans la première partie de ce blog, nous avons présenté le contexte général de notre solution de détection d’expressions de tonalités dans les textes.
Dans cette seconde partie, nous aborderons les principales étapes de modélisation qui ont abouti à l’entraînement d’un modèle que l’on utilise chez nos divers projets clients.
Backbone Model
Avec l’émergence des approches Deep Learning, plusieurs approches pour résoudre les problèmes de Sequence tagging ont fait jour. Mais on peut les regrouper en deux principales catégories :
Des approches “RNN-based” :
Ces approches se basent sur 3 briques principales :
- Une brique d’embedding de la séquence d’entrée afin de la representer, sous forme vectorielle. Ces vecteurs peuvent être constitués avec des méthodes statiques (GloVe, FastText) ou contextuels afin de les enrichir avec des informations supplémentaires sur le contexte les entourant (CharacterCNN, CharacterLSTM)
- Une couche de RNN ou Bi-RNN : largement utilisés dans les problèmes séquentiels pour incorporer des informations sur les tokens passés (et futurs pour les bidirectionnels) relativement à un token spécifique. Cette couche permet, in-fine, d’obtenir des représentations vectorielles de grande qualité.
- - Une couche de classification : Afin d’assigner un label à chaque vecteur de logits de la séquence encodée.
Des approches “Transformers-based”
qui ne diffèrent pas trop des approches “RNN-based” mis à part l’ajout du mécanisme d’auto-attention qui contribue grandement à la construction de représentations vectorielles très riches.
Dans notre cas, on utilise une librairie interne “saola” (open-source très prochainement, suivez La Javaness R&D pour ne rien rater) qui pour l’instant supporte les approches “Transformers-based” (en s’appuyant sur la librairie transformers de Hugging Face). Le modèle adopté pour cette tâche de NER est un CamemBERT-base.
Processing
Pour localiser les tonalités au sein d’un texte, on s’intéresse bien sûr à sémantique du message, et aux éléments de contexte. Mais d’autres signes peuvent être révélateurs, comme l’utilisation excessive de majuscules et de ponctuations, les fautes d’orthographes excessives (peut-être que l’auteur ne fait pas attention à l’orthographe, sans doute la juge-t-elle secondaire et facultative dans le message qu’il veut faire passer ou bien l’expérience qu’il veut partager, cela peut aussi indiquer que le message a été rédigé dans l’urgence, l’énervement, que l’auteur maîtrise mal le français, les outils informatiques, …)
Les fautes d’orthographes sont gérées par le tokenizer du transformers utilisé (CamemBERT dans notre cas). En effet, quand un mot n’est pas reconnu lors du mapping token → index dans la table d’embedding, il est subdivisé en WordPieces
afin de trouver de quand même trouver un mapping adéquat à une partie du mot (radical ou suffixe).
Mais cela n’est pas suffisant pour capturer les effets “locaux” mentionnés plus tôt. Regardons ce qui se passe dans cet exemple :
Les ponctuations excessives sont collées au dernier token, impliquant une subdivision par le CamemBERT Tokenizer lors de la tokenization de la séquence.
Dans notre librairie interne La Javaness R&D “saola”, la prédiction attribuée au radical du mot (le premier sub-token) est retenue pour le mot en entier. Dans cet exemple, on assigne au token Blague???!!!!!
la prédiction faite pour le radical de son radical _B
.
On voit alors l’inconvénient dans cet exemple : Les ponctuations excessives ne sont pas complètement prise en compte dans la prédiction. Certes, le mécanisme de “self-attention” et de les encodeurs des transformers font que l’encoding de chaque token contient une certaine information sur tout ce qui est autour de lui, mais se reposer sur l’auto-attention pour déceler cette information et en faire usage pour l’inférence s’avère insuffisant. (Voir paragraphe Performances)
La solution adoptée pour palier à ça et forcer le modèle à encoder ces ponctuations pour être considérées comme des tokens indépendants est de simplement séparer les ponctuations (intercaler des espaces entre elles).
N.B : Cette solution ne résout pas le problème de différentiation entre un token en minuscule et en majuscule. Mais cela est géré par le tokenizer en assignant des mapping différents à un même mot. Notamment dans le cas précédent, “blague” existe dans le vocabulaire du CamemBERT tandis que “BLAGUE” n’existe pas, d’où sa subdivision en word-pieces.
Expériences BERT
Poids encodeurs
Le dataset adopté pour l’entrainement de ce modèle est constitué de ~ 1000 messages. Le nombre de paramètres du CamemBERT avoisine les 110M. Pour cette raison, nous avons figé les paramètres de certaines couches d’encodeurs du transformers, pour diminuer le nombre de paramètres à entraîner et à optimiser. On pourra voir la manière dont cela est fait ici.
Cela consiste à passer l’attribut requires_grad=False
du tenseur correspondant à l’encodeur à fixer lors de la définition du modèle.
On a effectué conduit les expériences suivantes sur les dernières couches d’encodeurs du transformers :
- Fixer tous les encodeurs et n’entraîner que la tête de classification (ClassificationHead) : 16.100 trainable parameters / 110M
- Fixer tous les encodeurs sauf l’encodeur 11 : 7.1M trainable parameters / 110M
- Fixer tous les encodeurs sauf les encodeurs 11, 10 : 14.2M trainable parameters / 110M
- Fixer tous les encodeurs sauf les encodeurs 11, 10, 9 : 21.3M trainable parameters / 110M
- Fixer tous les encodeurs sauf les encodeurs 11, 10, 9, 8 : 28.4M trainable parameters / 110M
- Fixer tous les encodeurs sauf les encodeurs 11, 10, 9, 8, 7 : 35.5M trainable parameters / 110M
Les résultats dans le paragraphe Performances
Ajout d’un CRF
La tête de classification du transformers (TokenClassificationHead
) est un simple perceptron qui permet de passer d’un batch contenant des tenseurs de taille (max_seq_len, hidden_state_dim)
vers des tenseurs de taille (max_seq_len, num_labels)
où :
max_seq_len
correspond à la longueur maximale de la séquencehidden_state_dim
est la dimension d’embedding des encodeurs du CamemBERT (dont la valeur est 768)num_labels
est le nombre de classes auxquelles on doit assigner chaque token de la séquence.
Suite à cela, on parcourt chacun des max_seq_len
vecteurs pour voir quelle est la position du logits de valeur maximale pour déterminer la classe prédite. Cela peut créer des incohérences de prédictions. En effet, le fait qu’il y ait des séquences prédiction impossible n’est pas pris en compte pendant l’inférence.
Par exemple il est impossible de passer d’un token I-Ei vers un token I-Ej ou bien d’un token B-Ei à un token I-Ej. Ceci est une information a priori connue qui est certes indirectement prise en compte lors de l’entrainement (vu que ce genre de séquences est complètement absent du dataset d’entraînement). Dans la majorité des cas, il n’y a pas besoin de forcer certaines prédictions. Mais si on compte tirer parti de cette interdépendance, le Conditional Random Field (CRF) est l’outil adéquat. (pour en savoir plus)
On utilise la librairie pytorch-crf
(github) pour cela.
Performances
*Le F1-score n’inclue pas les statistiques du tag “O”
**Sur les textes où l’on a séparé les ponctuations
Conformément à notre intuition, on constate que la séparation des ponctuations permet de gagner énormément en performances (2.5 points de F1-score en validation).
L’ajout d’un CRF permet de gagner 1 point de f1-score. Néanmoins l’entraînement est plus lent à cause de la nature séquentielle du problème de même pour la prédiction à cause du décodage de Viterbi.
Le fait de figer des poids accélère l’entrainement. Mais en se penchant plus en détails sur les performances par classes, on voit que les modèles sont très performants sur les classes majoritaires (dont la support est élevé) mais ignorent totalement les autres classes. pour résoudre ce problème, il faudrait idéalement alimenter en données les classes dont le support est faible et effectuer un ré-entrainement. Mais on a décidé, on part sur un modèle moins performant en globalité mais qui couvre un maximum de classes.
Analyses d’erreurs et perspectives
Le choix du meilleur modèle se fait sur la base de l’analyse des :
- Scores micros
- Scores par classe
- Matrice de confusions
Selon ces critères, c’est le modèle 2 (puis le Modèle 3 où on a ajouté une couche CRF) qui ont de bonnes performances car ils ont un bon score global puis couvrent la majorité des classes définies.
On voit directement l’apport du CRF sur les prédictions : Il nous permet d’avoir des séquences prédites plus robustes et cohérentes (On ne passe pas d’un B-Agressivité à un I-Colère car cette transition est impossible)
En analysant la matrice de confusions, on constate que la majorité des confusion est faite entre les classes E2-Insatisfaction, E3-Colère et E4-Agressivité. On remarque aussi qu’il y a certains tokens qui ne sont pas détectés en tant que tonalité et à l’inverse des tokens faussement détectés en tonalités.
On voit dans cet exemple, que le modèle détecte plus de chose que ce qui est annoté, mais la prédiction n’est pas entièrement fausse, elle est n’est juste pas exactement en ligne avec ce que l’annotateur a labellisé. De plus le modèle détecte un groupe de mots d’insatisfaction que l’annotateur n’a pas jugé nécessaire de sélectionner même si cela est correct.
Les performances peuvent sembler être faibles et le modèle très peu performant, mais si l’on s’autorise une marge m
de tokens non détectés, par rapport au vrai span, en dessous de laquelle on considèrera que la prédiction est correcte, voici ce que seraient les scores.
On voit que si l’on s’autorise 10 tokens de confusion tonalité-O (Tonalité quelconque au lieu de “O” ou bien l’inverse) on obtient un F1-score de 55% (~58% f1-score avec le CRF). Ceci est une métrique qui permet de bien visualiser le potentiel réel du modèle. On effet en pratique, l’utilisateur voudra, dans un grand texte, savoir où se situent les différents spans/groupes de mots porteur de tonalités, leurs délimitations exacte importe peu et cela va permettre d’aller analyser directement les passages interessants.
Pour de futurs travaux, il y a certaines pistes à explorer afin d’améliorer les scores notamment :
- Explorer des approches qui se concentrent sur les caractéristiques locales des mots : Étant donné que ces caractéristiques locales sont très déterminantes pour la classification (Usage de majuscules, ponctuations excessives), il serait plus judicieux de les encoder directement avec des embeddings adaptés au lieu des words-pieces (contrainte lors de l’utilisation des transformers). On pense notamment à CharacterCNN, CharacterLSTM, CharacterBERT.
- Alimenter les classes minoritaires par plus de données
- Tester des approches à l’état de l’art du NER (LUKE, NER as dependency parsing)
Applications chez nos clients
De par la diversité des coeurs de métiers de nos clients, chaque projet entrepris chez La Javaness R&D est unique. De ce fait, le modèle développé en interne est rarement utilisable tel quel sans aucune modification ni adaptation au domaine d’application.
Ce modèle a été par exemple utilisé pour effectuer de l’active learning en sélectionnant des données plus interessantes pour les entrainements (couplées avec des méthodes de similarité comme l’explique notre collègue Tuan dans cet article Medium), en jugeant sur la nécessité d’ajouter des classes spécifiques ou se contenter aux classes génériques mentionnées et effectuer des analyses de données pour avoir une vision plus complète sur le dataset étudié.
Conclusion
Nous voici arrivé à terme de cet article sur l’utilisation des méthodes de “Named Entities Recognition” pour détecter des expressions “non normées”, des expressions d’émotions et de tonalité dans notre cas.
On a vu qu’il a fallu constituer notre propre dataset et un guide d’annotation personnalisé avec des directives d’annotations adaptées pour palier à ce problème de compréhension de langage naturel.
En ce qui concerne la modélisation, il a fallu trouver une métrique d’évaluation adaptée et qui se rapproche d’une évaluation naturelle des prédictions et qui puisse convenablement statuer sur leur qualité.
Remerciement
Merci à notre collègue Paul DUMAITRE pour la revue de l’article.
A propos de l’auteur
KILANI Al Houceine est data scientist à La Javaness depuis octobre 2020.