NLP & fastai | ULMFiT

Pierre Guillou
16 min readSep 13, 2019

--

Ce post concerne les vidéos 8, 9, et 10 du cours fastai de Rachel Thomas sur NLP (A code-first introduction to NLP) ainsi que la vidéo 1 (notes) en entier et les parties de la vidéo 10 (notes) de 2018 et des vidéos 2019 [3 (notes), 4 (notes) et 12 (notes)] sur NLP du cours de Jeremy Howard (Introduction to Machine Learning for Coders). Son objectif est d’expliquer les concepts clés du ULMFiT en NLP présentés dans ces vidéos et leurs notebooks 5-nn-imdb.ipynb, nn-imdb-more.ipynb, review-cv-transfer.ipynb, review-nlp-transfer.ipynb, nn-vietnamese, nn-vietnamese-bwd et nn-turkish.ipynb associés.

Autres posts de la série NLP & fastai: Topic Modeling | Sentiment Classification | Language Model | Transfer Learning | MultiFit | French Language Model | Portuguese Model Language | RNN | LSTM & GRU | SentencePiece | Sequence-to-Sequence Model (seq2seq) | Attention Mechanism | Transformer Model | GPT-2

Motivation

Image Credit: Machine Learning vs. Traditional Statistics: Different philosophies, Different Approaches

Afin de classifier un texte par thème ou par sentiment, il existe depuis longtemps des techniques statistiques (lire les posts sur le Topic Modeling par SVD ou NMF et sur le Sentiment Classification par Naïve Bayes ou Logistic Regression avec des NGrams variants de 1 à 3). Elles ont l’avantage de pouvoir être utilisées même avec un corpus de petite taille mais en revenache elles présentent l’inconvénient d’être basées sur des hypothèses du type indépendance des caractéristiques (features) du corpus, ce qui est rarement le cas. Par ailleurs, elles n’apprennent rien de la structure et de la sémantique du corpus d’entraînement. Elles ne peuvent donc pas généraliser leur connaissance statistique à un nouveau corpus.

Avec l’accès à de grands corpus de textes (Wikipédia par exemple mais aussi l’ensemble du Web) et l’utilisation de modèles de Deep Learning, ces limites sont entrain d’être dépassées. Il est en effet possible depuis 2017 d’utiliser des techniques de modélisation de langage par apprentissage qui entraînent le modèle à comprendre de manière générale la langue du corpus d’entraînement, cad sa structure (orthographe, grammaire, syntaxe) mais aussi ses concepts (sens d’un mot par rapport aux autres mots de la phrase, relations hiérarchiques, relations entre des mots qui sont espacés dans une phrase, à qui ou à quoi fait référence un pronom personnel, connaissances issues du contenu du corpus, etc.). Ainsi, à la différence des techniques statistiques, aucune hypothèse n’est faite sur les caractéristiques du corpus d’entraînement, ce qui permet la généralisation du modèle à de nouveaux corpus.

Ces modèles entraînés sur de larges corpus sont connus sous l’expression Language Model (LM) Généraux. Ils sont entraînés à prédire le prochain mot d’une phrase à partir de l’état actuel (hidden state), cad les mots précédents. Leur flexibilité est une de leur plus grande qualité. En effet, ils peuvent être facilement spécialisés à partir de corpus plus petits de domaine particulier (critiques de filmes, documents médicaux, articles de sport, etc.).

Note: nous utiliserons l’expression LM Général pour tout LM entraîné sur un grand corpus non lié à un domaine spécifique comme l’ensemble des articles de Wikipedia dans une langue donnée (cf. ce post pour entraîner un LM dans une autre langue que l’anglais).

