Transformers pré-entraînés avec Hugging Face

Démarrez avec le package Transformers de Hugging Face pour l'analyse des sentiments, la traduction, la classification de texte zéro-shot, le résumé, et la reconnaissance d'entités nommées (anglais et français)

Les transformers sont certainement parmi les modèles d'apprentissage profonds les plus populaires du moment.

À l'origine, les transformers ont été présentés comme une nouvelle architecture pour la traduction linguistique [Attention is All you Need, 2017 ]

Et en fait, ils sont encore principalement utilisés pour le traitement du langage naturel.

Voici quelques exemples:

  • classement de texte :
    • analyse des sentiments : ce texte est-il positif ou négatif ?
    • tri de documents : dans quel dossier ce document ou cet e-mail doit-il aller ?
  • génération de texte :
    • écrivez un article de blog à partir de zéro sur ce qu'il faut faire dans le jardin au printemps. C'est l'une des choses que GPT-3 peut faire.
  • reconnaissance d'entités nommées :
    • extraire des entités importantes du texte, telles que les noms de personnes, les dates, les prix, l'emplacement, etc.
  • étiquetage des parties du discours :
    • baliser des parties du texte selon leur rôle grammatical : noms, verbes, adjectifs, ...
  • traduction bien sûr

Dans cet article, vous utiliserez des modèles de transformateurs pré-entraînés pour effectuer certaines de ces tâches.

Nous allons utiliser la bibliothèque Hugging Face, qui fournit une interface simple et de haut niveau à TensorFlow ou Pytorch pour les transformateurs.

Hugging Face gère également un hub, ce qui facilite le partage et l'accès aux modèles et aux ensembles de données .

Vous pouvez exécuter ce tutoriel sur Google Colab en cliquant ici .

Il n'est pas nécessaire d'avoir une formation spécifique en programmation ou en apprentissage automatique, vous verrez que Hugging Face permet à quiconque d'utiliser très facilement des modèles de transformateurs pré-entraînés.

Enfin, veuillez noter que ce tutoriel a été traduit automatiquement depuis sa version anglaise !

Installation sur Google Colab

Le package Transformers n'est pas installé par défaut sur Google Colab. Alors installons-le avec pip :

In [ ]:
!pip install transformers[sentencepiece]
Collecting transformers[sentencepiece]
  Downloading https://files.pythonhosted.org/packages/b5/d5/c6c23ad75491467a9a84e526ef2364e523d45e2b0fae28a7cbe8689e7e84/transformers-4.8.1-py3-none-any.whl (2.5MB)
     |████████████████████████████████| 2.5MB 25.9MB/s 
Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (20.9)
Requirement already satisfied: filelock in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (3.0.12)
Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (1.19.5)
Collecting tokenizers<0.11,>=0.10.1
  Downloading https://files.pythonhosted.org/packages/d4/e2/df3543e8ffdab68f5acc73f613de9c2b155ac47f162e725dcac87c521c11/tokenizers-0.10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (3.3MB)
     |████████████████████████████████| 3.3MB 36.5MB/s 
Requirement already satisfied: importlib-metadata; python_version < "3.8" in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (4.5.0)
Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (2.23.0)
Requirement already satisfied: tqdm>=4.27 in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (4.41.1)
Requirement already satisfied: regex!=2019.12.17 in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (2019.12.20)
Collecting sacremoses
  Downloading https://files.pythonhosted.org/packages/75/ee/67241dc87f266093c533a2d4d3d69438e57d7a90abb216fa076e7d475d4a/sacremoses-0.0.45-py3-none-any.whl (895kB)
     |████████████████████████████████| 901kB 32.8MB/s 
