Entraînement d’un modèle “Transformer” avec HuggingFace

Sébastien Carpentier
Sébastien Carpentier
31 Mars, 2023
7 minutes

Dans cet article, nous aborderons le pré-entraînement d’un modèle Transformer à l’aide de la bibliothèque Transformers de HuggingFace. Nous recourons au hub de modèle de HuggingFace afin d’initialiser un modèle vierge. Bien qu’il reste vivement recommandé d’utiliser des modèles pré-entraînés, cela peut s’avérer utile dès lors qu’il n’y a pas de poids, ni de tokenizer pour une langue et un modèle souhaité.

1. Le dataset

Cet article se basera sur le pré-entraînement d’un modèle RoBERTa dans le but de faire de la complétion de texte. D’autres applications sont possibles à condition de réentraîner (fine tuning) le modèle et de changer la tête de ce dernier en rapport avec la tâche.

Pour accomplir cet entraînement, nous allons recourir à un large corpus composé de lignes de texte dans la langue ciblée afin de permettre à notre modèle de créer la modélisation la plus exhaustive possible du langage. Rappelez-vous que ce type de modèle demande une très grande quantité de données ! Vous pouvez vous reporter au hub datasets de HuggingFace (https://huggingface.co/datasets) en filtrant avec la tâche fill-mask et la langue souhaitée. Cependant attention, des datasets comme oscar-en peuvent atteindre un volume de 3To.

2. Le tokenizer

Nous avons maintenant notre dataset. Notre modèle ne prenant pas de données textuelles, nous devons traduire ce dataset en valeurs numériques à partir desquelles notre modèle pourra travailler. C'est le rôle du tokenizer.
Dans un premier temps, notre tokenizer se chargera de découper nos phrases en tokens, puis transformera ses tokens en valeurs numériques. Il existe plusieurs façons de “tokeniser” un texte :

- Basé sur les mots :
Chaque mot ou ponctuation peut être séparé. Nous obtiendrions alors un vocabulaire de taille très importante, voire trop. Par exemple, si les suffixes de “maison” et “maisonnette” sont différents, le concept représenté est identique.

- Basé sur les caractères :
En séparant chaque caractère, le volume total de notre vocabulaire serait fortement allégé. Néanmoins, nos entrées seraient très longues et pourraient être handicapantes pour entraîner le modèle.

- Basé sur les sous-mots :
Dans cette approche notre algorithme de tokenisation se basera sur les statistiques d’apparition de sous séquence (n-grammes) de lettres pour en créer un seul token. Les mots peuvent donc se représenter sur un ou plusieurs tokens en fonction des sous séquence de lettres qui les composent.

- Et bien d’autres…

J’utiliserai ici un dataset léger, en format texte ligne par ligne et le tokenizer ByteLevelBPE, qui se rapproche d’une tokenisation en sous mot, mais travail sur les bytes, sans vocabulaire comme suit :

code

L'entraînement du tokenizer requiert de lui fournir les tokens spéciaux utilisés par notre modèle. Ces derniers seront utilisés par le modèle pour indiquer les débuts et fin de phrase ou encore l’emplacement d’un masque pour un entraînement en modélisation de langage masqué.

Cet entraînement peut prendre un certain temps. Ne pas oublier de sauver le tokenizer à la fin. Cela nous permettra de l'instancier de nouveau plus tard sans entraînement, à l’aide des fichiers [vocab.json] et [merges.txt] générés par la sauvegarde.

Nous pouvons maintenant tester le tokenizer en lui passant une phrase :

Nous voyons que la phrase est transformée en 7 tokens, le premier et le dernier étant la représentation d’un début et d’une fin de phrase. Chacun de ses tokens est transformé en valeur numérique appelée ID.

Le masque d’attention représente les ID sur lesquelles les têtes d’attention devront travailler. Dans notre cas, tous les ID sont à considérer sur la tâche, sur de la réponse aux questions, nous aurions un masque débutant par des 1 puis des 0 pour ne considérer que la question et inversement pour la réponse.

Nous pouvons maintenant charger un tokenizer plus rapide fournit par HuggingFace et adapté au modèle cible : RobertaTokenizerFast; et l’initialiser avec notre sauvegarde.

code

Ce dernier sera plus rapide, car une partie est codée en Rust.

3. L’entrainement

Nous allons maintenant pouvoir instancier notre modèle. Comme pour le tokenizer, nous utiliserons un modèle de HuggingFace non entraîné après avoir préalablement déclaré sa configuration (nombre de layers, nombre de têtes d’attention, etc.).

Nous ajouterons aussi un data collator à notre tokenizer fast afin de préciser que l’on recourt au masking du dataset et la probabilité d’apparition des masques dans celui-ci. Le but de notre entraînement étant de retrouver les mots du dataset d’origine masqués aléatoirement afin de créer une modélisation du langage. Cela relève d’une approche auto-supervisée, où X est la phrase à compléter et Y le mot masqué (déjà connu grâce à la donnée d’origine). Il n’y a donc pas d’annotations préalables nécessaires : nous pouvons donc travailler avec de très larges corpus sans trop de difficultés.

Finalement, nous pouvons instancier un trainer dans le but de lancer l'entraînement par la méthode train. Ce dernier peut recevoir une méthode de calcul des métriques, un dataset de validation, etc. Le trainer générera des logs au format “tensorboard” durant l'entraînement. Il est aussi possible de renseigner les métriques à utiliser pendant le training en renseignant une fonction de calcul de ces dernières au TrainingArguments.compute_metrics.

codecode

4. Conclusion

À la fin de cet entraînement, nous avons un modèle encodeur qui a appris une modélisation du langage ciblé. Il est actuellement effectif sur les tâches de complétion de masques, mais pas sur des tâches de type classification, etc.

Afin de s'entraîner sur une tâche de classification, par exemple, une nouvelle tête devra être mise en place et un fine tuning sera requis sur un dataset de même langue relatif à la tâche. L’avantage de cette méthode se situe notamment dans le fait qu’il faut un corpus de très grande taille pour entraîner le modèle. Par cette approche, on peut donc former un dataset conséquent plus simplement sans avoir à l'annoter. Le fine tuning sur la tâche finale profite de la modélisation du langage et requiert un dataset de taille bien plus faible qui sera plus rapide à annoter pour un entraînement supervisé. Cet aspect sera abordé lors d’un prochain article.

5. Références