Bien sûr la question de la qualité d’un LM Général est essentielle (ce qui revient à vérifier sa “grande” profondeur en termes de couches et nombre de paramètres et s’il a été entraîné sur un corpus à la fois très grand mais aussi très varié comme les LM du type GPT-2 ou BERT entraînés sur des millions de pages Web). Pour l’évaluer, on vérifie la capacité (performance) du LM Général à surpasser des modèles de NLP construits avec une architecture spécifique pour accomplir une tâche bien définie sur un corpus particulier:

  • tout d’abord sans entraînement supplémentaire (ie, sans spécialisation au corpus particulier utilisé par les autres modèles NLP);
  • puis, en le spécialisant au corpus particulier utilisé par les autres modèles NLP en utilisant la technique de Transfer Learning.

Nous allons nous intéresser dans ce post à cette technique de spécialisation d’un LM Général en tentant de répondre à la question suivante:

Est-il possible de surpasser l’état de l’art (SOTA ou State of The Art), cad les performances de modèles NLP déjà publiées, dans la classification de textes en utilisant la technique de Transfer Learning d’un LM Général pré-entraîné et cela même si le corpus d’entraînement du domaine de classification est petit?

L’objet de ce post est de répondre à cette question en se basant sur le cours NLP de Rachel Thomas et Jeremy Howard qui présente le ULMFiT (Universal Language Model Fine-Tuning for Text Classification).

Note: Jeremy Howard et son équipe sont entrain de vérifier que l’ULMFiT peut aussi s’appliquer avec succès à d’autres applications que la classification de textes.

ULMFiT

ULMFiT signifie Universal Language Model Fine-Tuning for Text Classification (Jeremy Howard présente ULMFiT à la fin de la leçon 10 de la partie 2 de son cours sur le Deep Learning).

Ce modèle est apparu la première fois en janvier 2018 dans un article descriptif publié sur arxiv.org par Jeremy Howard et Sebastian Ruder intitulé “Universal Language Model Fine-tuning for Text Classification” et il est devenu en peu de temps la référence en NLP et précisément en classification de textes.

Son entraînement repose sur les 3 étapes suivantes:

  1. Entraînement d’un LM Général d’une langue donnée à partir d’un grand corpus de données textuelles type Wikipedia (de l’ordre de 100 millions de tokens) en utilisant l’architecture d’un AWD-LSTM ou d’un QRNN (cf. post sur LM Général): ce LM Général apprend ainsi à comprendre la langue en question.
  2. Spécialisation par Transfer Learning du LM Général pré-entraîné à partir du corpus des textes à classer (cf. post sur Transfer Learning): ce LM Spécialisé (à partir d’un LM Général) a appris à présent les spécificités du domaine des textes à classer.
  3. A partir du corpus des textes à classer, entraînement d’un classificateur dont les premières couches (celles qui encodent un texte en un vecteur d’activation) sont issues par Transfer Learning du LM Spécialisé.

L’étape 2 demande d’utiliser les techniques de Discr (discriminative fine-tuning) et STLR (Slanted Triangular Learning rates) pour entraîner finement (fine-tuning) le LM Spécialisé à partir du LM Général (Transfer Learning). L’étape 3 utilise en plus la technique de gradual unfreezing afin d’entraîner finement les couches du classificateur dont les premières correspondent à celles de l’encoder du LM Spécialisé (Transfer Learning).

Les 3 étapes d’entraînement d’un modèle ULMFiT (Image Credit: Universal Language Model Fine-tuning for Text Classification)

La méthode ULMFiT est universelle car elle fonctionne sur tout type de corpus de classification, utilise une architecture unique de modèle de classification (AWD-LSTM avec des vecteurs d’embeddings des mots de taille 400, 3 couches, 1150 activations par couche, et un BPTT batch size de 70) et le même processus d’entraînement, ne demande aucun feature engineering du modèle de classification ni aucun pré-traitement de son corpus et ne demande aucune information sur le domaine du corpus.

Note: en plus de permettre d’entraîner un forward classifier, la méthode ULMFiT peut aussi être utilisée pour entraîner un backard classifier (prédiction du mot précédent) car il est possible d’entraîner un bidirectionnal language model. En prenant la moyenne des prédictions du forward et backward classifier, la classification est souvent meilleure.