Collecting huggingface-hub==0.0.12
  Downloading https://files.pythonhosted.org/packages/2f/ee/97e253668fda9b17e968b3f97b2f8e53aa0127e8807d24a547687423fe0b/huggingface_hub-0.0.12-py3-none-any.whl
Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (3.13)
Collecting sentencepiece==0.1.91; extra == "sentencepiece"
  Downloading https://files.pythonhosted.org/packages/f2/e2/813dff3d72df2f49554204e7e5f73a3dc0f0eb1e3958a4cad3ef3fb278b7/sentencepiece-0.1.91-cp37-cp37m-manylinux1_x86_64.whl (1.1MB)
     |████████████████████████████████| 1.1MB 24.4MB/s 
Requirement already satisfied: protobuf; extra == "sentencepiece" in /usr/local/lib/python3.7/dist-packages (from transformers[sentencepiece]) (3.12.4)
Requirement already satisfied: pyparsing>=2.0.2 in /usr/local/lib/python3.7/dist-packages (from packaging->transformers[sentencepiece]) (2.4.7)
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata; python_version < "3.8"->transformers[sentencepiece]) (3.4.1)
Requirement already satisfied: typing-extensions>=3.6.4; python_version < "3.8" in /usr/local/lib/python3.7/dist-packages (from importlib-metadata; python_version < "3.8"->transformers[sentencepiece]) (3.7.4.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->transformers[sentencepiece]) (2021.5.30)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->transformers[sentencepiece]) (1.24.3)
Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->transformers[sentencepiece]) (2.10)
Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->transformers[sentencepiece]) (3.0.4)
Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from sacremoses->transformers[sentencepiece]) (1.15.0)
Requirement already satisfied: click in /usr/local/lib/python3.7/dist-packages (from sacremoses->transformers[sentencepiece]) (7.1.2)
Requirement already satisfied: joblib in /usr/local/lib/python3.7/dist-packages (from sacremoses->transformers[sentencepiece]) (1.0.1)
Requirement already satisfied: setuptools in /usr/local/lib/python3.7/dist-packages (from protobuf; extra == "sentencepiece"->transformers[sentencepiece]) (57.0.0)
Installing collected packages: tokenizers, sacremoses, huggingface-hub, sentencepiece, transformers
Successfully installed huggingface-hub-0.0.12 sacremoses-0.0.45 sentencepiece-0.1.91 tokenizers-0.10.3 transformers-4.8.1

Analyse des sentiments en anglais

Dans cet article, nous utiliserons l'interface de pipeline de haut niveau, ce qui facilite grandement l'utilisation de modèles de transformers pré-entraînés.

Il nous faut juste dire au pipeline ce qu'il doit faire, et éventuellement de lui dire quel modèle utiliser pour cette tâche.

Ici, nous allons faire une analyse des sentiments en anglais.

Nous sélectionnons donc la tâche sentiment-analysis et gardons le modèle par défaut :

In [ ]:
from transformers import pipeline
classifier = pipeline("sentiment-analysis")




Le pipeline est prêt, et nous pouvons maintenant l'utiliser :

In [ ]:
classifier(["this is a great tutorial, thank you", 
            "your content just sucks"])
Out[ ]:
[{'label': 'POSITIVE', 'score': 0.9998582601547241},
 {'label': 'NEGATIVE', 'score': 0.9971919059753418}]

Nous avons envoyé deux phrases par le pipeline.

La première est considéréé comme positive et la deuxième négative, avec un niveau de confiance très élevé.

Voyons maintenant ce qui se passe si nous envoyons des phrases en français :

In [ ]:
classifier(["Ton tuto est vraiment bien", 
            "il est complètement nul"])
Out[ ]:
[{'label': 'POSITIVE', 'score': 0.7650704979896545},
 {'label': 'POSITIVE', 'score': 0.8282670974731445}]

Cette fois, le classement ne fonctionne pas...

En effet, la deuxième phrase, est classée comme positive.

Ce n'est pas une surprise : le modèle par défaut pour la tâche d'analyse des sentiments a été entraîné sur du texte anglais, et il ne comprend donc pas le français.

Analyse des sentiments en néerlandais, allemand, français, espagnol et italien

Alors, que faire si vous souhaitez travailler avec du texte dans une autre langue, disons le français ?

Il vous suffit de rechercher sur le hub un modèle de classification français.

Plusieurs modèles sont disponibles, et j'ai décidé de sélectionner nlptown/bert-base-multilingual-uncased-sentiment.

Nous pouvons spécifier ce modèle lors de la création de notre pipeline sentiment-analysis :

In [ ]:
multilang_classifier = pipeline("sentiment-analysis", 
                                model="nlptown/bert-base-multilingual-uncased-sentiment")





In [ ]:
multilang_classifier(["Ton tuto est vraiment bien", 
                      "il est complètement nul"])
Out[ ]:
[{'label': '5 stars', 'score': 0.5787978172302246},
 {'label': '1 star', 'score': 0.9223358035087585}]

Et ça marche ! La deuxième phrase est maintenant correctement classée comme très négative.

Vous vous demandez peut-être pourquoi la confiance pour la première phrase est plus faible. Je suis presque sûr que c'est parce que cette phrase obtient également un score élevé pour « 4 stars ».

Essayons maintenant avec une critique réelle trouvéé sur Google pour un restaurant près de chez moi :

In [ ]:
import pprint
sentence="Contente de pouvoir retourner au restaurant... Quelle déception... L accueil peu chaleureux... Un plat du jour plus disponible à 12h45...rien à me proposer à la place... Une pizza pas assez cuite et pour finir une glace pleine de glaçons... Et au gout très fade... Je pensais que les serveuses seraient plus aimable à l idée de retrouver leur clientèle.. Dommage"
pprint.pprint(sentence)
('Contente de pouvoir retourner au restaurant... Quelle déception... L accueil '
 'peu chaleureux... Un plat du jour plus disponible à 12h45...rien à me '
 'proposer à la place... Une pizza pas assez cuite et pour finir une glace '
 'pleine de glaçons... Et au gout très fade... Je pensais que les serveuses '
 'seraient plus aimable à l idée de retrouver leur clientèle.. Dommage')
In [ ]:
multilang_classifier([sentence])
Out[ ]:
[{'label': '2 stars', 'score': 0.5843755602836609}]

2 étoiles ! sur Google Review, cet avis a 1 étoile. Ce n'est pas une mauvaise prédiction, et je pense que le score doit être assez élevé pour "1 star" également.

Traduction anglais-français

Essayons de faire un peu de traduction, de l'anglais vers le français.

Encore une fois, nous recherchons le hub, et nous nous retrouvons avec ce pipeline :

In [ ]:
en_to_fr = pipeline("translation_en_to_fr", 
                    model="Helsinki-NLP/opus-mt-en-fr")






In [ ]:
en_to_fr("your tutorial is really good")
Out[ ]:
[{'translation_text': 'votre tutoriel est vraiment bon'}]

Cela fonctionne bien. Traduisons dans l'autre sens. Pour cela, nous devons changer la tâche et le modèle :

In [ ]:
fr_to_en = pipeline("translation_fr_to_en", 
                    model="Helsinki-NLP/opus-mt-fr-en")






In [ ]:
fr_to_en("ton tutoriel est super")
Out[ ]:
[{'translation_text': 'Your tutorial is great.'}]

Parfait!

Classement "zero-shot" en français

De nos jours, de très grands modèles d'apprentissage en profondeur sont entraînés sur de vastes ensembles de données collectés sur Internet.

Ces modèles en savent déjà beaucoup, et n'ont donc pas besoin d'en apprendre beaucoup plus.

En règle générale, il est possible d'affiner ces modèles pour un cas d'utilisation spécifique comme la classification de texte avec un très petit jeu de données spécifique supplémentaire. C'est ce qu'on appelle l'apprentissage en quelques coups, ou few-shot learning.

Et parfois, nous pouvons même faire du zero shot learning : des tâches spécifiques peuvent être effectuées sans aucun entraînement spécifique. C'est ce que nous allons faire maintenant.