Enfin, la comparaison entre différentes configurations d’entraînement d’un classificateur montre que la méthode ULMFiT surpasse en performance toutes les autres quelque soit la taille du corpus d’entraînement (cf. capture d’écran ci-dessous).

Performance d’un modèle ULMFiT selon la taille du corpus d’entraînement (Image Credit: Introducing state of the art text classification with universal language models)

Implémentation en Python de la méthode ULMFiT

Ressources à consulter en particulier: vidéos 8, 9 et 10 et notebooks 5-nn-imdb.ipynb, nn-imdb-more.ipynb, review-nlp-transfer.ipynb, nn-vietnamese, nn-vietnamese-bwd et nn-turkish.ipynb.

Le code ci-dessous utilise Python et différentes bibliothèques (dont fastai v1) dans un Jupyter Notebook sur un OS avec GPU (cf. tous les tutoriaux d’installation de fastai v1 sur GPU).

Note: pour l’installation de fastai v1 sur votre ordinateur Windows 10 avec GPU, lire “How to install fastai v1 on Windows 10”. Cette installation est utile pour faire des tests à partir de petits corpus mais si vous souhaitez entraîner un LM sur un gros corpus, il est recommandé de choisir un GPU en ligne du type NVIDIA T4 ou même V100.

Nous n’y utilisons pas toutes les options possibles de codage utilisées par Rachel Thomas et Jeremy Howard afin d’attirer l’attention du lecteur sur les points essentiels.

Les 5 étapes basiques (hors étape d’application) de la création d’un modèle ULMFiT de classification de textes que nous détaillons ci-après sont ainsi les suivantes:

  1. Initialisation (importation des bibliothèques de notre environnement de travail)
  2. Téléchargement du corpus d’entraînement et vérification
  3. Création du DataBunch (tokenisation, puis numérisation)
  4. Création du learner du Language Model Spécialisé par Transfer Learning et entraînement
  5. Création du learner du Classificateur par Transfer Learning et entraînement
  6. Ensemble (option) | Appliquer les mêmes étapes pour un Classificateur créé par Transfer Learning d’un LM Backward

Voici à présent des explications détaillées sur ces 5 étapes ainsi que sur une option d’amélioration de la performance du modèle de classification.

1. Initialisation

Il s’agit de construire notre environnement de travail en important les bibliothèques que nous utiliserons dans le Jupyter Notebook.

Nous allons importer la bibliothèque fastai v1 (et son module fastai.text) qui permet de manipuler des corpus de texte de l’importation du corpus textuel à la création du DataBunch et imposer l’autoreload des fichiers de la bibliothèque ainsi que l’affichage des graphiques matplotlib dans le notebook. Nous définissons également notre batch size en tenant compte de la performance du GPU que nous allons utilisé (ie, batch size de 48 pour GPU de faible performance et de 128 dans le cas contraire), notre chemin path et répertoire pour les données à importer ainsi que la langue (lang = ‘en’ ici pour anglais) de notre corpus spécialisé.

Voici le code correspondant à implémenter:

# import fastai and fastai text
from fastai import *
from fastai.text import *
%reload_ext autoreload
%autoreload 2 # reload fastai files when they have been changed
%matplotlib inline # plot graphics in the notebook
bs=128 # choose batch size torch.cuda.set_device(0) # choose GPU if more than one
data_path = Config.data_path() # path to data
lang = 'en' # corpus language
name = f'{lang}wiki'
path = data_path/name
path.mkdir(exist_ok=True, parents=True)
lm_fns = [f'{lang}_wt', f'{lang}_wt_vocab']

2. Téléchargement du corpus d’entraînement et vérification

Il nous faut à présent importer nos données textuelles d’un domaine particulier puis, avant de les manipuler, il s’agit de vérifier leur bonne importation.

Note: comme bonne pratique, il est recommandé d’importer d’abord un échantillon des données afin de développer notre code avant de l’appliquer à l’ensemble des données.

Nous utilisons ici le grand jeu de données de critiques de films d’IMDB (100 000 movie reviews). Nous utiliserons la version hébergée dans le cadre des jeux de données fast.ai sur AWS Open Datasets.

Le jeu de données contient un nombre identique de critiques positives et négatives qui sont les plus polarisées: un avis négatif a un score ≤ 4 sur 10, et un avis positif a un score ≥ 7 sur 10 (les avis neutres ne sont pas inclus dans le jeu de données). Le jeu de données est divisé en 3 datasets dans les répertoires train, test et unsup avec 25 000 critiques étiquetées (négatif/positif) dans train, la même chose dans test et 50 000 critiques non étiquetées dans unsup.

Importation

# sample
# path = untar_data(URLs.IMDB_SAMPLE)
# full dataset# full dataset
path = untar_data(URLs.IMDB)path.ls()# results
[WindowsPath('D:/fastai/data/imdb/imdb.vocab'),
WindowsPath('D:/fastai/data/imdb/lm_databunch'),
WindowsPath('D:/fastai/data/imdb/models'),
WindowsPath('D:/fastai/data/imdb/README'),
WindowsPath('D:/fastai/data/imdb/test'),
WindowsPath('D:/fastai/data/imdb/tmp_clas'),
WindowsPath('D:/fastai/data/imdb/tmp_lm'),
WindowsPath('D:/fastai/data/imdb/train'),
WindowsPath('D:/fastai/data/imdb/unsup')]
(path/'train').ls()# results
[WindowsPath('D:/fastai/data/imdb/train/labeledBow.feat'),
WindowsPath('D:/fastai/data/imdb/train/neg'),
WindowsPath('D:/fastai/data/imdb/train/pos'),
WindowsPath('D:/fastai/data/imdb/train/unsupBow.feat')]

Vérification

# train
!ls {path}/'train/pos' | wc -l # 12500
!ls {path}/'train/neg' | wc -l # 12500
# test
!ls {path}/'test/pos' | wc -l # 12500
!ls {path}/'test/neg' | wc -l # 12500
# unsup
!ls {path}/'unsup' | wc -l # 50000
# Print the first lines of one text
!head -n 4 {(path/'train/pos').ls()[0]}

3. Création du DataBunch (tokenisation, puis numérisation)

Afin de pouvoir manipuler nos données textuelles à des fins d’entraînement d’un modèle de Deep Learning, il nous faut avant toute chose créer un vocabulaire en les tokénisant (un token peut représenter un début ou fin de phrase, un mot, un effet de style comme une ou des majuscules, un symbole de ponctuation, un symbole pour les mots non retenus, etc.) puis les numériser en remplaçant chaque token d’une phrase par son id dans le vocabulaire généré. Ces opérations se font lors de la création du DataBunch du corpus dans la bibliothèque fastai.

Note: par défaut, la bibliothèque fastai utilise le tokenizer SpaCy (vocab de 60 000 caractères par défaut). Depuis juillet 2019, elle dispose aussi de SentencePiece (vocab de 30 000 tokens par défaut).

DataBunch

Nous utilisons ici le Data Block Api de fastai.text pour créer le DataBunch du Language Model.

POINT CLE 1 | Pour entraîner notre LM Spécialisé, nous allons utilisé tous les datasets à notre disposition (train, test, unsup) qu’ils contiennent des critiques étiquetées ou non puisque les labels des données de notre LM sont directement les mots. Nous allons donc lister les 3 datasets dans le databunch ci-dessous, et cette augmentation de données d’entraînement à notre disposition nous permettra alors d’augmenter le nombre d’epochs jusqu’à 10 et cela sans overfitting.

%%time
#Inputs: all the text files in path
#We may have other temp folders that contain text files so we only keep what's in train, test and unsup
#We randomly split and keep 10% (10,000 reviews) for validation
#We want to do a language model so we label accordingly
data_lm = (TextList.from_folder(path)
.filter_by_folder(include=['train', 'test', 'unsup'])
.split_by_rand_pct(0.1, seed=42)
.label_for_lm()
.databunch(bs=bs, num_workers=1))
# Save DataBunch
data_lm.save(f'{path}/lm_databunch')