Nous recherchons dans le hub un modèle de classification zero-shot français, et nous créons le pipeline :

In [ ]:
classifier = pipeline("zero-shot-classification", 
                      model="BaptisteDoyen/camembert-base-xlni")





Dans l'exemple ci-dessous, je propose une phrase à classer, et je précise également les catégories.

Il est important de noter que le modèle n'a pas été entraîné avec ces catégories, vous pouvez les modifier à volonté !

In [ ]:
sequence = "Colin est en train d'écrire un article au sujet du traitement du langage naturel"
candidate_labels = ["science","politique","education", "news"]
classifier(sequence, candidate_labels)     
Out[ ]:
{'labels': ['science', 'news', 'education', 'politique'],
 'scores': [0.4613836407661438,
  0.20861364901065826,
  0.20573210716247559,
  0.12427058815956116],
 'sequence': "Colin est en train d'écrire un article au sujet du traitement du langage naturel"}

Les probabilités prédites semblent raisonnables. Cette phrase concerne en effet la science, l'actualité et l'éducation. Et n'a rien à voir avec la politique.

Essayons maintenant ceci :

In [ ]:
sequence = "Laurent Wauquiez reconduit à la tête de la région Rhône-Alpes-Auvergne à la suite du deuxième tour des élections."
candidate_labels = ["politique", "musique"]
classifier(sequence, candidate_labels)   
Out[ ]:
{'labels': ['politique', 'musique'],
 'scores': [0.6573010087013245, 0.34269899129867554],
 'sequence': 'Laurent Wauquiez reconduit à la tête de la région Rhône-Alpes-Auvergne à la suite du deuxième tour des élections.'}

Cette fois, c'est bien la catégorie politique qui sort en premier

N'hésitez pas à essayer d'autres phrases et d'autres catégories. Vous pouvez également changer de modèle si vous souhaitez effectuer une classification zero zhot en anglais ou dans une autre langue.

Résumé en français

Résumer du texte est un cas d'usage intéressant des transformers.

Ici, nous utilisons un modèle entraîné sur un jeu de données obtenu en scrapant https://actu.orange.fr/, à nouveau trouvé sur le hub Hugging Face :

In [ ]:
summarizer = pipeline("summarization", 
                       model="moussaKam/barthez-orangesum-title")




Reprenons les deux premiers paragraphes d'un article sur le Covid-19 lu dans Le Monde :

In [ ]:
import pprint
sentence = "La pandémie ne marque pas le pas. Le variant Delta poursuit son essor planétaire au grand dam de pays impatients de retrouver une vie normale. La pandémie a fait près de quatre millions de morts dans le monde depuis que le bureau de l’Organisation mondiale de la santé (OMS) en Chine a fait état de l’apparition de la maladie fin décembre 2019, selon un bilan établi par l’Agence France-Presse (AFP) à partir de sources officielles, lundi à 12 heures. Les Etats-Unis sont le pays le plus touché tant en nombre de morts (603 967) que de cas. Le Brésil, qui compte 513 474 morts, est suivi par l’Inde (396 730), le Mexique (232 564) et le Pérou (191 899), le pays qui déplore le plus de morts par rapport à sa population. Ces chiffres, qui reposent sur les bilans quotidiens des autorités nationales de santé, sont globalement sous-évalués. L’Organisation mondiale de la santé (OMS) estime que le bilan de la pandémie pourrait être deux à trois fois plus élevé que celui officiellement calculé."
pprint.pprint(sentence)
('La pandémie ne marque pas le pas. Le variant Delta poursuit son essor '
 'planétaire au grand dam de pays impatients de retrouver une vie normale. La '
 'pandémie a fait près de quatre millions de morts dans le monde depuis que le '
 'bureau de l’Organisation mondiale de la santé (OMS) en Chine a fait état de '
 'l’apparition de la maladie fin décembre 2019, selon un bilan établi par '
 'l’Agence France-Presse (AFP) à partir de sources officielles, lundi à 12 '
 'heures. Les Etats-Unis sont le pays le plus touché tant en nombre de morts '
 '(603 967) que de cas. Le Brésil, qui compte 513 474 morts, est suivi par '
 'l’Inde (396 730), le Mexique (232 564) et le Pérou (191 899), le pays qui '
 'déplore le plus de morts par rapport à sa population. Ces chiffres, qui '
 'reposent sur les bilans quotidiens des autorités nationales de santé, sont '
 'globalement sous-évalués. L’Organisation mondiale de la santé (OMS) estime '
 'que le bilan de la pandémie pourrait être deux à trois fois plus élevé que '
 'celui officiellement calculé.')