Exploration

# get train and valid datasets tokenized and numericalized by fastai, and the vocab of tokens
train_ds = data_lm.train_ds
valid_ds = data_lm.valid_ds
vocab = data_lm.vocab
# number of texts in train and valid
len(train_ds), len(valid_ds)
# size of vocab
len(vocab.itos), len(vocab.stoi)
# display the 10 first tokens
vocab.itos[:10]
# display the first train review
review = train_ds.x[0]
review
# display the id token list of the train review 0
tokens = review.data
tokens
# from a token list, display the corresponding text
' '.join(np.array(vocab.itos)[tokens])# Finally, show beginning of a batch
data_lm.show_batch()

Résultat de la tokénisation d’une review:

Text xxbos xxmaj once again xxmaj mr. xxmaj costner has dragged out a movie for far longer than necessary . xxmaj aside from the terrific sea rescue sequences , of which there are very few i just did not care about any of the characters . xxmaj most of us have ghosts in the closet , and xxmaj costner 's character are realized early on , and then forgotten until much later , by which time i did not care .

La tokénisation a en fait inséré des tokens spécifiques dont la liste est en ligne. Par exemple, xxunk (unknown) remplace un mot ou ensemble de caractères non retenu dans le vocabulaire du corpus (du fait, par exemple, de sa faible fréquence d’occurrence).

Note: nous pouvons obtenir un token à partir de son index (liste vocab.itos) et inversement, nous pouvons obtenir l’index du token de tout mot ou ensemble de caractères (dictionnaire vocab.stoi).

4. Création du learner du Language Model Spécialisé par Transfer Learning et entraînement

C’est à cette étape que nous appliquons le Transfer Learning pour la première fois en important dans notre learner l’architecture du Language Model Général pré-entraîné avec ses poids et son vocab.

Il y a ici 2 possibilités selon que le LM Général pré-entraîné est:

  • le modèle AWD-LSTM anglais (ASGD Weight-Dropped LSTM) présent dans la bibliothèque fastai. Il faut alors préciser pretrained=True dans le learner de la manière suivante:
learn_lm = language_model_learner(data_lm, AWD_LSTM, pretrained=True, drop_mult=0.5).to_fp16()

Note: le Language Model AWD-LSTM a été entraîné à partir du corpus WikiText-103 créé par Stephen Merity. Ce corpus est un sous-ensemble de Wikipedia en anglais qui contient plus de 100 millions de tokens dont ceux de ponctuation. AWS-LSTM représente donc un LM Général de la langue anglaise.

  • le modèle AWD-LSTM d’une autre langue que l’anglais et pré-entraîné avec un large corpus issu par exemple de Wikipedia. Il faut alors passer le fichier des poids du modèle et son vocab avec pretrained_fnames=lm_fns dans le learner de la manière suivante:
lang = 'vi' # use the letters that correspond to your LM language
lm_fns = [f'{lang}_wt', f'{lang}_wt_vocab']
learn_lm = language_model_learner(data_lm, AWD_LSTM, pretrained_fnames=lm_fns, drop_mult=0.5).to_fp16()

Note: lire ce post pour savoir comment entraîner un LM Général dans une langue autre que l’anglais.

Dans le premiers cas de figure, voici le code global:

# load DataBunch
data_lm = load_data(path, 'lm_databunch', bs=bs)
# Create LM learner
learn_lm = language_model_learner(data_lm, AWD_LSTM, pretrained=True, drop_mult=0.5).to_fp16()

POINT CLE 2 | Utiliser la méthode to_fp16() sur le LM learner. Cette méthode appelée Mixed Precision (MP) signifie qu’au lieu d’utiliser 32 bits (single precision floats), nous allons utiliser 16 bits (half precision floats). Si la plupart des CPU ne l’accepte pas, les GPU l’acceptent depuis 2 ans, en particulier les GPU NVIDIA (MP s’appelle Tensor Cores chez NVIDIA) et Google, ce qui augmente la vitesse de calcul de 8 à 10 fois quand la Mixed Precision est activée. Cependant, si 16 bits (half precision floats) sont suffisants pour le calcul du gradient, il nous faut 32 bits (single precision floats) pour la multiplication du learning rate avec le gradient (car valeurs très petites qui risquent alors d’être mises à zéro). C’est pour cela que fastai a implémenté dans la méthode to_fp16() la Mixed Precision.

POINT CLE 3 | Régulariser le learner par l’argument drop_mult. Le dropout est le fait de supprimer au hasard à chaque epoch des activations dans les couches, ce qui permet au modèle de mieux généraliser car cela l’oblige à trouver une combinaison des poids qui fonctionne pour le plus grand nombre de cas. L’argument drop_mult dans le language_model_learner(data_lm, AWD_LSTM, pretrained=True, drop_mult=0.5) entraîne la multiplication par sa valeur des valeurs par défaut des 5 dropout du modèle AWD-LSTM (1.0 laisse donc les valeurs par défaut des 5 dropout inchangées). Si votre LM overfit pendant l’entraînement, il vaut mieux augmenter la valeur de drop_mult (jusqu’à 1.0). Sinon, il faut la diminuer.

Note: Jeremy et son équipe viennent de découvrir (juillet 2019) que plus de dropout (ie, valeur de drop_mult jusqu’à 1.0) rend le LM plus facile à entraîner (plus constant/résilient) et améliore la performance du classificateur qui l’utilisera en Transfer Learning (même si celle du LM à proprement parlé sera moins élevée) (video). A ce stade, l’interprétation pourrait être que plus le LM est entraîné à généraliser (fort dropout) et plus il peut s’adapter à des tâches particulières comme la traduction ou la classification.

IMPORTANT | Focus sur le vocabulaire de notre learner vs celui du modèle AWS-LSTM

A chaque token du vocab de notre DataBunch (provenant des critiques de films IMDB), le learner recherche s’il existe dans le vocab de WikiText-103, cad dans le vocab du modèle AWD-LSTM. Si oui, le vecteur embedding de ce token dans AWS-LSTM va être copié-collé dans celui du même token dans notre learner (ie, Transfer Learning). Si non, le vecteur embedding de ce token sera initialisé avec des valeurs aléatoires, valeurs qui seront ensuite mises à jour lors de l’entraînement du learner.

# get vocab of WikiText-103
wiki_itos = pickle.load(open(Config().model_path()/'wt103-1/itos_wt103.pkl', 'rb'))
# compare size of vocabs
len(wiki_itos), len(vocab.itos)
# get the encoder of our learner
enc = learn_lm.model[0].encoder
enc.weight.size()
# get the embeding vector of a token
enc.weight[vocab.stoi[token]]

Entraînement du learner

. L’étape 3 utilise en plus la technique de gradual unfreezing

Nous pouvons à présent rechercher le meilleur Learning Rate pour entraîner notre learner (les techniques de Discr (discriminative fine-tuning) et STLR (Slanted Triangular Learning rates) pour entraîner finement (fine-tuning) le LM Spécialisé à partir du LM Général (Transfer Learning) seront utilisées).

learn_lm.lr_find()
learn_lm.recorder.plot()
lr = 1e-3
lr *= bs/48

Nous allons tout d’abord entraîner les vecteurs d’embeddings des mots qui n’étaient pas dans le vocab du corpus général. Ces vecteurs ayant été initialisés avec des valeurs aléatoires, il faut d’abord les entraîner (par exemple sur 1 epoch) avant d’entraîner l’ensemble du modèle.

learn_lm.fit_one_cycle(1, lr*10, moms=(0.8,0.7))
learn_lm.save('fit_1')

Nous pouvons ensuite unfreeze() notre learner afin de pouvoir entraîner l’ensemble de notre modèle sur 10 epochs avec un Learning Rate plus faible.

learn_lm.load('fit_1');learn_lm.unfreeze()
learn_lm.fit_one_cycle(10, lr, moms=(0.8,0.7))
# save learner and vocab
mdl_path = path/'models'
mdl_path.mkdir(exist_ok=True)
learn_lm.to_fp32().save(mdl_path/lm_fns[0], with_opt=False)
learn_lm.data.vocab.save(mdl_path/(lm_fns[1] + '.pkl'))

Enfin, nous devons veiller à sauvegarder l’encoder de notre LM Spécialisé puisque nous le transférerons à notre classificateur: cet ensemble de couches et de paramètres contient la compréhension par le modèle de l’utilisation de la langue des 2 corpus d’entraînement dans le domaine du second corpus.

# save the encoder part of the learner
learn_lm.save_encoder('fine_tuned_enc_10')

5. Création du learner du Classificateur par Transfer Learning et entraînement

Nous devons d’abord créer son databunch en respectant un point important: lui passer le vocab créé par le LM Spécialisé.

data_clas = (TextList.from_folder(path, vocab=data_lm.vocab)
.split_by_folder(valid='test')
.label_from_folder(classes=['neg', 'pos'])
.databunch(bs=bs, num_workers=1))
data_clas.save('imdb_textlist_class')

C’est en effet par rapport à ce vocab que le classificateur va évaluer le sentiment d’une phrase. Si le vocab du databunch du classificateur est différent, les premières couches du classificateur qui sont issues par Transfer Lean

Nous pouvons à présent créer le learner de notre classificateur dans lequel nous allons importer l’encoder du LM Spécialisé:

learn_c = text_classifier_learner(data_clas, AWD_LSTM, drop_mult=0.5).to_fp16()learn_c.load_encoder('fine_tuned_enc_10')

En plus des techniques de Discr (discriminative fine-tuning) et STLR (Slanted Triangular Learning rates) pour entraîner finement (fine-tuning) le classificateur à partir du LM Spécialisé (Transfer Learning), nous allons entraîner notre learner en appliquant le gradual unfreezing: nous bloquons (freeze()) toutes ses premières couches car nous souhaitons d’abord entraîner sur 1 epoch les dernières couches initialisées avec des valeurs aléatoires:

learn_c.freeze()lr=2e-2
lr *= bs/48
learn_c.fit_one_cycle(1, lr, moms=(0.8,0.7))

Puis nous allons entraîner de plus en plus de couches en les débloquant au fur et à mesure à partir des dernières pour finalement les entraîner toutes en même temps (unfreeze()):

learn_c.freeze_to(-2)
learn_c.fit_one_cycle(1, slice(lr/(2.6**4),lr), moms=(0.8,0.7))
learn_c.freeze_to(-3)
learn_c.fit_one_cycle(1, slice(lr/2/(2.6**4),lr/2), moms=(0.8,0.7))
learn_c.unfreeze()
learn_c.fit_one_cycle(2, slice(lr/10/(2.6**4),lr/10), moms=(0.8,0.7))
learn_c.save('clas')

6. Ensemble (option) | Appliquer les mêmes étapes pour un Classificateur créé par Transfer Learning d’un LM Backward

Comme le montre Jeremy Howard à la fin du notebook nn-vietnamese.ipynb, il est également possible de combiner (ensemble) 2 modèles pour améliorer notre prédiction.

Le second modèle de classification qu’il montre est nn-vietnamese-bwd.ipynb où le LM Général, LM Spécialisé et le classificateur sont entraînés à partir d’un databunch inversé: au lieu de prévoir le prochain mot, un LM Inversé (backward) prédit le mot qui précédait.

Tout le code d’implémentation se trouve dans les 2 notebooks indiqués.

Articles conseillés sur NLP et LM

À propos de l’auteur: Pierre Guillou est consultant en Intelligence Artificielle au Brésil et en France. Merci de le contacter via son profil Linkedin.

--

--