In [ ]:
summarizer(sentence, max_length=80)
Out[ ]:
[{'summary_text': 'Coronavirus : près de 4 millions de morts dans le monde'}]

Le résumé est assez lapidaire, mais plutôt bon.

Reconnaissance d'entités nommées en français

La reconnaissance d'entités nommées (NER pour Named Entity Recognition) peut servir de base à de nombreuses applications intéressantes.

Par exemple, on pourrait analyser des rapports financiers à la recherche de dates, de prix, de noms de sociétés.

Voyons comment faire cela.

Ici, nous utilisons un équivalent français de BERT, appelé CamemBERT, affiné pour NER :

In [ ]:
ner = pipeline("token-classification", model="Jean-Baptiste/camembert-ner")





In [ ]:
nes = ner("Colin est parti à Saint-André acheter de la mozzarella")
pprint.pprint(nes)
[{'end': 5,
  'entity': 'PER',
  'index': 1,
  'score': 0.94243556,
  'start': 0,
  'word': '▁Colin'},
 {'end': 23,
  'entity': 'LOC',
  'index': 5,
  'score': 0.99605554,
  'start': 17,
  'word': '▁Saint'},
 {'end': 24,
  'entity': 'LOC',
  'index': 6,
  'score': 0.9967083,
  'start': 23,
  'word': '-'},
 {'end': 29,
  'entity': 'LOC',
  'index': 7,
  'score': 0.99609375,
  'start': 24,
  'word': 'André'}]

Nous devons faire un peu de post-traitement pour agréger les entités nommées du même type.

Voici un algorithme simple pour le faire (il peut certainement être amélioré !)

In [ ]:
cur = None
agg = []
for ne in nes: 
  entity=ne['entity']
  if entity != cur: 
    if cur is None: 
      cur = entity
    if agg: 
      print(cur, ner.tokenizer.convert_tokens_to_string(agg))
      agg = []
      cur = entity
  agg.append(ne['word'])
print(cur, ner.tokenizer.convert_tokens_to_string(agg))
PER Colin
LOC Saint-André

Nous avons trouvé deux entités nommées :

  • PERSONNE : Colin
  • LIEU : Saint-André

Perspectives

Dans cet article, vous avez vu comme il est facile d'utiliser un transformateur pré-entraîné, en utilisant le package de transformers de Hugging Face.

Ceci est possible grâce à tous les chercheurs qui ont conçu et entraîné les modèles, et qui les ont partagés sur le hub Hugging Face.

Si vous voulez en savoir plus sur les transformers, je vous encourage à suivre le cours Hugging Face . Cela ne devrait pas vous prendre plus d'une journée, surtout si vous connaissez déjà le deep learning.

Dans le prochain article, nous verrons comment régler un transformer pour une tâche spécifique, grâce au transfer learning.


N'hésitez pas à me donner votre avis dans les commentaires ! Je répondrai à toutes les questions.

Et si vous avez aimé cet article, vous pouvez souscrire à ma newsletter pour être prévenu lorsque j'en sortirai un nouveau. Pas plus d'un mail par semaine, promis!

Retour


Encore plus de data science et de machine learning !

Rejoignez ma mailing list pour plus de posts et du contenu exclusif:

Je ne partagerai jamais vos infos.
Partagez si vous aimez cet article: