@@ -38,26 +38,25 @@ Ce processus d'ajustement fin d'un modèle de langage pré-entraîné sur des do
-Plongeons-y !
+Allons-y !
-🙋 Si les termes "modélisation du langage masqué" et "modèle pré-entraîné" ne vous sont pas familiers, consultez le [Chapitre 1](/course/fr/chapiter1), où nous expliquons tous ces concepts fondamentaux, vidéos à l'appui !
+🙋 Si les termes « modélisation du langage masqué » et « modèle pré-entraîné » ne vous sont pas familiers, consultez le [chapitre 1](/course/fr/chapiter1), où nous expliquons tous ces concepts fondamentaux, vidéos à l'appui !
## Choix d'un modèle pré-entraîné pour la modélisation du langage masqué
-Pour commencer, nous allons choisir un modèle pré-entraîné approprié pour la modélisation du langage masqué. Comme le montre la capture d'écran suivante, vous pouvez trouver une liste de candidats en appliquant le filtre "Fill-Mask" sur le [*Hub*] (https://huggingface.co/models?pipeline_tag=fill-mask&sort=downloads) :
+Pour commencer, nous allons choisir un modèle pré-entraîné approprié pour la modélisation du langage masqué. Comme le montre la capture d'écran suivante, vous pouvez trouver une liste de candidats en appliquant le filtre « *Fill-Mask* » sur le [*Hub*](https://huggingface.co/models?pipeline_tag=fill-mask&sort=downloads) :
-Bien que les modèles de la famille BERT et RoBERTa soient les plus téléchargés, nous utiliserons un modèle appelé [DistilBERT](https://huggingface.co/distilbert-base-uncased)
-qui peut être entraîné beaucoup plus rapidement avec peu ou pas de perte de performance en aval. Ce modèle a été entraîné à l'aide d'une technique spéciale appelée [_distillation de connaissances_](https://en.wikipedia.org/wiki/Knowledge_distillation), où un grand "modèle maître" comme BERT est utilisé pour guider l'entraînement d'un "modèle élève" qui a beaucoup moins de paramètres. Une explication des détails de la distillation de connaissances nous mènerait trop loin dans cette section, mais si vous êtes intéressé, vous pouvez lire tout cela dans [_Natural Language Processing with Transformers_](https://learning.oreilly.com/library/view/natural-language-processing/9781098103231/ch05.html) (familièrement connu comme le manuel Transformers).
+Bien que les modèles de la famille BERT et RoBERTa soient les plus téléchargés, nous utiliserons un modèle appelé [DistilBERT](https://huggingface.co/distilbert-base-uncased) qui peut être entraîné beaucoup plus rapidement avec peu ou pas de perte de performance en aval. Ce modèle a été entraîné à l'aide d'une technique spéciale appelée [_distillation de connaissances_](https://en.wikipedia.org/wiki/Knowledge_distillation), où un grand modèle *enseignant* comme BERT est utilisé pour guider l'entraînement d'un modèle *étudiant* qui a beaucoup moins de paramètres. Une explication des détails de la distillation de connaissances nous mènerait trop loin dans cette section mais si vous êtes intéressé, vous pouvez lire tout cela dans le livre [_Natural Language Processing with Transformers_](https://learning.oreilly.com/library/view/natural-language-processing/9781098103231/ch05.html).
{#if fw === 'pt'}
@@ -74,13 +73,13 @@ Nous pouvons voir combien de paramètres ce modèle possède en appelant la mét
```python
distilbert_num_parameters = model.num_parameters() / 1_000_000
-print(f"'>>> DistilBERT number of parameters: {round(distilbert_num_parameters)}M'")
-print(f"'>>> BERT number of parameters: 110M'")
+print(f"'>>> DistilBERT nombre de paramètres : {round(distilbert_num_parameters)}M'")
+print(f"'>>> BERT nombre de paramètres : 110M'")
```
```python out
-'>>> DistilBERT number of parameters: 67M'
-'>>> BERT number of parameters: 110M'
+'>>> DistilBERT nombre de paramètres : 67M'
+'>>> BERT nombre de paramètres : 110M'
```
{:else}
@@ -97,7 +96,7 @@ model = TFAutoModelForMaskedLM.from_pretrained(model_checkpoint)
Nous pouvons voir combien de paramètres ce modèle possède en appelant la méthode `summary()` :
```python
-model(model.dummy_inputs) # Build the model
+model(model.dummy_inputs) # Construire le modèle
model.summary()
```
@@ -122,13 +121,13 @@ _________________________________________________________________
{/if}
-Avec environ 67 millions de paramètres, DistilBERT est environ deux fois plus petit que le modèle de base de BERT, ce qui se traduit approximativement par une accélération de l'entraînement d'un facteur deux - très bien ! Voyons maintenant quels types de *tokens* ce modèle prédit comme étant les compléments les plus probables d'un petit échantillon de texte :
+Avec environ 67 millions de paramètres, DistilBERT est environ deux fois plus petit que le modèle de base de BERT, ce qui se traduit approximativement par une accélération de l'entraînement d'un facteur deux. Voyons maintenant quels types de *tokens* ce modèle prédit comme étant les compléments les plus probables d'un petit échantillon de texte :
```python
text = "This is a great [MASK]."
```
-En tant qu'êtres humains, nous pouvons imaginer de nombreuses possibilités pour le *token* `[MASK]`, telles que "jour", "promenade" ou "peinture". Pour les modèles pré-entraînés, les prédictions dépendent du corpus sur lequel le modèle a été entraîné, puisqu'il apprend à détecter les modèles statistiques présents dans les données. Comme BERT, DistilBERT a été pré-entraîné sur les ensembles de données [English Wikipedia](https://huggingface.co/datasets/wikipedia) et [BookCorpus](https://huggingface.co/datasets/bookcorpus), nous nous attendons donc à ce que les prédictions pour `[MASK]` reflètent ces domaines. Pour prédire le masque, nous avons besoin du *tokenizer* de DistilBERT pour produire les entrées du modèle, alors téléchargeons-le également depuis le *Hub* :
+En tant qu'êtres humains, nous pouvons imaginer de nombreuses possibilités pour le *token* `[MASK]`, telles que « jour », « promenade » ou « peinture ». Pour les modèles pré-entraînés, les prédictions dépendent du corpus sur lequel le modèle a été entraîné puisqu'il apprend à détecter les modèles statistiques présents dans les données. Comme BERT, DistilBERT a été pré-entraîné sur les jeux de données [*English Wikipedia*](https://huggingface.co/datasets/wikipedia) et [*BookCorpus*](https://huggingface.co/datasets/bookcorpus), nous nous attendons donc à ce que les prédictions pour `[MASK]` reflètent ces domaines. Pour prédire le masque, nous avons besoin du *tokenizer* de DistilBERT pour produire les entrées du modèle, alors téléchargeons-le également depuis le *Hub* :
```python
from transformers import AutoTokenizer
@@ -136,7 +135,7 @@ from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```
-Avec un *tokenizer* et un modèle, nous pouvons maintenant passer notre exemple de texte au modèle, extraire les logits, et imprimer les 5 meilleurs candidats :
+Avec un *tokenizer* et un modèle, nous pouvons maintenant passer notre exemple de texte au modèle, extraire les logits, et afficher les 5 meilleurs candidats :
{#if fw === 'pt'}
@@ -145,7 +144,7 @@ import torch
inputs = tokenizer(text, return_tensors="pt")
token_logits = model(**inputs).logits
-# Trouvez l'emplacement de [MASK] et extrayez ses logits
+# Trouve l'emplacement de [MASK] et extrait ses logits
mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1]
mask_token_logits = token_logits[0, mask_token_index, :]
# Choisissez les candidats [MASK] avec les logits les plus élevés
@@ -163,7 +162,7 @@ import tensorflow as tf
inputs = tokenizer(text, return_tensors="np")
token_logits = model(**inputs).logits
-# Trouvez l'emplacement de [MASK] et extrayez ses logits
+# Trouve l'emplacement de [MASK] et extrait ses logits
mask_token_index = np.argwhere(inputs["input_ids"] == tokenizer.mask_token_id)[0, 1]
mask_token_logits = token_logits[0, mask_token_index, :]
# On choisit les candidats [MASK] avec les logits les plus élevés
@@ -177,19 +176,19 @@ for token in top_5_tokens:
{/if}
```python out
-'>>> This is a great deal.'
-'>>> This is a great success.'
-'>>> This is a great adventure.'
-'>>> This is a great idea.'
-'>>> This is a great feat.'
+'>>> This is a great deal.' # C'est une bonne affaire
+'>>> This is a great success.' # C'est un grand succès
+'>>> This is a great adventure.' # C'est une grande aventure
+'>>> This is a great idea.' # C'est une bonne idée
+'>>> This is a great feat.' # C'est un grand exploit
```
-Nous pouvons voir dans les sorties que les prédictions du modèle se réfèrent à des termes de tous les jours, ce qui n'est peut-être pas surprenant étant donné le fondement de la Wikipédia anglaise. Voyons comment nous pouvons changer ce domaine pour quelque chose d'un peu plus spécialisé : des critiques de films très polarisées !
+Nous pouvons voir dans les sorties que les prédictions du modèle se réfèrent à des termes de tous les jours, ce qui n'est peut-être pas surprenant étant donné le fondement de Wikipédia. Voyons comment nous pouvons changer ce domaine pour quelque chose d'un peu plus spécialisé : des critiques de films !
## Le jeu de données
-Pour illustrer l'adaptation au domaine, nous utiliserons le célèbre [Large Movie Review Dataset](https://huggingface.co/datasets/imdb) (ou IMDb en abrégé), qui est un corpus de critiques de films souvent utilisé pour évaluer les modèles d'analyse de sentiments. En affinant DistilBERT sur ce corpus, nous espérons que le modèle de langage adaptera son vocabulaire des données factuelles de Wikipédia sur lesquelles il a été pré-entraîné aux éléments plus subjectifs des critiques de films. Nous pouvons obtenir les données du *Hub* avec la fonction `load_dataset()` de 🤗 *Datasets* :
+Pour illustrer l'adaptation au domaine, nous utiliserons le célèbre [*Large Movie Review Dataset*](https://huggingface.co/datasets/imdb) (ou IMDb en abrégé), qui est un corpus de critiques de films souvent utilisé pour évaluer les modèles d'analyse de sentiments. En *finetunant* DistilBERT sur ce corpus, nous espérons que le modèle de langage adaptera son vocabulaire des données factuelles de Wikipédia sur lesquelles il a été pré-entraîné aux éléments plus subjectifs des critiques de films. Nous pouvons obtenir les données du *Hub* avec la fonction `load_dataset()` de 🤗 *Datasets* :
```python
from datasets import load_dataset
@@ -215,7 +214,7 @@ DatasetDict({
})
```
-Nous pouvons voir que les parties `train` et `test` sont chacune composées de 25 000 critiques, alors qu'il y a une partie non étiquetée appelée `unsupervised` qui contient 50 000 critiques. Jetons un coup d'œil à quelques échantillons pour avoir une idée du type de texte auquel nous avons affaire. Comme nous l'avons fait dans les chapitres précédents du cours, nous allons enchaîner les fonctions `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire :
+Nous pouvons voir que les parties `train` et `test` sont chacune composées de 25 000 critiques, alors qu'il y a une partie non étiquetée appelée `unsupervised` qui contient 50 000 critiques. Jetons un coup d'œil à quelques échantillons pour avoir une idée du type de texte auquel nous avons affaire. Comme nous l'avons fait dans les chapitres précédents du cours, nous allons enchaîner les fonctions `Dataset.shuffle()` et `Dataset.select()` pour créer un échantillon aléatoire :
```python
sample = imdb_dataset["train"].shuffle(seed=42).select(range(3))
@@ -237,15 +236,15 @@ for row in sample:
'>>> Label: 1'
```
-Oui, ce sont bien des critiques de films, et si vous êtes assez vieux, vous pouvez même comprendre le commentaire dans la dernière critique sur le fait de posséder une version VHS 😜 ! Bien que nous n'ayons pas besoin des étiquettes pour la modélisation du langage, nous pouvons déjà voir qu'un `0` dénote une critique négative, tandis qu'un `1` correspond à une critique positive.
+Oui, ce sont bien des critiques de films, et si vous êtes assez âgés, vous pouvez même comprendre le commentaire dans la dernière critique sur le fait de posséder une version VHS 😜 ! Bien que nous n'ayons pas besoin des étiquettes pour la modélisation du langage, nous pouvons déjà voir qu'un `0` dénote une critique négative, tandis qu'un `1` correspond à une critique positive.
-✏️ **Essayez !** Créez un échantillon aléatoire de la répartition `unsupervised` et vérifiez que les étiquettes ne sont ni `0` ni `1`. Pendant que vous y êtes, vous pouvez aussi vérifier que les étiquettes dans les fractions `train` et `test` sont bien `0` ou `1`. C'est un contrôle utile que tout praticien en NLP devrait effectuer au début d'un nouveau projet !
+✏️ **Essayez !** Créez un échantillon aléatoire de la répartition `unsupervised` et vérifiez que les étiquettes ne sont ni `0` ni `1`. Pendant que vous y êtes, vous pouvez aussi vérifier que les étiquettes dans les échantillons `train` et `test` sont bien `0` ou `1`. C'est un contrôle utile que tout praticien en NLP devrait effectuer au début d'un nouveau projet !
-Maintenant que nous avons jeté un coup d'œil rapide aux données, plongeons dans leur préparation pour la modélisation du langage masqué. Comme nous allons le voir, il y a quelques étapes supplémentaires à suivre par rapport aux tâches de classification de séquences que nous avons vues au [Chapitre 3](/course/fr/chapter3). Allons-y !
+Maintenant que nous avons jeté un coup d'œil rapide aux données, plongeons dans leur préparation pour la modélisation du langage masqué. Comme nous allons le voir, il y a quelques étapes supplémentaires à suivre par rapport aux tâches de classification de séquences que nous avons vues au [chapitre 3](/course/fr/chapter3). Allons-y !
## Prétraitement des données
@@ -253,7 +252,7 @@ Maintenant que nous avons jeté un coup d'œil rapide aux données, plongeons da
Pour la modélisation autorégressive et la modélisation du langage masqué, une étape commune de prétraitement consiste à concaténer tous les exemples, puis à diviser le corpus entier en morceaux de taille égale. C'est très différent de notre approche habituelle, où nous nous contentons de *tokenizer* les exemples individuels. Pourquoi tout concaténer ? La raison est que les exemples individuels peuvent être tronqués s'ils sont trop longs, ce qui entraînerait la perte d'informations qui pourraient être utiles pour la tâche de modélisation du langage !
-Donc pour commencer, nous allons d'abord tokeniser notre corpus comme d'habitude, mais _sans_ mettre l'option `truncation=True` dans notre *tokenizer*. Nous allons aussi récupérer les IDs des mots s'ils sont disponibles (ce qui sera le cas si nous utilisons un *tokenizer* rapide, comme décrit dans [Chapter 6](/course/fr/chapter6/3)), car nous en aurons besoin plus tard pour faire le masquage des mots entiers. Nous allons envelopper cela dans une simple fonction, et pendant que nous y sommes, nous allons supprimer les colonnes `text` et `label` puisque nous n'en avons plus besoin :
+Donc pour commencer, nous allons d'abord tokeniser notre corpus comme d'habitude, mais _sans_ mettre l'option `truncation=True` dans notre *tokenizer*. Nous allons aussi récupérer les identifiants des mots s'ils sont disponibles (ce qui sera le cas si nous utilisons un *tokenizer* rapide, comme décrit dans le [chapitre 6](/course/fr/chapter6/3)), car nous en aurons besoin plus tard pour faire le masquage de mots entiers. Nous allons envelopper cela dans une simple fonction, et pendant que nous y sommes, nous allons supprimer les colonnes `text` et `label` puisque nous n'en avons plus besoin :
```python
def tokenize_function(examples):
@@ -263,7 +262,7 @@ def tokenize_function(examples):
return result
-# Use batched=True to activate fast multithreading!
+# Utilisation de batched=True pour activer le multithreading rapide !
tokenized_datasets = imdb_dataset.map(
tokenize_function, batched=True, remove_columns=["text", "label"]
)
@@ -295,19 +294,20 @@ Maintenant que nos critiques de films ont été tokenisées, l'étape suivante c
tokenizer.model_max_length
```
+
```python out
512
```
-Cette valeur est dérivée du fichier *tokenizer_config.json* associé à un point de contrôle ; dans ce cas, nous pouvons voir que la taille du contexte est de 512 *tokens*, tout comme avec BERT.
+Cette valeur est dérivée du fichier *tokenizer_config.json* associé à un *checkpoint*. Dans ce cas, nous pouvons voir que la taille du contexte est de 512 *tokens*, tout comme avec BERT.
-✏️ **Essayez !** Certains *transformers*, comme [BigBird](https://huggingface.co/google/bigbird-roberta-base) et [Longformer](hf.co/allenai/longformer-base-4096), ont une longueur de contexte beaucoup plus longue que BERT et les autres premiers *transformers*. Instanciez le *tokenizer* pour l'un de ces points de contrôle et vérifiez que le `model_max_length` correspond à ce qui est indiqué sur sa carte.
+✏️ **Essayez !** Certains *transformers*, comme [BigBird](https://huggingface.co/google/bigbird-roberta-base) et [Longformer](hf.co/allenai/longformer-base-4096), ont une longueur de contexte beaucoup plus longue que BERT et les autres premiers *transformers*. Instanciez le *tokenizer* pour l'un de ces *checkpoints* et vérifiez que le `model_max_length` correspond à ce qui est indiqué sur sa carte.
-Ainsi, pour réaliser nos expériences sur des GPU comme ceux de Google Colab, nous choisirons quelque chose d'un peu plus petit qui peut tenir en mémoire :
+Ainsi, pour réaliser nos expériences sur des GPUs comme ceux disponibles sur Google Colab, nous choisirons quelque chose d'un peu plus petit qui peut tenir en mémoire :
```python
chunk_size = 128
@@ -315,11 +315,11 @@ chunk_size = 128
-Notez que l'utilisation d'une petite taille de fragment peut être préjudiciable dans les scénarios du monde réel, vous devez donc utiliser une taille qui correspond au cas d'utilisation auquel vous appliquerez votre modèle.
+Notez que l'utilisation d'une petite taille peut être préjudiciable dans les scénarios du monde réel. Vous devez donc utiliser une taille qui correspond au cas d'utilisation auquel vous appliquerez votre modèle.
-Maintenant vient la partie amusante. Pour montrer comment la concaténation fonctionne, prenons quelques commentaires de notre ensemble d'entraînement et imprimons le nombre de *tokens* par commentaire :
+Maintenant vient la partie amusante. Pour montrer comment la concaténation fonctionne, prenons quelques commentaires de notre ensemble d'entraînement et affichons le nombre de *tokens* par commentaire :
```python
# Le découpage produit une liste de listes pour chaque caractéristique
@@ -342,14 +342,14 @@ concatenated_examples = {
k: sum(tokenized_samples[k], []) for k in tokenized_samples.keys()
}
total_length = len(concatenated_examples["input_ids"])
-print(f"'>>> Concatenated reviews length: {total_length}'")
+print(f"'>>> Longueur des critiques concaténées : {total_length}'")
```
```python out
-'>>> Concatenated reviews length: 951'
+'>>> Longueur des critiques concaténées : 951'
```
-Super, la longueur totale est correcte. Donc maintenant, nous allons diviser les exemples concaténés en morceaux de la taille donnée par `block_size`. Pour ce faire, nous itérons sur les caractéristiques de `concatenated_examples` et utilisons une compréhension de liste pour créer des tranches de chaque caractéristique. Le résultat est un dictionnaire de *chunks* pour chaque caractéristique :
+Super, la longueur totale est correcte. Donc maintenant, nous allons diviser les exemples concaténés en morceaux de la taille donnée par `block_size`. Pour ce faire, nous itérons sur les caractéristiques de `concatenated_examples` et utilisons une compréhension de liste pour créer des *chunks* de chaque caractéristique. Le résultat est un dictionnaire de *chunks* pour chaque caractéristique :
```python
chunks = {
@@ -374,8 +374,8 @@ for chunk in chunks["input_ids"]:
Comme vous pouvez le voir dans cet exemple, le dernier *chunk* sera généralement plus petit que la taille maximale des morceaux. Il y a deux stratégies principales pour gérer cela :
-* abandonner le dernier morceau s'il est plus petit que `chunk_size`.
-* remplir le dernier morceau jusqu'à ce que sa longueur soit égale à `chunk_size`.
+* Abandonner le dernier morceau s'il est plus petit que `chunk_size`.
+* Rembourrer le dernier morceau jusqu'à ce que sa longueur soit égale à `chunk_size`.
Nous adopterons la première approche ici, donc nous allons envelopper toute la logique ci-dessus dans une seule fonction que nous pouvons appliquer à nos jeux de données tokenisés :
@@ -383,16 +383,16 @@ Nous adopterons la première approche ici, donc nous allons envelopper toute la
def group_texts(examples):
# Concaténation de tous les textes
concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()}
- # Calculer la longueur des textes concaténés
+ # Calcule la longueur des textes concaténés
total_length = len(concatenated_examples[list(examples.keys())[0]])
# Nous laissons tomber le dernier morceau s'il est plus petit que chunk_size
total_length = (total_length // chunk_size) * chunk_size
- # Split by chunks of max_len
+ # Fractionnement par chunk de max_len
result = {
k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)]
for k, t in concatenated_examples.items()
}
- # Create a new labels column
+ # Créer une nouvelle colonne d'étiquettes
result["labels"] = result["input_ids"].copy()
return result
```
@@ -423,7 +423,7 @@ DatasetDict({
})
```
-Vous pouvez voir que le regroupement puis le découpage des textes a produit beaucoup plus d'exemples que nos 25 000 exemples initiaux pour les divisions `train` et `test`. C'est parce que nous avons maintenant des exemples impliquant des "*tokens* contigus" qui s'étendent sur plusieurs exemples du corpus original. Vous pouvez le voir explicitement en cherchant les *tokens* spéciaux `[SEP]` et `[CLS]` dans l'un des *chunks* :
+Vous pouvez voir que le regroupement puis le découpage des textes a produit beaucoup plus d'exemples que nos 25 000 exemples initiaux pour les divisions `train` et `test`. C'est parce que nous avons maintenant des exemples impliquant des *tokens* contigus qui s'étendent sur plusieurs exemples du corpus original. Vous pouvez le voir explicitement en cherchant les *tokens* spéciaux `[SEP]` et `[CLS]` dans l'un des *chunks* :
```python
tokenizer.decode(lm_datasets["train"][1]["input_ids"])
@@ -443,11 +443,11 @@ tokenizer.decode(lm_datasets["train"][1]["labels"])
".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless"
```
-Comme prévu par notre fonction `group_texts()` ci-dessus, cela semble identique aux `input_ids` décodés - mais alors comment notre modèle peut-il apprendre quoi que ce soit ? Il nous manque une étape clé : insérer des *tokens* à des positions aléatoires dans les entrées ! Voyons comment nous pouvons le faire à la volée pendant le réglage fin en utilisant un collateur de données spécial.
+Comme prévu par notre fonction `group_texts()` ci-dessus, cela semble identique aux `input_ids` décodés. Mais alors comment notre modèle peut-il apprendre quoi que ce soit ? Il nous manque une étape clé : insérer des *tokens* à des positions aléatoires dans les entrées ! Voyons comment nous pouvons le faire à la volée pendant le *finetuning* en utilisant un collateur de données spécial.
-## *Finetuning* de DistilBERT avec l'API `Trainer`.
+##
Finetuning de DistilBERT avec l'API `Trainer`
-Le *finetuning* d'un modèle de langage masqué est presque identique au *finetuning* d'un modèle de classification de séquences, comme nous l'avons fait dans le [Chapitre 3](/course/fr/chapter3). La seule différence est que nous avons besoin d'un collecteur de données spécial qui peut masquer de manière aléatoire certains des *tokens* dans chaque lot de textes. Heureusement, 🤗 *Transformers* est livré préparé avec un `DataCollatorForLanguageModeling` dédié à cette tâche. Nous devons juste lui passer le *tokenizer* et un argument `mlm_probability` qui spécifie quelle fraction des *tokens* à masquer. Nous choisirons 15%, qui est la quantité utilisée pour BERT et un choix commun dans la littérature :
+Le *finetuning* d'un modèle de langage masqué est presque identique au *finetuning* d'un modèle de classification de séquences, comme nous l'avons fait dans le [chapitre 3](/course/fr/chapter3). La seule différence est que nous avons besoin d'un collecteur de données spécial qui peut masquer de manière aléatoire certains des *tokens* dans chaque batch de textes. Heureusement, 🤗 *Transformers* est livré préparé avec un `DataCollatorForLanguageModeling` dédié à cette tâche. Nous devons juste lui passer le *tokenizer* et un argument `mlm_probability` qui spécifie quelle fraction des *tokens* à masquer. Nous choisirons 15%, qui est la quantité utilisée pour BERT et un choix commun dans la littérature :
```python
from transformers import DataCollatorForLanguageModeling
@@ -455,7 +455,7 @@ from transformers import DataCollatorForLanguageModeling
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15)
```
-Pour voir comment le masquage aléatoire fonctionne, nous allons donner quelques exemples au compilateur de données. Puisqu'il s'attend à une liste de `dict`s, où chaque `dict` représente un seul morceau de texte contigu, nous itérons d'abord sur le jeu de données avant de nourrir le lot au collateur. Nous supprimons la clé `"word_ids"` pour ce collateur de données car il ne l'attend pas :
+Pour voir comment le masquage aléatoire fonctionne, nous allons donner quelques exemples au collateur de données. Puisqu'il s'attend à une liste de `dict` où chaque `dict` représente un seul morceau de texte contigu, nous itérons d'abord sur le jeu de données avant de donner le batch au collateur. Nous supprimons la clé `"word_ids"` pour ce collateur de données car il ne l'attend pas :
```python
samples = [lm_datasets["train"][i] for i in range(2)]
@@ -472,21 +472,21 @@ for chunk in data_collator(samples)["input_ids"]:
'>>> .... at.. [MASK]... [MASK]... high. a classic line plucked inspector : i\'[MASK] here to [MASK] one of your [MASK]. student : welcome to bromwell [MASK]. i expect that many adults of my age think that [MASK]mwell [MASK] is [MASK] fetched. what a pity that it isn\'t! [SEP] [CLS] [MASK]ness ( or [MASK]lessness as george 宇in stated )公 been an issue for years but never [MASK] plan to help those on the street that were once considered human [MASK] did everything from going to school, [MASK], [MASK] vote for the matter. most people think [MASK] the homeless'
```
-Super, ça a marché ! Nous pouvons voir que le *token* `[MASK]` a été inséré de façon aléatoire à différents endroits dans notre texte. Ce seront les *tokens* que notre modèle devra prédire pendant l'entraînement. Et la beauté du collecteur de données est qu'il va rendre aléatoire l'insertion du `[MASK]` à chaque lot !
+Super, ça a marché ! Nous pouvons voir que le *token* `[MASK]` a été inséré de façon aléatoire à différents endroits dans notre texte. Ce seront les *tokens* que notre modèle devra prédire pendant l'entraînement. Et la beauté du collecteur de données est qu'il va rendre aléatoire l'insertion du `[MASK]` à chaque batch !
-✏️ **Essayez** Exécutez le code ci-dessus plusieurs fois pour voir le masquage aléatoire se produire sous vos yeux ! Remplacez aussi la méthode `tokenizer.decode()` par `tokenizer.convert_ids_to_tokens()` pour voir que parfois un seul *token* d'un mot donné est masqué, et pas les autres.
+✏️ **Essayez** Exécutez le code ci-dessus plusieurs fois pour voir le masquage aléatoire se produire sous vos yeux ! Remplacez aussi la méthode `tokenizer.decode()` par `tokenizer.convert_ids_to_tokens()` pour voir que parfois un seul *token* d'un mot donné est masqué et pas les autres.
{#if fw === 'pt'}
-Un effet secondaire du masquage aléatoire est que nos métriques d'évaluation ne seront pas déterministes lorsque nous utilisons le `Trainer`, puisque nous utilisons le même collateur de données pour les ensembles d'entraînement et de test. Nous verrons plus tard, lorsque nous examinerons le *finetuning* avec 🤗 *Accelerate*, comment nous pouvons utiliser la flexibilité d'une boucle d'évaluation personnalisée pour geler le caractère aléatoire.
+Un effet secondaire du masquage aléatoire est que nos métriques d'évaluation ne seront pas déterministes lorsque nous utilisons la fonction `Trainer` puisque nous utilisons le même collateur de données pour les échantillons d'entraînement et de test. Nous verrons plus tard, lorsque nous examinerons le *finetuning* avec 🤗 *Accelerate*, comment nous pouvons utiliser la flexibilité d'une boucle d'évaluation personnalisée pour geler le caractère aléatoire.
{/if}
-Lors de l'entraînement des modèles pour la modélisation du langage masqué, une technique qui peut être utilisée est de masquer des mots entiers ensemble, et pas seulement des *tokens* individuels. Cette approche est appelée _masquage de mots entiers_. Si nous voulons utiliser le masquage de mots entiers, nous devons construire nous-mêmes un collateur de données. Un collateur de données est simplement une fonction qui prend une liste d'échantillons et les convertit en un lot, alors faisons-le maintenant ! Nous utiliserons les IDs des mots calculés plus tôt pour faire une correspondance entre les indices des mots et les *tokens* correspondants, puis nous déciderons aléatoirement quels mots masquer et appliquerons ce masque sur les entrées. Notez que les étiquettes sont toutes `-100` sauf celles qui correspondent aux mots masqués.
+Lors de l'entraînement des modèles pour la modélisation du langage masqué, une technique qui peut être utilisée est de masquer des mots entiers ensemble et pas seulement des *tokens* individuels. Cette approche est appelée _masquage de mots entiers_. Si nous voulons utiliser le masquage de mots entiers, nous devons construire nous-mêmes un collateur de données. Un collateur de données est simplement une fonction qui prend une liste d'échantillons et les convertit en un batch. Faisons-le ! Nous utiliserons les identifiants des mots calculés plus tôt pour faire une correspondance entre les indices des mots et les *tokens*, puis nous déciderons aléatoirement quels mots masquer et appliquerons ce masque sur les entrées. Notez que les étiquettes sont toutes `-100` sauf celles qui correspondent aux mots masqués.
{#if fw === 'pt'}
@@ -503,7 +503,7 @@ def whole_word_masking_data_collator(features):
for feature in features:
word_ids = feature.pop("word_ids")
- # Création d'une carte entre les mots et les indices des tokens correspondants.
+ # Création d'une correspondance entre les mots et les indices des tokens correspondants
mapping = collections.defaultdict(list)
current_word_index = -1
current_word = None
@@ -543,7 +543,7 @@ def whole_word_masking_data_collator(features):
for feature in features:
word_ids = feature.pop("word_ids")
- # Création d'une carte entre les mots et les indices des tokens correspondants.
+ # Création d'une correspondance entre les mots et les indices des tokens correspondants
mapping = collections.defaultdict(list)
current_word_index = -1
current_word = None
@@ -592,7 +592,7 @@ for chunk in batch["input_ids"]:
-Maintenant que nous avons deux collateurs de données, le reste des étapes de mise au point est standard. L'entraînement peut prendre un certain temps sur Google Colab si vous n'avez pas la chance d'avoir un mythique GPU P100 😭, donc nous allons d'abord réduire la taille de l'ensemble d'entraînement à quelques milliers d'exemples. Ne vous inquiétez pas, nous obtiendrons quand même un modèle de langage assez décent ! Un moyen rapide de réduire la taille d'un jeu de données dans 🤗 *Datasets* est la fonction `Dataset.train_test_split()` que nous avons vue au [Chapitre 5](/course/fr/chapter5) :
+Maintenant que nous avons deux collateurs de données, les étapes restantes du *finetuning* sont standards. L'entraînement peut prendre un certain temps sur Google Colab si vous n'avez pas la chance de tomber sur un mythique GPU P100 😭. Ainsi nous allons d'abord réduire la taille du jeu d'entraînement à quelques milliers d'exemples. Ne vous inquiétez pas, nous obtiendrons quand même un modèle de langage assez décent ! Un moyen rapide de réduire la taille d'un jeu de données dans 🤗 *Datasets* est la fonction `Dataset.train_test_split()` que nous avons vue au [chapitre 5](/course/fr/chapter5) :
```python
train_size = 10_000
@@ -617,7 +617,7 @@ DatasetDict({
})
```
-Cela a automatiquement créé de nouvelles divisions `train` et `test`, avec la taille de l'ensemble d'entraînement fixée à 10.000 exemples et la validation fixée à 10% de cela. N'hésitez pas à augmenter cela si vous avez un GPU puissant ! La prochaine chose que nous devons faire est de nous connecter au *Hub*. Si vous exécutez ce code dans un *notebook*, vous pouvez le faire avec la fonction utilitaire suivante :
+Cela a automatiquement créé de nouvelles divisions `train` et `test` avec la taille du jeu d'entraînement fixée à 10.000 exemples et la validation fixée à 10% de cela. N'hésitez pas à augmenter la taille si vous avez un GPU puissant ! La prochaine chose que nous devons faire est de nous connecter au *Hub*. Si vous exécutez ce code dans un *notebook*, vous pouvez le faire avec la fonction suivante :
```python
from huggingface_hub import notebook_login
@@ -653,9 +653,9 @@ tf_eval_dataset = downsampled_dataset["test"].to_tf_dataset(
)
```
-Ensuite, nous configurons nos hyperparamètres d'entraînement et compilons notre modèle. Nous utilisons la fonction `create_optimizer()` de la bibliothèque 🤗 *Transformers*, qui nous donne un optimiseur `AdamW` avec une décroissance linéaire du taux d'apprentissage. Nous utilisons également la perte intégrée au modèle, qui est la perte par défaut lorsqu'aucune perte n'est spécifiée comme argument de `compile()`, et nous définissons la précision d'entraînement à `"mixed_float16"`. Notez que si vous utilisez un GPU Colab ou un autre GPU qui n'a pas le support accéléré de float16, vous devriez probablement commenter cette ligne.
+Ensuite, nous configurons nos hyperparamètres d'entraînement et compilons notre modèle. Nous utilisons la fonction `create_optimizer()` de la bibliothèque 🤗 *Transformers*, qui nous donne un optimiseur `AdamW` avec une décroissance linéaire du taux d'apprentissage. Nous utilisons également la perte intégrée au modèle, qui est la perte par défaut lorsqu'aucune perte n'est spécifiée comme argument de `compile()`, et nous définissons la précision d'entraînement à `"mixed_float16"`. Notez que si vous utilisez un GPU Colab ou un autre GPU qui n'a pas le support accéléré en float16, vous devriez probablement commenter cette ligne.
-De plus, nous mettons en place un `PushToHubCallback` qui sauvegardera le modèle sur le Hub après chaque époque. Vous pouvez spécifier le nom du dépôt vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, pour pousser le modèle vers l'organisation [`huggingface-course`] (https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/distilbert-finetuned-imdb"`. Par défaut, le dépôt utilisé sera dans votre espace de noms et nommé après le répertoire de sortie que vous avez défini, donc dans notre cas, ce sera `"lewtun/distilbert-finetuned-imdb"`.
+De plus, nous mettons en place un `PushToHubCallback` qui sauvegardera le modèle sur le *Hub* après chaque époque. Vous pouvez spécifier le nom du dépôt vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, pour pousser le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/distilbert-finetuned-imdb"`. Par défaut, le dépôt utilisé sera dans votre espace de noms et nommé après le répertoire de sortie que vous avez défini, donc dans notre cas, ce sera `"lewtun/distilbert-finetuned-imdb"`.
```python
from transformers import create_optimizer
@@ -671,7 +671,7 @@ optimizer, schedule = create_optimizer(
)
model.compile(optimizer=optimizer)
-# Train in mixed-precision float16
+# Entraîner en mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")
callback = PushToHubCallback(
@@ -679,7 +679,7 @@ callback = PushToHubCallback(
)
```
-Nous sommes maintenant prêts à exécuter `model.fit()`. Mais avant de le faire, regardons brièvement la _perplexité_, qui est une métrique commune pour évaluer la performance des modèles de langage.
+Nous sommes maintenant prêts à exécuter `model.fit()`. Mais avant, regardons brièvement la _perplexité_ qui est une métrique commune pour évaluer la performance des modèles de langage.
{:else}
@@ -689,7 +689,7 @@ Une fois que nous sommes connectés, nous pouvons spécifier les arguments pour
from transformers import TrainingArguments
batch_size = 64
-# Montrer la perte d'entraînement à chaque époque.
+# Montrer la perte d'entraînement à chaque époque
logging_steps = len(downsampled_dataset["train"]) // batch_size
model_name = model_checkpoint.split("/")[-1]
@@ -707,9 +707,9 @@ training_args = TrainingArguments(
)
```
-Ici, nous avons modifié quelques options par défaut, y compris `logging_steps` pour s'assurer que nous suivons la perte d'entraînement à chaque époque. Nous avons également utilisé `fp16=True` pour activer l'entraînement en précision mixte, ce qui nous donne un autre gain de vitesse. Par défaut, le `Trainer` va supprimer toutes les colonnes qui ne font pas partie de la méthode `forward()` du modèle. Cela signifie que si vous utilisez le collateur de masquage de mots entiers, vous devrez également définir `remove_unused_columns=False` pour vous assurer que nous ne perdons pas la colonne `word_ids` pendant l'entraînement.
+Ici, nous avons modifié quelques options par défaut, y compris `logging_steps` pour s'assurer que nous suivons la perte d'entraînement à chaque époque. Nous avons également utilisé `fp16=True` pour activer l'entraînement en précision mixte, ce qui nous donne un autre gain de vitesse. Par défaut, `Trainer` va supprimer toutes les colonnes qui ne font pas partie de la méthode `forward()` du modèle. Cela signifie que si vous utilisez le collateur de masquage de mots entiers, vous devrez également définir `remove_unused_columns=False` pour vous assurer que nous ne perdons pas la colonne `word_ids` pendant l'entraînement.
-Notez que vous pouvez spécifier le nom du référentiel vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/distilbert-finetuned-imdb"``TrainingArguments`. Par défaut, le dépôt utilisé sera dans votre espace de noms et nommé après le répertoire de sortie que vous avez défini, donc dans notre cas ce sera `"lewtun/distilbert-finetuned-imdb"`.
+Notez que vous pouvez spécifier le nom du dépôt vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/distilbert-finetuned-imdb"` `TrainingArguments`. Par défaut, le dépôt utilisé sera dans votre espace de noms et nommé après le répertoire de sortie que vous avez défini, donc dans notre cas ce sera `"lewtun/distilbert-finetuned-imdb"`.
Nous avons maintenant tous les ingrédients pour instancier le `Trainer`. Ici, nous utilisons juste le collateur standard `data_collator`, mais vous pouvez essayer le collateur de masquage de mots entiers et comparer les résultats comme exercice :
@@ -725,7 +725,7 @@ trainer = Trainer(
)
```
-Nous sommes maintenant prêts à exécuter `trainer.train()` . Mais avant de le faire, regardons brièvement la _perplexité_, qui est une métrique commune pour évaluer la performance des modèles de langage.
+Nous sommes maintenant prêts à exécuter `trainer.train()`. Mais avant, regardons brièvement la _perplexité_ qui est une métrique commune pour évaluer la performance des modèles de langage.
{/if}
@@ -733,11 +733,11 @@ Nous sommes maintenant prêts à exécuter `trainer.train()` . Mais avant de le
-Contrairement à d'autres tâches, comme la classification de textes ou la réponse à des questions, sur lesquelles nous disposons d'un corpus étiqueté pour nous entraîner, la modélisation du langage ne s'appuie sur aucune étiquette explicite. Alors comment déterminer ce qui fait un bon modèle de langage ? Comme pour la fonction de correction automatique de votre téléphone, un bon modèle de langage est celui qui attribue des probabilités élevées aux phrases grammaticalement correctes et des probabilités faibles aux phrases absurdes. Pour vous donner une meilleure idée de ce à quoi cela ressemble, vous pouvez trouver en ligne des séries entières de "ratés d'autocorrection", où le modèle du téléphone d'une personne a produit des compléments plutôt amusants (et souvent inappropriés) !
+Contrairement à d'autres tâches, comme la classification de textes ou la réponse à des questions, sur lesquelles nous disposons d'un corpus étiqueté pour entraîner, la modélisation du langage ne s'appuie sur aucune étiquette explicite. Alors comment déterminer ce qui fait un bon modèle de langage ? Comme pour la fonction de correction automatique de votre téléphone, un bon modèle de langage est celui qui attribue des probabilités élevées aux phrases grammaticalement correctes et des probabilités faibles aux phrases absurdes. Pour vous donner une meilleure idée de ce à quoi cela ressemble, vous pouvez trouver en ligne des séries entières de « ratés d'autocorrection » où le modèle d'un téléphone produit des compléments plutôt amusants (et souvent inappropriés) !
{#if fw === 'pt'}
-En supposant que notre ensemble de test se compose principalement de phrases grammaticalement correctes, une façon de mesurer la qualité de notre modèle de langage est de calculer les probabilités qu'il attribue au mot suivant dans toutes les phrases de l'ensemble de test. Des probabilités élevées indiquent que le modèle n'est pas "surpris" ou "perplexe" par les exemples non vus, et suggèrent qu'il a appris les modèles de base de la grammaire de la langue. Il existe plusieurs définitions mathématiques de la perplexité, mais celle que nous utiliserons la définit comme l'exponentielle de la perte d'entropie croisée. Ainsi, nous pouvons calculer la perplexité de notre modèle pré-entraîné en utilisant la fonction `Trainer.evaluate()` pour calculer la perte d'entropie croisée sur l'ensemble de test, puis en prenant l'exponentielle du résultat :
+En supposant que notre ensemble de test se compose principalement de phrases grammaticalement correctes, une façon de mesurer la qualité de notre modèle de langage est de calculer les probabilités qu'il attribue au mot suivant dans toutes les phrases de l'ensemble de test. Des probabilités élevées indiquent que le modèle n'est pas « surpris » ou « perplexe » vis-à-vis des exemples non vus, et suggèrent qu'il a appris les modèles de base de la grammaire de la langue. Il existe plusieurs définitions mathématiques de la perplexité. Celle que nous utiliserons la définit comme l'exponentielle de la perte d'entropie croisée. Ainsi, nous pouvons calculer la perplexité de notre modèle pré-entraîné en utilisant la fonction `Trainer.evaluate()` pour calculer la perte d'entropie croisée sur l'ensemble de test, puis en prenant l'exponentielle du résultat :
```python
import math
@@ -748,22 +748,22 @@ print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
{:else}
-En supposant que notre ensemble de test se compose principalement de phrases grammaticalement correctes, une façon de mesurer la qualité de notre modèle de langage est de calculer les probabilités qu'il attribue au mot suivant dans toutes les phrases de l'ensemble de test. Des probabilités élevées indiquent que le modèle n'est pas "surpris" ou "perplexe" par les exemples non vus, et suggèrent qu'il a appris les modèles de base de la grammaire de la langue. Il existe plusieurs définitions mathématiques de la perplexité, mais celle que nous utiliserons la définit comme l'exponentielle de la perte d'entropie croisée. Ainsi, nous pouvons calculer la perplexité de notre modèle pré-entraîné en utilisant la méthode `model.evaluate()` pour calculer la perte d'entropie croisée sur l'ensemble de test, puis en prenant l'exponentielle du résultat :
+En supposant que notre ensemble de test se compose principalement de phrases grammaticalement correctes, une façon de mesurer la qualité de notre modèle de langage est de calculer les probabilités qu'il attribue au mot suivant dans toutes les phrases de l'ensemble de test. Des probabilités élevées indiquent que le modèle n'est pas « surpris » ou « perplexe » vis-à-vis des exemples non vus, et suggèrent qu'il a appris les modèles de base de la grammaire de la langue. Il existe plusieurs définitions mathématiques de la perplexité. Celle que nous utiliserons la définit comme l'exponentielle de la perte d'entropie croisée. Ainsi, nous pouvons calculer la perplexité de notre modèle pré-entraîné en utilisant la fonction `model.evaluate()` pour calculer la perte d'entropie croisée sur l'ensemble de test, puis en prenant l'exponentielle du résultat :
```python
import math
eval_loss = model.evaluate(tf_eval_dataset)
-print(f"Perplexity: {math.exp(eval_loss):.2f}")
+print(f"Perplexité : {math.exp(eval_loss):.2f}")
```
{/if}
```python out
->>> Perplexity: 21.75
+>>> Perplexité : 21.75
```
-Un score de perplexité plus faible signifie un meilleur modèle de langue, et nous pouvons voir ici que notre modèle de départ a une valeur assez élevée. Voyons si nous pouvons la réduire en l'affinant ! Pour ce faire, nous commençons par exécuter la boucle d'entraînement :
+Un score de perplexité faible signifie un meilleur modèle de langue. Nous pouvons voir ici que notre modèle de départ a une valeur assez élevée. Voyons si nous pouvons la réduire en l'affinant ! Pour ce faire, nous commençons par exécuter la boucle d'entraînement :
{#if fw === 'pt'}
@@ -785,27 +785,27 @@ et ensuite calculer la perplexité résultante sur l'ensemble de test comme pré
```python
eval_results = trainer.evaluate()
-print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}")
+print(f">>> Perplexité : {math.exp(eval_results['eval_loss']):.2f}")
```
{:else}
```python
eval_loss = model.evaluate(tf_eval_dataset)
-print(f"Perplexity: {math.exp(eval_loss):.2f}")
+print(f"Perplexité : {math.exp(eval_loss):.2f}")
```
{/if}
```python out
->>> Perplexity: 11.32
+>>> Perplexité : 11.32
```
Joli. C'est une réduction considérable de la perplexité, ce qui nous indique que le modèle a appris quelque chose sur le domaine des critiques de films !
{#if fw === 'pt'}
-Une fois l'entraînement terminé, nous pouvons pousser la carte modèle avec les informations d'entraînement vers le Hub (les points de contrôle sont sauvegardés pendant l'entraînement lui-même) :
+Une fois l'entraînement terminé, nous pouvons pousser la carte de modèle avec les informations d'entraînement vers le *Hub* (les *checkpoints* sont sauvegardés pendant l'entraînement lui-même) :
```python
trainer.push_to_hub()
@@ -815,7 +815,7 @@ trainer.push_to_hub()
-✏️ **Votre tour !** Exécutez l'entraînement ci-dessus après avoir remplacé le collecteur de données par le collecteur de mots entiers masqués. Obtenez-vous de meilleurs résultats ?
+✏️ **A votre tour !** Exécutez l'entraînement ci-dessus après avoir remplacé le collecteur de données par le collecteur de mots entiers masqués. Obtenez-vous de meilleurs résultats ?
@@ -823,21 +823,21 @@ trainer.push_to_hub()
Dans notre cas d'utilisation, nous n'avons pas eu besoin de faire quelque chose de spécial avec la boucle d'entraînement, mais dans certains cas, vous pourriez avoir besoin de mettre en œuvre une logique personnalisée. Pour ces applications, vous pouvez utiliser 🤗 *Accelerate*. Jetons un coup d'œil !
-## *Finetuning* de DistilBERT avec 🤗 Accelerate
+##
Finetuning de DistilBERT avec 🤗
Accelerate
-Comme nous l'avons vu avec le `Trainer`, le réglage fin d'un modèle de langage masqué est très similaire à l'exemple de classification de texte du [Chapitre 3](/course/fr/chapter3). En fait, la seule subtilité est l'utilisation d'un collateur de données spécial, et nous l'avons déjà couvert plus tôt dans cette section !
+Comme nous l'avons vu, avec `Trainer` le *finetuning* d'un modèle de langage masqué est très similaire à l'exemple de classification de texte du [chapitre 3](/course/fr/chapter3). En fait, la seule subtilité est l'utilisation d'un collateur de données spécial, et nous l'avons déjà couvert plus tôt dans cette section !
-Cependant, nous avons vu que `DataCollatorForLanguageModeling` applique aussi un masquage aléatoire à chaque évaluation, donc nous verrons quelques fluctuations dans nos scores de perplexité à chaque entrainement. Une façon d'éliminer cette source d'aléatoire est d'appliquer le masquage _une fois_ sur l'ensemble de test, puis d'utiliser le collateur de données par défaut dans 🤗 *Transformers* pour collecter les lots pendant l'évaluation. Pour voir comment cela fonctionne, implémentons une fonction simple qui applique le masquage sur un lot, similaire à notre première rencontre avec `DataCollatorForLanguageModeling` :
+Cependant, nous avons vu que `DataCollatorForLanguageModeling` applique aussi un masquage aléatoire à chaque évaluation. Nous verrons donc quelques fluctuations dans nos scores de perplexité à chaque entrainement. Une façon d'éliminer cette source d'aléat est d'appliquer le masquage _une fois_ sur l'ensemble de test, puis d'utiliser le collateur de données par défaut dans 🤗 *Transformers* pour collecter les batchs pendant l'évaluation. Pour voir comment cela fonctionne, implémentons une fonction simple qui applique le masquage sur un batch, similaire à notre première rencontre avec `DataCollatorForLanguageModeling` :
```python
def insert_random_mask(batch):
features = [dict(zip(batch, t)) for t in zip(*batch.values())]
masked_inputs = data_collator(features)
- # Create a new "masked" column for each column in the dataset
+ # Créer une nouvelle colonne "masquée" pour chaque colonne du jeu de données
return {"masked_" + k: v.numpy() for k, v in masked_inputs.items()}
```
-Ensuite, nous allons appliquer cette fonction à notre jeu de test et laisser tomber les colonnes non masquées afin de les remplacer par les colonnes masquées. Vous pouvez utiliser le masquage de mots entiers en remplaçant le `data_collator` ci-dessus par celui qui est approprié, dans ce cas vous devez supprimer la première ligne ici :
+Ensuite, nous allons appliquer cette fonction à notre jeu de test et laisser tomber les colonnes non masquées afin de les remplacer par les colonnes masquées. Vous pouvez utiliser le masquage de mots entiers en remplaçant le `data_collator` ci-dessus par celui qui est approprié. Dans ce cas vous devez supprimer la première ligne ici :
```py
downsampled_dataset = downsampled_dataset.remove_columns(["word_ids"])
@@ -873,13 +873,13 @@ eval_dataloader = DataLoader(
)
```
-Forme ici, nous suivons les étapes standard avec 🤗 *Accelerate*. Le premier ordre du jour est de charger une version fraîche du modèle pré-entraîné :
+Nous suivons les étapes standard avec 🤗 *Accelerate*. La première est de charger une version fraîche du modèle pré-entraîné :
```
model = AutoModelForMaskedLM.from_pretrained(model_checkpoint)
```
-Ensuite, nous devons spécifier l'optimiseur ; nous utiliserons le standard `AdamW` :
+Ensuite, nous devons spécifier l'optimiseur. Nous utiliserons le standard `AdamW` :
```python
from torch.optim import AdamW
@@ -929,7 +929,7 @@ repo_name
'lewtun/distilbert-base-uncased-finetuned-imdb-accelerate'
```
-puis créer et cloner le référentiel en utilisant la classe `Repository` du 🤗 *Hub* :
+puis créer et cloner le dépôt en utilisant la classe `Repository` du 🤗 *Hub* :
```python
from huggingface_hub import Repository
@@ -1000,9 +1000,9 @@ Cool, nous avons été en mesure d'évaluer la perplexité à chaque époque et
{/if}
-### Utilisation de notre modèle *finetuné*
+### Utilisation de notre modèle
finetuné
-Vous pouvez interagir avec votre modèle affiné soit en utilisant son *widget* sur le *Hub*, soit localement avec le `pipeline` de 🤗 *Transformers*. Utilisons cette dernière pour télécharger notre modèle en utilisant le pipeline `fill-mask` :
+Vous pouvez interagir avec votre modèle *finetuné* soit en utilisant son *widget* sur le *Hub*, soit localement avec le `pipeline` de 🤗 *Transformers*. Utilisons ce dernier pour télécharger notre modèle en utilisant le pipeline `fill-mask` :
```python
from transformers import pipeline
@@ -1012,7 +1012,7 @@ mask_filler = pipeline(
)
```
-Nous pouvons ensuite alimenter le pipeline avec notre exemple de texte "C'est un grand [MASK]" et voir quelles sont les 5 premières prédictions :
+Nous pouvons ensuite donner au pipeline notre exemple de texte « this is a great [MASK] » et voir quelles sont les 5 premières prédictions :
```python
preds = mask_filler(text)
@@ -1033,10 +1033,10 @@ Notre modèle a clairement adapté ses pondérations pour prédire les mots qui
-Ceci conclut notre première expérience d'entraînement d'un modèle de langage. Dans la [section 6](/course/fr/chapter7/section6), vous apprendrez comment entraîner un modèle autorégressif comme GPT-2 à partir de zéro ; allez-y si vous voulez voir comment vous pouvez pré-entraîner votre propre *transformer* !
+Ceci conclut notre première expérience d'entraînement d'un modèle de langage. Dans la [section 6](/course/fr/chapter7/section6), vous apprendrez comment entraîner à partir de zéro un modèle autorégressif comme GPT-2. Allez-y si vous voulez voir comment vous pouvez pré-entraîner votre propre *transformer* !
-✏️ **Essayez !** Pour quantifier les avantages de l'adaptation au domaine, ajustez un classificateur sur les étiquettes IMDb pour les points de contrôle DistilBERT pré-entraînés et ajustés. Si vous avez besoin d'un rafraîchissement sur la classification de texte, consultez le [Chapitre 3](/course/fr/chapter3).
+✏️ **Essayez !** Pour quantifier les avantages de l'adaptation au domaine, finetunez un classifieur sur le jeu de données IMDb pour à la fois, le checkpoint de DistilBERT pré-entraîné et e checkpoint de DistilBERT finetuné. Si vous avez besoin d'un rafraîchissement sur la classification de texte, consultez le [chapitre 3](/course/fr/chapter3).
diff --git a/chapters/fr/chapter7/4.mdx b/chapters/fr/chapter7/4.mdx
index 48d83a6da..d7d868936 100644
--- a/chapters/fr/chapter7/4.mdx
+++ b/chapters/fr/chapter7/4.mdx
@@ -22,16 +22,16 @@
{/if}
-Plongeons maintenant dans la traduction. Il s'agit d'une autre [tâche de séquence à séquence](/cours/fr/chapitre1/7), ce qui signifie que c'est un problème qui peut être formulé comme le passage d'une séquence à une autre. En ce sens, le problème est assez proche de la tâche de [résumé](/cours/fr/chapitre7/6) et vous pouvez adapter ce que nous allons voir ici à d'autres problèmes de séquence à séquence tels que :
+Plongeons maintenant dans la traduction. Il s'agit d'une autre [tâche de séquence à séquence](/course/fr/chapitre1/7), ce qui signifie que c'est un problème qui peut être formulé comme le passage d'une séquence à une autre. En ce sens, le problème est assez proche de la tâche de [résumé](/course/fr/chapitre7/6) et vous pouvez adapter ce que nous allons voir ici à d'autres problèmes de séquence à séquence tels que :
-- le **transfert de style** : créer un modèle qui *traduit* des textes écrits dans un certain style vers un autre (par exemple, du formel au décontracté ou de l'anglais shakespearien à l'anglais moderne).
-- la **génération de réponse à des questions** : Création d'un modèle qui génère des réponses à des questions, compte tenu d'un contexte.
+- Le **transfert de style** ? c'est-à-dire créer un modèle qui *traduit* des textes écrits dans un certain style vers un autre (par exemple, du formel au décontracté ou de l'anglais shakespearien à l'anglais moderne).
+- La **génération de réponse à des questions** c'est-à-dire créer un modèle qui génère des réponses à des questions compte tenu d'un contexte.
-Si vous disposez d'un corpus suffisamment important de textes en deux langues (ou plus), vous pouvez entraîner un nouveau modèle de traduction à partir de zéro, comme nous le ferons dans la section sur la [modélisation causale du langage](/cours/fr/chapitre7/6). Il est toutefois plus rapide de *finetuner* un modèle de traduction existant, qu'il s'agisse d'un modèle multilingue comme mT5 ou mBART que vous souhaitez adapter à une paire de langues spécifique, ou même d'un modèle spécialisé dans la traduction d'une langue vers une autre que vous souhaitez adapter à votre corpus spécifique.
+Si vous disposez d'un corpus de textes suffisamment important en deux langues différentes (ou plus), vous pouvez entraîner un nouveau modèle de traduction à partir de zéro, comme nous le ferons dans la section sur la [modélisation causale du langage](/course/fr/chapitre7/6). Il est toutefois plus rapide de *finetuner* un modèle de traduction existant, qu'il s'agisse d'un modèle multilingue comme mT5 ou mBART que vous souhaitez adapter à une paire de langues spécifique, ou même d'un modèle spécialisé dans la traduction d'une langue vers une autre que vous souhaitez adapter à votre corpus spécifique.
-Dans cette section, nous allons *finetuner* un modèle Marian pré-entraîné pour traduire de l'anglais au français (puisque de nombreux employés de Hugging Face parlent ces deux langues) sur le [KDE4 dataset](https://huggingface.co/datasets/kde4), qui est un jeu de données de fichiers localisés pour les [KDE apps](https://apps.kde.org/). Le modèle que nous utiliserons a été pré-entraîné sur un large corpus de textes français et anglais provenant du [jeu de données Opus](https://opus.nlpl.eu/), qui contient en fait le jeu de données KDE4. Mais même si le modèle pré-entraîné que nous utilisons a vu ces données pendant son pré-entraînement, nous verrons que nous pouvons obtenir une meilleure version de ce modèle après un *finetuning*.
+Dans cette section, nous allons *finetuner* un modèle Marian pré-entraîné pour traduire de l'anglais au français (puisque de nombreux employés de Hugging Face parlent ces deux langues) sur le jeu de données [KDE4](https://huggingface.co/datasets/kde4) qui est un jeu de données de fichiers localisés pour les applications [KDE](https://apps.kde.org/). Le modèle que nous utiliserons a été pré-entraîné sur un large corpus de textes français et anglais provenant du jeu de données [Opus](https://opus.nlpl.eu/) qui contient en fait le jeu de données KDE4. A noter que même si le modèle pré-entraîné que nous utilisons a vu ces données pendant son pré-entraînement, nous verrons que nous pouvons obtenir une meilleure version de ce modèle après un *finetuning*.
Une fois que nous aurons terminé, nous aurons un modèle capable de faire des prédictions comme celle-ci :
@@ -43,11 +43,11 @@ Une fois que nous aurons terminé, nous aurons un modèle capable de faire des p
-Comme dans les sections précédentes, vous pouvez trouver le modèle réel que nous allons entraîner et télécharger sur le *Hub* en utilisant le code ci-dessous et vérifier ses prédictions [ici](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr?text=This+plugin+allows+you+to+automatically+translate+web+pages+between+several+languages.).
+Comme dans les sections précédentes, vous pouvez trouver, télécharger et vérifier les précisions de ce modèle sur le [*Hub*](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr?text=This+plugin+allows+you+to+automatically+translate+web+pages+between+several+languages.).
## Préparation des données
-Pour affiner ou entraîner un modèle de traduction à partir de zéro, nous avons besoin d'un jeu de données adapté à cette tâche. Comme mentionné précédemment, nous utiliserons le jeu de données [KDE4](https://huggingface.co/datasets/kde4) dans cette section, mais vous pouvez adapter le code pour utiliser vos propres données assez facilement, tant que vous avez des paires de phrases dans les deux langues que vous voulez traduire de et vers. Reportez-vous au [Chapitre 5](/course/fr/chapter5) si vous avez besoin d'un rappel sur la façon de charger vos données personnalisées dans un `Dataset`.
+Pour *finetuner* ou entraîner un modèle de traduction à partir de zéro, nous avons besoin d'un jeu de données adapté à cette tâche. Comme mentionné précédemment, nous utiliserons le jeu de données [KDE4](https://huggingface.co/datasets/kde4) dans cette section. Notez que vous pouvez adapter assez facilement le code pour utiliser vos propres données du moment que vous disposez de paires de phrases dans les deux langues que vous voulez traduire. Reportez-vous au [chapitre 5](/course/fr/chapter5) si vous avez besoin d'un rappel sur la façon de charger vos données personnalisées dans un `Dataset`.
### Le jeu de données KDE4
@@ -59,11 +59,11 @@ from datasets import load_dataset, load_metric
raw_datasets = load_dataset("kde4", lang1="en", lang2="fr")
```
-Si vous souhaitez travailler avec une autre paire de langues, vous pouvez les spécifier par leurs codes. Au total, 92 langues sont disponibles pour cet ensemble de données ; vous pouvez les voir toutes en développant les étiquettes de langue sur sa [fiche](https://huggingface.co/datasets/kde4).
+Si vous souhaitez travailler avec une autre paire de langues, 92 langues sont disponibles au total pour ce jeu de données. Vous pouvez les voir dans la [carte du jeu de données](https://huggingface.co/datasets/kde4).
-Jetons un coup d'œil au jeu de données :
+Jetons un coup d'œil au jeu de données :
```py
raw_datasets
@@ -78,7 +78,7 @@ DatasetDict({
})
```
-Nous avons 210 173 paires de phrases, mais dans un seul split, donc nous devrons créer notre propre ensemble de validation. Comme nous l'avons vu dans le [Chapitre 5](/course/fr/chapter5), un `Dataset` possède une méthode `train_test_split()` qui peut nous aider. Nous allons fournir une graine pour la reproductibilité :
+Nous avons 210 173 paires de phrases. Cependant regroupées dans un seul échantillon. Nous devrons donc créer notre propre jeu de validation. Comme nous l'avons vu dans le [chapitre 5](/course/fr/chapter5), un `Dataset` possède une méthode `train_test_split()` qui peut nous aider. Nous allons fournir une graine pour la reproductibilité :
```py
split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20)
@@ -98,7 +98,7 @@ DatasetDict({
})
```
-Nous pouvons renommer la clé "test" en "validation" comme ceci :
+Nous pouvons renommer la clé `test` en `validation` comme ceci :
```py
split_datasets["validation"] = split_datasets.pop("test")
@@ -115,8 +115,8 @@ split_datasets["train"][1]["translation"]
'fr': 'Par défaut, développer les fils de discussion'}
```
-Nous obtenons un dictionnaire contenant deux phrases dans la paire de langues demandée.
-Une particularité de ce jeu de données rempli de termes techniques informatiques est qu'ils sont tous entièrement traduits en français. Cependant, les ingénieurs français sont souvent paresseux et laissent la plupart des mots spécifiques à l'informatique en anglais lorsqu'ils parlent. Ici, par exemple, le mot "threads" pourrait très bien apparaître dans une phrase française, surtout dans une conversation technique. Mais dans ce jeu de données, il a été traduit par le plus correct "fils de discussion". Le modèle pré-entraîné que nous utilisons, qui a été pré-entraîné sur un plus grand corpus de phrases françaises et anglaises, prend l'option la plus facile de laisser le mot tel quel :
+Nous obtenons un dictionnaire contenant deux phrases dans la paire de langues qui nous intéresse.
+Une particularité de ce jeu de données rempli de termes techniques informatiques est qu'ils sont tous entièrement traduits en français. Cependant, les ingénieurs français sont souvent paresseux et laissent la plupart des mots spécifiques à l'informatique en anglais lorsqu'ils parlent. Ici, par exemple, le mot « *threads* » pourrait très bien apparaître dans une phrase française, surtout dans une conversation technique. Mais dans ce jeu de données, il a été traduit en « fils de discussion ». Le modèle pré-entraîné que nous utilisons (qui a été pré-entraîné sur un plus grand corpus de phrases françaises et anglaises) prend l'option de laisser le mot tel quel :
```py
from transformers import pipeline
@@ -130,8 +130,8 @@ translator("Default to expanded threads")
[{'translation_text': 'Par défaut pour les threads élargis'}]
```
-Un autre exemple de ce comportement peut être observé avec le mot "*plugin*", qui n'est pas officiellement un mot français mais que la plupart des locuteurs natifs comprendront et ne prendront pas la peine de traduire.
-Dans le jeu de données KDE4, ce mot a été traduit en français par le plus officiel "module d'extension" :
+Un autre exemple de ce comportement peut être observé avec le mot « *plugin* » qui n'est pas officiellement un mot français mais que la plupart des francophones comprendront et ne prendront pas la peine de traduire.
+Dans le jeu de données KDE4, ce mot a été traduit en français par le plus officiel « module d'extension » :
```py
split_datasets["train"][172]["translation"]
@@ -142,7 +142,7 @@ split_datasets["train"][172]["translation"]
'fr': "Impossible d'importer %1 en utilisant le module d'extension d'importation OFX. Ce fichier n'a pas un format correct."}
```
-Notre modèle pré-entraîné, cependant, s'en tient au mot anglais compact et familier :
+Notre modèle pré-entraîné, lui, s'en tient au mot anglais :
```py
translator(
@@ -154,13 +154,13 @@ translator(
[{'translation_text': "Impossible d'importer %1 en utilisant le plugin d'importateur OFX. Ce fichier n'est pas le bon format."}]
```
-Il sera intéressant de voir si notre modèle *finetuné* tient compte de ces particularités de l'ensemble de données (alerte *spoiler* : il le fera).
+Il sera intéressant de voir si notre modèle *finetuné* tient compte de ces particularités (alerte *spoiler* : il le fera).
-✏️ **Votre tour !** Un autre mot anglais souvent utilisé en français est "email". Trouvez le premier échantillon dans l'ensemble de données d'entraînement qui utilise ce mot. Comment est-il traduit ? Comment le modèle pré-entraîné traduit-il la même phrase anglaise ?
+✏️ **A votre tour !** Un autre mot anglais souvent utilisé en français est « *email* ». Trouvez le premier échantillon dans l'échantillon d'entraînement qui utilise ce mot. Comment est-il traduit ? Comment le modèle pré-entraîné traduit-il cette même phrase ?
@@ -177,11 +177,11 @@ model_checkpoint = "Helsinki-NLP/opus-mt-en-fr"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, return_tensors="tf")
```
-Vous pouvez également remplacer le `model_checkpoint` par tout autre modèle que vous préférez à partir du [*Hub*](https://huggingface.co/models), ou un dossier local où vous avez sauvegardé un modèle pré-entraîné et un *tokenizer*.
+Vous pouvez remplacer le `model_checkpoint` par un tout autre modèle disponible sur le [*Hub*](https://huggingface.co/models) qui aurait votre préférence, ou par un dossier en local où vous avez sauvegardé un modèle pré-entraîné et un *tokenizer*.
-💡 Si vous utilisez un *tokenizer* multilingue tel que mBART, mBART-50, ou M2M100, vous devrez définir les codes de langue de vos entrées et cibles dans le *tokenizer* en définissant `tokenizer.src_lang` et `tokenizer.tgt_lang` aux bonnes valeurs.
+💡 Si vous utilisez un *tokenizer* multilingue tel que mBART, mBART-50 ou M2M100, vous devrez définir les codes de langue de vos entrées et cibles dans le *tokenizer* en définissant `tokenizer.src_lang` et `tokenizer.tgt_lang` aux bonnes valeurs.
@@ -194,7 +194,7 @@ with open(file_path) as f:
content = f.read()
```
-Ici, les deux opérations connexes qui sont exécutées en paire sont les actions d'ouverture et de fermeture du fichier. L'objet correspondant au fichier ouvert `f` n'existe qu'à l'intérieur du bloc indenté sous le `with` ; l'ouverture se produit avant ce bloc et la fermeture à la fin du bloc.
+Ici, les deux opérations connexes qui sont exécutées en paire sont les actions d'ouverture et de fermeture du fichier. L'objet correspondant au fichier ouvert `f` n'existe qu'à l'intérieur du bloc indenté sous le `with`. L'ouverture se produit avant ce bloc et la fermeture à la fin du bloc.
Dans le cas présent, le gestionnaire de contexte `as_target_tokenizer()` va définir le *tokenizer* dans la langue de sortie (ici, le français) avant l'exécution du bloc indenté, puis le redéfinir dans la langue d'entrée (ici, l'anglais).
@@ -209,7 +209,7 @@ with tokenizer.as_target_tokenizer():
targets = tokenizer(fr_sentence)
```
-Si nous oublions de tokeniser les cibles dans le gestionnaire de contexte, elles seront tokenisées par le *tokenizer* d'entrée, ce qui, dans le cas d'un modèle marial, ne va pas du tout bien se passer :
+Si nous oublions de tokeniser les cibles dans le gestionnaire de contexte, elles seront tokenisées par le *tokenizer* d'entrée, ce qui dans le cas d'un modèle Marian, ne va pas du tout bien se passer :
```python
wrong_targets = tokenizer(fr_sentence)
@@ -222,9 +222,9 @@ print(tokenizer.convert_ids_to_tokens(targets["input_ids"]))
['▁Par', '▁défaut', ',', '▁développer', '▁les', '▁fils', '▁de', '▁discussion', '']
```
-Comme on peut le voir, utiliser le *tokenizer* anglais pour prétraiter une phrase française donne un batch de *tokens* plus important, puisque le *tokenizer* ne connaît aucun mot français (sauf ceux qui apparaissent aussi en anglais, comme "discussion").
+Comme on peut le voir, utiliser le *tokenizer* anglais pour prétraiter une phrase française donne un batch de *tokens* plus important, puisque le *tokenizer* ne connaît aucun mot français (sauf ceux qui apparaissent aussi en anglais, comme « discussion »).
-Les `inputs` et les `targets` sont des dictionnaires avec nos clés habituelles (identifiants d'entrée, masque d'attention, etc.), donc la dernière étape est de définir une clé `"labels"` dans les entrées. Nous faisons cela dans la fonction de prétraitement que nous allons appliquer sur les jeux de données :
+Les `inputs` et les `targets` sont des dictionnaires avec nos clés habituelles (identifiants d'entrée, masque d'attention, etc.). La dernière étape est de définir une clé `"labels"` dans les entrées. Nous faisons cela dans la fonction de prétraitement que nous allons appliquer sur les jeux de données :
```python
max_input_length = 128
@@ -236,7 +236,7 @@ def preprocess_function(examples):
targets = [ex["fr"] for ex in examples["translation"]]
model_inputs = tokenizer(inputs, max_length=max_input_length, truncation=True)
- # Set up the tokenizer for targets
+ # Configurer le tokenizer pour les cibles.
with tokenizer.as_target_tokenizer():
labels = tokenizer(targets, max_length=max_target_length, truncation=True)
@@ -248,17 +248,17 @@ Notez que nous avons fixé des longueurs maximales similaires pour nos entrées
-💡 Si vous utilisez un modèle T5 (plus précisément, un des points de contrôle `t5-xxx`), le modèle s'attendra à ce que les entrées de texte aient un préfixe indiquant la tâche à accomplir, comme Si vous utilisez un modèle T5 (plus précisément, un des points de contrôle `t5-xxx`), le modèle s'attendra à ce que les entrées de texte aient un préfixe indiquant la tâche à accomplir, comme `translate : Anglais vers Français:`..
+💡 Si vous utilisez un modèle T5 (plus précisément, un des *checkpoints* `t5-xxx`), le modèle s'attendra à ce que les entrées aient un préfixe indiquant la tâche à accomplir, comme `translate: English to French:`.
-⚠️ Nous ne faisons pas attention au masque d'attention des cibles, car le modèle ne s'y attend pas. Au lieu de cela, les étiquettes correspondant à un *token* de *padding* doivent être mises à `-100` afin qu'elles soient ignorées dans le calcul de la perte. Cela sera fait par notre collateur de données plus tard puisque nous appliquons le *padding* dynamique, mais si vous utilisez le *padding* ici, vous devriez adapter la fonction de prétraitement pour mettre tous les labels qui correspondent au *token* de *padding* à `-100`.
+⚠️ Nous ne faisons pas attention au masque d'attention des cibles car le modèle ne s'y attend pas. Au lieu de cela, les étiquettes correspondant à un *token* de *padding* doivent être mises à `-100` afin qu'elles soient ignorées dans le calcul de la perte. Cela sera fait par notre collateur de données plus tard puisque nous appliquons le *padding* dynamique, mais si vous utilisez le *padding* ici, vous devriez adapter la fonction de prétraitement pour mettre toutes les étiquettes qui correspondent au *token* de *padding* à `-100`.
-Nous pouvons maintenant appliquer ce prétraitement en une seule fois sur toutes les divisions de notre jeu de données :
+Nous pouvons maintenant appliquer ce prétraitement en une seule fois sur toutes les échantillons de notre jeu de données :
```py
tokenized_datasets = split_datasets.map(
@@ -272,11 +272,11 @@ Maintenant que les données ont été prétraitées, nous sommes prêts à *fine
{#if fw === 'pt'}
-## *Finetuner* le modèle avec l'API `Trainer`.
+##
Finetuner le modèle avec l'API `Trainer`
-Le code actuel utilisant le `Trainer` sera le même que précédemment, avec juste un petit changement : nous utilisons ici un [`Seq2SeqTrainer`](https://huggingface.co/transformers/main_classes/trainer.html#seq2seqtrainer), qui est une sous-classe de `Trainer` qui nous permettra de traiter correctement l'évaluation, en utilisant la méthode `generate()` pour prédire les sorties à partir des entrées. Nous y reviendrons plus en détail lorsque nous parlerons du calcul de la métrique.
+Le code actuel utilisant `Trainer` sera le même que précédemment, avec juste un petit changement : nous utilisons ici [`Seq2SeqTrainer`](https://huggingface.co/transformers/main_classes/trainer.html#seq2seqtrainer) qui est une sous-classe de `Trainer` qui nous permet de traiter correctement l'évaluation, en utilisant la méthode `generate()` pour prédire les sorties à partir des entrées. Nous y reviendrons plus en détail lorsque nous parlerons du calcul de la métrique.
-Tout d'abord, nous avons besoin d'un modèle réel à affiner. Nous allons utiliser l'API habituelle `AutoModel` :
+Tout d'abord, nous avons besoin d'un modèle à *finetuner*. Nous allons utiliser l'API habituelle `AutoModel` :
```py
from transformers import AutoModelForSeq2SeqLM
@@ -286,9 +286,9 @@ model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
{:else}
-## *Finetuning* du modèle avec Keras
+##
Finetuner du modèle avec Keras
-Tout d'abord, nous avons besoin d'un modèle réel à *finetuner*. Nous allons utiliser l'API habituelle `AutoModel` :
+Tout d'abord, nous avons besoin d'un modèle à *finetuner*. Nous allons utiliser l'API habituelle `AutoModel` :
```py
from transformers import TFAutoModelForSeq2SeqLM
@@ -298,8 +298,7 @@ model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint, from_pt=True)
-💡 Le *checkpoint* `Helsinki-NLP/opus-mt-en-fr` ne dispose que de poids PyTorch, donc vous aurez une erreur si vous essayez de charger le modèle sans utiliser l'argument
-`from_pt=True` dans la méthode `from_pretrained()`. Lorsque vous spécifiez `from_pt=True`, la bibliothèque téléchargera et convertira automatiquement les poids PyTorch pour vous. Comme vous pouvez le constater, il est très simple de passer d'un framework à l'autre dans 🤗 *Transformers* !
+💡 Le *checkpoint* `Helsinki-NLP/opus-mt-en-fr` ne dispose que de poids PyTorch, vous aurez donc une erreur si vous essayez de charger le modèle sans utiliser l'argument `from_pt=True` dans la méthode `from_pretrained()`. Lorsque vous spécifiez `from_pt=True`, la bibliothèque téléchargera et convertira automatiquement les poids PyTorch pour vous. Comme vous pouvez le constater, c'est très simple de passer d'un *framework* à l'autre dans 🤗 *Transformers* !
@@ -309,9 +308,9 @@ Notez que cette fois-ci, nous utilisons un modèle qui a été entraîné sur un
### Collecte des données
-Nous aurons besoin d'un assembleur de données pour gérer le rembourrage pour la mise en lots dynamique. Nous ne pouvons pas simplement utiliser un `DataCollatorWithPadding` comme dans [Chapter 3](/course/fr/chapter3) dans ce cas, parce que cela ne rembourre que les entrées (ID d'entrée, masque d'attention, et ID de type de jeton). Nos étiquettes doivent également être rembourrées à la longueur maximale rencontrée dans les étiquettes. Et, comme mentionné précédemment, la valeur de remplissage utilisée pour remplir les étiquettes doit être `-100` et non le jeton de remplissage du *tokenizer*, pour s'assurer que ces valeurs remplies sont ignorées dans le calcul de la perte.
+Nous aurons besoin d'un assembleur de données pour gérer le rembourrage pour la mise en batchs dynamique. Ici, nous ne pouvons pas simplement utiliser un `DataCollatorWithPadding` comme dans le [chapitre 3](/course/fr/chapter3) car cela ne rembourre que les entrées (identifiants d'entrée, masque d'attention, et *token* de type identifiants). Nos étiquettes doivent également être rembourrées à la longueur maximale rencontrée dans les étiquettes. Et, comme mentionné précédemment, la valeur de remplissage utilisée pour remplir les étiquettes doit être `-100` et non le *token* de *padding* du *tokenizer* afin de s'assurer que ces valeurs soient ignorées dans le calcul de la perte.
-Tout ceci est réalisé par un [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq). Comme le `DataCollatorWithPadding`, il prend le `tokenizer` utilisé pour prétraiter les entrées, mais il prend aussi le `model`. C'est parce que ce collateur de données sera également responsable de la préparation des ID d'entrée du décodeur, qui sont des versions décalées des étiquettes avec un jeton spécial au début. Comme ce décalage est effectué de manière légèrement différente selon les architectures, le `DataCollatorForSeq2Seq` a besoin de connaître l'objet `model` :
+Tout ceci est réalisé par un [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq). Comme le `DataCollatorWithPadding`, il prend le `tokenizer` utilisé pour prétraiter les entrées, mais également le `model`. C'est parce que ce collateur de données est également responsable de la préparation des identifiants d'entrée du décodeur, qui sont des versions décalées des étiquettes avec un *token* spécial au début. Comme ce décalage est effectué de manière légèrement différente selon les architectures, le `DataCollatorForSeq2Seq` a besoin de connaître l'objet `model` :
{#if fw === 'pt'}
@@ -331,7 +330,7 @@ data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="t
{/if}
-Pour le tester sur quelques échantillons, nous l'appelons simplement sur une liste d'exemples de notre ensemble d'entrainement tokénisé :
+Pour le tester sur quelques échantillons, nous l'appelons simplement sur une liste d'exemples de notre échantillon d'entrainement tokénisé :
```py
batch = data_collator([tokenized_datasets["train"][i] for i in range(1, 3)])
@@ -342,7 +341,7 @@ batch.keys()
dict_keys(['attention_mask', 'input_ids', 'labels', 'decoder_input_ids'])
```
-Nous pouvons vérifier que nos étiquettes ont été paddées à la longueur maximale du lot, en utilisant `-100` :
+Nous pouvons vérifier que nos étiquettes ont été rembourrées à la longueur maximale du batch, en utilisant `-100` :
```py
batch["labels"]
@@ -355,7 +354,7 @@ tensor([[ 577, 5891, 2, 3184, 16, 2542, 5, 1710, 0, -100,
550, 7032, 5821, 7907, 12649, 0]])
```
-Et nous pouvons également jeter un coup d'œil aux ID d'entrée du décodeur, pour voir qu'il s'agit de versions décalées des étiquettes :
+Nous pouvons aussi jeter un coup d'œil aux identifiants d'entrée du décodeur, pour voir qu'il s'agit de versions décalées des étiquettes :
```py
batch["decoder_input_ids"]
@@ -412,21 +411,21 @@ tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset(
{#if fw === 'pt'}
-La fonctionnalité que `Seq2SeqTrainer` ajoute à sa superclasse `Trainer` est la possibilité d'utiliser la méthode `generate()` pendant l'évaluation ou la prédiction. Pendant l'entraînement, le modèle utilisera les `decoder_input_ids` avec un masque d'attention assurant qu'il n'utilise pas les *tokens* après le *token* qu'il essaie de prédire, pour accélérer l'entraînement. Pendant l'inférence, nous ne pourrons pas les utiliser puisque nous n'aurons pas d'étiquettes, donc c'est une bonne idée d'évaluer notre modèle avec la même configuration.
+La fonctionnalité que `Seq2SeqTrainer` ajoute à sa superclasse `Trainer` est la possibilité d'utiliser la méthode `generate()` pendant l'évaluation ou la prédiction. Pendant l'entraînement, le modèle utilisera les `decoder_input_ids` avec un masque d'attention assurant qu'il n'utilise pas les *tokens* après le *token* qu'il essaie de prédire, pour accélérer l'entraînement. Pendant l'inférence, nous ne pourrons pas les utiliser puisque nous n'aurons pas d'étiquettes. Ainsi c'est une bonne idée d'évaluer notre modèle avec la même configuration.
-Comme nous l'avons vu dans le [Chapitre 1](/course/fr/chapter1/6), le décodeur effectue l'inférence en prédisant les *tokens* un par un. Quelque chose qui est implémenté en coulisses dans les 🤗 Transformers par la méthode `generate()`. Le `Seq2SeqTrainer` nous laissera utiliser cette méthode pour l'évaluation si nous définissons `predict_with_generate=True`.
+Comme nous l'avons vu dans le [chapitre 1](/course/fr/chapter1/6), le décodeur effectue l'inférence en prédisant les *tokens* un par un. C'est quelque chose qui est implémenté en coulisses dans 🤗 *Transformers* par la méthode `generate()`. Le `Seq2SeqTrainer` nous laissera utiliser cette méthode pour l'évaluation si nous indiquons `predict_with_generate=True`.
{/if}
-La métrique traditionnelle utilisée pour la traduction est le [score BLEU](https://en.wikipedia.org/wiki/BLEU), introduit dans [un article de 2002](https://aclanthology.org/P02-1040.pdf) par Kishore Papineni et al. Le score BLEU évalue dans quelle mesure les traductions sont proches de leurs étiquettes. Il ne mesure pas l'intelligibilité ou l'exactitude grammaticale des résultats générés par le modèle, mais utilise des règles statistiques pour garantir que tous les mots des résultats générés apparaissent également dans les cibles. En outre, il existe des règles qui pénalisent les répétitions des mêmes mots s'ils ne sont pas également répétés dans les cibles (pour éviter que le modèle ne produise des phrases telles que "the the the the the the the") et les phrases produites qui sont plus courtes que celles des cibles (pour éviter que le modèle ne produise des phrases telles que "the").
+La métrique traditionnelle utilisée pour la traduction est le [score BLEU](https://en.wikipedia.org/wiki/BLEU), introduit dans [un article de 2002](https://aclanthology.org/P02-1040.pdf) par Kishore Papineni et al. Le score BLEU évalue dans quelle mesure les traductions sont proches de leurs étiquettes. Il ne mesure pas l'intelligibilité ou l'exactitude grammaticale des résultats générés par le modèle, mais utilise des règles statistiques pour garantir que tous les mots des résultats générés apparaissent également dans les cibles. En outre, il existe des règles qui pénalisent les répétitions des mêmes mots s'ils ne sont pas également répétés dans les cibles (pour éviter que le modèle ne produise des phrases telles que « the the the the the the the ») et les phrases produites qui sont plus courtes que celles des cibles (pour éviter que le modèle ne produise des phrases telles que « the »).
-L'une des faiblesses de BLEU est qu'il s'attend à ce que le texte soit déjà tokenisé, ce qui rend difficile la comparaison des scores entre les modèles qui utilisent différents *tokenizers*. Par conséquent, la mesure la plus couramment utilisée aujourd'hui pour évaluer les modèles de traduction est [SacreBLEU](https://github.com/mjpost/sacrebleu), qui remédie à cette faiblesse (et à d'autres) en standardisant l'étape de tokenisation. Pour utiliser cette métrique, nous devons d'abord installer la bibliothèque SacreBLEU :
+L'une des faiblesses de BLEU est qu'il s'attend à ce que le texte soit déjà tokenisé, ce qui rend difficile la comparaison des scores entre les modèles qui utilisent différents *tokenizers*. Par conséquent, la mesure la plus couramment utilisée aujourd'hui pour évaluer les modèles de traduction est [SacreBLEU](https://github.com/mjpost/sacrebleu) qui remédie à cette faiblesse (et à d'autres) en standardisant l'étape de tokenisation. Pour utiliser cette métrique, nous devons d'abord installer la bibliothèque *SacreBLEU* :
```py
!pip install sacrebleu
```
-Nous pouvons ensuite le charger via `load_metric()` comme nous l'avons fait dans le [Chapitre 3](/course/fr/chapter3) :
+Nous pouvons ensuite charger ce score via `load_metric()` comme nous l'avons fait dans le [chapitre 3](/course/fr/chapter3) :
```py
from datasets import load_metric
@@ -434,7 +433,7 @@ from datasets import load_metric
metric = load_metric("sacrebleu")
```
-Cette métrique prend des textes comme entrées et cibles. Elle est conçue pour accepter plusieurs cibles acceptables, car il y a souvent plusieurs traductions acceptables de la même phrase. Le jeu de données que nous utilisons n'en fournit qu'une seule, mais il n'est pas rare en NLP de trouver des jeux de données qui donnent plusieurs phrases comme étiquettes. Ainsi, les prédictions doivent être une liste de phrases, mais les références doivent être une liste de listes de phrases.
+Cette métrique prend des textes comme entrées et cibles. Elle est conçue pour accepter plusieurs cibles acceptables car il y a souvent plusieurs traductions possibles d'une même phrase. Le jeu de données que nous utilisons n'en fournit qu'une seule, mais en NLP, il n'est pas rare de trouver des jeux de données ayant plusieurs phrases comme étiquettes. Ainsi, les prédictions doivent être une liste de phrases mais les références doivent être une liste de listes de phrases.
Essayons un exemple :
@@ -460,7 +459,7 @@ metric.compute(predictions=predictions, references=references)
'ref_len': 13}
```
-Cela donne un score BLEU de 46.75, ce qui est plutôt bon. Pour référence, le Transformer original dans l'article ["Attention Is All You Need"](https://arxiv.org/pdf/1706.03762.pdf) a obtenu un score BLEU de 41.8 sur une tâche de traduction similaire entre l'anglais et le français ! (Pour plus d'informations sur les métriques individuelles, comme `counts` et `bp`, voir le [Dépôt SacreBLEU](https://github.com/mjpost/sacrebleu/blob/078c440168c6adc89ba75fe6d63f0d922d42bcfe/sacrebleu/metrics/bleu.py#L74).) D'autre part, si nous essayons avec les deux mauvais types de prédictions (batchs de répétitions ou trop courts) qui sortent souvent des modèles de traduction, nous obtiendrons des scores BLEU plutôt mauvais :
+Cela donne un score BLEU de 46.75, ce qui est plutôt bon. A titre de comparaison, le *Transformer* original dans l'article [*Attention Is All You Need*](https://arxiv.org/pdf/1706.03762.pdf) a obtenu un score BLEU de 41.8 sur une tâche de traduction similaire entre l'anglais et le français ! (Pour plus d'informations sur les métriques individuelles, comme `counts` et `bp`, voir le [dépôt SacreBLEU](https://github.com/mjpost/sacrebleu/blob/078c440168c6adc89ba75fe6d63f0d922d42bcfe/sacrebleu/metrics/bleu.py#L74). D'autre part, si nous essayons avec les deux mauvais types de prédictions (répétitions ou prédiction trop courte) qui sortent souvent des modèles de traduction, nous obtiendrons des scores BLEU plutôt mauvais :
```py
predictions = ["This This This This"]
@@ -502,11 +501,11 @@ metric.compute(predictions=predictions, references=references)
'ref_len': 13}
```
-Le score peut aller de 0 à 100, et plus il est élevé, mieux c'est.
+Le score peut aller de 0 à 100. Plus il est élevé, mieux c'est.
{#if fw === 'tf'}
-Pour passer des sorties du modèle aux textes que la métrique peut utiliser, nous allons utiliser la méthode `tokenizer.batch_decode()`. Nous devons juste nettoyer tous les `-100` dans les étiquettes ; le *tokenizer* fera automatiquement la même chose pour le *token* de *padding*. Définissons une fonction qui prend notre modèle et un jeu de données et calcule des métriques sur ceux-ci. Comme la génération de longues séquences peut être lente, nous sous-échantillonnons l'ensemble de validation pour nous assurer que cela ne prend pas une éternité :
+Pour passer des sorties du modèle aux textes que la métrique peut utiliser, nous allons utiliser la méthode `tokenizer.batch_decode()`. Nous devons juste nettoyer tous les `-100` dans les étiquettes. Le *tokenizer* fera automatiquement la même chose pour le *token* de *padding*. Définissons une fonction qui prend notre modèle et un jeu de données et calcule des métriques sur ceux-ci. Comme la génération de longues séquences peut être lente, nous sous-échantillonnons l'ensemble de validation pour nous assurer que cela ne prend pas une éternité :
```py
import numpy as np
@@ -541,7 +540,7 @@ def compute_metrics():
{:else}
-Pour passer des sorties du modèle aux textes utilisables par la métrique, nous allons utiliser la méthode `tokenizer.batch_decode()`. Nous devons juste nettoyer tous les `-100`s dans les étiquettes (le tokenizer fera automatiquement la même chose pour le token de remplissage) :
+Pour passer des sorties du modèle aux textes utilisables par la métrique, nous allons utiliser la méthode `tokenizer.batch_decode()`. Nous devons juste nettoyer tous les `-100` dans les étiquettes. Le *tokenizer* fera automatiquement la même chose pour le *token* de *padding* :
```py
import numpy as np
@@ -549,17 +548,17 @@ import numpy as np
def compute_metrics(eval_preds):
preds, labels = eval_preds
- # In case the model returns more than the prediction logits
+ # Dans le cas où le modèle retourne plus que les logits de prédiction
if isinstance(preds, tuple):
preds = preds[0]
decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True)
- # Replace -100s in the labels as we can't decode them
+ # Remplacer les -100 dans les étiquettes car nous ne pouvons pas les décoder
labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
- # Some simple post-processing
+ # Quelques post-traitements simples
decoded_preds = [pred.strip() for pred in decoded_preds]
decoded_labels = [[label.strip()] for label in decoded_labels]
@@ -569,10 +568,10 @@ def compute_metrics(eval_preds):
{/if}
-Maintenant que c'est fait, nous sommes prêts à affiner notre modèle !
+Maintenant que c'est fait, nous sommes prêts à *finetuner* notre modèle !
-### *Finetuner* le modèle
+###
Finetuner le modèle
La première étape consiste à se connecter à Hugging Face, afin de pouvoir télécharger vos résultats sur le *Hub*. Il y a une fonction pratique pour vous aider à le faire dans un *notebook* :
@@ -582,7 +581,7 @@ from huggingface_hub import notebook_login
notebook_login()
```
-Cela affichera un widget où vous pourrez entrer vos identifiants de connexion à Hugging Face.
+Cela affichera un *widget* où vous pourrez entrer vos identifiants de connexion à Hugging Face.
Si vous ne travaillez pas dans un *notebook*, tapez simplement la ligne suivante dans votre terminal :
@@ -609,9 +608,9 @@ from transformers import create_optimizer
from transformers.keras_callbacks import PushToHubCallback
import tensorflow as tf
-# Le nombre d'étapes d'entraînement est le nombre d'échantillons dans l'ensemble de données, divisé par la taille du lot, puis multiplié par le nombre total d'époques.
-# par le nombre total d'époques. Notez que le jeu de données tf_train_dataset est ici un lot tf.data.Dataset,
-# et non le jeu de données original Hugging Face Dataset, donc son len() est déjà num_samples // batch_size.
+# Le nombre d'étapes d'entraînement est le nombre d'échantillons dans le jeu de données, divisé par la taille du batch,
+# puis multiplié par le nombre total d'époques. Notez que le jeu de données tf_train_dataset est ici un tf.data.Dataset,
+# et non le jeu de données original donc son len() est déjà num_samples // batch_size.
num_epochs = 3
num_train_steps = len(tf_train_dataset) * num_epochs
@@ -627,7 +626,7 @@ model.compile(optimizer=optimizer)
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```
-Ensuite, nous définissons un `PushToHubCallback` pour télécharger notre modèle sur le *Hub* pendant l'entraînement, comme nous l'avons vu dans [section 2]((/course/fr/chapter7/2)), et ensuite nous ajustons simplement le modèle avec ce callback :
+Ensuite, nous définissons un `PushToHubCallback` pour télécharger notre modèle sur le *Hub* pendant l'entraînement, comme nous l'avons vu dans la [section 2](/course/fr/chapter7/2), puis nous entraînons simplement le modèle avec ce *callback* :
```python
from transformers.keras_callbacks import PushToHubCallback
@@ -644,7 +643,7 @@ model.fit(
)
```
-Notez que vous pouvez spécifier le nom du référentiel vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"``Seq2SeqTrainingArguments`. Par défaut, le référentiel utilisé sera dans votre espace de noms et nommé après le répertoire de sortie que vous avez défini, donc ici ce sera `"sgugger/marian-finetuned-kde4-en-to-fr"` (qui est le modèle que nous avons lié au début de cette section).
+Notez que vous pouvez spécifier le nom du dépôt vers lequel vous voulez pousser le modèle avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` dans `Seq2SeqTrainingArguments`. Par défaut, le dépôt utilisé sera dans votre espace et nommé après le répertoire de sortie que vous avez défini. Ici ce sera `"sgugger/marian-finetuned-kde4-en-to-fr"` (qui est le modèle que nous avons lié au début de cette section).
@@ -652,7 +651,7 @@ Notez que vous pouvez spécifier le nom du référentiel vers lequel vous voulez
-Enfin, voyons à quoi ressemblent nos mesures maintenant que l'entraînement est terminé :
+Enfin, voyons à quoi ressemblent nos métriques maintenant que l'entraînement est terminé :
```py
print(compute_metrics())
@@ -662,7 +661,7 @@ print(compute_metrics())
{'bleu': 57.334066271545865}
```
-À ce stade, vous pouvez utiliser le widget d'inférence sur le *Hub* pour tester votre modèle et le partager avec vos amis. Vous avez réussi à *finetuner* un modèle sur une tâche de traduction. Félicitations !
+À ce stade, vous pouvez utiliser le *widget* d'inférence sur le *Hub* pour tester votre modèle et le partager avec vos amis. Vous avez réussi à *finetuner* un modèle sur une tâche de traduction. Félicitations !
{:else}
@@ -687,14 +686,14 @@ args = Seq2SeqTrainingArguments(
)
```
-En dehors des hyperparamètres habituels (comme le taux d'apprentissage, le nombre d'époques, la taille du lot et une certaine décroissance des poids), voici quelques changements par rapport à ce que nous avons vu dans les sections précédentes :
+En dehors des hyperparamètres habituels (comme le taux d'apprentissage, le nombre d'époques, la taille des batchs et une le taux de décroissance des poids), voici quelques changements par rapport à ce que nous avons vu dans les sections précédentes :
-- nous ne définissons pas d'évaluation régulière, car l'évaluation prend du temps ; nous allons juste évaluer notre modèle une fois avant l'entraînement et après,
-- nous avons mis `fp16=True`, ce qui accélère l'entraînement sur les GPUs modernes,
-- nous définissons `predict_with_generate=True`, comme discuté ci-dessus,
-- nous utilisons `push_to_hub=True` pour télécharger le modèle sur le *Hub* à la fin de chaque époque.
+- Nous ne définissons pas d'évaluation car elle prend du temps. Nous allons juste évaluer une fois notre modèle avant l'entraînement et après.
+- Nous avons mis `fp16=True`, ce qui accélère l'entraînement sur les GPUs modernes.
+- Nous définissons `predict_with_generate=True`, comme discuté ci-dessus.
+- Nous utilisons `push_to_hub=True` pour télécharger le modèle sur le *Hub* à la fin de chaque époque.
-Notez que vous pouvez spécifier le nom complet du référentiel vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` `Seq2SeqTrainingArguments`. Par défaut, le référentiel utilisé sera dans votre espace de noms et nommé d'après le répertoire de sortie que vous avez défini, donc dans notre cas ce sera `"sgugger/marian-finetuned-kde4-en-to-fr"` (qui est le modèle que nous avons lié au début de cette section).
+Notez que vous pouvez spécifier le nom complet du dépôt vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` à `Seq2SeqTrainingArguments`. Par défaut, le dépôt utilisé sera dans votre espace et nommé d'après le répertoire de sortie que vous avez défini. Dans notre cas ce sera `"sgugger/marian-finetuned-kde4-en-to-fr"` (qui est le modèle que nous avons lié au début de cette section).
@@ -733,9 +732,9 @@ trainer.evaluate(max_length=max_target_length)
'eval_steps_per_second': 0.341}
```
-A BLEU score of 39 is not too bad, which reflects the fact that our model is already good at translating English sentences to French ones.
+Un score BLEU de 39 n'est pas trop mauvais, ce qui reflète le fait que notre modèle est déjà bon pour traduire des phrases anglaises en phrases françaises.
-Next is the training, which will also take a bit of time:
+Vient ensuite l'entraînement, qui prendra également un peu de temps :
```python
trainer.train()
@@ -743,7 +742,7 @@ trainer.train()
Notez que pendant l'entraînement, chaque fois que le modèle est sauvegardé (ici, à chaque époque), il est téléchargé sur le *Hub* en arrière-plan. De cette façon, vous serez en mesure de reprendre votre entraînement sur une autre machine si nécessaire.
-Une fois l'entraînement terminé, nous évaluons à nouveau notre modèle - avec un peu de chance, nous verrons une amélioration du score BLEU !
+Une fois l'entraînement terminé, nous évaluons à nouveau notre modèle. Avec un peu de chance, nous verrons une amélioration du score BLEU !
```py
trainer.evaluate(max_length=max_target_length)
@@ -760,7 +759,7 @@ trainer.evaluate(max_length=max_target_length)
C'est une amélioration de près de 14 points, ce qui est formidable.
-Enfin, nous utilisons la méthode `push_to_hub()` pour nous assurer que nous téléchargeons la dernière version du modèle. Le `Trainer` rédige également une carte modèle avec tous les résultats de l'évaluation et la télécharge. Cette carte de modèle contient des métadonnées qui aident le *Hub* à choisir le widget pour la démo d'inférence. Habituellement, il n'y a pas besoin de dire quoi que ce soit car il peut inférer le bon *widget* à partir de la classe du modèle, mais dans ce cas, la même classe de modèle peut être utilisée pour toutes sortes de problèmes de séquence à séquence, donc nous spécifions que c'est un modèle de traduction :
+Enfin, nous utilisons la méthode `push_to_hub()` pour nous assurer que nous téléchargeons la dernière version du modèle. `Trainer` rédige également une carte de modèle avec tous les résultats de l'évaluation et la télécharge. Cette carte de modèle contient des métadonnées qui aident le *Hub* à choisir le *widget* pour l'inférence. Habituellement, il n'y a pas besoin de dire quoi que ce soit car il peut inférer le bon *widget* à partir de la classe du modèle, mais dans ce cas, la même classe de modèle peut être utilisée pour toutes sortes de problèmes de séquence à séquence. Ainsi nous spécifions que c'est un modèle de traduction :
```py
trainer.push_to_hub(tags="translation", commit_message="Training complete")
@@ -772,7 +771,7 @@ Cette commande renvoie l'URL du commit qu'elle vient de faire, si vous voulez l'
'https://huggingface.co/sgugger/marian-finetuned-kde4-en-to-fr/commit/3601d621e3baae2bc63d3311452535f8f58f6ef3'
```
-À ce stade, vous pouvez utiliser le widget d'inférence sur le Hub du modèle pour tester votre modèle et le partager avec vos amis. Vous avez réussi à *finetuner* un modèle sur une tâche de traduction. Félicitations !
+À ce stade, vous pouvez utiliser le *widget* d'inférence sur le *Hub* pour tester votre modèle et le partager avec vos amis. Vous avez réussi à *finetuner* un modèle sur une tâche de traduction. Félicitations !
Si vous souhaitez vous plonger un peu plus profondément dans la boucle d'entraînement, nous allons maintenant vous montrer comment faire la même chose en utilisant 🤗 *Accelerate*.
@@ -782,7 +781,7 @@ Si vous souhaitez vous plonger un peu plus profondément dans la boucle d'entra
## Une boucle d'entraînement personnalisée
-Jetons maintenant un coup d'œil à la boucle d'entraînement complète, afin que vous puissiez facilement personnaliser les parties dont vous avez besoin. Elle ressemblera beaucoup à ce que nous avons fait dans la [section 2](/course/fr/chapter7/2) et le [chapitre 3](/course/fr/chapter3/4).
+Jetons maintenant un coup d'œil à la boucle d'entraînement complète afin que vous puissiez facilement personnaliser les parties dont vous avez besoin. Elle ressemblera beaucoup à ce que nous avons fait dans la [section 2](/course/fr/chapter7/2) et dans le [chapitre 3](/course/fr/chapter3/4).
### Préparer le tout pour l'entraînement
@@ -803,7 +802,7 @@ eval_dataloader = DataLoader(
)
```
-Ensuite, nous réinstantifions notre modèle, pour nous assurer que nous ne poursuivons pas l'affinage précédent, mais que nous repartons du modèle pré-entraîné :
+Ensuite, nous réinstantifions notre modèle pour nous assurer que nous ne poursuivons pas le *finetuning* précédent et que nous repartons du modèle pré-entraîné :
```py
model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
@@ -817,7 +816,7 @@ from transformers import AdamW
optimizer = AdamW(model.parameters(), lr=2e-5)
```
-Une fois que nous avons tous ces objets, nous pouvons les envoyer à la méthode `accelerator.prepare()`. Rappelez-vous que si vous voulez vous entraîner sur des TPUs dans un *notebook* de Colab, vous devrez déplacer tout ce code dans une fonction d'entraînement, et qui ne devrait pas exécuter une cellule qui instancie un `Accelerator`.
+Une fois que nous avons tous ces objets, nous pouvons les envoyer à la méthode `accelerator.prepare()`. Rappelez-vous que si vous voulez entraîner sur des TPUs dans un *notebook* de Colab, vous devez déplacer tout ce code dans une fonction d'entraînement et ne devrait pas exécuter une cellule qui instancie un `Accelerator`.
```py
from accelerate import Accelerator
@@ -828,7 +827,7 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
)
```
-Maintenant que nous avons envoyé notre `train_dataloader` à `accelerator.prepare()`, nous pouvons utiliser sa longueur pour calculer le nombre d'étapes d'entraînement. Rappelez-vous que nous devrions toujours faire cela après avoir préparé le dataloader, car cette méthode va changer la longueur du `DataLoader`. Nous utilisons un programme linéaire classique du taux d'apprentissage à 0 :
+Maintenant que nous avons envoyé notre `train_dataloader` à `accelerator.prepare()`, nous pouvons utiliser sa longueur pour calculer le nombre d'étapes d'entraînement. Rappelez-vous que nous devrions toujours faire cela après avoir préparé le chargeur de données car cette méthode va changer la longueur du `DataLoader`. Nous utilisons un programme linéaire classique du taux d'apprentissage à 0 :
```py
from transformers import get_scheduler
@@ -845,7 +844,7 @@ lr_scheduler = get_scheduler(
)
```
-Enfin, pour pousser notre modèle vers le Hub, nous aurons besoin de créer un objet `Repository` dans un dossier de travail. Tout d'abord, connectez-vous au *Hub*, si vous n'êtes pas déjà connecté. Nous déterminerons le nom du dépôt à partir de l'ID du modèle que nous voulons donner à notre modèle (n'hésitez pas à remplacer le `repo_name` par votre propre choix ; il doit juste contenir votre nom d'utilisateur, ce que fait la fonction `get_full_repo_name()`) :
+Enfin, pour pousser notre modèle vers le *Hub*, nous aurons besoin de créer un objet `Repository` dans un dossier de travail. Tout d'abord, connectez-vous au *Hub* si vous n'êtes pas déjà connecté. Nous déterminerons le nom du dépôt à partir de l'identifiant du modèle que nous voulons donner à notre modèle (n'hésitez pas à remplacer le `repo_name` par votre propre choix, il doit juste contenir votre nom d'utilisateur, ce que fait la fonction `get_full_repo_name()`) :
```py
from huggingface_hub import Repository, get_full_repo_name
@@ -859,7 +858,7 @@ repo_name
'sgugger/marian-finetuned-kde4-en-to-fr-accelerate'
```
-Ensuite, nous pouvons cloner ce référentiel dans un dossier local. S'il existe déjà, ce dossier local doit être un clone du référentiel avec lequel nous travaillons :
+Ensuite, nous pouvons cloner ce dépôt dans un dossier local. S'il existe déjà, ce dossier local doit être un clone du dépôt avec lequel nous travaillons :
```py
output_dir = "marian-finetuned-kde4-en-to-fr-accelerate"
@@ -879,7 +878,7 @@ def postprocess(predictions, labels):
decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True)
- # Remplacer -100 dans les étiquettes car nous ne pouvons pas les décoder.
+ # Remplace -100 dans les étiquettes car nous ne pouvons pas les décoder
labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True)
@@ -889,11 +888,11 @@ def postprocess(predictions, labels):
return decoded_preds, decoded_labels
```
-La boucle d'entraînement ressemble beaucoup à celles de [section 2](/course/fr/chapter7/2) et [chapitre 3](/course/fr/chapter3), avec quelques différences dans la partie évaluation -- alors concentrons-nous sur cela !
+La boucle d'entraînement ressemble beaucoup à celles de la [section 2](/course/fr/chapter7/2) et du [chapitre 3](/course/fr/chapter3), avec quelques différences dans la partie évaluation. Donc concentrons-nous sur cela !
-La première chose à noter est que nous utilisons la méthode `generate()` pour calculer les prédictions, mais c'est une méthode sur notre modèle de base, pas le modèle enveloppé 🤗 Accelerate créé dans la méthode `prepare()`. C'est pourquoi nous déballons d'abord le modèle, puis nous appelons cette méthode.
+La première chose à noter est que nous utilisons la méthode `generate()` pour calculer les prédictions. C'est une méthode sur notre modèle de base et non pas le modèle enveloppé créé dans la méthode `prepare()`. C'est pourquoi nous déballons d'abord le modèle, puis nous appelons cette méthode.
-La deuxième chose est que, comme avec [token classification](/course/fr/chapter7/2), deux processus peuvent avoir paddé les entrées et les étiquettes à des formes différentes, donc nous utilisons `accelerator.pad_across_processes()` pour rendre les prédictions et les étiquettes de la même forme avant d'appeler la méthode `gather()`. Si nous ne faisons pas cela, l'évaluation va soit se tromper, soit se bloquer pour toujours.
+La deuxième chose est que, comme avec la classification de [*token*](/course/fr/chapter7/2), deux processus peuvent avoir rembourrés les entrées et les étiquettes à des formes différentes. Ainsi nous utilisons `accelerator.pad_across_processes()` pour rendre les prédictions et les étiquettes de la même forme avant d'appeler la méthode `gather()`. Si nous ne faisons pas cela, l'évaluation va soit se tromper, soit se bloquer pour toujours.
```py
from tqdm.auto import tqdm
@@ -957,11 +956,11 @@ epoch 1, BLEU score: 54.24
epoch 2, BLEU score: 54.44
```
-Une fois que c'est fait, vous devriez avoir un modèle qui a des résultats assez similaires à celui entraîné avec le `Seq2SeqTrainer`. Vous pouvez vérifier celui que nous avons formé en utilisant ce code à [*huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate*](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate). Et si vous voulez tester des modifications de la boucle d'entraînement, vous pouvez les mettre en œuvre directement en modifiant le code ci-dessus !
+Une fois que c'est fait, vous devriez avoir un modèle qui a des résultats assez similaires à celui entraîné avec `Seq2SeqTrainer`. Vous pouvez vérifier celui que nous avons entraîné en utilisant ce code sur [*huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate*](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate). Et si vous voulez tester des modifications de la boucle d'entraînement, vous pouvez les mettre en œuvre directement en modifiant le code ci-dessus !
{/if}
-### Utilisation du modèle *finetuné*.
+### Utilisation du modèle finetuné
Nous vous avons déjà montré comment vous pouvez utiliser le modèle que nous avons *finetuné* sur le *Hub* avec le *widget* d'inférence. Pour l'utiliser localement dans un `pipeline`, nous devons juste spécifier l'identifiant de modèle approprié :
@@ -978,7 +977,7 @@ translator("Default to expanded threads")
[{'translation_text': 'Par défaut, développer les fils de discussion'}]
```
-Comme prévu, notre modèle pré-entraîné a adapté ses connaissances au corpus sur lequel nous l'avons affiné, et au lieu de laisser le mot anglais "threads" seul, il le traduit maintenant par la version officielle française. Il en va de même pour "plugin" :
+Comme prévu, notre modèle pré-entraîné a adapté ses connaissances au corpus sur lequel nous l'avons *finetuné*. Et au lieu de laisser le mot anglais « *threads* », le modèle le traduit maintenant par la version française officielle. Il en va de même pour « *plugin* » :
```py
translator(
@@ -994,6 +993,6 @@ Un autre excellent exemple d'adaptation au domaine !
-✏️ **Votre tour !** Que retourne le modèle sur l'échantillon avec le mot "email" que vous avez identifié plus tôt ?
+✏️ **A votre tour !** Que retourne le modèle sur l'échantillon avec le mot « *email* » que vous avez identifié plus tôt ?
diff --git a/chapters/fr/chapter7/5.mdx b/chapters/fr/chapter7/5.mdx
index 0ba896f6d..47428e425 100644
--- a/chapters/fr/chapter7/5.mdx
+++ b/chapters/fr/chapter7/5.mdx
@@ -27,7 +27,7 @@ Dans cette section, nous allons voir comment les *transformers* peuvent être ut
-Bien qu'il existe déjà plusieurs modèles *finetunés* pour le résumé sur le [Hugging Face Hub](https://huggingface.co/models?pipeline_tag=summarization&sort=downloads), la plupart d'entre eux ne sont adaptés qu'aux documents en anglais. Ainsi, pour ajouter une touche d'originalité à cette section, nous allons entraîner un modèle bilingue pour l'anglais et l'espagnol. À la fin de cette section, vous disposerez d'un [modèle](https://huggingface.co/huggingface-course/mt5-small-finetuned-amazon-en-es) capable de résumer les commentaires des clients comme celui présenté ici :
+Bien qu'il existe déjà plusieurs modèles *finetunés* pour le résumé sur le [*Hub*](https://huggingface.co/models?pipeline_tag=summarization&sort=downloads), la plupart d'entre eux ne sont adaptés qu'aux documents en anglais. Ainsi, pour ajouter une touche d'originalité à cette section, nous allons entraîner un modèle bilingue pour l'anglais et l'espagnol. À la fin de cette section, vous disposerez d'un [modèle](https://huggingface.co/huggingface-course/mt5-small-finetuned-amazon-en-es) capable de résumer les commentaires des clients comme celui présenté ici :
@@ -36,7 +36,7 @@ Comme nous allons le voir, ces résumés sont concis car ils sont appris à part
## Préparation d'un corpus multilingue
-Nous allons utiliser le [Multilingual Amazon Reviews Corpus](https://huggingface.co/datasets/amazon_reviews_multi) pour créer notre résumeur bilingue. Ce corpus est constitué d'évaluations de produits Amazon en six langues et est généralement utilisé pour évaluer les classificateurs multilingues. Cependant, comme chaque critique est accompagnée d'un titre court, nous pouvons utiliser les titres comme résumés cibles pour l'apprentissage de notre modèle ! Pour commencer, téléchargeons les sous-ensembles anglais et espagnols depuis le *Hub* :
+Nous allons utiliser le [*Multilingual Amazon Reviews Corpus*](https://huggingface.co/datasets/amazon_reviews_multi) pour créer notre résumeur bilingue. Ce corpus est constitué de critiques de produits Amazon en six langues et est généralement utilisé pour évaluer les classifieurs multilingues. Cependant, comme chaque critique est accompagnée d'un titre court, nous pouvons utiliser les titres comme résumés cibles pour l'apprentissage de notre modèle ! Pour commencer, téléchargeons les sous-ensembles anglais et espagnols depuis le *Hub* :
```python
from datasets import load_dataset
@@ -63,7 +63,7 @@ DatasetDict({
})
```
-Comme vous pouvez le voir, pour chaque langue, il y a 200 000 évaluations pour la partie "entraînement", et 5 000 évaluations pour chacune des parties "validation" et "test". Les informations qui nous intéressent sont contenues dans les colonnes `review_body` et `review_title`. Voyons quelques exemples en créant une fonction simple qui prend un échantillon aléatoire de l'ensemble d'entraînement avec les techniques apprises au [Chapitre 5](/course/fr/chapter5) :
+Comme vous pouvez le voir, pour chaque langue, il y a 200 000 critiques pour la partie entraînement et 5 000 critiques pour chacune des parties validation et test. Les informations qui nous intéressent sont contenues dans les colonnes `review_body` et `review_title`. Voyons quelques exemples en créant une fonction simple qui prend un échantillon aléatoire de l'ensemble d'entraînement avec les techniques apprises au [chapitre 5](/course/fr/chapter5) :
```python
def show_samples(dataset, num_samples=3, seed=42):
@@ -77,18 +77,19 @@ show_samples(english_dataset)
```
```python out
-'>> Title: Worked in front position, not rear' # Travaillé en position avant, pas arrière
+'>> Title: Worked in front position, not rear'
+# Travaillé en position avant, pas arrière
'>> Review: 3 stars because these are not rear brakes as stated in the item description. At least the mount adapter only worked on the front fork of the bike that I got it for.'
-# 3 étoiles car ce ne sont pas des freins arrière comme indiqué dans la description de l'article. Au moins, l'adaptateur de montage ne fonctionnait que sur la fourche avant du vélo pour lequel je l'ai acheté.''
+# 3 étoiles car ce ne sont pas des freins arrière comme indiqué dans la description de l'article. Au moins, l'adaptateur de montage ne fonctionnait que sur la fourche avant du vélo pour lequel je l'ai acheté.
'>> Title: meh'
'>> Review: Does it’s job and it’s gorgeous but mine is falling apart, I had to basically put it together again with hot glue'
# Il fait son travail et il est magnifique mais le mien est en train de tomber en morceaux, j'ai dû le recoller avec de la colle chaude.
-'>> Title: Can\'t beat these for the money' # On ne peut pas faire mieux pour le prix
+'>> Title: Can\'t beat these for the money'
+# On ne peut pas faire mieux pour le prix
'>> Review: Bought this for handling miscellaneous aircraft parts and hanger "stuff" that I needed to organize; it really fit the bill. The unit arrived quickly, was well packaged and arrived intact (always a good sign). There are five wall mounts-- three on the top and two on the bottom. I wanted to mount it on the wall, so all I had to do was to remove the top two layers of plastic drawers, as well as the bottom corner drawers, place it when I wanted and mark it; I then used some of the new plastic screw in wall anchors (the 50 pound variety) and it easily mounted to the wall. Some have remarked that they wanted dividers for the drawers, and that they made those. Good idea. My application was that I needed something that I can see the contents at about eye level, so I wanted the fuller-sized drawers. I also like that these are the new plastic that doesn\'t get brittle and split like my older plastic drawers did. I like the all-plastic construction. It\'s heavy duty enough to hold metal parts, but being made of plastic it\'s not as heavy as a metal frame, so you can easily mount it to the wall and still load it up with heavy stuff, or light stuff. No problem there. For the money, you can\'t beat it. Best one of these I\'ve bought to date-- and I\'ve been using some version of these for over forty years.'
# Je l'ai acheté pour manipuler diverses pièces d'avion et des "trucs" de hangar que je devais organiser ; il a vraiment fait l'affaire. L'unité est arrivée rapidement, était bien emballée et est arrivée intacte (toujours un bon signe). Il y a cinq supports muraux - trois sur le dessus et deux sur le dessous. Je voulais le monter sur le mur, alors tout ce que j'ai eu à faire était d'enlever les deux couches supérieures de tiroirs en plastique, ainsi que les tiroirs d'angle inférieurs, de le placer où je voulais et de le marquer ; j'ai ensuite utilisé quelques-uns des nouveaux ancrages muraux à vis en plastique (la variété de 50 livres) et il s'est facilement monté sur le mur. Certains ont fait remarquer qu'ils voulaient des séparateurs pour les tiroirs, et qu'ils les ont fabriqués. Bonne idée. Pour ma part, j'avais besoin de quelque chose dont je pouvais voir le contenu à hauteur des yeux, et je voulais donc des tiroirs plus grands. J'aime aussi le fait qu'il s'agisse du nouveau plastique qui ne se fragilise pas et ne se fend pas comme mes anciens tiroirs en plastique. J'aime la construction entièrement en plastique. Elle est suffisamment résistante pour contenir des pièces métalliques, mais étant en plastique, elle n'est pas aussi lourde qu'un cadre métallique, ce qui permet de la fixer facilement au mur et de la charger d'objets lourds ou légers. Aucun problème. Pour le prix, c'est imbattable. C'est le meilleur que j'ai acheté à ce jour, et j'utilise des versions de ce type depuis plus de quarante ans.
-
```
@@ -97,40 +98,40 @@ show_samples(english_dataset)
-Cet échantillon montre la diversité des critiques que l'on trouve généralement en ligne, allant du positif au négatif (et tout ce qui se trouve entre les deux !). Bien que l'exemple avec le titre "meh" ne soit pas très informatif, les autres titres semblent être des résumés décents des critiques elles-mêmes. Entraîner un modèle de résumé sur l'ensemble des 400 000 avis prendrait beaucoup trop de temps sur un seul GPU, nous allons donc nous concentrer sur la génération de résumés pour un seul domaine de produits. Pour avoir une idée des domaines parmi lesquels nous pouvons choisir, convertissons `english_dataset` en `pandas.DataFrame` et calculons le nombre d'avis par catégorie de produits :
+Cet échantillon montre la diversité des critiques que l'on trouve généralement en ligne, allant du positif au négatif (et tout ce qui se trouve entre les deux !). Bien que l'exemple avec le titre « meh » ne soit pas très informatif, les autres titres semblent être des résumés décents des critiques. Entraîner un modèle de résumé sur l'ensemble des 400 000 avis prendrait beaucoup trop de temps sur un seul GPU, nous allons donc nous concentrer sur la génération de résumés pour un seul domaine de produits. Pour avoir une idée des domaines parmi lesquels nous pouvons choisir, convertissons `english_dataset` en `pandas.DataFrame` et calculons le nombre d'avis par catégorie de produits :
```python
english_dataset.set_format("pandas")
english_df = english_dataset["train"][:]
-# Afficher les comptes des 20 premiers produits
+# Afficher le compte des 20 premiers produits
english_df["product_category"].value_counts()[:20]
```
```python out
-home 17679
-apparel 15951
-wireless 15717
-other 13418
-beauty 12091
-drugstore 11730
-kitchen 10382
-toy 8745
-sports 8277
-automotive 7506
-lawn_and_garden 7327
-home_improvement 7136
-pet_products 7082
-digital_ebook_purchase 6749
-pc 6401
-electronics 6186
-office_product 5521
-shoes 5197
-grocery 4730
-book 3756
+home 17679 # maison
+apparel 15951 # vêtements
+wireless 15717 # sans fil
+other 13418 # autres
+beauty 12091 # beauté
+drugstore 11730 # pharmacie
+kitchen 10382 # cuisine
+toy 8745 # jouets
+sports 8277 # sports
+automotive 7506 # automobile
+lawn_and_garden 7327 # pelouse_et_jardin
+home_improvement 7136 # amélioration_de_la_maison
+pet_products 7082 # produits_pour_animaux_de_compagnie
+digital_ebook_purchase 6749 # achat_de_livres_numériques
+pc 6401 # ordinateur_personnel
+electronics 6186 # électronique
+office_product 5521 # produits_de_bureau
+shoes 5197 # chaussures
+grocery 4730 # épicerie
+book 3756 # livre
Name: product_category, dtype: int64
```
-Les produits les plus populaires dans l'ensemble de données anglaises concernent les articles ménagers, les vêtements et l'électronique sans fil. Pour rester dans le thème d'Amazon, nous allons nous concentrer sur le résumé des critiques de livres. Après tout, c'est la raison d'être de l'entreprise ! Nous pouvons voir deux catégories de produits qui correspondent à nos besoins (`book` et `digital_ebook_purchase`), nous allons donc filtrer les ensembles de données dans les deux langues pour ces produits uniquement. Comme nous l'avons vu dans le [Chapitre 5](/course/fr/chapter5), la fonction `Dataset.filter()` nous permet de découper un jeu de données de manière très efficace, nous pouvons donc définir une fonction simple pour le faire :
+Les produits les plus populaires du jeu de données anglais concernent les articles ménagers, les vêtements et l'électronique sans fil. Pour rester dans le thème d'Amazon, nous allons nous concentrer sur le résumé des critiques de livres. Après tout, c'est la raison d'être de l'entreprise ! Nous pouvons voir deux catégories de produits qui correspondent à nos besoins (`book` et `digital_ebook_purchase`). Nous allons donc filtrer les jeux de données dans les deux langues pour ces produits uniquement. Comme nous l'avons vu dans le [chapitre 5](/course/fr/chapter5), la fonction `Dataset.filter()` nous permet de découper un jeu de données de manière très efficace. Nous pouvons donc définir une fonction simple pour le faire :
```python
def filter_books(example):
@@ -140,7 +141,7 @@ def filter_books(example):
)
```
-Maintenant, lorsque nous appliquons cette fonction à `english_dataset` et `spanish_dataset`, le résultat ne contiendra que les lignes impliquant les catégories de livres. Avant d'appliquer le filtre, changeons le format de `english_dataset` de `"pandas"` à `"arrow"` :
+Maintenant, lorsque nous appliquons cette fonction à `english_dataset` et `spanish_dataset`, le résultat ne contient que les lignes impliquant les catégories de livres. Avant d'appliquer le filtre, changeons le format de `english_dataset` de `"pandas"` à `"arrow"` :
```python
english_dataset.reset_format()
@@ -155,15 +156,18 @@ show_samples(english_books)
```
```python out
-'>> Title: I\'m dissapointed.' # Je suis déçu
+'>> Title: I\'m dissapointed.'
+# Je suis déçu
'>> Review: I guess I had higher expectations for this book from the reviews. I really thought I\'d at least like it. The plot idea was great. I loved Ash but, it just didnt go anywhere. Most of the book was about their radio show and talking to callers. I wanted the author to dig deeper so we could really get to know the characters. All we know about Grace is that she is attractive looking, Latino and is kind of a brat. I\'m dissapointed.'
# Je suppose que j'avais de plus grandes attentes pour ce livre d'après les critiques. Je pensais vraiment que j'allais au moins l'aimer. L'idée de l'intrigue était géniale. J'aimais Ash, mais ça n'allait nulle part. La plus grande partie du livre était consacrée à leur émission de radio et aux conversations avec les auditeurs. Je voulais que l'auteur creuse plus profondément pour que nous puissions vraiment connaître les personnages. Tout ce que nous savons de Grace, c'est qu'elle est séduisante, qu'elle est latino et qu'elle est une sorte de garce. Je suis déçue.
-'>> Title: Good art, good price, poor design' # Un bon art, un bon prix, un mauvais design
+'>> Title: Good art, good price, poor design'
+# Un bon art, un bon prix, un mauvais design
'>> Review: I had gotten the DC Vintage calendar the past two years, but it was on backorder forever this year and I saw they had shrunk the dimensions for no good reason. This one has good art choices but the design has the fold going through the picture, so it\'s less aesthetically pleasing, especially if you want to keep a picture to hang. For the price, a good calendar'
# J'ai eu le calendrier DC Vintage ces deux dernières années, mais il était en rupture de stock pour toujours cette année et j'ai vu qu'ils avaient réduit les dimensions sans raison valable. Celui-ci a de bons choix artistiques mais le design a le pli qui traverse l'image, donc c'est moins esthétique, surtout si vous voulez garder une image à accrocher. Pour le prix, c'est un bon calendrier.
-'>> Title: Helpful' Utile
+'>> Title: Helpful'
+# Utile
'>> Review: Nearly all the tips useful and. I consider myself an intermediate to advanced user of OneNote. I would highly recommend.'
# Presque tous les conseils sont utiles et. Je me considère comme un utilisateur intermédiaire à avancé de OneNote. Je le recommande vivement.
```
@@ -186,16 +190,20 @@ show_samples(books_dataset)
```
```python out
-'>> Title: Easy to follow!!!!' # Facile à suivre!!!!
+'>> Title: Easy to follow!!!!'
+# Facile à suivre!!!!
'>> Review: I loved The dash diet weight loss Solution. Never hungry. I would recommend this diet. Also the menus are well rounded. Try it. Has lots of the information need thanks.'
# J'ai adoré The dash diet weight loss Solution. Jamais faim. Je recommande ce régime. Les menus sont également bien arrondis. Essayez-le. Il contient beaucoup d'informations, merci.
-'>> Title: PARCIALMENTE DAÑADO' # PARTIELLEMENT ENDOMMAGÉ
+'>> Title: PARCIALMENTE DAÑADO'
+# PARTIELLEMENT ENDOMMAGÉ
'>> Review: Me llegó el día que tocaba, junto a otros libros que pedí, pero la caja llegó en mal estado lo cual dañó las esquinas de los libros porque venían sin protección (forro).'
# Il est arrivé le jour prévu, avec d'autres livres que j'avais commandés, mais la boîte est arrivée en mauvais état, ce qui a endommagé les coins des livres car ils étaient livrés sans protection (doublure).
-'>> Title: no lo he podido descargar' # Je n'ai pas pu le télécharger
-'>> Review: igual que el anterior' # même chose que ci-dessus
+'>> Title: no lo he podido descargar'
+# Je n'ai pas pu le télécharger
+'>> Review: igual que el anterior'
+# même chose que ci-dessus
```
Cela ressemble certainement à un mélange de critiques anglaises et espagnoles ! Maintenant que nous avons un corpus d'entraînement, une dernière chose à vérifier est la distribution des mots dans les critiques et leurs titres. Ceci est particulièrement important pour les tâches de résumé, où les résumés de référence courts dans les données peuvent biaiser le modèle pour qu'il ne produise qu'un ou deux mots dans les résumés générés. Les graphiques ci-dessous montrent les distributions de mots, et nous pouvons voir que les titres sont fortement biaisés vers seulement 1 ou 2 mots :
@@ -215,32 +223,32 @@ Maintenant que nous avons préparé notre corpus, voyons quelques *transformers*
## Modèles pour le résumé de texte
-Si vous y pensez, le résumé de texte est une tâche similaire à la traduction automatique : nous avons un corps de texte, comme une critique, que nous aimerions "traduire" en une version plus courte qui capture les caractéristiques saillantes de l'entrée. En conséquence, la plupart des modèles Transformer pour le résumé adoptent l'architecture encodeur-décodeur que nous avons rencontrée pour la première fois dans le [Chapitre 1](/course/fr/chapter1), bien qu'il y ait quelques exceptions comme la famille de modèles GPT qui peut également être utilisée pour le résumé dans des contextes peu complexes. Le tableau suivant présente quelques modèles pré-entraînés populaires qui peuvent être *finetunés* pour le résumé.
+Si vous y pensez, le résumé de texte est une tâche similaire à la traduction automatique. Nous avons un corps de texte, comme une critique, que nous aimerions « traduire » en une version plus courte qui capture les caractéristiques saillantes de l'entrée. En conséquence, la plupart des *transformers* pour le résumé adoptent l'architecture encodeur-décodeur que nous avons rencontrée pour la première fois dans le [chapitre 1](/course/fr/chapter1), bien qu'il y ait quelques exceptions comme la famille de modèles GPT qui peut également être utilisée pour le résumé dans des contextes peu complexes. Le tableau suivant présente quelques modèles pré-entraînés populaires qui peuvent être *finetunés* pour le résumé.
| *Transformers* | Description | Multilingue ? |
| :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: |
-| [GPT-2](https://huggingface.co/gpt2-xl) | Bien qu'il soit entraîné comme un modèle de langage autorégressif, vous pouvez faire en sorte que GPT-2 génère des résumés en ajoutant "TL;DR" à la fin du texte d'entrée. | ❌ |
-| [PEGASUS](https://huggingface.co/google/pegasus-large) | Utilise un objectif de pré-entraînement pour prédire les phrases masquées dans les textes à plusieurs phrases. Cet objectif de pré-entraînement est plus proche du résumé que de la modélisation du langage standard et obtient des scores élevés sur des benchmarks populaires. | ❌ |
-| [T5](https://huggingface.co/t5-base) | Une architecture universelle de *transformer* qui formule toutes les tâches dans un cadre texte à texte ; par exemple, le format d'entrée du modèle pour résumer un document est `summarize : ARTICLE`. | ❌ |
+| [GPT-2](https://huggingface.co/gpt2-xl) | Bien qu'il soit entraîné comme un modèle de langage autorégressif, vous pouvez faire en sorte que le GPT-2 génère des résumés en ajoutant `TL;DR` à la fin du texte d'entrée. | ❌ |
+| [PEGASUS](https://huggingface.co/google/pegasus-large) | Utilise un objectif de pré-entraînement pour prédire les phrases masquées dans les textes à plusieurs phrases. Cet objectif de pré-entraînement est plus proche du résumé que de la modélisation du langage standard et obtient des scores élevés sur des *benchmarks* populaires. | ❌ |
+| [T5](https://huggingface.co/t5-base) | Une architecture universelle de *transformer* qui formule toutes les tâches dans un cadre texte à texte. Par exemple, le format d'entrée du modèle pour résumer un document est `summarize: ARTICLE`. | ❌ |
| [mT5](https://huggingface.co/google/mt5-base) | Une version multilingue de T5, pré-entraînée sur le corpus multilingue Common Crawl (mC4), couvrant 101 langues. | ✅ |
| [BART](https://huggingface.co/facebook/bart-base) | Une architecture de *transformer* avec une pile d'encodeurs et de décodeurs entraînés pour reconstruire l'entrée corrompue qui combine les schémas de pré-entraînement de BERT et GPT-2. | ❌ |
| [mBART-50](https://huggingface.co/facebook/mbart-large-50) | Une version multilingue de BART, pré-entraînée sur 50 langues. | ✅ |
-Comme vous pouvez le voir dans ce tableau, la majorité des modèles Transformer pour le résumé (et en fait la plupart des tâches de NLP) sont monolingues. C'est une bonne chose si votre tâche se déroule dans une langue "à haute ressource" comme l'anglais ou l'allemand, mais moins pour les milliers d'autres langues utilisées dans le monde. Heureusement, il existe une catégorie de modèles Transformer multilingues, comme mT5 et mBART, qui viennent à la rescousse. Ces modèles sont pré-entraînés en utilisant la modélisation du langage, mais avec une particularité : au lieu de s'entraîner sur un corpus d'une seule langue, ils sont entraînés conjointement sur des textes dans plus de 50 langues à la fois !
+Comme vous pouvez le voir dans ce tableau, la majorité des *transformers* pour le résumé (et en fait la plupart des tâches de NLP) sont monolingues. C'est une bonne chose si votre tâche se déroule dans une langue « à haute ressource » comme l'anglais ou l'allemand, mais moins pour les milliers d'autres langues utilisées dans le monde. Heureusement, il existe une catégorie de *transformers* multilingues, comme mT5 et mBART, qui viennent à la rescousse. Ces modèles sont pré-entraînés en utilisant la modélisation du langage mais avec une particularité : au lieu d'être entraîné sur un corpus d'une seule langue, ils sont entraînés conjointement sur des textes dans plus de 50 langues !
-Nous allons nous concentrer sur mT5, une architecture intéressante basée sur T5 qui a été pré-entraînée dans un cadre texte à texte. Dans T5, chaque tâche NLP est formulée en termes d'un préfixe d'invite comme `summarize:` qui conditionne le modèle à adapter le texte généré à l'invite. Comme le montre la figure ci-dessous, cela rend T5 extrêmement polyvalent, car vous pouvez résoudre de nombreuses tâches avec un seul modèle !
+Nous allons nous concentrer sur mT5, une architecture intéressante basée sur T5 qui a été pré-entraînée dans un cadre texte à texte. Dans T5, chaque tâche de NLP est formulée en termes d'un préfixe de *prompt* comme `summarize:` qui conditionne le modèle à adapter le texte généré au *prompt*. Comme le montre la figure ci-dessous, cela rend le T5 extrêmement polyvalent car vous pouvez résoudre de nombreuses tâches avec un seul modèle !
-mT5 n'utilise pas de préfixes, mais partage une grande partie de la polyvalence de T5 et a l'avantage d'être multilingue. Maintenant que nous avons choisi un modèle, voyons comment préparer nos données pour l'entraînement.
+mT5 n'utilise pas de préfixes mais partage une grande partie de la polyvalence de T5 et a l'avantage d'être multilingue. Maintenant que nous avons choisi un modèle, voyons comment préparer nos données pour l'entraînement.
-✏️ **Essayez** Une fois que vous avez travaillé sur cette section, voyez comment mT5 se compare à mBART en affinant ce dernier avec les mêmes techniques. Pour des points bonus, vous pouvez aussi essayer de *finetuner* le T5 uniquement sur les critiques anglaises. Puisque le T5 a un préfixe spécial, vous devrez ajouter `summarize:` aux exemples d'entrée dans les étapes de prétraitement ci-dessous.
+✏️ **Essayez !** Une fois que vous aurez terminé cette section, comparez le mT5 à mBART en *finetunant* ce dernier avec les mêmes techniques. Pour des points bonus, vous pouvez aussi essayer de *finetuner* le T5 uniquement sur les critiques anglaises. Puisque le T5 a un préfixe spécial, vous devrez ajouter `summarize:` aux entrées dans les étapes de prétraitement ci-dessous.
@@ -248,7 +256,7 @@ mT5 n'utilise pas de préfixes, mais partage une grande partie de la polyvalence
-Notre prochaine tâche est de tokeniser et d'encoder nos critiques et leurs titres. Comme d'habitude, nous commençons par charger le *tokenizer* associé au point de contrôle du modèle pré-entraîné. Nous utiliserons `mt5-small` comme point de contrôle afin de pouvoir affiner le modèle en un temps raisonnable :
+Notre prochaine tâche est de tokeniser et d'encoder nos critiques et leurs titres. Comme d'habitude, nous commençons par charger le *tokenizer* associé au *checkpoint* du modèle pré-entraîné. Nous utiliserons `mt5-small` comme *checkpoint* afin de pouvoir *finetuner* le modèle en un temps raisonnable :
```python
from transformers import AutoTokenizer
@@ -259,7 +267,7 @@ tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
-💡 Aux premiers stades de vos projets de NLP, une bonne pratique consiste à entraîner une classe de "petits" modèles sur un petit échantillon de données. Cela vous permet de déboguer et d'itérer plus rapidement vers un flux de travail de bout en bout. Une fois que vous avez confiance dans les résultats, vous pouvez toujours faire évoluer le modèle en changeant simplement le point de contrôle du modèle !
+💡 Aux premiers stades de vos projets de NLP, une bonne pratique consiste à entraîner une classe de « petits » modèles sur un petit échantillon de données. Cela vous permet de déboguer et d'itérer plus rapidement vers un flux de travail de bout en bout. Une fois que vous avez confiance dans les résultats, vous pouvez toujours faire évoluer le modèle en changeant simplement le *checkpoint* du modèle !
@@ -276,7 +284,7 @@ inputs
{'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}
```
-Ici nous pouvons voir les familiers `input_ids` et `attention_mask` que nous avons rencontrés dans nos premières expériences de fine-tuning au [Chapitre 3](/course/fr/chapter3). Décodons ces identifiants d'entrée avec la fonction `convert_ids_to_tokens()` du tokenizer pour voir à quel type de tokenizer nous avons affaire :
+Ici nous pouvons voir les familiers `input_ids` et `attention_mask` que nous avons rencontrés dans nos premières expériences de *finetuning* au [chapitre 3](/course/fr/chapter3). Décodons ces identifiants d'entrée avec la fonction `convert_ids_to_tokens()` du *tokenizer* pour voir à quel type de *tokenizer* nous avons affaire :
```python
tokenizer.convert_ids_to_tokens(inputs.input_ids)
@@ -286,7 +294,7 @@ tokenizer.convert_ids_to_tokens(inputs.input_ids)
['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', '']
```
-Le caractère spécial Unicode `▁` et le *token* de fin de séquence `` indiquent que nous avons affaire au *tokenizer* de SentencePiece, qui est basé sur l'algorithme de segmentation Unigram discuté dans le [Chapitre 6](/course/chapter6). Unigram est particulièrement utile pour les corpus multilingues car il permet à SentencePiece d'être agnostique vis-à-vis des accents, de la ponctuation et du fait que de nombreuses langues, comme le japonais, n'ont pas de caractères d'espacement.
+Le caractère Unicode spécial `▁` et le *token* de fin de séquence `` indiquent que nous avons affaire au *tokenizer* de SentencePiece, qui est basé sur l'algorithme de segmentation Unigram discuté dans le [chapitre 6](/course/chapter6). Unigram est particulièrement utile pour les corpus multilingues car il permet à SentencePiece d'être agnostique vis-à-vis des accents, de la ponctuation et du fait que de nombreuses langues, comme le japonais, n'ont pas de caractères d'espacement.
Pour tokeniser notre corpus, nous devons faire face à une subtilité associée au résumé : comme nos étiquettes sont également du texte, il est possible qu'elles dépassent la taille maximale du contexte du modèle. Cela signifie que nous devons appliquer une troncature à la fois aux critiques et à leurs titres pour nous assurer de ne pas transmettre des entrées trop longues à notre modèle. Les tokenizers de 🤗 *Transformers* fournissent une fonction très pratique `as_target_tokenizer()` qui vous permet de tokeniser les étiquettes en parallèle avec les entrées. Ceci est typiquement fait en utilisant un gestionnaire de contexte à l'intérieur d'une fonction de prétraitement qui encode d'abord les entrées, et ensuite encode les étiquettes comme une colonne séparée. Voici un exemple d'une telle fonction pour mT5 :
@@ -299,7 +307,7 @@ def preprocess_function(examples):
model_inputs = tokenizer(
examples["review_body"], max_length=max_input_length, truncation=True
)
- # Configurer le *tokenizer* pour les cibles.
+ # Configurer le tokenizer pour les cibles
with tokenizer.as_target_tokenizer():
labels = tokenizer(
examples["review_title"], max_length=max_target_length, truncation=True
@@ -321,7 +329,7 @@ Maintenant que le corpus a été prétraité, examinons certaines métriques cou
-💡 Vous avez peut-être remarqué que nous avons utilisé `batched=True` dans notre fonction `Dataset.map()` ci-dessus. Cela permet de coder les exemples par lots de 1 000 (par défaut) et d'utiliser les capacités de multithreading des *tokenizers* rapides de 🤗 *Transformers*. Lorsque cela est possible, essayez d'utiliser `batched=True` pour tirer le meilleur parti de votre prétraitement !
+💡 Vous avez peut-être remarqué que nous avons utilisé `batched=True` dans notre fonction `Dataset.map()` ci-dessus. Cela permet de coder les exemples par lots de 1 000 (par défaut) et d'utiliser les capacités de *multithreading* des *tokenizers* rapides de 🤗 *Transformers*. Lorsque cela est possible, essayez d'utiliser `batched=True` pour tirer le meilleur parti de votre prétraitement !
@@ -330,32 +338,34 @@ Maintenant que le corpus a été prétraité, examinons certaines métriques cou
-Par rapport à la plupart des autres tâches que nous avons abordées dans ce cours, la mesure des performances des tâches de génération de texte comme le résumé ou la traduction n'est pas aussi simple. Par exemple, pour une critique telle que "J'ai adoré lire les Hunger Games", il existe plusieurs résumés valides, comme "J'ai adoré Hunger Games" ou "Hunger Games est une excellente lecture". Il est clair que l'application d'une sorte de correspondance exacte entre le résumé généré et l'étiquette n'est pas une bonne solution - même les humains auraient de mauvais résultats avec une telle mesure, car nous avons tous notre propre style d'écriture.
+Par rapport à la plupart des autres tâches que nous avons abordées dans ce cours, la mesure des performances des tâches de génération de texte comme le résumé ou la traduction n'est pas aussi simple. Par exemple, pour une critique telle que « J'ai adoré lire les Hunger Games », il existe plusieurs résumés valides, comme « J'ai adoré Hunger Games » ou « Hunger Games est une excellente lecture ». Il est clair que l'application d'une sorte de correspondance exacte entre le résumé généré et l'étiquette n'est pas une bonne solution. En effet, même les humains auraient de mauvais résultats avec une telle mesure, car nous avons tous notre propre style d'écriture.
-Pour le résumé, l'une des métriques les plus couramment utilisées est le [score ROUGE](https://en.wikipedia.org/wiki/ROUGE_(metric)) (abréviation de Recall-Oriented Understudy for Gisting Evaluation). L'idée de base de cette métrique est de comparer un résumé généré avec un ensemble de résumés de référence qui sont généralement créés par des humains. Pour être plus précis, supposons que nous voulions comparer les deux résumés suivants :
+Pour le résumé, l'une des métriques les plus couramment utilisées est le [score ROUGE](https://en.wikipedia.org/wiki/ROUGE_(metric)) (abréviation de *Recall-Oriented Understudy for Gisting Evaluation*). L'idée de base de cette métrique est de comparer un résumé généré avec un ensemble de résumés de référence qui sont généralement créés par des humains. Pour être plus précis, supposons que nous voulions comparer les deux résumés suivants :
```python
generated_summary = "I absolutely loved reading the Hunger Games"
+# "J'ai absolument adoré lire les Hunger Games"
reference_summary = "I loved reading the Hunger Games"
+# "J'ai adoré lire les Hunger Games"
```
Une façon de les comparer pourrait être de compter le nombre de mots qui se chevauchent, qui dans ce cas serait de 6. Cependant, cette méthode est un peu grossière, c'est pourquoi ROUGE se base sur le calcul des scores de _précision_ et de _rappel_ pour le chevauchement.
-🙋 Ne vous inquiétez pas si c'est la première fois que vous entendez parler de précision et de rappel - nous allons parcourir ensemble quelques exemples explicites pour que tout soit clair. Ces métriques sont généralement rencontrées dans les tâches de classification, donc si vous voulez comprendre comment la précision et le rappel sont définis dans ce contexte, nous vous recommandons de consulter les [guides de `scikit-learn`](https://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html).
+🙋 Ne vous inquiétez pas si c'est la première fois que vous entendez parler de précision et de rappel. Nous allons parcourir ensemble quelques exemples explicites pour que tout soit clair. Ces métriques sont généralement rencontrées dans les tâches de classification, donc si vous voulez comprendre comment la précision et le rappel sont définis dans ce contexte, nous vous recommandons de consulter les [guides de `scikit-learn`](https://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html).
Pour ROUGE, le rappel mesure la proportion du résumé de référence qui est capturée par le résumé généré. Si nous ne faisons que comparer des mots, le rappel peut être calculé selon la formule suivante :
-$$ \mathrm{Recall} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, reference\, summary}} $$
+$$ \mathrm{Recall} = \frac{\mathrm{Nombre\,de\,mots\,qui\,se\,chevauchent}}{\mathrm{Nombre\, total\, de\, mots\, dans\, le\, résumé\, de\, réference}} $$
-Pour notre exemple simple ci-dessus, cette formule donne un rappel parfait de 6/6 = 1 ; c'est-à-dire que tous les mots du résumé de référence ont été produits par le modèle. Cela peut sembler génial, mais imaginez que le résumé généré ait été "J'ai vraiment aimé lire les Hunger Games toute la nuit". Le rappel serait également parfait, mais le résumé serait sans doute moins bon puisqu'il serait verbeux. Pour traiter ces scénarios, nous calculons également la précision, qui, dans le contexte de ROUGE, mesure la proportion du résumé généré qui était pertinente :
+Pour notre exemple simple ci-dessus, cette formule donne un rappel parfait de 6/6 = 1, c'est-à-dire que tous les mots du résumé de référence ont été produits par le modèle. Cela peut sembler génial, mais imaginez que le résumé généré ait été « J'ai vraiment aimé lire les Hunger Games toute la nuit ». Le rappel serait également parfait, mais le résumé serait sans doute moins bon puisqu'il serait verbeux. Pour traiter ces scénarios, nous calculons également la précision, qui dans le contexte de ROUGE, mesure la proportion du résumé généré qui est pertinente :
-$$ \mathrm{Precision} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, generated\, summary}} $$
+$$ \mathrm{Precision} = \frac{\mathrm{Nombre\,de\,mots\,qui\,se\,chevauchent}}{\mathrm{Nombre\, total\, de\, mots\, dans\, le\, résumé\, généré}} $$
-En appliquant cela à notre résumé verbeux, on obtient une précision de 6/10 = 0,6, ce qui est considérablement moins bon que la précision de 6/7 = 0,86 obtenue par notre résumé plus court. En pratique, la précision et le rappel sont généralement calculés, puis le score F1 (la moyenne harmonique de la précision et du rappel) est indiqué. Nous pouvons le faire facilement dans 🤗 *Datasets* en installant d'abord le paquet `rouge_score` :
+En appliquant cela à notre résumé verbeux, on obtient une précision de 6/10 = 0,6, ce qui est considérablement moins bon que la précision de 6/7 = 0,86 obtenue par notre résumé plus court. En pratique, la précision et le rappel sont généralement calculés, puis le score F1 (la moyenne harmonique de la précision et du rappel) est indiqué. Nous pouvons le faire facilement dans 🤗 *Datasets* en installant d'abord le *package* `rouge_score` :
```py
!pip install rouge_score
@@ -385,7 +395,7 @@ scores
'rougeLsum': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92))}
```
-Whoa, il y a un batch d'informations dans cette sortie. Qu'est-ce que ça veut dire ? Tout d'abord, 🤗 *Datasets* calcule en fait des intervalles de confiance pour la précision, le rappel et le score F1 ; ce sont les attributs `low`, `mid`, et `high` que vous pouvez voir ici. De plus, 🤗 *Datasets* calcule une variété de scores ROUGE qui sont basés sur différents types de granularité du texte lors de la comparaison des résumés générés et de référence. La variante `rouge1` est le chevauchement des unigrammes. C'est juste une façon fantaisiste de dire le chevauchement des mots et c'est exactement la métrique dont nous avons discuté ci-dessus. Pour vérifier cela, nous allons extraire la valeur "moyenne" de nos scores :
+Whoa, il y a pas mal d'informations dans cette sortie. Qu'est-ce que ça veut dire ? Tout d'abord, 🤗 *Datasets* calcule des intervalles de confiance pour la précision, le rappel et le score F1. Ce sont les attributs `low`, `mid`, et `high` que vous pouvez voir ici. De plus, 🤗 *Datasets* calcule une variété de scores ROUGE qui sont basés sur différents types de granularité du texte lors de la comparaison des résumés générés et de référence. La variante `rouge1` est le chevauchement des unigrammes. C'est juste une façon fantaisiste de dire le chevauchement des mots et c'est exactement la métrique dont nous avons discuté ci-dessus. Pour vérifier cela, nous allons extraire la valeur `mid` de nos scores :
```python
scores["rouge1"].mid
@@ -395,19 +405,19 @@ scores["rouge1"].mid
Score(precision=0.86, recall=1.0, fmeasure=0.92)
```
-Super, les chiffres de précision et de rappel correspondent ! Maintenant, qu'en est-il des autres scores ROUGE ? `rouge2` mesure le chevauchement entre les bigrammes (pensez au chevauchement des paires de mots), tandis que `rougeL` et `rougeLsum` mesurent les plus longues séquences de mots correspondants en recherchant les plus longues sous-souches communes dans les résumés générés et de référence. La "somme" dans `rougeLsum` fait référence au fait que cette métrique est calculée sur un résumé entier, alors que `rougeL` est calculée comme une moyenne sur des phrases individuelles.
+Super, les chiffres de précision et de rappel correspondent ! Maintenant, qu'en est-il des autres scores ROUGE ? `rouge2` mesure le chevauchement entre les bigrammes (chevauchement des paires de mots), tandis que `rougeL` et `rougeLsum` mesurent les plus longues séquences de mots correspondants en recherchant les plus longues sous-souches communes dans les résumés générés et de référence. Le « sum » dans `rougeLsum` fait référence au fait que cette métrique est calculée sur un résumé entier, alors que `rougeL` est calculée comme une moyenne sur des phrases individuelles.
-✏️ **Essayez** Créez votre propre exemple de résumé généré et de référence et voyez si les scores ROUGE obtenus correspondent à un calcul manuel basé sur les formules de précision et de rappel. Pour des points bonus, divisez le texte en bigrammes et comparez la précision et le rappel pour la métrique `rouge2`.
+✏️ **Essayez !** Créez votre propre exemple de résumé généré et de référence et voyez si les scores ROUGE obtenus correspondent à un calcul manuel basé sur les formules de précision et de rappel. Pour des points bonus, divisez le texte en bigrammes et comparez la précision et le rappel pour la métrique `rouge2`.
-Nous utiliserons ces scores ROUGE pour suivre les performances de notre modèle, mais avant cela, faisons ce que tout bon praticien de NLP devrait faire : créer une base de référence solide, mais simple !
+Nous utiliserons ces scores ROUGE pour suivre les performances de notre modèle, mais avant cela, faisons ce que tout bon praticien de NLP devrait faire : créer une *baseline* solide, mais simple !
### Création d'une base de référence solide
-Une base de référence commune pour le résumé de texte consiste à prendre simplement les trois premières phrases d'un article, souvent appelée la base de référence _lead-3_. Nous pourrions utiliser des points pour suivre les limites de la phrase, mais cela échouera avec des acronymes comme "U.S." ou "U.N.". -- Nous allons donc utiliser la bibliothèque `nltk`, qui inclut un meilleur algorithme pour gérer ces cas. Vous pouvez installer le paquetage en utilisant `pip` comme suit :
+Une *baseline* commune pour le résumé de texte consiste à prendre simplement les trois premières phrases d'un article, souvent appelée la *baseline* _lead-3_. Nous pourrions utiliser les points pour tracker les limites des phrases mais cela échouera avec des acronymes comme « U.S. » ou « U.N. ». Nous allons donc utiliser la bibliothèque `nltk`, qui inclut un meilleur algorithme pour gérer ces cas. Vous pouvez installer le *package* en utilisant `pip` comme suit :
```python
!pip install nltk
@@ -421,7 +431,7 @@ import nltk
nltk.download("punkt")
```
-Ensuite, nous importons le *tokenizer* de `nltk` et créons une fonction simple pour extraire les trois premières phrases d'une critique. La convention dans le résumé de texte est de séparer chaque résumé avec une nouvelle ligne, donc nous allons également inclure ceci et le tester sur un exemple d'entraînement :
+Ensuite, nous importons le *tokenizer* de `nltk` et créons une fonction simple pour extraire les trois premières phrases d'une critique. La convention dans le résumé de texte est de séparer chaque résumé avec une nouvelle ligne, donc nous allons également inclure ceci et tester le tout sur un exemple d'entraînement :
```python
from nltk.tokenize import sent_tokenize
@@ -435,12 +445,15 @@ print(three_sentence_summary(books_dataset["train"][1]["review_body"]))
```
```python out
-'I grew up reading Koontz, and years ago, I stopped,convinced i had "outgrown" him.' # J'ai grandi en lisant Koontz, et il y a des années, j'ai arrêté, convaincu que je l'avais "dépassé"
-'Still,when a friend was looking for something suspenseful too read, I suggested Koontz.' " Pourtant, quand une amie cherchait un livre à suspense, je lui ai suggéré Koontz.
-'She found Strangers.' # Elle a trouvé Strangers.
+'I grew up reading Koontz, and years ago, I stopped,convinced i had "outgrown" him.'
+# J'ai grandi en lisant Koontz, et il y a des années, j'ai arrêté, convaincu que je l'avais "dépassé"
+'Still,when a friend was looking for something suspenseful too read, I suggested Koontz.'
+# "Pourtant, quand une amie cherchait un livre à suspense, je lui ai suggéré Koontz."
+'She found Strangers.'
+# Elle a trouvé Strangers.
```
-Cela semble fonctionner, alors implémentons maintenant une fonction qui extrait ces "résumés" d'un ensemble de données et calcule les scores ROUGE pour la ligne de base :
+Cela semble fonctionner, alors implémentons maintenant une fonction qui extrait ces résumés d'un jeu de données et calcule les scores ROUGE pour la ligne de base :
```python
def evaluate_baseline(dataset, metric):
@@ -463,13 +476,13 @@ rouge_dict
{'rouge1': 16.74, 'rouge2': 8.83, 'rougeL': 15.6, 'rougeLsum': 15.96}
```
-Nous pouvons voir que le score de `rouge2` est significativement plus bas que le reste ; ceci reflète probablement le fait que les titres des revues sont typiquement concis et donc que la ligne de base de lead-3 est trop verbeuse. Maintenant que nous disposons d'une bonne base de travail, concentrons-nous sur le réglage fin de mT5 !
+Nous pouvons voir que le score de `rouge2` est significativement plus bas que le reste. Ceci reflète probablement le fait que les titres des critiques sont typiquement concis et donc que la *baseline* *lead-3* est trop verbeuse. Maintenant que nous disposons d'une bonne *baseline*, concentrons-nous sur le *finetuning* du mT5 !
{#if fw === 'pt'}
-## *Finetuning* de mT5 avec l'API `Trainer`.
+## Finetuning de mT5 avec l'API `Trainer`
-Le *finetuning* d'un modèle pour le résumé est très similaire aux autres tâches que nous avons couvertes dans ce chapitre. La première chose à faire est de charger le modèle pré-entraîné depuis le checkpoint `mt5-small`. Puisque la compression est une tâche de séquence à séquence, nous pouvons charger le modèle avec la classe `AutoModelForSeq2SeqLM`, qui téléchargera automatiquement et mettra en cache les poids :
+Le *finetuning* d'un modèle pour le résumé est très similaire aux autres tâches que nous avons couvertes dans ce chapitre. La première chose à faire est de charger le modèle pré-entraîné à partir du *checkpoint* `mt5-small`. Puisque la compression est une tâche de séquence à séquence, nous pouvons charger le modèle avec la classe `AutoModelForSeq2SeqLM`, qui téléchargera automatiquement et mettra en cache les poids :
```python
from transformers import AutoModelForSeq2SeqLM
@@ -479,9 +492,9 @@ model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
{:else}
-## *Finetuning* de mT5 avec Keras
+## Finetuning de mT5 avec Keras
-Le *finetuning* d'un modèle pour le résumé est très similaire aux autres tâches que nous avons couvertes dans ce chapitre. La première chose à faire est de charger le modèle pré-entraîné à partir du point de contrôle `mt5-small`. Puisque la compression est une tâche de séquence à séquence, nous pouvons charger le modèle avec la classe `AutoModelForSeq2SeqLM`, qui téléchargera automatiquement et mettra en cache les poids :
+Le *finetuning* d'un modèle pour le résumé est très similaire aux autres tâches que nous avons couvertes dans ce chapitre. La première chose à faire est de charger le modèle pré-entraîné à partir du *checkpoint* `mt5-small`. Puisque la compression est une tâche de séquence à séquence, nous pouvons charger le modèle avec la classe `TFAutoModelForSeq2SeqLM`, qui téléchargera automatiquement et mettra en cache les poids :
```python
from transformers import TFAutoModelForSeq2SeqLM
@@ -493,7 +506,7 @@ model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint)
-💡 Si vous vous demandez pourquoi vous ne voyez aucun avertissement concernant l'affinement du modèle sur une tâche en aval, c'est parce que pour les tâches de séquence à séquence, nous conservons tous les poids du réseau. Comparez cela à notre modèle de classification de texte dans [Chapitre 3](/course/fr/chapter3), où la tête du modèle pré-entraîné a été remplacée par un réseau initialisé de manière aléatoire.
+💡 Si vous vous demandez pourquoi vous ne voyez aucun avertissement concernant le *finetuning* du modèle sur une tâche en aval, c'est parce que pour les tâches de séquence à séquence, nous conservons tous les poids du réseau. Comparez cela à notre modèle de classification de texte du [chapitre 3](/course/fr/chapter3) où la tête du modèle pré-entraîné a été remplacée par un réseau initialisé de manière aléatoire.
@@ -539,11 +552,11 @@ args = Seq2SeqTrainingArguments(
)
```
-Ici, l'argument `predict_with_generate` a été défini pour indiquer que nous devons générer des résumés pendant l'évaluation afin de pouvoir calculer les scores ROUGE pour chaque époque. Comme discuté dans [Chapter 1](/course/fr/chapter1), le décodeur effectue l'inférence en prédisant les tokens un par un, et ceci est implémenté par la méthode `generate()` du modèle. Définir `predict_with_generate=True` indique au `Seq2SeqTrainer` d'utiliser cette méthode pour l'évaluation. Nous avons également ajusté certains des hyperparamètres par défaut, comme le taux d'apprentissage, le nombre d'époques, et le taux de décroissance des poids, et nous avons réglé l'option `save_total_limit` pour ne sauvegarder que jusqu'à 3 *checkpoints* pendant l'entraînement. C'est parce que même la "petite" version de mT5 utilise environ un Go d'espace disque, et nous pouvons gagner un peu de place en limitant le nombre de copies que nous sauvegardons.
+Ici, l'argument `predict_with_generate` a été défini pour indiquer que nous devons générer des résumés pendant l'évaluation afin de pouvoir calculer les scores ROUGE pour chaque époque. Comme discuté au [chapitre 1](/course/fr/chapter1), le décodeur effectue l'inférence en prédisant les *tokens* un par un, et ceci est implémenté par la méthode `generate()`. Définir `predict_with_generate=True` indique au `Seq2SeqTrainer` d'utiliser cette méthode pour l'évaluation. Nous avons également ajusté certains des hyperparamètres par défaut, comme le taux d'apprentissage, le nombre d'époques, et le taux de décroissance des poids, et nous avons réglé l'option `save_total_limit` pour ne sauvegarder que jusqu'à trois *checkpoints* pendant l'entraînement. C'est parce que même la plus petite version de mT5 utilise environ 1 Go d'espace disque, et nous pouvons gagner un peu de place en limitant le nombre de copies que nous sauvegardons.
-L'argument `push_to_hub=True` nous permettra de pousser le modèle vers le Hub après l'entraînement ; vous trouverez le dépôt sous votre profil utilisateur dans l'emplacement défini par `output_dir`. Notez que vous pouvez spécifier le nom du dépôt vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"`à `Seq2SeqTrainingArguments`.
+L'argument `push_to_hub=True` nous permettra de pousser le modèle vers le *Hub* après l'entraînement. Vous trouverez le dépôt sous votre profil utilisateur dans l'emplacement défini par `output_dir`. Notez que vous pouvez spécifier le nom du dépôt vers lequel vous voulez pousser avec l'argument `hub_model_id` (en particulier, vous devrez utiliser cet argument pour pousser vers une organisation). Par exemple, lorsque nous avons poussé le modèle vers l'organisation [`huggingface-course`](https://huggingface.co/huggingface-course), nous avons ajouté `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"` à `Seq2SeqTrainingArguments`.
-La prochaine chose que nous devons faire est de fournir à l'entraîneur une fonction `compute_metrics()` afin que nous puissions évaluer notre modèle pendant l'entraînement. Pour le résumé, c'est un peu plus compliqué que de simplement appeler `rouge_score.compute()` sur les prédictions du modèle, puisque nous devons _décoder_ les sorties et les étiquettes en texte avant de pouvoir calculer les scores ROUGE. La fonction suivante fait exactement cela, et utilise également la fonction `sent_tokenize()` de `nltk` pour séparer les phrases du résumé avec des nouvelles lignes :
+La prochaine chose que nous devons faire est de fournir à `Seq2SeqTrainer` une fonction `compute_metrics()` afin que nous puissions évaluer notre modèle pendant l'entraînement. Pour le résumé, c'est un peu plus compliqué que de simplement appeler `rouge_score.compute()` sur les prédictions du modèle, puisque nous devons _décoder_ les sorties et les étiquettes en texte avant de pouvoir calculer les scores ROUGE. La fonction suivante fait exactement cela, et utilise également la fonction `sent_tokenize()` de `nltk` pour séparer les phrases du résumé avec des nouvelles lignes :
```python
@@ -565,16 +578,16 @@ def compute_metrics(eval_pred):
result = rouge_score.compute(
predictions=decoded_preds, references=decoded_labels, use_stemmer=True
)
- # Extract the median scores
+ # Extraire les scores médians
result = {key: value.mid.fmeasure * 100 for key, value in result.items()}
return {k: round(v, 4) for k, v in result.items()}
```
{/if}
-Ensuite, nous devons définir un collateur de données pour notre tâche de séquence à séquence. Comme mT5 est un modèle Transformer encodeur-décodeur, une des subtilités de la préparation de nos lots est que, pendant le décodage, nous devons décaler les étiquettes d'une unité vers la droite. Ceci est nécessaire pour garantir que le décodeur ne voit que les étiquettes de vérité terrain précédentes et non les étiquettes actuelles ou futures, qui seraient faciles à mémoriser pour le modèle. Cela ressemble à la façon dont l'auto-attention masquée est appliquée aux entrées dans une tâche comme [la modélisation causale du langage](/course/fr/chapter7/6).
+Ensuite, nous devons définir un collateur de données pour notre tâche de séquence à séquence. Comme mT5 est un *transformer* encodeur-décodeur, une des subtilités de la préparation de nos batchs est que, pendant le décodage, nous devons décaler les étiquettes d'une unité vers la droite. Ceci est nécessaire pour garantir que le décodeur ne voit que les étiquettes de vérité terrain précédentes et non les étiquettes actuelles ou futures, qui seraient faciles à mémoriser pour le modèle. Cela ressemble à la façon dont l'auto-attention masquée est appliquée aux entrées dans une tâche comme [la modélisation causale du langage](/course/fr/chapter7/6).
-Heureusement, 🤗 *Transformers* fournit un collateur `DataCollatorForSeq2Seq` qui rembourrera dynamiquement les entrées et les étiquettes pour nous. Pour instancier ce collateur, nous devons simplement fournir le *tokenizer* et le `model` :
+Heureusement, 🤗 *Transformers* fournit un collateur `DataCollatorForSeq2Seq` qui rembourrera dynamiquement les entrées et les étiquettes pour nous. Pour instancier ce collateur, nous devons simplement fournir le *tokenizer* et le *modèle* :
{#if fw === 'pt'}
@@ -594,7 +607,7 @@ data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="t
{/if}
-Voyons ce que produit ce collateur lorsqu'on lui donne un petit lot d'exemples. Tout d'abord, nous devons supprimer les colonnes contenant des chaînes de caractères, car le collateur ne saura pas comment remplir ces éléments :
+Voyons ce que produit ce collateur lorsqu'on lui donne un petit batch d'exemples. Tout d'abord, nous devons supprimer les colonnes contenant des chaînes de caractères, car le collateur ne saura pas comment remplir ces éléments :
```python
tokenized_datasets = tokenized_datasets.remove_columns(
@@ -602,7 +615,7 @@ tokenized_datasets = tokenized_datasets.remove_columns(
)
```
-Comme le collateur attend une liste de `dict`s, où chaque `dict` représente un seul exemple dans l'ensemble de données, nous devons également mettre les données dans le format attendu avant de les transmettre au collateur de données :
+Comme le collateur attend une liste de `dict`, où chaque `dict` représente un seul exemple du jeu de données, nous devons également mettre les données dans le format attendu avant de les transmettre au collateur de données :
```python
features = [tokenized_datasets["train"][i] for i in range(2)]
@@ -625,11 +638,11 @@ data_collator(features)
[ 0, 259, 27531, 13483, 259, 7505]])}
```
-La principale chose à remarquer ici est que le premier exemple est plus long que le second, donc les `input_ids` et `attention_mask` du second exemple ont été complétés sur la droite avec un jeton `[PAD]` (dont l'ID est `0`). De même, nous pouvons voir que les `labels` ont été complétés par des `-100`s, pour s'assurer que les *tokens* de remplissage sont ignorés par la fonction de perte. Et enfin, nous pouvons voir un nouveau `decoder_input_ids` qui a déplacé les étiquettes vers la droite en insérant un jeton `[PAD]` dans la première entrée.
+La principale chose à remarquer ici est que le premier exemple est plus long que le second, donc les `input_ids` et `attention_mask` du second exemple ont été complétés sur la droite avec un *token* `[PAD]` (dont l'identifiant est `0`). De même, nous pouvons voir que les `labels` ont été complétés par des `-100`, pour s'assurer que les *tokens* de remplissage sont ignorés par la fonction de perte. Et enfin, nous pouvons voir un nouveau `decoder_input_ids` qui a déplacé les étiquettes vers la droite en insérant un *token* `[PAD]` dans la première entrée.
{#if fw === 'pt'}
-Nous avons enfin tous les ingrédients dont nous avons besoin pour nous entraîner ! Nous devons maintenant simplement instancier le formateur avec les arguments standards :
+Nous avons enfin tous les ingrédients dont nous avons besoin pour l'entraînement ! Nous devons maintenant simplement instancier le `Seq2SeqTrainer` avec les arguments :
```python
from transformers import Seq2SeqTrainer
@@ -669,7 +682,7 @@ trainer.evaluate()
'eval_steps_per_second': 4.914}
```
-D'après les scores, nous pouvons voir que notre modèle a largement surpassé notre ligne de base lead-3. Bien ! La dernière chose à faire est de pousser les poids du modèle vers le *Hub*, comme suit :
+D'après les scores, nous pouvons voir que notre modèle a largement surpassé notre *baseline* *lead-3*. Bien ! La dernière chose à faire est de pousser les poids du modèle vers le *Hub*, comme suit :
```
trainer.push_to_hub(commit_message="Training complete", tags="summarization")
@@ -679,13 +692,13 @@ trainer.push_to_hub(commit_message="Training complete", tags="summarization")
'https://huggingface.co/huggingface-course/mt5-finetuned-amazon-en-es/commit/aa0536b829b28e73e1e4b94b8a5aacec420d40e0'
```
-Ceci sauvegardera le point de contrôle et les fichiers de configuration dans `output_dir`, avant de télécharger tous les fichiers sur le *Hub*. En spécifiant l'argument `tags`, nous nous assurons également que le widget sur le Hub sera celui d'un pipeline de résumé au lieu de celui de la génération de texte par défaut associé à l'architecture mT5 (pour plus d'informations sur les balises de modèle, voir la [🤗 documentation du *Hub*](https://huggingface.co/docs/hub/main#how-is-a-models-type-of-inference-api-and-widget-determined)). La sortie de `trainer.push_to_hub()` est une URL vers le hash du commit Git, donc vous pouvez facilement voir les changements qui ont été faits au dépôt de modèle !
+Ceci sauvegardera le *checkpoint* et les fichiers de configuration dans `output_dir`, avant de télécharger tous les fichiers sur le *Hub*. En spécifiant l'argument `tags`, nous nous assurons également que le *widget* sur le *Hub* sera celui d'un pipeline de résumé au lieu de celui de la génération de texte par défaut associé à l'architecture mT5 (pour plus d'informations sur les balises de modèle, voir la [documentation du *Hub*](https://huggingface.co/docs/hub/main#how-is-a-models-type-of-inference-api-and-widget-determined)). La sortie de `trainer.push_to_hub()` est une URL vers le hash du commit Git, donc vous pouvez facilement voir les changements qui ont été faits au dépôt de modèle !
-Pour conclure cette section, voyons comment nous pouvons également affiner mT5 en utilisant les fonctionnalités de bas niveau fournies par 🤗 *Accelerate*.
+Pour conclure cette section, voyons comment nous pouvons également *finetuner* mT5 en utilisant les fonctionnalités de bas niveau fournies par 🤗 *Accelerate*.
{:else}
-Nous sommes presque prêts à nous entraîner ! Nous devons juste convertir nos jeux de données en `tf.data.Dataset`s en utilisant le collateur de données que nous avons défini ci-dessus, et ensuite `compile()` et `fit()` le modèle. D'abord, les jeux de données :
+Nous sommes presque prêts à nous entraîner ! Nous devons juste convertir nos jeux de données en `tf.data.Dataset` en utilisant le collateur de données que nous avons défini ci-dessus, puis utiliser `compile()` et `fit()`. D'abord, les jeux de données :
```python
tf_train_dataset = tokenized_datasets["train"].to_tf_dataset(
@@ -708,9 +721,9 @@ Maintenant, nous définissons nos hyperparamètres d'entraînement et nous compi
from transformers import create_optimizer
import tensorflow as tf
-# Le nombre d'étapes d'entraînement est le nombre d'échantillons dans l'ensemble de données, divisé par la taille du batch, puis multiplié par le nombre total d'époques.
-# par le nombre total d'époques. Notez que le jeu de données tf_train_dataset est ici un batch tf.data.Dataset,
-# et non le jeu de données original Hugging Face Dataset, donc son len() est déjà num_samples // batch_size.
+# Le nombre d'étapes d'entraînement est le nombre d'échantillons dans le jeu de données, divisé par la taille du batch,
+# puis multiplié par le nombre total d'époques. Notez que le jeu de données tf_train_dataset est ici un tf.data.Dataset,
+# et non le jeu de données original donc son len() est déjà num_samples // batch_size.
num_train_epochs = 8
num_train_steps = len(tf_train_dataset) * num_train_epochs
model_name = model_checkpoint.split("/")[-1]
@@ -728,7 +741,7 @@ model.compile(optimizer=optimizer)
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```
-Et enfin, nous ajustons le modèle. Nous utilisons un `PushToHubCallback` pour sauvegarder le modèle sur le *Hub* après chaque époque, ce qui nous permettra de l'utiliser pour l'inférence plus tard :
+Et enfin, nous *finetunons* le modèle. Nous utilisons un `PushToHubCallback` pour sauvegarder le modèle sur le *Hub* après chaque époque, ce qui nous permettra de l'utiliser pour l'inférence plus tard :
```python
from transformers.keras_callbacks import PushToHubCallback
@@ -781,13 +794,13 @@ result = {key: value.mid.fmeasure * 100 for key, value in result.items()}
{#if fw === 'pt'}
-## *Finetuning* de mT5 avec 🤗 *Accelerate*
+## Finetuning de mT5 avec 🤗 Accelerate
-Le *finetuning* de notre modèle avec 🤗 *Accelerate* est très similaire à l'exemple de classification de texte que nous avons rencontré dans [Chapitre 3](/course/fr/chapter3). Les principales différences seront la nécessité de générer explicitement nos résumés pendant l'Entraînement et de définir comment nous calculons les scores ROUGE (rappelons que le `Seq2SeqTrainer` s'est occupé de la génération pour nous). Voyons comment nous pouvons mettre en œuvre ces deux exigences dans 🤗 *Accelerate* !
+Le *finetuning* de notre modèle avec 🤗 *Accelerate* est très similaire à l'exemple de classification de texte que nous avons rencontré dans le [chapitre 3](/course/fr/chapter3). Les principales différences seront la nécessité de générer explicitement nos résumés pendant l'entraînement et de définir comment nous calculons les scores ROUGE (rappelons que le `Seq2SeqTrainer` s'est occupé de la génération pour nous). Voyons comment nous pouvons mettre en œuvre ces deux exigences dans 🤗 *Accelerate* !
### Préparer tout pour l'entraînement
-La première chose que nous devons faire est de créer un `DataLoader` pour chacun de nos splits. Puisque les chargeurs de données PyTorch attendent des batchs de tenseurs, nous devons définir le format à `"torch"` dans nos jeux de données :
+La première chose que nous devons faire est de créer un `DataLoader` pour chacun de nos échantillons. Puisque les chargeurs de données PyTorch attendent des batchs de tenseurs, nous devons définir le format à `"torch"` dans nos jeux de données :
```python
tokenized_datasets.set_format("torch")
@@ -837,17 +850,17 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
-🚨 Si vous vous entraînez sur un TPU, vous devrez déplacer tout le code ci-dessus dans une fonction d'entraînement dédiée. Voir le [Chapitre 3](/course/fr/chapter3) pour plus de détails.
+🚨 Si vous vous entraînez sur un TPU, vous devrez déplacer tout le code ci-dessus dans une fonction d'entraînement dédiée. Voir le [chapitre 3](/course/fr/chapter3) pour plus de détails.
Maintenant que nous avons préparé nos objets, il reste trois choses à faire :
-* définir le programme du taux d'apprentissage,
+* définir le programmeur du taux d'apprentissage,
* implémenter une fonction pour post-traiter les résumés pour l'évaluation,
-* créer un référentiel sur le *Hub* vers lequel nous pouvons pousser notre modèle.
+* créer un dépôt sur le *Hub* vers lequel nous pouvons pousser notre modèle.
-Pour le programme de taux d'apprentissage, nous utiliserons le programme linéaire standard des sections précédentes :
+Pour le programmeur de taux d'apprentissage, nous utiliserons le programmeur linéaire standard des sections précédentes :
```python
from transformers import get_scheduler
@@ -864,7 +877,7 @@ lr_scheduler = get_scheduler(
)
```
-Pour le post-traitement, nous avons besoin d'une fonction qui divise les résumés générés en phrases séparées par des nouvelles lignes. C'est le format attendu par la métrique ROUGE, et nous pouvons y parvenir avec le bout de code suivant :
+Pour le post-traitement, nous avons besoin d'une fonction qui divise les résumés générés en phrases séparées par des nouvelles lignes. C'est le format attendu par la métrique ROUGE et nous pouvons y parvenir avec le bout de code suivant :
```python
def postprocess_text(preds, labels):
@@ -880,7 +893,7 @@ def postprocess_text(preds, labels):
Cela devrait vous sembler familier si vous vous rappelez comment nous avons défini la fonction `compute_metrics()` du `Seq2SeqTrainer`.
-Enfin, nous devons créer un dépôt de modèles sur le *Hub*. Pour cela, nous pouvons utiliser la bibliothèque 🤗 *Hub*, qui porte le nom approprié. Nous avons juste besoin de définir un nom pour notre référentiel, et la bibliothèque a une fonction utilitaire pour combiner l'ID du référentiel avec le profil de l'utilisateur :
+Enfin, nous devons créer un dépôt de modèles sur le *Hub*. Pour cela, nous pouvons utiliser la bibliothèque 🤗 *Hub*, qui porte le nom approprié. Nous avons juste besoin de définir un nom pour notre dépôt, et la bibliothèque a une fonction utilitaire pour combiner l'identifiant du dépôt avec le profil de l'utilisateur :
```python
from huggingface_hub import get_full_repo_name
@@ -894,7 +907,7 @@ repo_name
'lewtun/mt5-finetuned-amazon-en-es-accelerate'
```
-Nous pouvons maintenant utiliser ce nom de référentiel pour cloner une version locale dans notre répertoire de résultats qui stockera les artefacts d'entraînement :
+Nous pouvons maintenant utiliser ce nom de dépôt pour cloner une version locale dans notre répertoire de résultats qui stockera les artefacts d'entraînement :
```python
from huggingface_hub import Repository
@@ -903,7 +916,7 @@ output_dir = "results-mt5-finetuned-squad-accelerate"
repo = Repository(output_dir, clone_from=repo_name)
```
-This will allow us to push the artifacts back to the Hub by calling the `repo.push_to_hub()` method during training! Let's now wrap up our analysis by writing out the training loop.
+Cela nous permettra de pousser les artefacts vers le *Hub* en appelant la méthode `repo.push_to_hub()` pendant l'entraînement ! Concluons maintenant notre analyse en écrivant la boucle d'entraînement.
### Boucle d'entraînement
@@ -912,7 +925,7 @@ La boucle d'entraînement pour le résumé est assez similaire aux autres exempl
1. entraîner le modèle en itérant sur tous les exemples dans `train_dataloader` pour chaque époque,
2. générer les résumés du modèle à la fin de chaque époque, en générant d'abord les *tokens* puis en les décodant (ainsi que les résumés de référence) en texte,
3. calculer les scores ROUGE en utilisant les mêmes techniques que nous avons vues précédemment,
-4. sauvegarder les points de contrôle et pousser le tout vers le *Hub*. Ici, nous nous appuyons sur l'argument `blocking=False` de l'objet `Repository` afin de pouvoir pousser les points de contrôle par époque de manière _asynchrone_. Cela nous permet de poursuivre l'entraînement sans avoir à attendre le téléchargement quelque peu lent associé à un modèle de la taille d'un Go !
+4. sauvegarder les *checkpoints* et pousser le tout vers le *Hub*. Ici, nous nous appuyons sur l'argument `blocking=False` de l'objet `Repository` afin de pouvoir pousser les *checkpoints* par époque de manière _asynchrone_. Cela nous permet de poursuivre l'entraînement sans avoir à attendre le téléchargement quelque peu lent associé à un modèle de la taille d'1 Go !
Ces étapes peuvent être vues dans le bloc de code suivant :
@@ -950,7 +963,7 @@ for epoch in range(num_train_epochs):
)
labels = batch["labels"]
- # Si nous n'avons pas rempli la longueur maximale, nous devons également remplir les étiquettes.
+ # Si nous n'avons pas rempli la longueur maximale, nous devons également remplir les étiquettes
labels = accelerator.pad_across_processes(
batch["labels"], dim=1, pad_index=tokenizer.pad_token_id
)
@@ -958,7 +971,7 @@ for epoch in range(num_train_epochs):
generated_tokens = accelerator.gather(generated_tokens).cpu().numpy()
labels = accelerator.gather(labels).cpu().numpy()
- # Remplacer -100 dans les étiquettes car nous ne pouvons pas les décoder.
+ # Remplacer -100 dans les étiquettes car nous ne pouvons pas les décoder
labels = np.where(labels != -100, labels, tokenizer.pad_token_id)
if isinstance(generated_tokens, tuple):
generated_tokens = generated_tokens[0]
@@ -1008,9 +1021,9 @@ Et c'est tout ! Une fois que vous l'aurez exécuté, vous aurez un modèle et de
{/if}
-## Utilisation de votre modèle *finetuné*
+## Utilisation de votre modèle finetuné
-Une fois que vous avez poussé le modèle vers le *Hub*, vous pouvez jouer avec lui soit via le widget d'inférence, soit avec un objet `pipeline`, comme suit :
+Une fois que vous avez poussé le modèle vers le *Hub*, vous pouvez jouer avec lui soit via le *widget* d'inférence, soit avec un objet `pipeline`, comme suit :
```python
from transformers import pipeline
@@ -1041,9 +1054,11 @@ print_summary(100)
'>>> Review: Nothing special at all about this product... the book is too small and stiff and hard to write in. The huge sticker on the back doesn’t come off and looks super tacky. I would not purchase this again. I could have just bought a journal from the dollar store and it would be basically the same thing. It’s also really expensive for what it is.'
# Ce produit n'a rien de spécial... le livre est trop petit et rigide et il est difficile d'y écrire. L'énorme autocollant au dos ne se détache pas et a l'air super collant. Je n'achèterai plus jamais ce produit. J'aurais pu simplement acheter un journal dans un magasin à un dollar et ce serait à peu près la même chose. Il est également très cher pour ce qu'il est.
-'>>> Title: Not impressed at all... buy something else' # Pas du tout impressionné... achetez autre chose.
+'>>> Title: Not impressed at all... buy something else'
+# Pas du tout impressionné... achetez autre chose.
-'>>> Summary: Nothing special at all about this product' # Rien de spécial à propos de ce produit
+'>>> Summary: Nothing special at all about this product'
+# Rien de spécial à propos de ce produit
```
Ce n'est pas si mal ! Nous pouvons voir que notre modèle a été capable d'effectuer un résumé _abstractif_ en augmentant certaines parties de la critique avec de nouveaux mots. Et peut-être que l'aspect le plus cool de notre modèle est qu'il est bilingue, donc nous pouvons également générer des résumés de critiques en espagnol :
@@ -1053,13 +1068,16 @@ print_summary(0)
```
```python out
-'>>> Review: Es una trilogia que se hace muy facil de leer. Me ha gustado, no me esperaba el final para nada' # C'est une trilogie qui se lit très facilement. J'ai aimé, je ne m'attendais pas du tout à la fin.
+'>>> Review: Es una trilogia que se hace muy facil de leer. Me ha gustado, no me esperaba el final para nada'
+# C'est une trilogie qui se lit très facilement. J'ai aimé, je ne m'attendais pas du tout à la fin.
-'>>> Title: Buena literatura para adolescentes' # Bonne littérature pour les adolescents
+'>>> Title: Buena literatura para adolescentes'
+# Bonne littérature pour les adolescents
-'>>> Summary: Muy facil de leer' # Très facile à lire
+'>>> Summary: Muy facil de leer'
+# Très facile à lire
```
-Le résumé se traduit par "Très facile à lire", ce qui, comme nous pouvons le constater, a été extrait directement de la critique. Néanmoins, cela montre la polyvalence du modèle mT5 et vous a donné un aperçu de ce que c'est que de traiter un corpus multilingue !
+Le résumé a été extrait directement de la critique. Néanmoins, cela montre la polyvalence du modèle mT5 et vous a donné un aperçu de ce que c'est que de traiter un corpus multilingue !
Ensuite, nous allons nous intéresser à une tâche un peu plus complexe : entraîner un modèle de langue à partir de zéro.
diff --git a/chapters/fr/chapter7/6.mdx b/chapters/fr/chapter7/6.mdx
index a4a4fa81d..a6c81f76d 100644
--- a/chapters/fr/chapter7/6.mdx
+++ b/chapters/fr/chapter7/6.mdx
@@ -22,25 +22,25 @@
{/if}
-Jusqu'à présent, nous avons surtout utilisé des modèles pré-entraînés et les avons *finetunés* pour de nouveaux cas d'utilisation en réutilisant les poids du pré-entraînement. Comme nous l'avons vu dans le [Chapitre 1](/course/fr/chapter1), ceci est communément appelé _apprentissage par transfert_, et c'est une stratégie très efficace pour appliquer les modèles Transformer à la plupart des cas d'utilisation du monde réel où les données étiquetées sont rares. Dans ce chapitre, nous allons adopter une approche différente et entraîner un modèle complètement nouveau à partir de zéro. C'est une bonne approche à adopter si vous avez beaucoup de données et qu'elle est très différente des données de pré-entraînement utilisées pour les modèles disponibles. Cependant, le pré-entraînement d'un modèle de langue nécessite beaucoup plus de ressources informatiques que le simple affinage d'un modèle existant. Parmi les exemples où il peut être utile d'entraîner un nouveau modèle, citons les ensembles de données constitués de notes de musique, de séquences moléculaires telles que l'ADN ou de langages de programmation. Ces derniers ont récemment gagné en popularité grâce à des outils tels que TabNine et Copilot de GitHub, alimentés par le modèle Codex d'OpenAI, qui peuvent générer de longues séquences de code. Cette tâche de génération de texte est mieux abordée avec des modèles de langage autorégressifs ou causaux tels que GPT-2.
+Jusqu'à présent, nous avons surtout réutilisé des modèles pré-entraînés et les avons *finetunés* sur de nouveaux cas d'usage. Comme nous l'avons vu dans le [chapitre 1](/course/fr/chapter1), ceci est communément appelé _apprentissage par transfert_, et il s'agit d'une stratégie très efficace pour appliquer les *transformers* à la plupart des applications du monde réel où les données étiquetées sont rares. Dans ce chapitre, nous allons adopter une approche différente consistant à entraîner un modèle complètement nouveau à partir de zéro. C'est une bonne démarche à adopter si vous avez beaucoup de données et qu'elles sont très différentes des données de pré-entraînement utilisées par les modèles disponibles. Cependant, le pré-entraînement d'un modèle de langue nécessite beaucoup plus de ressources informatiques que le simple *finetuning* d'un modèle existant. Parmi les exemples où il peut être utile d'entraîner un nouveau modèle, citons les jeux de données constitués de notes de musique, de séquences moléculaires telles que l'ADN, ou de langages de programmation. Ces derniers ont récemment gagné en popularité grâce à des outils tels que TabNine et Copilot de GitHub (alimentés par le modèle Codex d'OpenAI) qui peuvent générer de longues séquences de code. Cette tâche de génération de texte est mieux abordée avec des modèles de langage autorégressifs ou causaux tels que le GPT-2.
-Dans cette section, nous allons construire une version réduite d'un modèle de génération de code : nous nous concentrerons sur les compléments d'une ligne au lieu des fonctions ou des classes complètes, en utilisant un sous-ensemble de code Python. Lorsque vous travaillez avec des données en Python, vous êtes souvent en contact avec la pile de données scientifiques Python, composée des bibliothèques `matplotlib`, `seaborn`, `pandas` et `scikit-learn`. Lors de l'utilisation de ces *frameworks*, il est fréquent d'avoir besoin de rechercher des commandes spécifiques, il serait donc bien d'utiliser un modèle pour compléter ces appels pour nous.
+Dans cette section, nous allons construire une version réduite d'un modèle de génération de code Python. Nous nous concentrerons sur la complétion d'une ligne de code au lieu de fonctions ou de classes complètes. Lorsque vous travaillez sur des projets de science des données en Python, vous êtes souvent en contact avec les bibliothèques `matplotlib`, `seaborn`, `pandas` et `scikit-learn`. Lors de l'utilisation de ces *frameworks*, il est fréquent d'avoir besoin de rechercher des commandes spécifiques. Il serait donc bien d'utiliser un modèle pour compléter ces appels pour nous.
-Dans le [Chapitre 6](/course/fr/chapter6), nous avons créé un *tokenizer* efficace pour traiter le code source Python, mais nous avons toujours besoin d'un ensemble de données à grande échelle pour pré-entraîner un modèle. Ici, nous allons appliquer notre *tokenizer* à un corpus de code Python provenant des dépôts GitHub. Nous utiliserons ensuite l'API `Trainer` et 🤗 *Accelerate* pour entraîner le modèle. C'est parti !
+Dans le [chapitre 6](/course/fr/chapter6), nous avons créé un *tokenizer* efficace pour traiter du code Python. Nous avons besoin d'un jeu de données à grande échelle pour pré-entraîner un modèle. Ici, nous allons appliquer notre *tokenizer* à un corpus de code Python provenant des dépôts GitHub. Nous utiliserons ensuite l'API `Trainer` et 🤗 *Accelerate* pour entraîner le modèle. C'est parti !
-Il s'agit en fait de la présentation du modèle qui a été entraîné et téléchargé sur le *Hub* à l'aide du code présenté dans cette section. Vous pouvez le trouver [ici](https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28). Notez qu'étant donné qu'il y a une certaine randomisation dans la génération du texte, vous obtiendrez probablement un résultat légèrement différent.
+Il s'agit d'une présentation du modèle qui a été entraîné à l'aide du code présenté dans cette section et qui a ensuité été téléchargé sur le *Hub*. Vous pouvez le trouver [ici](https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28). Notez qu'étant donné qu'il y a un certains aléat dans la génération du texte, vous obtiendrez probablement un résultat légèrement différent.
## Collecte des données
-Le code Python est disponible en abondance dans les dépôts de code tels que GitHub, que nous pouvons utiliser pour créer un ensemble de données en récupérant chaque dépôt Python. C'est l'approche adoptée dans le [manuel Transformers](https://learning.oreilly.com/library/view/natural-language-processing/9781098103231/) pour pré-entraîner un grand modèle GPT-2. En utilisant un dépôt GitHub d'environ 180 Go contenant approximativement 20 millions de fichiers Python appelé `codeparrot`, les auteurs ont construit un ensemble de données qu'ils ont ensuite partagé sur le [*Hub*](https://huggingface.co/datasets/transformersbook/codeparrot).
+On peut trouver du code Python en abondance dans les dépôts de code tels que GitHub, que nous pouvons utiliser pour créer un jeu de données en récupérant chaque dépôt Python. C'est l'approche adoptée dans le [livre *Natural Language Processing with Transformers*](https://learning.oreilly.com/library/view/natural-language-processing/9781098103231/) pour pré-entraîner un grand GPT-2. En utilisant un dépôt GitHub d'environ 180 Go contenant approximativement 20 millions de fichiers Python, les auteurs du livre ont construit un jeu de données appelé `codeparrot` qu'ils ont ensuite partagé sur le [*Hub*](https://huggingface.co/datasets/transformersbook/codeparrot).
-Cependant, s'entraîner sur l'ensemble du corpus prend beaucoup de temps et demande beaucoup de calculs, et nous n'avons besoin que du sous-ensemble du jeu de données concerné par la pile Python pour la science des données. Commençons donc par filtrer l'ensemble de données `codeparrot` pour tous les fichiers qui incluent l'une des bibliothèques de cette pile. En raison de la taille de l'ensemble de données, nous voulons éviter de le télécharger ; à la place, nous utiliserons la fonctionnalité de streaming pour le filtrer à la volée. Pour nous aider à filtrer les échantillons de code utilisant les bibliothèques que nous avons mentionnées précédemment, nous utiliserons la fonction suivante :
+Cependant, entraîner sur l'ensemble du corpus prend beaucoup de temps et demande beaucoup de ressources de calculs. Dans notre cas, nous n'avons besoin que du sous-ensemble du jeu de données qui est relatif aux codes portant sur la science des données. Commençons donc par filtrer le jeu de données `codeparrot` en ne gardant que les fichiers incluant l'une des bibliothèques de science des données énumérées précédemment. En raison de la taille du jeu de données, nous voulons éviter de le télécharger. Nous utiliserons donc la fonctionnalité de *streaming* de 🤗 *Datasets* afin de le filtrer à la volée. Pour nous aider à filtrer les échantillons de code utilisant les bibliothèques que nous avons mentionnées précédemment, nous utilisons la fonction suivante :
```py
def any_keyword_in_string(string, keywords):
@@ -66,7 +66,7 @@ print(
False True
```
-Nous pouvons l'utiliser pour créer une fonction qui diffusera l'ensemble de données et filtrera les éléments que nous voulons :
+Nous pouvons l'utiliser pour créer une fonction qui va *streamer* le jeu de donner et filtrer les éléments que nous voulons :
```py
def filter_streaming_dataset(dataset, filters):
@@ -81,7 +81,7 @@ def filter_streaming_dataset(dataset, filters):
return Dataset.from_dict(filtered_dict)
```
-Ensuite, nous pouvons simplement appliquer cette fonction à l'ensemble de données en continu :
+Ensuite, nous pouvons simplement appliquer cette fonction :
```py
# Cette cellule prendra beaucoup de temps à s'exécuter, donc vous devriez la sauter et aller à la suivante !
@@ -98,9 +98,9 @@ filtered_data = filter_streaming_dataset(data, filters)
3.26% of data after filtering.
```
-Cela nous laisse avec environ 3 % de l'ensemble de données original, ce qui est tout de même assez important. L'ensemble de données résultant est de 6 Go et se compose de 600 000 scripts Python !
+Cela nous laisse avec environ 3 % du jeu de données original, ce qui est tout de même assez important puisqu'il fait 6 Go et se compose de 600 000 scripts Python !
-Le filtrage de l'ensemble complet de données peut prendre de 2 à 3 heures, selon votre machine et votre bande passante. Si vous ne voulez pas passer par ce long processus vous-même, nous fournissons l'ensemble de données filtré sur le *Hub* pour que vous puissiez le télécharger :
+Le filtrage peut prendre de 2 à 3 heures, selon votre machine et votre bande passante. Si vous ne voulez pas passer par ce long processus, nous fournissons sur le *Hub* le jeu de données filtré pour que vous puissiez le télécharger :
```py
from datasets import load_dataset, DatasetDict
@@ -133,11 +133,11 @@ DatasetDict({
-Le pré-entraînement du modèle de langue prendra un certain temps. Nous vous suggérons d'exécuter d'abord la boucle d'entraînement sur un échantillon des données en décommentant les deux lignes partielles ci-dessus, et de vous assurer que l'entraînement se termine avec succès et que les modèles sont stockés. Rien n'est plus frustrant qu'un entraînement qui échoue à la dernière étape parce que vous avez oublié de créer un dossier ou parce qu'il y a une faute de frappe à la fin de la boucle d'entraînement !
+Le pré-entraînement du modèle de langue prendra un certain temps. Nous vous suggérons donc d'exécuter d'abord la boucle d'entraînement sur un petit échantillon des données en décommentant les deux lignes dans le code ci-dessus. Assurez-vous alors que l'entraînement se termine avec succès et que les modèles sont stockés. Rien n'est plus frustrant qu'un entraînement qui échoue à la dernière étape car vous avez oublié de créer un dossier ou parce qu'il y a une faute de frappe à la fin de la boucle d'entraînement !
-Examinons un exemple tiré de l'ensemble de données. Nous ne montrerons que les 200 premiers caractères de chaque champ :
+Examinons un exemple tiré du jeu de données. Nous ne montrerons que les 200 premiers caractères de chaque champ :
```py
for key in raw_datasets["train"][0]:
@@ -169,16 +169,16 @@ Nous pouvons voir que le champ `content` contient le code sur lequel nous voulon
-La première étape sera de tokeniser les données, afin de pouvoir les utiliser pour l'entraînement. Puisque notre objectif est principalement d'autocompléter des appels de fonction courts, nous pouvons garder la taille du contexte relativement petite. L'avantage est que nous pouvons entraîner le modèle beaucoup plus rapidement et qu'il nécessite beaucoup moins de mémoire. S'il est important pour votre application d'avoir plus de contexte (par exemple, si vous voulez que le modèle écrive des tests unitaires basés sur un fichier avec la définition de la fonction), assurez-vous d'augmenter ce nombre, mais gardez également à l'esprit que cela s'accompagne d'une plus grande empreinte mémoire du GPU. Pour l'instant, fixons la taille du contexte à 128 *tokens*, par opposition aux 1 024 ou 2 048 utilisés dans GPT-2 ou GPT-3, respectivement.
+La première étape est de tokeniser les données afin de pouvoir les utiliser pour l'entraînement. Puisque notre objectif est d'autocompléter de courts appels de fonctions, nous pouvons garder la taille du contexte relativement petite. L'avantage est que nous pouvons entraîner le modèle beaucoup plus rapidement et qu'il nécessite beaucoup moins de mémoire. Si c'est important pour votre application d'avoir davantage de contexte (par exemple, si vous voulez que le modèle écrive des tests unitaires basés sur un fichier avec la définition de la fonction), assurez-vous d'augmenter ce nombre. Gardez néanmoins à l'esprit que cela s'accompagne d'une plus grande empreinte mémoire du GPU. Pour l'instant, fixons la taille du contexte à 128 *tokens*, par opposition aux 1 024 ou 2 048 utilisés respectivement dans le GPT-2 et le GPT-3.
-La plupart des documents contiennent beaucoup plus de 128 *tokens*, donc le fait de tronquer les entrées à la longueur maximale éliminerait une grande partie de notre jeu de données. A la place, nous utiliserons l'option `return_overflowing_tokens` pour tokeniser l'entrée entière et la diviser en plusieurs morceaux, comme nous l'avons fait dans [Chapter 6](/course/chapter6/4). Nous utiliserons également l'option `return_length` pour retourner automatiquement la longueur de chaque morceau créé. Souvent, le dernier morceau sera plus petit que la taille du contexte, et nous nous débarrasserons de ces morceaux pour éviter les problèmes de remplissage ; nous n'en avons pas vraiment besoin puisque nous avons beaucoup de données de toute façon.
+La plupart des documents contiennent beaucoup plus de 128 *tokens*, donc le fait de tronquer les entrées à la longueur maximale éliminerait une grande partie de notre jeu de données. A la place, nous allons utiliser l'option `return_overflowing_tokens` pour tokeniser l'entrée entière et la diviser en plusieurs morceaux, comme nous l'avons fait dans le [chapitre 6](/course/fr/chapter6/4). Nous utiliserons également l'option `return_length` pour retourner automatiquement la longueur de chaque morceau créé. Souvent, le dernier morceau est plus petit que la taille du contexte et nous nous en débarrasserons pour éviter les problèmes de *padding*. Nous n'en avons pas vraiment besoin puisque de toute façon nous avons beaucoup de données.
-Voyons exactement comment cela fonctionne en examinant les deux premiers exemples :
+Voyons comment cela fonctionne en examinant les deux premiers exemples :
```py
from transformers import AutoTokenizer
@@ -205,9 +205,9 @@ Input chunk lengths: [128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128
Chunk mapping: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
```
-Nous pouvons voir que nous obtenons 34 segments au total à partir de ces deux exemples. En regardant les longueurs des *chunks*, nous pouvons voir que les *chunks* à la fin des deux documents ont moins de 128 *tokens* (117 et 41, respectivement). Ils ne représentent qu'une petite fraction du total des *chunks* que nous avons, donc nous pouvons les jeter sans risque. Avec le champ `overflow_to_sample_mapping`, nous pouvons aussi reconstruire quels *chunks* appartenaient à quels échantillons d'entrée.
+Nous pouvons voir que nous obtenons 34 morceaux à partir de ces deux exemples. En regardant leurs longueurs, nous pouvons voir qu'ils se terminent avec moins de 128 *tokens* (117 et 41, respectivement). Ils ne représentent qu'une petite fraction du total des morceaux que nous avons (2/34), donc nous pouvons les jeter sans risque. Avec le champ `overflow_to_sample_mapping`, nous pouvons aussi reconstruire quels morceaux appartenaient à quels échantillons d'entrée.
-Avec cette opération, nous utilisons une fonctionnalité pratique de la fonction `Dataset.map()` dans 🤗 *Datasets*, qui est qu'elle ne nécessite pas de mappage un à un ; comme nous l'avons vu dans la [section 3](/course/fr/chapter7/3), nous pouvons créer des batchs avec plus ou moins d'éléments que le batchd'entrée. Ceci est utile lorsque l'on effectue des opérations telles que l'augmentation ou le filtrage des données qui modifient le nombre d'éléments. Dans notre cas, lors de la tokenisation de chaque élément en *chunks* de la taille de contexte spécifiée, nous créons de nombreux échantillons de chaque document. Nous devons juste nous assurer de supprimer les colonnes existantes, car elles ont une taille conflictuelle. Si nous voulions les garder, nous pourrions les répéter de manière appropriée et les retourner dans l'appel `Dataset.map()` :
+Avec cette opération, nous utilisons une fonctionnalité pratique de la fonction `Dataset.map()` de 🤗 *Datasets*. En effet, celle-ci ne nécessite pas une correspondance un à un comme nous l'avons vu dans la [section 3](/course/fr/chapter7/3). Nous pouvons créer des batchs avec plus ou moins d'éléments que le batch d'entrée. C'est utile lorsque l'on effectue des opérations telles que l'augmentation ou le filtrage des données qui modifient le nombre d'éléments. Dans notre cas, lors de la tokenisation de chaque élément en morceaux de longeur de la taille de contexte spécifiée, nous créons de nombreux échantillons de chaque document. Nous devons juste nous assurer de supprimer les colonnes existantes, car elles ont une taille conflictuelle. Si nous voulions les garder, nous pourrions les répéter de manière appropriée et les retourner dans l'appel `Dataset.map()` :
```py
def tokenize(element):
@@ -244,20 +244,20 @@ DatasetDict({
})
```
-Nous avons maintenant 16,7 millions d'exemples avec 128 *tokens* chacun, ce qui correspond à environ 2,1 milliards de *tokens* au total. Pour référence, les modèles GPT-3 et Codex d'OpenAI sont entraînés sur 300 et 100 milliards de *tokens*, respectivement, où les modèles Codex sont initialisés à partir des points de contrôle GPT-3. Notre objectif dans cette section n'est pas de rivaliser avec ces modèles, qui peuvent générer des textes longs et cohérents, mais de créer une version réduite fournissant une fonction d'autocomplétion rapide pour les scientifiques des données.
+Nous avons maintenant 16,7 millions d'exemples avec 128 *tokens* chacun, ce qui correspond à environ 2,1 milliards de *tokens* au total. A titre de comparaison, les modèles GPT-3 et Codex d'OpenAI sont entraînés sur 300 et 100 milliards de *tokens*, respectivement. Les modèles Codex étant initialisés à partir des *checkpoints* GPT-3. Notre objectif dans cette section n'est pas de rivaliser avec ces modèles, qui peuvent générer des textes longs et cohérents, mais de créer une version réduite fournissant une fonction d'autocomplétion rapide.
-Maintenant que l'ensemble de données est prêt, configurons le modèle !
+Maintenant que le jeu de données est prêt, configurons le modèle !
-✏️ **Essayez** Se débarrasser de tous les morceaux qui sont plus petits que la taille du contexte n'était pas un gros problème ici parce que nous utilisons de petites fenêtres de contexte. Si vous augmentez la taille du contexte (ou si vous avez un corpus de documents courts), la fraction des morceaux qui sont jetés augmentera également. Une façon plus efficace de préparer les données est de joindre tous les échantillons dans un batch avec un *token* `eos_token_id` entre les deux, puis d'effectuer le chunking sur les séquences concaténées. Comme exercice, modifiez la fonction `tokenize()` pour utiliser cette approche. Notez que vous devrez mettre `truncation=False` et enlever les autres arguments du *tokenizer* pour obtenir la séquence complète des IDs des *tokens*.
+✏️ **Essayez !** Se débarrasser de tous les morceaux qui sont plus petits que la taille du contexte n'était pas un gros problème ici parce que nous utilisons de petites fenêtres de contexte. Si vous augmentez la taille du contexte (ou si vous avez un corpus de documents courts), la fraction des morceaux qui sont jetés augmentera. Une façon plus efficace de préparer les données est de joindre tous les échantillons dans un batch avec un *token* `eos_token_id` entre les deux, puis d'effectuer le découpage sur les séquences concaténées. Comme exercice, modifiez la fonction `tokenize()` pour utiliser cette approche. Notez que vous devrez mettre `truncation=False` et enlever les autres arguments du *tokenizer* pour obtenir la séquence complète des identifiants des *tokens*.
## Initialisation d'un nouveau modèle
-Notre première étape consiste à initialiser fraîchement un modèle GPT-2. Nous utiliserons la même configuration pour notre modèle que pour le petit modèle GPT-2, donc nous chargeons la configuration pré-entraînée, nous nous assurons que la taille du *tokenizer* correspond à la taille du vocabulaire du modèle et nous passons les identifiants des *tokens* `bos` et `eos` (début et fin de séquence) :
+Notre première étape consiste à initialiser un GPT-2. Pour notre modèle, nous utiliserons la même configuration que pour le petit modèle GPT-2. Ainsi nous chargeons la configuration pré-entraînée, nous nous assurons que la taille du *tokenizer* correspond à la taille du vocabulaire du modèle et nous passons les identifiants des *tokens* `bos` et `eos` (début et fin de séquence) :
{#if fw === 'pt'}
@@ -273,7 +273,7 @@ config = AutoConfig.from_pretrained(
)
```
-Avec cette configuration, nous pouvons charger un nouveau modèle. Notez que c'est la première fois que nous n'utilisons pas la fonction `from_pretrained()`, puisque nous initialisons nous-mêmes un modèle :
+Avec cette configuration, nous pouvons charger un nouveau modèle. Notez que c'est la première fois que nous n'utilisons pas la fonction `from_pretrained()` puisque nous initialisons nous-mêmes un modèle :
```py
model = GPT2LMHeadModel(config)
@@ -299,11 +299,11 @@ config = AutoConfig.from_pretrained(
)
```
-Avec cette configuration, nous pouvons charger un nouveau modèle. Notez que c'est la première fois que nous n'utilisons pas la fonction `from_pretrained()`, puisque nous initialisons nous-mêmes un modèle :
+Avec cette configuration, nous pouvons charger un nouveau modèle. Notez que c'est la première fois que nous n'utilisons pas la fonction `from_pretrained()` puisque nous initialisons nous-mêmes un modèle :
```py
model = TFGPT2LMHeadModel(config)
-model(model.dummy_inputs) # Builds the model
+model(model.dummy_inputs) # Construit le modèle
model.summary()
```
@@ -321,9 +321,9 @@ _________________________________________________________________
{/if}
-Notre modèle comporte 124 millions de paramètres que nous devrons régler. Avant de commencer l'entraînement, nous devons configurer un collateur de données qui se chargera de créer les lots. Nous pouvons utiliser le collateur `DataCollatorForLanguageModeling`, qui est conçu spécifiquement pour la modélisation du langage (comme son nom le suggère subtilement). En plus de l'empilage et du remplissage des lots, il s'occupe aussi de la création des étiquettes du modèle de langage -- dans la modélisation causale du langage, les entrées servent aussi d'étiquettes (juste décalées d'un élément), et ce collateur de données les crée à la volée pendant l'entraînement pour ne pas avoir à dupliquer les `input_ids`.
+Notre modèle comporte 124 millions de paramètres que nous devrons régler. Avant de commencer l'entraînement, nous devons configurer un collateur de données qui se chargera de créer les batchs. Nous pouvons utiliser le collateur `DataCollatorForLanguageModeling`, qui est conçu spécifiquement pour la modélisation du langage (comme son nom le suggère subtilement). En plus de l'empilage et du rembourrage des batchs, il s'occupe aussi de la création des étiquettes du modèle de langage. Dans la modélisation causale du langage, les entrées servent aussi d'étiquettes (juste décalées d'un élément) et que le collateur de données crée à la volée pendant l'entraînement pour ne pas avoir à dupliquer les `input_ids`.
-Notez que `DataCollatorForLanguageModeling` supporte à la fois le *masked language modeling* (MLM) et le *causal language modeling* (CLM). Par défaut, il prépare les données pour MLM, mais nous pouvons passer à CLM en définissant l'argument `mlm=False` :
+Notez que `DataCollatorForLanguageModeling` supporte à la fois la modélisation du langage masqué (MLM pour *masked language modeling*) et la modélisation du langage causal (CLM pour *causal language modeling*). Par défaut, il prépare les données pour la MLM mais nous pouvons passer à la CLM en définissant l'argument `mlm=False` :
{#if fw === 'pt'}
@@ -401,7 +401,7 @@ tf_eval_dataset = tokenized_dataset["valid"].to_tf_dataset(
-Nous avons maintenant tout ce qu'il faut pour former notre modèle - ce n'était pas si compliqué après tout ! Avant de commencer l'entraînement, nous devons nous connecter à Hugging Face. Si vous travaillez dans un *notebook*, vous pouvez le faire avec la fonction utilitaire suivante :
+Nous avons maintenant tout ce qu'il faut pour entraîner notre modèle. Ce n'était pas si compliqué ! Avant de commencer l'entraînement, nous devons nous connecter à Hugging Face. Si vous travaillez dans un *notebook*, vous pouvez le faire avec la fonction utilitaire suivante :
```python
from huggingface_hub import notebook_login
@@ -409,7 +409,7 @@ from huggingface_hub import notebook_login
notebook_login()
```
-Cela affichera un widget où vous pourrez entrer vos identifiants de connexion à Hugging Face.
+Cela affichera un *widget* où vous pourrez entrer vos identifiants de connexion à Hugging Face.
Si vous ne travaillez pas dans un *notebook*, tapez simplement la ligne suivante dans votre terminal :
@@ -419,7 +419,7 @@ huggingface-cli login
{#if fw === 'pt'}
-Tout ce qu'il reste à faire est de configurer les arguments d'entraînement et de lancer le `Trainer`. Nous utiliserons un programme de taux d'apprentissage en cosinus avec un certain réchauffement et une taille de lot effective de 256 (`per_device_train_batch_size` * `gradient_accumulation_steps`). L'accumulation du gradient est utilisée lorsqu'un seul lot ne tient pas en mémoire, et construit le gradient de manière incrémentale à travers plusieurs passages avant/arrière. Nous verrons cela en action lorsque nous créerons la boucle d'entraînement avec 🤗 *Accelerate*.
+Tout ce qu'il reste à faire est de configurer les arguments d'entraînement et de lancer la fonction `Trainer`. Nous utiliserons un programme de taux d'apprentissage de type cosinus avec un réchauffement et une taille de batch de 256 (`per_device_train_batch_size` x `gradient_accumulation_steps`). L'accumulation du gradient est utilisée lorsqu'un seul batch ne tient pas en mémoire, et construit le gradient de manière incrémentale à travers plusieurs passages en avant/en arrière. Nous verrons cela en action lorsque nous créerons la boucle d'entraînement avec 🤗 *Accelerate*.
```py
from transformers import Trainer, TrainingArguments
@@ -452,13 +452,13 @@ trainer = Trainer(
)
```
-Maintenant, nous pouvons simplement lancer le `Trainer` et attendre que l'entraînement se termine. Selon que vous l'exécutez sur la totalité ou sur un sous-ensemble de l'ensemble d'entraînement, cela prendra respectivement 20 ou 2 heures, alors prenez quelques cafés et un bon livre à lire !
+Maintenant, nous pouvons simplement lancer le `Trainer` et attendre que l'entraînement se termine. Selon que vous l'exécutez sur la totalité ou sur un sous-ensemble de l'échantillon d'entraînement, cela prendra respectivement 20 ou 2 heures. Alors prenez quelques cafés et un bon livre à lire !
```py
trainer.train()
```
-Une fois l'entraînement terminé, nous pouvons pousser le modèle et le *tokenizer* vers le Hub :
+Une fois l'entraînement terminé, nous pouvons pousser le modèle et le *tokenizer* vers le *Hub* :
```py
trainer.push_to_hub()
@@ -466,7 +466,7 @@ trainer.push_to_hub()
{:else}
-Tout ce qu'il reste à faire est de configurer les hyperparamètres d'entraînement et d'appeler `compile()` et `fit()`. Nous utiliserons un programme de taux d'apprentissage avec un certain échauffement pour améliorer la stabilité de l'entraînement :
+Tout ce qu'il reste à faire est de configurer les hyperparamètres d'entraînement et d'appeler `compile()` et `fit()`. Nous utiliserons un programme de taux d'apprentissage avec un réchauffement pour améliorer la stabilité de l'entraînement :
```py
from transformers import create_optimizer
@@ -481,11 +481,11 @@ optimizer, schedule = create_optimizer(
)
model.compile(optimizer=optimizer)
-# Train in mixed-precision float16
+# Entraîner en mixed-precision float16
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```
-Maintenant, nous pouvons simplement appeler `model.fit()` et attendre que l'entraînement se termine. Selon que vous l'exécutez sur la totalité ou sur un sous-ensemble de l'ensemble d'entraînement, cela prendra respectivement 20 ou 2 heures, alors prenez quelques cafés et un bon livre à lire ! Une fois l'entraînement terminé, nous pouvons pousser le modèle et le *tokenizer* vers le *Hub* :
+Maintenant, nous pouvons simplement appeler `model.fit()` et attendre que l'entraînement se termine. Selon que vous l'exécutez sur la totalité ou sur un sous-ensemble de l'échantillon d'entraînement, cela prendra respectivement 20 ou 2 heures. Alors prenez quelques cafés et un bon livre à lire ! Une fois l'entraînement terminé, nous pouvons pousser le modèle et le *tokenizer* vers le *Hub* :
```py
from transformers.keras_callbacks import PushToHubCallback
@@ -499,7 +499,7 @@ model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback
-✏️ **Essayez** Il ne nous a fallu qu'une trentaine de lignes de code en plus des `TrainingArguments` pour passer des textes bruts à l'entraînement de GPT-2. Essayez-le avec votre propre jeu de données et voyez si vous pouvez obtenir de bons résultats !
+✏️ **Essayez !** Il ne nous a fallu qu'une trentaine de lignes de code en plus des `TrainingArguments` pour passer des textes bruts à l'entraînement du GPT-2. Essayez-le avec votre propre jeu de données et voyez si vous pouvez obtenir de bons résultats !
@@ -507,19 +507,19 @@ model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback
{#if fw === 'pt'}
-💡 Si vous avez accès à une machine avec plusieurs GPUs, essayez d'y exécuter le code. Le `Trainer` gère automatiquement plusieurs machines, et cela peut accélérer considérablement l'entraînement.
+💡 Si vous avez accès à une machine avec plusieurs GPUs, essayez d'y exécuter le code. `Trainer` gère automatiquement plusieurs machines ce qui peut accélérer considérablement l'entraînement.
{:else}
-💡 Si vous avez accès à une machine avec plusieurs GPU, vous pouvez essayer d'utiliser un contexte `MirroredStrategy` pour accélérer considérablement l'entraînement. Vous devrez créer un objet `tf.distribute.MirroredStrategy`, et vous assurer que les commandes `to_tf_dataset` ainsi que la création du modèle et l'appel à `fit()` sont tous exécutés dans son contexte `scope()`. Vous pouvez consulter la documentation à ce sujet [ici](https://www.tensorflow.org/guide/distributed_training#use_tfdistributestrategy_with_keras_modelfit).
+💡 Si vous avez accès à une machine avec plusieurs GPUs, vous pouvez essayer d'utiliser `MirroredStrategy` pour accélérer considérablement l'entraînement. Vous devrez créer un objet `tf.distribute.MirroredStrategy` et vous assurer que les commandes `to_tf_dataset` ainsi que la création du modèle et l'appel à `fit()` sont tous exécutés dans `scope()`. Vous pouvez consulter la documentation à ce sujet [ici](https://www.tensorflow.org/guide/distributed_training#use_tfdistributestrategy_with_keras_modelfit).
{/if}
-## Génération de code avec un pipeline
+## Génération de code avec le pipeline
-C'est maintenant le moment de vérité : voyons comment le modèle entraîné fonctionne réellement ! Nous pouvons voir dans les logs que la perte a diminué régulièrement, mais pour mettre le modèle à l'épreuve, regardons comment il fonctionne sur certains messages. Pour ce faire, nous allons envelopper le modèle dans une `pipeline` de génération de texte, et nous allons le mettre sur le GPU pour des générations rapides s'il y en a un de disponible :
+C'est maintenant le moment de vérité : voyons comment le modèle entraîné fonctionne réellement ! Nous pouvons voir dans les logs que la perte a diminué régulièrement, mais pour mettre le modèle à l'épreuve, regardons comment il fonctionne sur certains messages. Pour ce faire, nous allons envelopper le modèle dans un `pipeline` de génération de texte et, s'il y en a un de disponible, utiliser un GPU pour avoir des générations rapidement :
{#if fw === 'pt'}
@@ -600,7 +600,8 @@ txt = """\
# tableau de données avec profession, revenu et nom
df = pd.DataFrame({'profession': x, 'income':y, 'name': z})
-# calculer le revenu moyen par profession"""
+# calculer le revenu moyen par profession
+"""
print(pipe(txt, num_return_sequences=1)[0]["generated_text"])
```
@@ -612,7 +613,7 @@ df = pd.DataFrame({'profession': x, 'income':y, 'name': z})
profession = df.groupby(['profession']).mean()
```
-Pas mal, c'est la bonne façon de faire. Enfin, voyons si nous pouvons aussi l'utiliser pour `scikit-learn` et mettre en place un modèle *Random Forest* :
+Pas mal, c'est la bonne façon de faire. Enfin, voyons si nous pouvons aussi l'utiliser pour `scikit-learn` et utiliser un modèle *Random Forest* :
```py
txt = """
@@ -636,23 +637,23 @@ rf
{#if fw === 'tf'}
-Au vu de ces quelques exemples, il semble que le modèle ait appris une partie de la syntaxe de la pile Python pour la science des données. Bien sûr, nous devrions évaluer le modèle de manière plus approfondie avant de le déployer dans le monde réel, mais il s'agit tout de même d'un prototype impressionnant.
+Au vu de ces quelques exemples, il semble que le modèle ait appris une partie de la syntaxe des bibliothèques Python de science des données. Bien sûr, nous devrions évaluer le modèle de manière plus approfondie avant de le déployer dans le monde réel, mais il s'agit tout de même d'un prototype impressionnant.
{:else}
-Au vu de ces quelques exemples, il semble que le modèle ait appris une partie de la syntaxe de la pile de science des données Python (bien sûr, nous devrions l'évaluer de manière plus approfondie avant de déployer le modèle dans le monde réel). Cependant, il est parfois nécessaire de personnaliser davantage l'entraînement du modèle afin d'obtenir les performances nécessaires pour un cas d'utilisation donné. Par exemple, que se passe-t-il si l'on souhaite mettre à jour dynamiquement la taille du lot ou si l'on dispose d'une boucle d'entraînement conditionnelle qui ignore les mauvais exemples à la volée ? Une option serait de sous-classer le `Trainer` et d'ajouter les changements nécessaires, mais parfois il est plus simple d'écrire la boucle d'entraînement à partir de zéro. C'est là qu'intervient 🤗 *Accelerate*.
+Au vu de ces quelques exemples, il semble que le modèle ait appris une partie de la syntaxe des bibliothèques Python de science des données. Bien sûr, nous devrions évaluer le modèle de manière plus approfondie avant de le déployer dans le monde réel, mais il s'agit tout de même d'un prototype impressionnant. Parfois, il est nécessaire de personnaliser davantage l'entraînement du modèle afin d'obtenir les performances nécessaires pour un cas d'utilisation donné. Par exemple, que se passe-t-il si l'on souhaite mettre à jour dynamiquement la taille du batch ou si l'on dispose d'une boucle d'entraînement conditionnelle qui ignore les mauvais exemples à la volée ? Une option serait de sous-classer le `Trainer` et d'ajouter les changements nécessaires, mais parfois il est plus simple d'écrire la boucle d'entraînement à partir de zéro. C'est là qu'intervient 🤗 *Accelerate*.
{/if}
{#if fw === 'pt'}
-## Entraîner avec 🤗 *Accelerate*
+## Entraîner avec 🤗
Accelerate
-Nous avons vu comment entraîner un modèle avec le `Trainer`, qui peut permettre une certaine personnalisation. Cependant, parfois nous voulons un contrôle total sur la boucle d'entraînement, ou nous voulons faire quelques changements exotiques. Dans ce cas, 🤗 *Accelerate* est un excellent choix, et dans cette section, nous allons suivre les étapes pour l'utiliser pour entraîner notre modèle. Pour rendre les choses plus intéressantes, nous allons également ajouter une touche à la boucle d'entraînement.
+Nous avons vu comment entraîner un modèle avec le `Trainer`, qui permet une certaine personnalisation. Cependant, parfois nous voulons un contrôle total sur la boucle d'entraînement ou nous souhaitons faire quelques changements exotiques. Dans ce cas, 🤗 *Accelerate* est un excellent choix, et dans cette section, nous allons suivre les étapes pour l'utiliser pour entraîner notre modèle. Pour rendre les choses plus intéressantes, nous allons également ajouter une touche à la boucle d'entraînement.
-Puisque nous sommes principalement intéressés par l'autocomplétion sensible pour les bibliothèques de science des données, il est logique de donner plus de poids aux échantillons d'entraînement qui utilisent davantage ces bibliothèques. Nous pouvons facilement identifier ces exemples grâce à l'utilisation de mots-clés tels que `plt`, `pd`, `sk`, `fit`, et `predict`, qui sont les noms d'importation les plus fréquents pour `matplotlib.pyplot`, `pandas`, et `sklearn` ainsi que le modèle fit/predict de ce dernier. Si chacun d'entre eux est représenté par un seul token, nous pouvons facilement vérifier s'ils apparaissent dans la séquence d'entrée. Les *tokens* peuvent avoir un préfixe d'espacement, donc nous vérifierons aussi ces versions dans le vocabulaire du *tokenizer*. Pour vérifier que cela fonctionne, nous ajouterons un *token* de test qui devrait être divisé en plusieurs *tokens* :
+Puisque nous sommes principalement intéressés par l'autocomplétion pour les bibliothèques de science des données, il est logique de donner plus de poids aux échantillons d'entraînement qui utilisent davantage ces bibliothèques. Nous pouvons facilement identifier ces exemples grâce à l'utilisation de mots-clés tels que `plt`, `pd`, `sk`, `fit`, et `predict`, qui sont les noms d'importation les plus fréquents pour `matplotlib.pyplot`, `pandas`, et `sklearn` ainsi que les fonctions `fit` et `predict` de cette dernière. Si chacun d'entre eux est représenté par un seul *token*, nous pouvons facilement vérifier s'ils apparaissent dans la séquence d'entrée. Les *tokens* peuvent avoir un préfixe d'espacement, donc nous vérifierons aussi ces versions dans le vocabulaire du *tokenizer*. Pour vérifier que cela fonctionne, nous ajouterons un *token* de test qui devrait être divisé en plusieurs *tokens* :
```py
keytoken_ids = []
@@ -688,31 +689,31 @@ import torch
def keytoken_weighted_loss(inputs, logits, keytoken_ids, alpha=1.0):
- # Shift so that tokens < n predict n
+ # Décalage pour que tokens < n prédisent n
shift_labels = inputs[..., 1:].contiguous()
shift_logits = logits[..., :-1, :].contiguous()
- # Calculate per-token loss
+ # Calcul de la perte par token
loss_fct = CrossEntropyLoss(reduce=False)
loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
- # Resize and average loss per sample
+ # Redimensionnement et perte moyenne par échantillon
loss_per_sample = loss.view(shift_logits.size(0), shift_logits.size(1)).mean(axis=1)
- # Calculate and scale weighting
+ # Calculer et échelonner la pondération
weights = torch.stack([(inputs == kt).float() for kt in keytoken_ids]).sum(
axis=[0, 2]
)
weights = alpha * (1.0 + weights)
- # Calculate weighted average
+ # Calculer la moyenne pondérée
weighted_loss = (loss_per_sample * weights).mean()
return weighted_loss
```
-Avant de commencer à s'entraîner avec cette nouvelle fonction de perte géniale, nous devons préparer quelques éléments :
+Avant de commencer à entraîner avec cette nouvelle fonction de perte géniale, nous devons préparer quelques éléments :
-- nous avons besoin de chargeurs de données pour charger les données par lots.
-- nous devons définir les paramètres de décroissance du poids.
-- de temps en temps, nous voulons évaluer, il est donc logique d'envelopper le code d'évaluation dans une fonction.
+- Nous avons besoin de chargeurs de données pour charger les données par batch.
+- Nous devons définir les paramètres de décroissance des poids.
+- De temps en temps, nous voulons évaluer, il est donc logique d'envelopper le code d'évaluation dans une fonction.
-Commençons par les chargeurs de données. Nous avons seulement besoin de définir le format du jeu de données à `"torch"`, et ensuite nous pouvons le passer à un PyTorch `DataLoader` avec la taille de lot appropriée :
+Commençons par les chargeurs de données. Nous avons seulement besoin de définir le format du jeu de données à `"torch"` et ensuite nous pouvons le passer à un PyTorch `DataLoader` avec la taille de batch appropriée :
```py
from torch.utils.data.dataloader import DataLoader
@@ -722,7 +723,7 @@ train_dataloader = DataLoader(tokenized_dataset["train"], batch_size=32, shuffle
eval_dataloader = DataLoader(tokenized_dataset["valid"], batch_size=32)
```
-Ensuite, nous regroupons les paramètres de façon à ce que l'optimiseur sache lesquels bénéficieront d'une décroissance de poids supplémentaire. Habituellement, tous les termes de biais et de poids LayerNorm en sont exemptés ; voici comment nous pouvons le faire :
+Ensuite, nous regroupons les paramètres de façon à ce que l'optimiseur sache lesquels bénéficieront d'une décroissance de poids supplémentaire. Habituellement, tous les termes de biais et les poids de la *LayerNorm* en sont exemptés. Voici comment nous pouvons le faire :
```py
weight_decay = 0.1
@@ -741,7 +742,7 @@ def get_grouped_params(model, no_decay=["bias", "LayerNorm.weight"]):
]
```
-Puisque nous voulons évaluer le modèle régulièrement sur l'ensemble de validation pendant l'entraînement, écrivons une fonction pour cela aussi. Elle passe simplement par le dataloader d'évaluation et rassemble toutes les pertes à travers les processus :
+Puisque nous voulons évaluer le modèle régulièrement sur l'ensemble de validation pendant l'entraînement, écrivons une fonction pour cela aussi. Elle passe simplement par le *dataloader* d'évaluation et rassemble toutes les pertes à travers les processus :
```py
def evaluate():
@@ -760,13 +761,13 @@ def evaluate():
return loss.item(), perplexity.item()
```
-Avec la fonction `evaluate()` nous pouvons rapporter la perte et la [perplexité](/course/fr/chapter7/3) à intervalles réguliers. Ensuite, nous redéfinissons notre modèle pour nous assurer que nous nous entraînons à nouveau à partir de zéro :
+Avec la fonction `evaluate()` nous pouvons rapporter la perte et la [perplexité](/course/fr/chapter7/3) à intervalles réguliers. Ensuite, nous redéfinissons notre modèle pour nous assurer que nous entraînons à nouveau à partir de zéro :
```py
model = GPT2LMHeadModel(config)
```
-Nous pouvons ensuite définir notre optimiseur, en utilisant la fonction précédente pour diviser les paramètres de la décroissance du poids :
+Nous pouvons ensuite définir notre optimiseur, en utilisant la fonction précédente pour diviser les paramètres de décroissance des poids :
```py
from torch.optim import AdamW
@@ -788,11 +789,11 @@ model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare(
-🚨 Si vous vous entraînez sur un TPU, vous devrez déplacer tout le code commençant à la cellule ci-dessus dans une fonction d'entraînement dédiée. Voir le [Chapitre 3](/course/fr/chapter3) pour plus de détails.
+🚨 Si vous vous entraînez sur un TPU, vous devrez déplacer tout le code commençant à la cellule ci-dessus dans une fonction d'entraînement dédiée. Voir le [chapitre 3](/course/fr/chapter3) pour plus de détails.
-Maintenant que nous avons envoyé notre `train_dataloader` à `accelerator.prepare()`, nous pouvons utiliser sa longueur pour calculer le nombre d'étapes d'entraînement. Rappelez-vous que nous devons toujours faire cela après avoir préparé le dataloader, car cette méthode modifiera sa longueur. Nous utilisons un programme linéaire classique du taux d'apprentissage à 0 :
+Maintenant que nous avons envoyé notre `train_dataloader` à `accelerator.prepare()`, nous pouvons utiliser sa longueur pour calculer le nombre d'étapes d'entraînement. Rappelez-vous que nous devons toujours faire cela après avoir préparé le *dataloader* car cette méthode modifiera sa longueur. Nous utilisons un programme linéaire classique du taux d'apprentissage à 0 :
```py
num_train_epochs = 1
@@ -807,7 +808,7 @@ lr_scheduler = get_scheduler(
)
```
-Enfin, pour pousser notre modèle vers le Hub, nous aurons besoin de créer un objet `Repository` dans un dossier de travail. Tout d'abord, connectez-vous au *Hub*, si vous n'êtes pas déjà connecté. Nous déterminerons le nom du dépôt à partir de l'ID du modèle que nous voulons donner à notre modèle (n'hésitez pas à remplacer le `repo_name` par votre propre choix ; il doit juste contenir votre nom d'utilisateur, ce que fait la fonction `get_full_repo_name()`) :
+Enfin, pour pousser notre modèle vers le *Hub*, nous aurons besoin de créer un objet `Repository` dans un dossier de travail. Tout d'abord, connectez-vous au *Hub*, si vous n'êtes pas déjà connecté. Nous déterminerons le nom du dépôt à partir de l'identifiant du modèle que nous voulons donner à notre modèle (n'hésitez pas à remplacer le `repo_name` par votre propre choix. Il doit juste contenir votre nom d'utilisateur, ce que fait la fonction `get_full_repo_name()`) :
```py
from huggingface_hub import Repository, get_full_repo_name
@@ -821,7 +822,7 @@ repo_name
'sgugger/codeparrot-ds-accelerate'
```
-Ensuite, nous pouvons cloner ce référentiel dans un dossier local. S'il existe déjà, ce dossier local doit être un clone existant du référentiel avec lequel nous travaillons :
+Ensuite, nous pouvons cloner ce dépôt dans un dossier local. S'il existe déjà, ce dossier local doit être un clone existant du dépôt avec lequel nous travaillons :
```py
output_dir = "codeparrot-ds-accelerate"
@@ -840,7 +841,7 @@ evaluate()
(10.934126853942871, 56057.14453125)
```
-Ce sont des valeurs très élevées pour la perte et la perplexité, mais ce n'est pas surprenant puisque nous n'avons pas encore entraîné le modèle. Avec cela, nous avons tout préparé pour écrire la partie principale du script d'entraînement : la boucle d'entraînement. Dans la boucle d'entraînement, nous itérons sur le chargeur de données et transmettons les lots au modèle. Avec les logits, nous pouvons alors évaluer notre fonction de perte personnalisée. Nous mettons à l'échelle la perte par le nombre d'étapes d'accumulation du gradient afin de ne pas créer de plus grandes pertes en agrégeant plus d'étapes. Avant de procéder à l'optimisation, nous découpons également les gradients pour une meilleure convergence. Enfin, tous les quelques pas, nous évaluons le modèle sur l'ensemble d'évaluation avec notre nouvelle fonction `evaluate()` :
+Ce sont des valeurs très élevées pour la perte et la perplexité, mais ce n'est pas surprenant puisque nous n'avons pas encore entraîné le modèle. Avec cela, nous avons tout préparé pour écrire la partie principale du script d'entraînement : la boucle d'entraînement. Dans celle-ci, nous itérons sur le chargeur de données et transmettons les batchs au modèle. Avec les logits, nous pouvons alors évaluer notre fonction de perte personnalisée. Nous mettons à l'échelle la perte par le nombre d'étapes d'accumulation du gradient afin de ne pas créer de plus grandes pertes en agrégeant plus d'étapes. Avant de procéder à l'optimisation, nous découpons également les gradients pour une meilleure convergence. Enfin, tous les quelques pas, nous évaluons le modèle sur l'ensemble d'évaluation avec notre nouvelle fonction `evaluate()` :
```py
from tqdm.notebook import tqdm
@@ -887,17 +888,17 @@ for epoch in range(num_train_epochs):
)
```
-Et voilà, vous disposez maintenant de votre propre boucle d'entraînement personnalisée pour les modèles de langage causal tels que GPT-2, que vous pouvez encore adapter à vos besoins.
+Et voilà, vous disposez maintenant de votre propre boucle d'entraînement personnalisée pour les modèles de langage causal tels que le GPT-2. Vous pouvez encore l'adapter à vos besoins.
-✏️ **Essayez** Vous pouvez créer votre propre fonction de perte personnalisée, adaptée à votre cas d'utilisation, ou ajouter une autre étape personnalisée dans la boucle d'entraînement.
+✏️ **Essayez !** Vous pouvez créer votre propre fonction de perte personnalisée, adaptée à votre cas d'utilisation, ou ajouter une autre étape personnalisée dans la boucle d'entraînement.
-✏️ **Essayez** Lorsque vous effectuez de longues expériences d'entraînement, il est bon d'enregistrer les mesures importantes à l'aide d'outils tels que TensorBoard ou Weights & Biases. Ajoutez une journalisation appropriée à la boucle d'entraînement afin de pouvoir toujours vérifier comment se déroule l'entraînement.
+✏️ **Essayez !** Lorsque vous effectuez de longues expériences d'entraînement, il est bon d'enregistrer les mesures importantes à l'aide d'outils tels que *TensorBoard* ou *Weights & Biases*. Ajoutez l'un d'eux à la boucle d'entraînement afin de pouvoir toujours vérifier comment se déroule l'entraînement.
diff --git a/chapters/fr/chapter7/7.mdx b/chapters/fr/chapter7/7.mdx
index e301b1bac..359e84211 100644
--- a/chapters/fr/chapter7/7.mdx
+++ b/chapters/fr/chapter7/7.mdx
@@ -22,26 +22,26 @@
{/if}
-Il est temps de s'intéresser à la réponse aux questions ! Cette tâche peut prendre plusieurs formes, mais celle sur laquelle nous allons nous concentrer dans cette section est appelée réponse aux questions *extractives*. Il s'agit de poser des questions sur un document et d'identifier les réponses sous forme de "morceaux de texte" dans le document lui-même.
+Il est temps de s'intéresser à la réponse aux questions ! Cette tâche peut prendre plusieurs formes mais celle sur laquelle nous allons nous concentrer dans cette section est appelée réponse aux questions *extractives*. Il s'agit de poser des questions sur un document et d'identifier les réponses sous forme de « d'étendue de texte » dans le document lui-même.
-Nous allons affiner un modèle BERT sur le [jeu de données SQuAD](https://rajpurkar.github.io/SQuAD-explorer/), qui consiste en des questions posées par des *crowdworkers* sur un ensemble d'articles de Wikipedia. Cela nous donnera un modèle capable de calculer des prédictions comme celle-ci :
+Nous allons *finetuner* un modèle BERT sur le [jeu de données SQuAD](https://rajpurkar.github.io/SQuAD-explorer/), qui consiste en des questions posées par des *crowdworkers* sur un ensemble d'articles de Wikipedia. Cela nous donnera un modèle capable de calculer des prédictions comme celui-ci :
-Il s'agit en fait de la présentation du modèle qui a été entraîné et téléchargé sur le *Hub* à l'aide du code présenté dans cette section. Vous pouvez le trouver et vérifier les prédictions [ici](https://huggingface.co/huggingface-course/bert-finetuned-squad?context=%F0%9F%A4%97+Transformers+is+backed+by+the+three+most+popular+deep+learning+libraries+%E2%80%94+Jax%2C+PyTorch+and+TensorFlow+%E2%80%94+with+a+seamless+integration+between+them.+It%27s+straightforward+to+train+your+models+with+one+before+loading+them+for+inference+with+the+other.&question=Which+deep+learning+libraries+back+%F0%9F%A4%97+Transformers%3F)
+Il s'agit d'une présentation du modèle qui a été entraîné à l'aide du code présenté dans cette section et qui a ensuité été téléchargé sur le *Hub*. Vous pouvez le trouver [ici](https://huggingface.co/huggingface-course/bert-finetuned-squad?context=%F0%9F%A4%97+Transformers+is+backed+by+the+three+most+popular+deep+learning+libraries+%E2%80%94+Jax%2C+PyTorch+and+TensorFlow+%E2%80%94+with+a+seamless+integration+between+them.+It%27s+straightforward+to+train+your+models+with+one+before+loading+them+for+inference+with+the+other.&question=Which+deep+learning+libraries+back+%F0%9F%A4%97+Transformers%3F)
-💡 Les modèles à codeur unique comme BERT ont tendance à être excellents pour extraire les réponses à des questions factuelles comme "Qui a inventé l'architecture Transformer ?", mais ne sont pas très performants lorsqu'on leur pose des questions ouvertes comme "Pourquoi le ciel est-il bleu ?". Dans ces cas plus difficiles, les modèles encodeurs-décodeurs comme T5 et BART sont généralement utilisés pour synthétiser les informations d'une manière assez similaire au [résumé de texte](/cours/fr/chapter7/5). Si vous êtes intéressé par ce type de réponse aux questions *génératives*, nous vous recommandons de consulter notre [démo](https://yjernite.github.io/lfqa.html) basée sur le [jeu de données ELI5](https://huggingface.co/datasets/eli5).
+💡 Les modèles basé que sur l'encodeur comme BERT ont tendance à être excellents pour extraire les réponses à des questions factuelles comme « Qui a inventé l'architecture Transformer ? » mais ne sont pas très performants lorsqu'on leur pose des questions ouvertes comme « Pourquoi le ciel est-il bleu ? ». Dans ces cas plus difficiles, les modèles encodeurs-décodeurs comme le T5 et BART sont généralement utilisés pour synthétiser les informations d'une manière assez similaire au [résumé de texte](/course/fr/chapter7/5). Si vous êtes intéressé par ce type de réponse aux questions *génératives*, nous vous recommandons de consulter notre [démo](https://yjernite.github.io/lfqa.html) basée sur le [jeu de données ELI5](https://huggingface.co/datasets/eli5).
## Préparation des données
-Le jeu de données le plus utilisé comme référence académique pour la réponse extractive aux questions est [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/), c'est donc celui que nous utiliserons ici. Il existe également une référence plus difficile [SQuAD v2](https://huggingface.co/datasets/squad_v2), qui comprend des questions sans réponse. Tant que votre propre jeu de données contient une colonne pour les contextes, une colonne pour les questions et une colonne pour les réponses, vous devriez être en mesure d'adapter les étapes ci-dessous.
+Le jeu de données le plus utilisé comme référence académique pour la réponse extractive aux questions est [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/). C'est donc celui que nous utiliserons ici. Il existe également une version plus difficile [SQuAD v2](https://huggingface.co/datasets/squad_v2), qui comprend des questions sans réponse. Tant que votre propre jeu de données contient une colonne pour les contextes, une colonne pour les questions et une colonne pour les réponses, vous devriez être en mesure d'adapter les étapes ci-dessous.
### Le jeu de données SQuAD
@@ -53,7 +53,7 @@ from datasets import load_dataset
raw_datasets = load_dataset("squad")
```
-Nous pouvons alors jeter un coup d'œil à cet objet pour en savoir plus sur le jeu de données SQuAD :
+Nous pouvons jeter un coup d'œil à cet objet pour en savoir plus sur le jeu de données SQuAD :
```py
raw_datasets
@@ -72,7 +72,7 @@ DatasetDict({
})
```
-On dirait que nous avons tout ce dont nous avons besoin avec les champs `context`, `question` et `answers`, alors imprimons-les pour le premier élément de notre ensemble d'entraînement :
+On dirait que nous avons tout ce dont nous avons besoin avec les champs `context`, `question` et `answers`. Affichons-les pour le premier élément de notre ensemble d'entraînement :
```py
print("Context: ", raw_datasets["train"][0]["context"])
@@ -83,11 +83,12 @@ print("Answer: ", raw_datasets["train"][0]["answers"])
```python out
Context: 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.'
# Sur le plan architectural, l'école a un caractère catholique. Au sommet du dôme doré du bâtiment principal se trouve une statue dorée de la Vierge Marie. Immédiatement devant le bâtiment principal et face à lui, se trouve une statue en cuivre du Christ, les bras levés, avec la légende "Venite Ad Me Omnes". À côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basilique se trouve la Grotte, un lieu marial de prière et de réflexion. Il s'agit d'une réplique de la grotte de Lourdes, en France, où la Vierge Marie serait apparue à Sainte Bernadette Soubirous en 1858. Au bout de l'allée principale (et dans une ligne directe qui passe par 3 statues et le Dôme d'or), se trouve une statue de pierre simple et moderne de Marie'.
-Question: 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?' # A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes, en France ?
+Question: 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?'
+# A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes, en France ?
Answer: {'text': ['Saint Bernadette Soubirous'], 'answer_start': [515]}
```
-Les champs `context` et `question` sont très simples à utiliser. Le champ `answers` est un peu plus délicat car il compile un dictionnaire avec deux champs qui sont tous deux des listes. C'est le format qui sera attendu par la métrique `squad` lors de l'évaluation ; si vous utilisez vos propres données, vous n'avez pas nécessairement besoin de vous soucier de mettre les réponses dans le même format. Le champ `text` est assez évident, et le champ `answer_start` contient l'indice du caractère de départ de chaque réponse dans le contexte.
+Les champs `context` et `question` sont très simples à utiliser. Le champ `answers` est un peu plus délicat car il compile un dictionnaire avec deux champs qui sont tous deux des listes. C'est le format qui sera attendu par la métrique `squad` lors de l'évaluation. Si vous utilisez vos propres données, vous n'avez pas nécessairement besoin de vous soucier de mettre les réponses dans le même format. Le champ `text` est assez évident et le champ `answer_start` contient l'indice du caractère de départ de chaque réponse dans le contexte.
Pendant l'entraînement, il n'y a qu'une seule réponse possible. Nous pouvons vérifier cela en utilisant la méthode `Dataset.filter()` :
@@ -114,7 +115,7 @@ print(raw_datasets["validation"][2]["answers"])
{'text': ['Santa Clara, California', "Levi's Stadium", "Levi's Stadium in the San Francisco Bay Area at Santa Clara, California."], 'answer_start': [403, 355, 355]}
```
-Nous ne nous plongerons pas dans le script d'évaluation car tout sera enveloppé par une métrique 🤗 *Datasets* pour nous, mais la version courte est que certaines des questions ont plusieurs réponses possibles, et ce script va comparer une réponse prédite à toutes les réponses acceptables et prendre le meilleur score. Si nous regardons l'échantillon de l'indice 2, par exemple :
+Nous ne nous plongerons pas dans le script d'évaluation car tout sera enveloppé pour nous par une métrique de 🤗 *Datasets*. La version courte est que certaines des questions ont plusieurs réponses possibles, et ce script va comparer une réponse prédite à toutes les réponses acceptables et prendre le meilleur score. Par exemple, si nous regardons l'échantillon de l'indice 2 :
```py
print(raw_datasets["validation"][2]["context"])
@@ -124,7 +125,8 @@ print(raw_datasets["validation"][2]["question"])
```python out
'Super Bowl 50 was an American football game to determine the champion of the National Football League (NFL) for the 2015 season. The American Football Conference (AFC) champion Denver Broncos defeated the National Football Conference (NFC) champion Carolina Panthers 24–10 to earn their third Super Bowl title. The game was played on February 7, 2016, at Levi\'s Stadium in the San Francisco Bay Area at Santa Clara, California. As this was the 50th Super Bowl, the league emphasized the "golden anniversary" with various gold-themed initiatives, as well as temporarily suspending the tradition of naming each Super Bowl game with Roman numerals (under which the game would have been known as "Super Bowl L"), so that the logo could prominently feature the Arabic numerals 50.'
# Le Super Bowl 50 était un match de football américain visant à déterminer le champion de la National Football League (NFL) pour la saison 2015. Les Denver Broncos, champions de la Conférence de football américain (AFC), ont battu les Carolina Panthers, champions de la Conférence nationale de football (NFC), 24 à 10, pour remporter leur troisième titre de Super Bowl. Le match s'est déroulé le 7 février 2016 au Levi\'s Stadium, dans la baie de San Francisco, à Santa Clara, en Californie. Comme il s'agissait du 50e Super Bowl, la ligue a mis l'accent sur l'" anniversaire doré " avec diverses initiatives sur le thème de l'or, ainsi qu'en suspendant temporairement la tradition de nommer chaque match du Super Bowl avec des chiffres romains (en vertu de laquelle le match aurait été appelé " Super Bowl L "), afin que le logo puisse mettre en évidence les chiffres arabes 50.''
-'Where did Super Bowl 50 take place?' # Où a eu lieu le Super Bowl 50 ?
+'Where did Super Bowl 50 take place?'
+# Où a eu lieu le Super Bowl 50 ?
```
nous pouvons voir que la réponse peut effectivement être l'une des trois possibilités que nous avons vues précédemment.
@@ -133,9 +135,9 @@ nous pouvons voir que la réponse peut effectivement être l'une des trois possi
-Commençons par le prétraitement des données d'entraînement. La partie la plus difficile sera de générer des étiquettes pour la réponse à la question, qui seront les positions de début et de fin des *tokens* correspondant à la réponse dans le contexte.
+Commençons par le prétraitement des données d'entraînement. La partie la plus difficile est de générer des étiquettes pour la réponse à la question, c'est-à-dire les positions de début et de fin des *tokens* correspondant à la réponse dans le contexte.
-Mais ne nous emballons pas. Tout d'abord, nous devons convertir le texte de l'entrée en identifiants que le modèle peut comprendre, en utilisant un *tokenizer* :
+Mais ne nous emballons pas. Tout d'abord, à l'aide d'un *tokenizer*, nous devons convertir le texte d'entrée en identifiants que le modèle peut comprendre :
```py
from transformers import AutoTokenizer
@@ -144,7 +146,7 @@ model_checkpoint = "bert-base-cased"
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```
-Comme mentionné précédemment, nous allons *finetuner* un modèle BERT, mais vous pouvez utiliser n'importe quel autre type de modèle tant qu'il a un *tokenizer* rapide implémenté. Vous pouvez voir toutes les architectures qui sont livrées avec une version rapide dans [ce grand tableau](https://huggingface.co/transformers/#supported-frameworks), et pour vérifier que l'objet `tokenizer` que vous utilisez est bien soutenu par des 🤗 *Tokenizers* vous pouvez regarder son attribut `is_fast` :
+Comme mentionné précédemment, nous allons *finetuner* un modèle BERT, mais vous pouvez utiliser n'importe quel autre type de modèle tant qu'il a un *tokenizer* rapide implémenté. Vous pouvez voir toutes les architectures qui sont livrées avec un *tokenizer* rapide dans [ce tableau](https://huggingface.co/transformers/#supported-frameworks), et pour vérifier que l'objet `tokenizer` que vous utilisez est bien soutenu par 🤗 *Tokenizers* vous pouvez regarder son attribut `is_fast` :
```py
tokenizer.is_fast
@@ -154,7 +156,7 @@ tokenizer.is_fast
True
```
-Nous pouvons transmettre à notre *tokenizer* la question et le contexte ensemble, et il insérera correctement les *tokens* spéciaux pour former une phrase comme celle-ci :
+Nous pouvons transmettre à notre *tokenizer* la question et le contexte ensemble. Il insérera correctement les *tokens* spéciaux pour former une phrase comme celle-ci :
```
[CLS] question [SEP] context [SEP]
@@ -181,30 +183,30 @@ tokenizer.decode(inputs["input_ids"])
'and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]'
'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [SEP] Architecturalement, '
-l'école a un caractère catholique. Au sommet du dôme doré du bâtiment principal se trouve une statue dorée de la Vierge '
-Marie. Immédiatement devant le bâtiment principal et face à lui, se trouve une statue en cuivre du Christ, les bras ''levés''.
-'levés avec la légende " Venite Ad Me Omnes ". A côté du bâtiment principal se trouve la basilique du Sacré-Cœur.
+'l école a un caractère catholique. Au sommet du dôme doré du bâtiment principal se trouve une statue dorée de la Vierge '
+'Marie. Immédiatement devant le bâtiment principal et face à lui, se trouve une statue en cuivre du Christ, les bras '
+'levés avec la légende " Venite Ad Me Omnes ". A côté du bâtiment principal se trouve la basilique du Sacré '
'Cœur. Immédiatement derrière la basilique se trouve la Grotte, un lieu marial de prière et de réflexion. Il s'agit d'une '
'réplique de la grotte de Lourdes, en France, où la Vierge Marie serait apparue à Sainte Bernadette '
-Soubirous en 1858. Au bout de l'allée principale ( et en ligne directe qui passe par 3 statues '
-'et le Dôme d'or), se trouve une statue de Marie en pierre, simple et moderne. [SEP]''
+'Soubirous en 1858. Au bout de l'allée principale ( et en ligne directe qui passe par 3 statues '
+'et le Dôme d'or), se trouve une statue de Marie en pierre, simple et moderne. [SEP]'
```
-Les étiquettes seront alors l'index des *tokens* de début et de fin de la réponse, et le modèle sera chargé de prédire un logit de début et de fin par *token* dans l'entrée, les étiquettes théoriques étant les suivantes :
+Les étiquettes sont l'index des *tokens* de début et de fin de la réponse. Le modèle sera chargé de prédire dans l'entrée un logit de début et de fin par *token*, les étiquettes théoriques étant les suivantes :
-Dans ce cas, le contexte n'est pas trop long, mais certains des exemples de l'ensemble de données ont des contextes très longs qui dépasseront la longueur maximale que nous avons fixée (qui est de 384 dans ce cas). Comme nous l'avons vu dans le [Chapitre 6](/course/fr/chapter6/4) lorsque nous avons exploré les internes du pipeline `question-answering`, nous allons traiter les contextes longs en créant plusieurs caractéristiques d'entraînement à partir d'un échantillon de notre jeu de données, avec une fenêtre glissante entre eux.
+Dans ce cas, le contexte n'est pas trop long, mais certains des exemples du jeu de données ont des contextes très longs qui dépasseront la longueur maximale que nous avons fixée (qui est de 384 dans ce cas). Comme nous l'avons vu dans le [chapitre 6](/course/fr/chapter6/4) lorsque nous avons exploré le pipeline de `question-answering`, nous allons traiter les contextes longs en créant plusieurs caractéristiques d'entraînement à partir d'un échantillon de notre jeu de données et avec une fenêtre glissante entre eux.
-Pour voir comment cela fonctionne en utilisant l'exemple actuel, nous pouvons limiter la longueur à 100 et utiliser une fenêtre glissante de 50 *tokens*. Pour rappel, nous utilisons
+Pour voir comment cela fonctionne sur notre exemple, nous pouvons limiter la longueur à 100 et utiliser une fenêtre glissante de 50 *tokens*. Pour rappel, nous utilisons :
- `max_length` pour définir la longueur maximale (ici 100)
- `truncation="only_second"` pour tronquer le contexte (qui est en deuxième position) quand la question avec son contexte est trop longue
- `stride` pour fixer le nombre de *tokens* se chevauchant entre deux morceaux successifs (ici 50)
-- `return_overflowing_tokens=True` pour indiquer au tokenizer que l'on veut les *tokens* qui débordent
+- `return_overflowing_tokens=True` pour indiquer au *tokenizer* que l'on veut les *tokens* qui débordent
```py
inputs = tokenizer(
@@ -222,21 +224,21 @@ for ids in inputs["input_ids"]:
```python out
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basi [SEP]'
-'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [SEP] Sur le plan architectural, l'école a un caractère catholique. Au sommet du dôme doré du bâtiment principal se trouve une statue dorée de la Vierge Marie. Immédiatement devant le bâtiment principal et face à lui, se trouve une statue en cuivre du Christ, les bras levés, avec la légende " Venite Ad Me Omnes ". À côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basi [SEP]''.
+'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [SEP] Sur le plan architectural, l école a un caractère catholique. Au sommet du dôme doré du bâtiment principal se trouve une statue dorée de la Vierge Marie. Immédiatement devant le bâtiment principal et face à lui, se trouve une statue en cuivre du Christ, les bras levés, avec la légende " Venite Ad Me Omnes ". À côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basi [SEP]'
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin [SEP]'
-'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [le bâtiment principal et face à lui, une statue en cuivre du Christ aux bras levés avec la légende " Venite Ad Me Omnes ". À côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basilique se trouve la Grotte, un lieu marial de prière et de réflexion. Il s'agit d'une réplique de la grotte de Lourdes, en France, où la Vierge [SEP]''.
+'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [SEP] le bâtiment principal et face à lui, une statue en cuivre du Christ aux bras levés avec la légende " Venite Ad Me Omnes ". À côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basilique se trouve la Grotte, un lieu marial de prière et de réflexion. Il s agit d'une réplique de la grotte de Lourdes, en France, où la Vierge [SEP]'
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 [SEP]'
-'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [A côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basilique se trouve la Grotte, un lieu marial de prière et de réflexion. Il s'agit d'une réplique de la grotte de Lourdes, en France, où la Vierge Marie serait apparue à Sainte Bernadette Soubirous en 1858. Au bout de l'allée principale ( et dans une ligne directe qui relie par 3 [SEP]''.
+'[CLS] A qui la Vierge Marie serait-elle apparue en 1858 à Lourdes en France ? [SEP] A côté du bâtiment principal se trouve la basilique du Sacré-Cœur. Immédiatement derrière la basilique se trouve la Grotte, un lieu marial de prière et de réflexion. Il s agit d une réplique de la grotte de Lourdes, en France, où la Vierge Marie serait apparue à Sainte Bernadette Soubirous en 1858. Au bout de l allée principale ( et dans une ligne directe qui relie par 3 [SEP]'
'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP]. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]'
-'[CLS] A qui la Vierge Marie est-elle prétendument apparue en 1858 à Lourdes France ? [SEP]. Il s'agit d'une réplique de la grotte de Lourdes, en France, où la Vierge Marie serait apparue à Sainte Bernadette Soubirous en 1858. Au bout de l'allée principale (et dans une ligne directe qui passe par 3 statues et le Dôme d'or), se trouve une simple statue de pierre moderne de Marie. [SEP]'
+'[CLS] A qui la Vierge Marie est-elle prétendument apparue en 1858 à Lourdes France ? [SEP]. Il s agit d une réplique de la grotte de Lourdes, en France, où la Vierge Marie serait apparue à Sainte Bernadette Soubirous en 1858. Au bout de l allée principale (et dans une ligne directe qui passe par 3 statues et le Dôme d or), se trouve une simple statue de pierre moderne de Marie. [SEP]'
```
-Comme nous pouvons le voir, notre exemple a été divisé en quatre entrées, chacune d'entre elles contenant la question et une partie du contexte. Notez que la réponse à la question ("Bernadette Soubirous") n'apparaît que dans la troisième et dernière entrée, donc en traitant les longs contextes de cette façon, nous allons créer quelques exemples d'entraînement où la réponse n'est pas incluse dans le contexte. Pour ces exemples, les étiquettes seront `start_position = end_position = 0` (donc nous prédisons le *token* `[CLS]`). Nous définirons également ces étiquettes dans le cas malheureux où la réponse a été tronquée de sorte que nous n'avons que le début (ou la fin) de celle-ci. Pour les exemples où la réponse est entièrement dans le contexte, les étiquettes seront l'index du *token* où la réponse commence et l'index du *token* où la réponse se termine.
+Comme nous pouvons le voir, notre exemple a été divisé en quatre entrées, chacune d'entre elles contenant la question et une partie du contexte. Notez que la réponse à la question (« Bernadette Soubirous ») n'apparaît que dans la troisième et la dernière entrée. Donc en traitant les longs contextes de cette façon, nous allons créer quelques exemples d'entraînement où la réponse n'est pas incluse dans le contexte. Pour ces exemples, les étiquettes seront `start_position = end_position = 0` (donc nous prédisons le *token* `[CLS]`). Nous définirons également ces étiquettes dans le cas malheureux où la réponse a été tronquée de sorte que nous n'avons que le début (ou la fin) de celle-ci. Pour les exemples où la réponse est entièrement dans le contexte, les étiquettes seront l'index du *token* où la réponse commence et l'index du *token* où la réponse se termine.
-L'ensemble de données nous fournit le caractère de début de la réponse dans le contexte, et en ajoutant la longueur de la réponse, nous pouvons trouver le caractère de fin dans le contexte. Pour faire correspondre ces indices aux *tokens*, nous devrons utiliser les mappages d'offset que nous avons étudiés au [Chapitre 6](/course/chapter6/4). Nous pouvons faire en sorte que notre *tokenizer* renvoie ces index en passant `return_offsets_mapping=True` :
+Le jeu de données nous fournit le caractère de début de la réponse dans le contexte, et en ajoutant la longueur de la réponse, nous pouvons trouver le caractère de fin dans le contexte. Pour faire correspondre ces indices aux *tokens*, nous devrons utiliser les correspondances *offset* que nous avons étudiés au [chapitre 6](/course/fr/chapter6/4). Nous pouvons faire en sorte que notre *tokenizer* renvoie ces index en passant `return_offsets_mapping=True` :
```py
inputs = tokenizer(
@@ -255,7 +257,7 @@ inputs.keys()
dict_keys(['input_ids', 'token_type_ids', 'attention_mask', 'offset_mapping', 'overflow_to_sample_mapping'])
```
-Comme nous pouvons le voir, nous récupérons les habituels ID d'entrée, ID de type de jeton, et masque d'attention, ainsi que le mappage d'offset dont nous avions besoin et une clé supplémentaire, `overflow_to_sample_mapping`. La valeur correspondante nous sera utile lorsque nous tokeniserons plusieurs textes en même temps (ce que nous devrions faire pour bénéficier du fait que notre *tokenizer* est soutenu par Rust). Puisqu'un échantillon peut donner plusieurs caractéristiques, il fait correspondre chaque caractéristique à l'exemple d'où elle provient. Parce qu'ici nous avons seulement tokenisé un exemple, nous obtenons une liste de `0`s :
+Comme nous pouvons le voir, nous récupérons les identifiants d'entrée, les *tokens* de type identifiant, le masque d'attention, ainsi que la correspondance *offset* dont nous avions besoin et une clé supplémentaire, `overflow_to_sample_mapping`. La valeur correspondante nous sera utile lorsque nous tokeniserons plusieurs textes en même temps (ce que nous devrions faire pour bénéficier du fait que notre *tokenizer* est en Rust). Puisqu'un échantillon peut donner plusieurs caractéristiques, il fait correspondre chaque caractéristique à l'exemple d'où elle provient. Parce qu'ici nous avons seulement tokenisé un exemple, nous obtenons une liste de `0` :
```py
inputs["overflow_to_sample_mapping"]
@@ -265,7 +267,7 @@ inputs["overflow_to_sample_mapping"]
[0, 0, 0, 0]
```
-Mais si nous tokenisons plus d'exemples, cela deviendra plus utile :
+Mais si nous tokenisons davantage d'exemples, cela deviendra plus utile :
```py
inputs = tokenizer(
@@ -292,11 +294,11 @@ Comme nous pouvons le voir, les trois premiers exemples (aux indices 2, 3 et 4 d
Ces informations seront utiles pour associer chaque caractéristique obtenue à son étiquette correspondante. Comme mentionné précédemment, ces étiquettes sont :
- `(0, 0)` si la réponse n'est pas dans l'espace correspondant du contexte.
-- `(start_position, end_position)` si la réponse est dans l'espace correspondant du contexte, avec `start_position` étant l'index du *token* (dans les IDs d'entrée) au début de la réponse et `end_position` étant l'index du *token* (dans les IDs d'entrée) où la réponse se termine.
+- `(start_position, end_position)` si la réponse est dans l'espace correspondant du contexte, avec `start_position` étant l'index du *token* (dans les identifiants d'entrée) au début de la réponse et `end_position` étant l'index du *token* (dans les identifiants d'entrée) où la réponse se termine.
-Pour déterminer ce qui est le cas et, le cas échéant, les positions des *tokens*, nous trouvons d'abord les indices qui commencent et finissent le contexte dans les IDs d'entrée. Nous pourrions utiliser les IDs du type de *token* pour le faire, mais puisque ceux-ci n'existent pas nécessairement pour tous les modèles (DistilBERT ne les requiert pas, par exemple), nous allons plutôt utiliser la méthode `sequence_ids()` du `BatchEncoding` que notre tokenizer retourne.
+Pour déterminer ce qui est le cas et, le cas échéant, les positions des *tokens*, nous trouvons d'abord les indices qui commencent et finissent le contexte dans les identifiants d'entrée. Nous pourrions utiliser les *tokens* de type identifiants pour le faire, mais puisque ceux-ci n'existent pas nécessairement pour tous les modèles (DistilBERT ne les requiert pas par exemple), nous allons plutôt utiliser la méthode `sequence_ids()` du `BatchEncoding` que notre *tokenizer* retourne.
-Une fois que nous avons ces indices de *tokens*, nous regardons les offsets correspondants, qui sont des tuples de deux entiers représentant l'étendue des caractères dans le contexte original. Nous pouvons ainsi détecter si le *chunk* du contexte dans cette fonctionnalité commence après la réponse ou se termine avant que la réponse ne commence (dans ce cas, l'étiquette est `(0, 0)`). Si ce n'est pas le cas, nous bouclons pour trouver le premier et le dernier *token* de la réponse :
+Une fois que nous avons ces indices de *tokens*, nous regardons les *offsets* correspondants, qui sont des *tuples* de deux entiers représentant l'étendue des caractères dans le contexte original. Nous pouvons ainsi détecter si le morceau de contexte dans cette fonctionnalité commence après la réponse ou se termine avant que la réponse ne commence (dans ce cas, l'étiquette est `(0, 0)`). Si ce n'est pas le cas, nous bouclons pour trouver le premier et le dernier *token* de la réponse :
```py
answers = raw_datasets["train"][2:6]["answers"]
@@ -319,12 +321,12 @@ for i, offset in enumerate(inputs["offset_mapping"]):
idx += 1
context_end = idx - 1
- # Si la réponse n'est pas entièrement dans le contexte, l'étiquette est (0, 0).
+ # Si la réponse n'est pas entièrement dans le contexte, l'étiquette est (0, 0)
if offset[context_start][0] > start_char or offset[context_end][1] < end_char:
start_positions.append(0)
end_positions.append(0)
else:
- # Otherwise it's the start and end token positions
+ # Sinon, ce sont les positions de début et de fin du token
idx = context_start
while idx <= context_end and offset[idx][0] <= start_char:
idx += 1
@@ -343,7 +345,7 @@ start_positions, end_positions
[85, 53, 21, 0, 0, 70, 33, 0, 40, 0, 0, 0, 68, 35, 0, 0, 0, 0, 0])
```
-Jetons un coup d'œil à quelques résultats pour vérifier que notre approche est correcte. Pour la première caractéristique, nous trouvons `(83, 85)` comme étiquettes, alors comparons la réponse théorique avec l'étendue décodée des *tokens* de 83 à 85 (inclus) :
+Jetons un coup d'œil à quelques résultats pour vérifier que notre approche est correcte. Pour la première caractéristique, nous trouvons `(83, 85)` comme étiquettes. Comparons alors la réponse théorique avec l'étendue décodée des *tokens* de 83 à 85 (inclus) :
```py
idx = 0
@@ -361,7 +363,7 @@ print(f"Theoretical answer: {answer}, labels give: {labeled_answer}")
'Theoretical answer: the Main Building, labels give: the Main Building'
```
-Donc, c'est une correspondance ! Maintenant, vérifions l'index 4, où nous avons mis les étiquettes à `(0, 0)`, ce qui signifie que la réponse n'est pas dans le *chunk* de contexte de cette caractéristique :
+Cela correspond ! Maintenant vérifions l'index 4, où nous avons mis les étiquettes à `(0, 0)`, signifiant que la réponse n'est pas dans le morceau de contexte de cette caractéristique :
```py
idx = 4
@@ -384,7 +386,7 @@ En effet, nous ne voyons pas la réponse dans le contexte.
-Maintenant que nous avons vu étape par étape comment prétraiter nos données d'entraînement, nous pouvons les regrouper dans une fonction que nous appliquerons à l'ensemble des données d'entraînement. Nous allons rembourrer chaque caractéristique à la longueur maximale que nous avons définie, car la plupart des contextes seront longs (et les échantillons correspondants seront divisés en plusieurs caractéristiques), il n'y a donc pas de réel avantage à appliquer un rembourrage dynamique ici :
+Maintenant que nous avons vu étape par étape comment prétraiter nos données d'entraînement, nous pouvons les regrouper dans une fonction que nous appliquerons à l'ensemble des données d'entraînement. Nous allons rembourrer chaque caractéristique à la longueur maximale que nous avons définie, car la plupart des contextes seront longs (et les échantillons correspondants seront divisés en plusieurs caractéristiques). Il n'y a donc pas de réel avantage à appliquer un rembourrage dynamique ici :
```py
max_length = 384
@@ -426,12 +428,12 @@ def preprocess_training_examples(examples):
idx += 1
context_end = idx - 1
- # Si la réponse n'est pas entièrement dans le contexte, l'étiquette est (0, 0).
+ # Si la réponse n'est pas entièrement dans le contexte, l'étiquette est (0, 0)
if offset[context_start][0] > start_char or offset[context_end][1] < end_char:
start_positions.append(0)
end_positions.append(0)
else:
- # Otherwise it's the start and end token positions
+ # Sinon, ce sont les positions de début et de fin du token
idx = context_start
while idx <= context_end and offset[idx][0] <= start_char:
idx += 1
@@ -447,9 +449,9 @@ def preprocess_training_examples(examples):
return inputs
```
-Notez que nous avons défini deux constantes pour déterminer la longueur maximale utilisée ainsi que la longueur de la fenêtre glissante, et que nous avons ajouté un petit nettoyage avant la tokénisation : certaines des questions dans le jeu de données SQuAD ont des espaces supplémentaires au début et à la fin qui n'ajoutent rien (et prennent de la place lors de la tokénisation si vous utilisez un modèle comme RoBERTa), donc nous avons supprimé ces espaces supplémentaires.
+Notez que nous avons défini deux constantes pour déterminer la longueur maximale utilisée ainsi que la longueur de la fenêtre glissante, et que nous avons ajouté un petit nettoyage avant la tokénisation : certaines des questions dans SQuAD ont des espaces supplémentaires au début et à la fin qui n'ajoutent rien (et prennent de la place lors de la tokénisation si vous utilisez un modèle comme RoBERTa), donc nous avons supprimé ces espaces supplémentaires.
-Pour appliquer cette fonction à l'ensemble de l'entraînement, nous utilisons la méthode `Dataset.map()` avec le flag `batched=True`. C'est nécessaire ici car nous changeons la longueur de l'ensemble de données (puisqu'un exemple peut donner plusieurs caractéristiques d'entraînement) :
+Pour appliquer cette fonction à l'ensemble de l'entraînement, nous utilisons la méthode `Dataset.map()` avec le flag `batched=True`. C'est nécessaire ici car nous changeons la longueur du jeu de données (puisqu'un exemple peut donner plusieurs caractéristiques d'entraînement) :
```py
train_dataset = raw_datasets["train"].map(
@@ -464,13 +466,13 @@ len(raw_datasets["train"]), len(train_dataset)
(87599, 88729)
```
-Comme nous pouvons le voir, le prétraitement a ajouté environ 1 000 caractéristiques. Notre ensemble d'entraînement est maintenant prêt à être utilisé - passons au prétraitement de l'ensemble de validation !
+Comme nous pouvons le voir, le prétraitement a ajouté environ 1 000 caractéristiques. Notre ensemble d'entraînement est maintenant prêt à être utilisé. Passons au prétraitement de l'ensemble de validation !
### Traitement des données de validation
-Le prétraitement des données de validation sera légèrement plus facile car nous n'avons pas besoin de générer des étiquettes (sauf si nous voulons calculer une perte de validation, mais ce nombre ne nous aidera pas vraiment à comprendre la qualité du modèle). La vraie joie sera d'interpréter les prédictions du modèle dans des étendues du contexte original. Pour cela, il nous suffit de stocker les mappages de décalage et un moyen de faire correspondre chaque caractéristique créée à l'exemple original dont elle provient. Puisqu'il y a une colonne ID dans l'ensemble de données original, nous utiliserons cet ID.
+Le prétraitement des données de validation sera légèrement plus facile car nous n'avons pas besoin de générer des étiquettes (sauf si nous voulons calculer une perte de validation, mais elle ne nous aidera pas vraiment à comprendre la qualité du modèle). Le réel plaisir sera d'interpréter les prédictions du modèle dans des étendues du contexte original. Pour cela, il nous suffit de stocker les correspondances d'*offset* et un moyen de faire correspondre chaque caractéristique créée à l'exemple original dont elle provient. Puisqu'il y a une colonne identifiant dans le jeu de données original, nous l'utiliserons.
-La seule chose que nous allons ajouter ici est un petit nettoyage des mappages de décalage. Ils contiendront les offsets pour la question et le contexte, mais une fois que nous serons dans la phase de post-traitement, nous n'aurons aucun moyen de savoir quelle partie des IDs d'entrée correspondait au contexte et quelle partie était la question (la méthode `sequence_ids()` que nous avons utilisée n'est disponible que pour la sortie du *tokenizer*). Donc, nous allons mettre les offsets correspondant à la question à `None` :
+La seule chose que nous allons ajouter ici est un petit nettoyage des correspondances d'*offset*. Elles contiendront les *offsets* pour la question et le contexte, mais une fois que nous serons à la phase de post-traitement, nous n'aurons aucun moyen de savoir quelle partie des identifiants d'entrée correspondait au contexte et quelle partie était la question (la méthode `sequence_ids()` que nous avons utilisée n'est disponible que pour la sortie du *tokenizer*). Donc, nous allons mettre les *offsets* correspondant à la question à `None` :
```py
def preprocess_validation_examples(examples):
@@ -503,7 +505,7 @@ def preprocess_validation_examples(examples):
return inputs
```
-Nous pouvons appliquer cette fonction sur l'ensemble des données de validation comme précédemment :
+Nous pouvons appliquer cette fonction sur l'ensemble de validation comme précédemment :
```py
validation_dataset = raw_datasets["validation"].map(
@@ -518,21 +520,21 @@ len(raw_datasets["validation"]), len(validation_dataset)
(10570, 10822)
```
-Dans ce cas, nous n'avons ajouté que quelques centaines d'échantillons, il semble donc que les contextes dans l'ensemble de données de validation soient un peu plus courts.
+Dans ce cas, nous n'avons ajouté que quelques centaines d'échantillons, il semble donc que les contextes dans l'ensemble de validation soient un peu plus courts.
Maintenant que nous avons prétraité toutes les données, nous pouvons passer à l'entraînement.
{#if fw === 'pt'}
-## *Finetuner* le modèle avec l'API `Trainer`
+##
Finetuner le modèle avec l'API `Trainer`
-Le code d'entraînement pour cet exemple ressemblera beaucoup au code des sections précédentes -- la chose la plus difficile sera d'écrire la fonction `compute_metrics()`. Puisque nous avons capitonné tous les échantillons à la longueur maximale que nous avons fixée, il n'y a pas de collateur de données à définir, donc ce calcul de métrique est vraiment la seule chose dont nous devons nous soucier. La partie la plus difficile sera de post-traiter les prédictions du modèle en travées de texte dans les exemples originaux ; une fois que nous aurons fait cela, la métrique de la bibliothèque 🤗 *Datasets* fera le gros du travail pour nous.
+Le code d'entraînement pour cet exemple ressemblera beaucoup au code des sections précédentes mais le calcul de la métrique avec la fonction `compute_metrics()` sera un défi unique. Puisque nous avons rembourré tous les échantillons à la longueur maximale que nous avons définie, il n'y a pas de collateur de données à définir. Ainsi le calcul de la métrique est vraiment la seule chose dont nous devons nous soucier. La partie la plus difficile sera de post-traiter les prédictions du modèle en étendues de texte dans les exemples originaux. Une fois que nous aurons fait cela, la métrique de la bibliothèque 🤗 *Datasets* fera le gros du travail pour nous.
{:else}
-## *Finetuner* fin du modèle avec Keras
+##
Finetuner fin du modèle avec Keras
-Le code d'entraînement de cet exemple ressemblera beaucoup au code des sections précédentes, mais le calcul des métriques sera un défi unique. Puisque nous avons capitonné tous les échantillons à la longueur maximale que nous avons définie, il n'y a pas de collateur de données à définir, donc le calcul de la métrique est vraiment la seule chose dont nous devons nous soucier. La partie la plus difficile sera de post-traiter les prédictions du modèle en travées de texte dans les exemples originaux ; une fois que nous aurons fait cela, la métrique de la bibliothèque 🤗 *Datasets* fera le gros du travail pour nous.
+Le code d'entraînement de cet exemple ressemblera beaucoup au code des sections précédentes, mais le calcul de la métrique sera un défi unique. Puisque nous avons rembourré tous les échantillons à la longueur maximale que nous avons définie, il n'y a pas de collateur de données à définir. Ainsi le calcul de la métrique est vraiment la seule chose dont nous devons nous soucier. La partie la plus difficile sera de post-traiter les prédictions du modèle en étendues de texte dans les exemples originaux. Une fois que nous aurons fait cela, la métrique de la bibliothèque 🤗 *Datasets* fera le gros du travail pour nous.
{/if}
@@ -548,16 +550,16 @@ Le code d'entraînement de cet exemple ressemblera beaucoup au code des sections
{/if}
-Le modèle produira des logits pour les positions de début et de fin de la réponse dans les IDs d'entrée, comme nous l'avons vu lors de notre exploration du [`question-answering` pipeline](/course/chapter6/4). L'étape de post-traitement sera similaire à ce que nous avons fait là-bas, donc voici un rappel rapide des actions que nous avons prises :
+Le modèle produira des logits pour les positions de début et de fin de la réponse dans les identifiants d'entrée, comme nous l'avons vu lors de notre exploration du pipeline de `question-answering` [au chapitre 6](/course/fr/chapter6/3b). L'étape de post-traitement sera similaire à ce que nous avons fait à ce chapitre là. Voici un rapide rappel des actions que nous avons prises :
- nous avons masqué les logits de début et de fin correspondant aux *tokens* en dehors du contexte,
-- nous avons ensuite converti les logits de début et de fin en probabilités en utilisant un softmax,
+- nous avons ensuite converti les logits de début et de fin en probabilités en utilisant une fonction SoftMax,
- nous avons attribué un score à chaque paire `(start_token, end_token)` en prenant le produit des deux probabilités correspondantes,
- nous avons cherché la paire avec le score maximum qui donnait une réponse valide (par exemple, un `start_token` inférieur au `end_token`).
-Ici, nous allons modifier légèrement ce processus car nous n'avons pas besoin de calculer les scores réels (juste la réponse prédite). Cela signifie que nous pouvons sauter l'étape du softmax. Pour aller plus vite, nous ne noterons pas non plus toutes les paires `(start_token, end_token)` possibles, mais seulement celles correspondant aux logits `n_best` les plus élevés (avec `n_best=20`). Puisque nous sauterons le softmax, ces scores seront des scores logit, et seront obtenus en prenant la somme des logits de début et de fin (au lieu du produit, à cause de la règle \\(\log(ab) = \log(a) + \log(b)\)).
+Ici, nous allons modifier légèrement ce processus car nous n'avons pas besoin de calculer les scores réels (juste la réponse prédite). Cela signifie que nous pouvons sauter l'étape de la SoftMax. Pour aller plus vite, nous ne donnerons pas non plus un score à toutes les paires `(start_token, end_token)` possibles, mais seulement celles correspondant aux `n_best` logits les plus élevés (avec `n_best=20`). Puisque nous sautons la SoftMax, les scores seront des scores logi, et seront obtenus en prenant la somme des logits de début et de fin (au lieu du produit, à cause de la règle \\(\log(ab) = \log(a) + \log(b)\\)).
-Pour démontrer tout cela, nous aurons besoin d'un certain type de prédictions. Puisque nous n'avons pas encore entraîné notre modèle, nous allons utiliser le modèle par défaut du pipeline d'assurance qualité pour générer quelques prédictions sur une petite partie de l'ensemble de validation. Nous pouvons utiliser la même fonction de traitement que précédemment ; parce qu'elle repose sur la constante globale `tokenizer`, nous devons juste changer cet objet pour le tokenizer du modèle que nous voulons utiliser temporairement :
+Pour démontrer tout cela, nous aurons besoin d'un certain type de prédictions. Puisque nous n'avons pas encore entraîné notre modèle, nous allons utiliser le modèle par défaut du pipeline de `question-answering` pour générer quelques prédictions sur une petite partie de l'ensemble de validation. Nous pouvons utiliser la même fonction de traitement que précédemment car elle repose sur la constante globale `tokenizer`, nous devons juste changer cet objet par le *tokenizer* du modèle que nous voulons utiliser temporairement :
```python
small_eval_set = raw_datasets["validation"].select(range(100))
@@ -577,7 +579,7 @@ Maintenant que le prétraitement est terminé, nous changeons le *tokenizer* pou
tokenizer = AutoTokenizer.from_pretrained(model_checkpoint)
```
-Nous supprimons ensuite les colonnes de notre `eval_set` qui ne sont pas attendues par le modèle, nous construisons un lot avec l'ensemble de ce petit ensemble de validation, et nous le passons au modèle. Si un GPU est disponible, nous l'utilisons pour aller plus vite :
+Nous supprimons ensuite les colonnes de notre `eval_set` qui ne sont pas attendues par le modèle. Nous construisons un batch avec tout de ce petit ensemble de validation et le passons au modèle. Si un GPU est disponible, nous l'utilisons pour aller plus vite :
{#if fw === 'pt'}
@@ -598,7 +600,7 @@ with torch.no_grad():
outputs = trained_model(**batch)
```
-Puisque le `Trainer` nous donnera les prédictions sous forme de tableaux NumPy, nous récupérons les logits de début et de fin et les convertissons dans ce format :
+Puisque `Trainer` nous donne les prédictions sous forme de tableaux NumPy, nous récupérons les logits de début et de fin et les convertissons dans ce format :
```python
start_logits = outputs.start_logits.cpu().numpy()
@@ -639,9 +641,9 @@ for idx, feature in enumerate(eval_set):
example_to_features[feature["example_id"]].append(idx)
```
-Avec cela en main, nous pouvons vraiment nous mettre au travail en parcourant en boucle tous les exemples et, pour chaque exemple, toutes les caractéristiques associées. Comme nous l'avons dit précédemment, nous allons regarder les scores logit pour les `n_meilleurs` logits de début et logits de fin, en excluant les positions qui donnent :
+Avec cela, nous pouvons vraiment nous mettre au travail en bouclant tous les exemples et, pour chaque exemple, toutes les caractéristiques associées. Comme nous l'avons dit précédemment, nous allons regarder les scores logit pour les `n_best` logits de début et logits de fin, en excluant les positions qui donnent :
-- une réponse qui ne serait pas dans le contexte.
+- une réponse qui ne serait pas dans le contexte
- une réponse avec une longueur négative
- une réponse qui est trop longue (nous limitons les possibilités à `max_answer_length=30`)
@@ -671,7 +673,7 @@ for example in small_eval_set:
# Ignore les réponses qui ne sont pas entièrement dans le contexte
if offsets[start_index] is None or offsets[end_index] is None:
continue
- # Ignorer les réponses dont la longueur est soit < 0 soit > max_answer_length.
+ # Ignore les réponses dont la longueur est soit < 0 soit > max_answer_length
if (
end_index < start_index
or end_index - start_index + 1 > max_answer_length
@@ -689,7 +691,7 @@ for example in small_eval_set:
predicted_answers.append({"id": example_id, "prediction_text": best_answer["text"]})
```
-Le format final des réponses prédites est celui qui sera attendu par la métrique que nous allons utiliser. Comme d'habitude, nous pouvons le charger à l'aide de la bibliothèque 🤗 *Datasets* :
+Le format final des réponses prédites est celui qui sera attendu par la métrique que nous allons utiliser. Comme d'habitude, nous pouvons la charger à l'aide de la bibliothèque 🤗 *Datasets* :
```python
from datasets import load_metric
@@ -697,7 +699,7 @@ from datasets import load_metric
metric = load_metric("squad")
```
-Cette métrique attend les réponses prédites dans le format que nous avons vu ci-dessus (une liste de dictionnaires avec une clé pour l'ID de l'exemple et une clé pour le texte prédit) et les réponses théoriques dans le format ci-dessous (une liste de dictionnaires avec une clé pour l'ID de l'exemple et une clé pour les réponses possibles) :
+Cette métrique attend les réponses prédites dans le format que nous avons vu ci-dessus (une liste de dictionnaires avec une clé pour l'identifiant de l'exemple et une clé pour le texte prédit) et les réponses théoriques dans le format ci-dessous (une liste de dictionnaires avec une clé pour l'identifiant de l'exemple et une clé pour les réponses possibles) :
```python
theoretical_answers = [
@@ -727,13 +729,13 @@ metric.compute(predictions=predicted_answers, references=theoretical_answers)
{'exact_match': 83.0, 'f1': 88.25}
```
-Encore une fois, c'est plutôt bon si l'on considère que, selon [son article](https://arxiv.org/abs/1910.01108v2), DistilBERT *finetuné* sur SQuAD obtient 79,1 et 86,9 pour ces scores sur l'ensemble des données.
+Encore une fois, c'est plutôt bon si l'on considère que, d'après [le papier](https://arxiv.org/abs/1910.01108v2) de DistilBERT, *finetuné* sur SQuAD, ce modèle obtient 79,1 et 86,9 pour ces scores sur l'ensemble du jeu de données.
{#if fw === 'pt'}
-Maintenant, mettons tout ce que nous venons de faire dans une fonction `compute_metrics()` que nous utiliserons dans le `Trainer`. Normalement, cette fonction `compute_metrics()` reçoit seulement un tuple `eval_preds` avec les logits et les labels. Ici, nous aurons besoin d'un peu plus, car nous devons chercher dans le jeu de données des caractéristiques pour le décalage et dans le jeu de données des exemples pour les contextes originaux, donc nous ne serons pas en mesure d'utiliser cette fonction pour obtenir des résultats d'évaluation réguliers pendant l'entraînement. Nous ne l'utiliserons qu'à la fin de l'entraînement pour vérifier les résultats.
+Maintenant, mettons tout ce que nous venons de faire dans une fonction `compute_metrics()` que nous utiliserons dans le `Trainer`. Normalement, cette fonction `compute_metrics()` reçoit seulement un *tuple* `eval_preds` avec les logits et les étiquettes. Ici, nous aurons besoin d'un peu plus, car nous devons chercher dans le jeu de données des caractéristiques pour le décalage et dans le jeu de données des exemples pour les contextes originaux. Ainsi nous ne serons pas en mesure d'utiliser cette fonction pour obtenir des résultats d'évaluation standards pendant l'entraînement. Nous ne l'utiliserons qu'à la fin de l'entraînement pour vérifier les résultats.
-La fonction `compute_metrics()` regroupe les mêmes étapes que précédemment ; nous ajoutons juste une petite vérification au cas où nous ne trouverions aucune réponse valide (dans ce cas nous prédisons une chaîne vide).
+La fonction `compute_metrics()` regroupe les mêmes étapes que précédemment. Nous ajoutons juste une petite vérification au cas où nous ne trouverions aucune réponse valide (dans ce cas nous prédisons une chaîne vide).
{:else}
@@ -769,7 +771,7 @@ def compute_metrics(start_logits, end_logits, features, examples):
# Ignore les réponses qui ne sont pas entièrement dans le contexte
if offsets[start_index] is None or offsets[end_index] is None:
continue
- # Ignore les réponses dont la longueur est soit < 0, soit > max_answer_length.
+ # Ignore les réponses dont la longueur est soit < 0, soit > max_answer_length
if (
end_index < start_index
or end_index - start_index + 1 > max_answer_length
@@ -805,13 +807,13 @@ compute_metrics(start_logits, end_logits, eval_set, small_eval_set)
{'exact_match': 83.0, 'f1': 88.25}
```
-C'est bien ! Maintenant, utilisons ceci pour affiner notre modèle.
+C'est bien ! Maintenant, utilisons ceci pour *finetuner* notre modèle.
-### *Finetuning* du modèle
+###
Finetuning du modèle
{#if fw === 'pt'}
-Nous sommes maintenant prêts à entraîner notre modèle. Créons-le d'abord, en utilisant la classe `AutoModelForQuestionAnswering` comme précédemment :
+Nous sommes maintenant prêts à entraîner notre modèle. Créons-le en utilisant la classe `AutoModelForQuestionAnswering` comme précédemment :
```python
model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
@@ -819,7 +821,7 @@ model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
{:else}
-Nous sommes maintenant prêts à entraîner notre modèle. Créons-le d'abord, en utilisant la classe `TFAutoModelForQuestionAnswering` comme précédemment :
+Nous sommes maintenant prêts à entraîner notre modèle. Créons-le en utilisant la classe `TFAutoModelForQuestionAnswering` comme précédemment :
```python
model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
@@ -829,7 +831,7 @@ model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
Comme d'habitude, nous recevons un avertissement indiquant que certains poids ne sont pas utilisés (ceux de la tête de pré-entraînement) et que d'autres sont initialisés de manière aléatoire (ceux de la tête de réponse aux questions). Vous devriez être habitué à cela maintenant, mais cela signifie que ce modèle n'est pas encore prêt à être utilisé et qu'il a besoin d'être *finetuné*. Une bonne chose que nous soyons sur le point de le faire !
-Pour pouvoir pousser notre modèle vers le *Hub*, nous devons nous connecter à Hugging Face. Si vous exécutez ce code dans un *notebook*, vous pouvez le faire avec la fonction utilitaire suivante, qui affiche un widget où vous pouvez entrer vos identifiants de connexion :
+Pour pouvoir pousser notre modèle vers le *Hub*, nous devons nous connecter à Hugging Face. Si vous exécutez ce code dans un *notebook*, vous pouvez le faire avec la fonction utilitaire suivante, qui affiche un *widget* où vous pouvez entrer vos identifiants de connexion :
```python
from huggingface_hub import notebook_login
@@ -845,11 +847,11 @@ huggingface-cli login
{#if fw === 'pt'}
-Une fois ceci fait, nous pouvons définir nos `TrainingArguments`. Comme nous l'avons dit lorsque nous avons défini notre fonction pour calculer la métrique, nous ne serons pas en mesure d'avoir une boucle d'évaluation régulière à cause de la signature de la fonction `compute_metrics()`. Nous pourrions écrire notre propre sous-classe de `Trainer` pour faire cela (une approche que vous pouvez trouver dans le [script d'exemple de réponse aux questions](https://github.com/huggingface/transformers/blob/master/examples/pytorch/question-answering/trainer_qa.py)), mais c'est un peu trop long pour cette section. A la place, nous n'évaluerons le modèle qu'à la fin de l'entraînement et nous vous montrerons comment faire une évaluation régulière dans "Une boucle d'entraînement personnalisée" ci-dessous.
+Une fois ceci fait, nous pouvons définir nos `TrainingArguments`. Comme nous l'avons dit lorsque nous avons défini notre fonction pour calculer la métrique, nous ne serons pas en mesure d'avoir une boucle d'évaluation standard à cause de la signature de la fonction `compute_metrics()`. Nous pourrions écrire notre propre sous-classe de `Trainer` pour faire cela (une approche que vous pouvez trouver dans le [script d'exemple de réponse aux questions](https://github.com/huggingface/transformers/blob/master/examples/pytorch/question-answering/trainer_qa.py)), mais c'est un peu trop long pour cette section. A la place, nous n'évaluerons le modèle qu'à la fin de l'entraînement et nous vous montrerons comment faire une évaluation cela dans le paragraphe « Une boucle d'entraînement personnalisée » ci-dessous.
-C'est vraiment là que l'API `Trainer` montre ses limites et que la bibliothèque 🤗 *Accelerate* brille : personnaliser la classe pour un cas d'utilisation spécifique peut être pénible, mais modifier une boucle d'entraînement entièrement exposée est facile.
+C'est là que l'API `Trainer` montre ses limites et que la bibliothèque 🤗 *Accelerate* brille : personnaliser la classe pour un cas d'utilisation spécifique peut être pénible, mais modifier une boucle d'entraînement est facile.
-Jetons un coup d'œil à notre `TrainingArguments` :
+Jetons un coup d'œil à notre `TrainingArguments` :
```python
from transformers import TrainingArguments
@@ -866,11 +868,11 @@ args = TrainingArguments(
)
```
-Nous avons déjà vu la plupart d'entre eux : nous définissons quelques hyperparamètres (comme le taux d'apprentissage, le nombre d'époques pour lesquelles nous nous entraînons, et une certaine décroissance de poids) et nous indiquons que nous voulons sauvegarder le modèle à la fin de chaque époque, sauter l'évaluation, et télécharger nos résultats vers le Model Hub. Nous activons également l'entraînement en précision mixte avec `fp16=True`, car cela peut accélérer l'entraînement sur un GPU récent.
+Nous avons déjà vu la plupart d'entre eux. Nous définissons quelques hyperparamètres (comme le taux d'apprentissage, le nombre d'époques d'entraînement, un taux de décroissance des poids) et nous indiquons que nous voulons sauvegarder le modèle à la fin de chaque époque, sauter l'évaluation, et télécharger nos résultats vers le *Hub*. Nous activons également l'entraînement en précision mixte avec `fp16=True`, car cela peut accélérer l'entraînement sur un GPU récent.
{:else}
-Maintenant que c'est fait, nous pouvons créer nos ensembles de données TF. Nous pouvons utiliser le simple collateur de données par défaut cette fois-ci :
+Maintenant que c'est fait, nous pouvons créer nos jeux de données TensorFlow. Nous pouvons utiliser le simple collateur de données par défaut cette fois-ci :
```python
from transformers import DefaultDataCollator
@@ -908,9 +910,9 @@ from transformers import create_optimizer
from transformers.keras_callbacks import PushToHubCallback
import tensorflow as tf
-# Le nombre d'étapes d'entraînement est le nombre d'échantillons dans le jeu de données, divisé par la taille du batch, puis multiplié par le nombre total d'époques.
-# par le nombre total d'époques. Notez que le jeu de données tf_train_dataset est ici un lot tf.data.Dataset,
-# et non le jeu de données original Hugging Face Dataset, donc son len() est déjà num_samples // batch_size.
+# Le nombre d'étapes d'entraînement est le nombre d'échantillons dans le jeu de données, divisé par la taille du batch,
+# puis multiplié par le nombre total d'époques. Notez que le jeu de données tf_train_dataset est ici un tf.data.Dataset,
+# et non le jeu de données original donc son len() est déjà num_samples // batch_size.
num_train_epochs = 3
num_train_steps = len(tf_train_dataset) * num_train_epochs
optimizer, schedule = create_optimizer(
@@ -925,11 +927,11 @@ model.compile(optimizer=optimizer)
tf.keras.mixed_precision.set_global_policy("mixed_float16")
```
-Enfin, nous sommes prêts à nous entraîner avec `model.fit()`. Nous utilisons un `PushToHubCallback` pour télécharger le modèle sur le *Hub* après chaque époque.
+Enfin, nous sommes prêts à entraîner avec `model.fit()`. Nous utilisons un `PushToHubCallback` pour télécharger le modèle sur le *Hub* après chaque époque.
{/if}
-Par défaut, le dépôt utilisé sera dans votre espace de noms et nommé après le répertoire de sortie que vous avez défini, donc dans notre cas il sera dans `"sgugger/bert-finetuned-squad"`. Nous pouvons passer outre en passant un `hub_model_id` ; par exemple, pour pousser le modèle dans l'organisation `huggingface_course` nous avons utilisé `hub_model_id= "huggingface_course/bert-finetuned-squad"` (qui est le modèle que nous avons lié au début de cette section).
+Par défaut, le dépôt utilisé sera dans votre espace et nommé après le répertoire de sortie que vous avez défini. Donc dans notre cas il sera dans `"sgugger/bert-finetuned-squad"`. Nous pouvons passer outre en passant un `hub_model_id`, par exemple, pour pousser le modèle dans l'organisation `huggingface_course` nous avons utilisé `hub_model_id= "huggingface_course/bert-finetuned-squad"` (qui est le modèle que nous avons lié au début de cette section).
{#if fw === 'pt'}
@@ -967,11 +969,11 @@ model.fit(tf_train_dataset, callbacks=[callback], epochs=num_train_epochs)
{/if}
-Notez que pendant l'entraînement, chaque fois que le modèle est sauvegardé (ici, à chaque époque), il est téléchargé sur le Hub en arrière-plan. Ainsi, vous pourrez reprendre votre entraînement sur une autre machine si nécessaire. L'ensemble de l'entraînement prend un certain temps (un peu plus d'une heure sur une Titan RTX), vous pouvez donc prendre un café ou relire les parties du cours qui vous ont semblé plus difficiles pendant qu'il se déroule. Notez également que dès que la première époque est terminée, vous verrez des poids téléchargés sur le Hub et vous pourrez commencer à jouer avec votre modèle sur sa page.
+Notez que pendant l'entraînement, chaque fois que le modèle est sauvegardé (ici, à chaque époque), il est téléchargé sur le *Hub* en arrière-plan. Ainsi, vous pourrez reprendre votre entraînement sur une autre machine si nécessaire. L'ensemble de l'entraînement prend un certain temps (un peu plus d'une heure sur une Titan RTX), vous pouvez donc prendre un café ou relire les parties du cours qui vous ont semblé plus difficiles pendant qu'il se déroule. Notez également que dès que la première époque est terminée, vous verrez des poids téléchargés sur le *Hub* et vous pourrez commencer à jouer avec votre modèle sur sa page.
{#if fw === 'pt'}
-Une fois l'entraînement terminé, nous pouvons enfin évaluer notre modèle (et prier pour ne pas avoir dépensé tout ce temps de calcul pour rien). La méthode `predict()` du `Trainer` retournera un tuple où les premiers éléments seront les prédictions du modèle (ici une paire avec les logits de début et de fin). Nous envoyons ceci à notre fonction `compute_metrics()` :
+Une fois l'entraînement terminé, nous pouvons enfin évaluer notre modèle (et prier pour ne pas avoir dépensé tout ce temps de calcul pour rien). La méthode `predict()` du `Trainer` retournera un *tuple* où les premiers éléments seront les prédictions du modèle (ici une paire avec les logits de début et de fin). Nous envoyons ceci à notre fonction `compute_metrics()` :
```python
predictions, _ = trainer.predict(validation_dataset)
@@ -999,7 +1001,7 @@ compute_metrics(
{'exact_match': 81.18259224219489, 'f1': 88.67381321905516}
```
-Super ! À titre de comparaison, les scores de base indiqués dans l'article du BERT pour ce modèle sont de 80,8 et 88,5, donc nous sommes exactement là où nous devrions être.
+Super ! À titre de comparaison, les scores indiqués dans l'article de BERT pour ce tâche sont de 80,8 et 88,5. Donc nous sommes exactement là où nous devrions être.
{#if fw === 'pt'}
@@ -1015,15 +1017,15 @@ Cela renvoie l'URL du commit qu'il vient de faire, si vous voulez l'inspecter :
'https://huggingface.co/sgugger/bert-finetuned-squad/commit/9dcee1fbc25946a6ed4bb32efb1bd71d5fa90b68'
```
-Le `Trainer` rédige également une fiche modèle avec tous les résultats de l'évaluation et la télécharge.
+Le `Trainer` rédige également une carte de modèle avec tous les résultats de l'évaluation et la télécharge.
{/if}
-À ce stade, vous pouvez utiliser le widget d'inférence sur le *Hub* du modèle pour tester le modèle et le partager avec vos amis, votre famille et vos animaux préférés. Vous avez réussi à *finetuner* un modèle sur une tâche de réponse à une question - félicitations !
+À ce stade, vous pouvez utiliser le *widget* d'inférence sur le *Hub* du modèle pour tester le modèle et le partager avec vos amis, votre famille et vos animaux préférés. Vous avez réussi à *finetuner* un modèle sur une tâche de réponse à une question. Félicitations !
-✏️ **Votre tour** Essayez un autre modèle d'architecture pour voir s'il est plus performant dans cette tâche !
+✏️ **A votre tour** Essayez un autre modèle pour voir s'il est plus performant pour cette tâche !
@@ -1033,11 +1035,11 @@ Si vous voulez plonger un peu plus profondément dans la boucle d'entraînement,
## Une boucle d'entraînement personnalisée
-Jetons maintenant un coup d'œil à la boucle d'entraînement complète, afin que vous puissiez facilement personnaliser les parties dont vous avez besoin. Elle ressemblera beaucoup à la boucle d'entraînement du [Chapitre 3](/course/fr/chapter3/4), à l'exception de la boucle d'évaluation. Nous serons en mesure d'évaluer le modèle régulièrement puisque nous ne sommes plus contraints par la classe `Trainer`.
+Jetons maintenant un coup d'œil à la boucle d'entraînement complète, afin que vous puissiez facilement personnaliser les parties dont vous avez besoin. Elle ressemblera beaucoup à la boucle d'entraînement du [chapitre 3](/course/fr/chapter3/4), à l'exception de la boucle d'évaluation. Nous serons en mesure d'évaluer le modèle régulièrement puisque nous ne sommes plus contraints par la classe `Trainer`.
### Préparer tout pour l'entraînement
-Tout d'abord, nous devons construire le `DataLoader`s à partir de nos jeux de données. Nous définissons le format de ces jeux de données à `"torch"`, et supprimons les colonnes dans le jeu de validation qui ne sont pas utilisées par le modèle. Ensuite, nous pouvons utiliser le `default_data_collator` fourni par Transformers comme `collate_fn` et mélanger l'ensemble d'entraînement, mais pas l'ensemble de validation :
+Tout d'abord, nous devons construire le `DataLoader`s à partir de nos jeux de données. Nous définissons le format de ces jeux de données à `"torch"` et supprimons les colonnes dans le jeu de validation qui ne sont pas utilisées par le modèle. Ensuite, nous pouvons utiliser le `default_data_collator` fourni par 🤗 *Transformers* comme `collate_fn` et mélanger l'ensemble d'entraînement mais pas celui de validation :
```py
from torch.utils.data import DataLoader
@@ -1058,13 +1060,13 @@ eval_dataloader = DataLoader(
)
```
-Ensuite, nous réinstantifions notre modèle, afin de nous assurer que nous ne poursuivons pas les réglages fins précédents mais que nous repartons du modèle pré-entraîné de BERT :
+Ensuite, nous réinstantifions notre modèle afin de nous assurer que nous ne poursuivons pas le *finetuning* précédent et que nous repartons du modèle BERT pré-entraîné :
```py
model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)
```
-Ensuite, nous aurons besoin d'un optimiseur. Comme d'habitude, nous utilisons le classique `AdamW`, qui est comme Adam, mais avec une correction dans la façon dont la décroissance du poids est appliquée :
+Ensuite, nous aurons besoin d'un optimiseur. Comme d'habitude, nous utilisons le classique `AdamW`, qui est comme Adam mais avec une correction dans la façon dont le taux de décroissance des poids est appliqué :
```py
from torch.optim import AdamW
@@ -1072,7 +1074,7 @@ from torch.optim import AdamW
optimizer = AdamW(model.parameters(), lr=2e-5)
```
-Une fois que nous avons tous ces objets, nous pouvons les envoyer à la méthode `accelerator.prepare()`. Rappelez-vous que si vous voulez vous entraîner sur des TPUs dans un *notebook* de Colab, vous devrez déplacer tout ce code dans une fonction d'entraînement, et qui ne devrait pas exécuter une cellule qui instancie un `Accelerator`. Nous pouvons forcer l'entraînement en précision mixte en passant `fp16=True` à l'`Accelerator` (ou, si vous exécutez le code comme un script, assurez-vous de remplir la 🤗 *Accelerate* `config` de manière appropriée).
+Une fois que nous avons tous ces objets, nous pouvons les envoyer à la méthode `accelerator.prepare()`. Rappelez-vous que si vous voulez entraîner sur des TPUs dans un *notebook* Colab, vous devrez déplacer tout ce code dans une fonction d'entraînement, et qui ne devrait pas exécuter une cellule qui instancie un `Accelerator`. Nous pouvons forcer l'entraînement en précision mixte en passant l'argument `fp16=True` à `Accelerator` (ou, si vous exécutez le code comme un script, assurez-vous de remplir la 🤗 *Accelerate* `config` de manière appropriée).
```py
from accelerate import Accelerator
@@ -1100,7 +1102,7 @@ lr_scheduler = get_scheduler(
)
```
-Pour pousser notre modèle vers le Hub, nous aurons besoin de créer un objet `Repository` dans un dossier de travail. Tout d'abord, connectez-vous au Hugging Face Hub, si vous n'êtes pas déjà connecté. Nous déterminerons le nom du dépôt à partir de l'ID du modèle que nous voulons donner à notre modèle (n'hésitez pas à remplacer le `repo_name` par votre propre choix ; il doit juste contenir votre nom d'utilisateur, ce que fait la fonction `get_full_repo_name()`) :
+Pour pousser notre modèle vers le *Hub*, nous aurons besoin de créer un objet `Repository` dans un dossier de travail. Tout d'abord, connectez-vous au *Hub*, si vous n'êtes pas déjà connecté. Nous déterminerons le nom du dépôt à partir de l'identifiant du modèle que nous voulons donner à notre modèle (n'hésitez pas à remplacer le `repo_name` par votre propre choix. Il doit juste contenir votre nom d'utilisateur, ce que fait la fonction `get_full_repo_name()`) :
```py
from huggingface_hub import Repository, get_full_repo_name
@@ -1114,7 +1116,7 @@ repo_name
'sgugger/bert-finetuned-squad-accelerate'
```
-Ensuite, nous pouvons cloner ce référentiel dans un dossier local. S'il existe déjà, ce dossier local doit être un clone du référentiel avec lequel nous travaillons :
+Ensuite, nous pouvons cloner ce dépôt dans un dossier local. S'il existe déjà, ce dossier local doit être un clone du dépôt avec lequel nous travaillons :
```py
output_dir = "bert-finetuned-squad-accelerate"
@@ -1127,8 +1129,8 @@ Nous pouvons maintenant télécharger tout ce que nous sauvegardons dans `output
Nous sommes maintenant prêts à écrire la boucle d'entraînement complète. Après avoir défini une barre de progression pour suivre l'évolution de l'entraînement, la boucle comporte trois parties :
-- l'entraînement proprement dit, qui est l'itération classique sur le `train_dataloader`, passage en avant du modèle, puis passage en arrière et étape d'optimisation.
-- l'évaluation, dans laquelle nous rassemblons toutes les valeurs pour `start_logits` et `end_logits` avant de les convertir en tableaux NumPy. Une fois la boucle d'évaluation terminée, nous concaténons tous les résultats. Notez que nous devons tronquer parce que l' `Accelerator` peut avoir ajouté quelques échantillons à la fin pour s'assurer que nous avons le même nombre d'exemples dans chaque processus.
+- l'entraînement à proprement dit, qui est l'itération classique sur le `train_dataloader`, passage en avant du modèle, puis passage en arrière et étape d'optimisation.
+- l'évaluation, dans laquelle nous rassemblons toutes les valeurs pour `start_logits` et `end_logits` avant de les convertir en tableaux NumPy. Une fois la boucle d'évaluation terminée, nous concaténons tous les résultats. Notez que nous devons tronquer car `Accelerator` peut avoir ajouté quelques échantillons à la fin pour s'assurer que nous avons le même nombre d'exemples dans chaque processus.
- sauvegarde et téléchargement, où nous sauvegardons d'abord le modèle et le *tokenizer*, puis appelons `repo.push_to_hub()`. Comme nous l'avons fait auparavant, nous utilisons l'argument `blocking=False` pour dire à la bibliothèque 🤗 *Hub* de pousser dans un processus asynchrone. De cette façon, l'entraînement continue normalement et cette (longue) instruction est exécutée en arrière-plan.
Voici le code complet de la boucle d'entraînement :
@@ -1193,20 +1195,20 @@ unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save)
```
-La première ligne est explicite : elle indique à tous les processus d'attendre que tout le monde soit à ce stade avant de continuer. C'est pour s'assurer que nous avons le même modèle dans chaque processus avant de sauvegarder. Ensuite, nous prenons le `unwrapped_model`, qui est le modèle de base que nous avons défini. La méthode `accelerator.prepare()` modifie le modèle pour qu'il fonctionne dans l'entraînement distribué, donc il n'aura plus la méthode `save_pretrained()` ; la méthode `accelerator.unwrap_model()` annule cette étape. Enfin, nous appelons `save_pretrained()` mais nous disons à cette méthode d'utiliser `accelerator.save()` au lieu de `torch.save()`.
+La première ligne est explicite : elle indique à tous les processus d'attendre que tout le monde soit à ce stade avant de continuer. C'est pour s'assurer que nous avons le même modèle dans chaque processus avant de sauvegarder. Ensuite, nous prenons le `unwrapped_model`, qui est le modèle de base que nous avons défini. La méthode `accelerator.prepare()` modifie le modèle pour qu'il fonctionne dans l'entraînement distribué. Donc il n'aura plus la méthode `save_pretrained()` car la méthode `accelerator.unwrap_model()` annule cette étape. Enfin, nous appelons `save_pretrained()` mais nous disons à cette méthode d'utiliser `accelerator.save()` au lieu de `torch.save()`.
-Une fois ceci fait, vous devriez avoir un modèle qui produit des résultats assez similaires à celui entraîné avec le `Trainer`. Vous pouvez vérifier le modèle que nous avons entraîné en utilisant ce code à [*huggingface-course/bert-finetuned-squad-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-squad-accelerate). Et si vous voulez tester des modifications de la boucle d'entraînement, vous pouvez les implémenter directement en modifiant le code ci-dessus !
+Une fois ceci fait, vous devriez avoir un modèle qui produit des résultats assez similaires à celui entraîné avec `Trainer`. Vous pouvez vérifier le modèle que nous avons entraîné en utilisant ce code à [*huggingface-course/bert-finetuned-squad-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-squad-accelerate). Et si vous voulez tester des modifications de la boucle d'entraînement, vous pouvez les implémenter directement en modifiant le code ci-dessus !
{/if}
-### Utilisation du modèle *finetuné*
+### Utilisation du modèle
finetuné
-Nous vous avons déjà montré comment vous pouvez utiliser le modèle que nous avons *finetuné* sur le *Hub* avec le widget d'inférence. Pour l'utiliser localement dans un `pipeline`, il suffit de spécifier l'identifiant du modèle :
+Nous vous avons déjà montré comment vous pouvez utiliser le modèle que nous avons *finetuné* sur le *Hub* avec le *widget* d'inférence. Pour l'utiliser localement dans un `pipeline`, il suffit de spécifier l'identifiant du modèle :
```py
from transformers import pipeline
-# Replace this with your own checkpoint
+# Remplacez par votre propre checkpoint
model_checkpoint = "huggingface-course/bert-finetuned-squad"
question_answerer = pipeline("question-answering", model=model_checkpoint)
diff --git a/chapters/fr/chapter7/8.mdx b/chapters/fr/chapter7/8.mdx
index 795ac72c3..aeea11abb 100644
--- a/chapters/fr/chapter7/8.mdx
+++ b/chapters/fr/chapter7/8.mdx
@@ -1,12 +1,12 @@
-# *Mastering NLP*
+# Maîtriser le
NLP
-Si vous êtes arrivé jusqu'ici dans le cours, félicitations ! Vous avez maintenant toutes les connaissances et les outils nécessaires pour aborder (presque) n'importe quelle tâche de NLP avec 🤗 *Transformers* et l'écosystème Hugging Face !
+Si vous êtes arrivé jusqu'ici dans le cours, félicitations ! Vous avez maintenant toutes les connaissances et les outils nécessaires pour aborder (presque) n'importe quelle tâche de *NLP* avec 🤗 *Transformers* et l'écosystème d'*Hugging Face* !
-Nous avons vu beaucoup de batchs différents de collecteurs de données, donc nous avons fait cette petite vidéo pour vous aider à trouver lequel utiliser pour chaque tâche :
+Nous avons vu beaucoup de collecteurs de données différents, c'est pourquoi nous avons fait cette petite vidéo pour vous aider à trouver lequel utiliser pour chaque tâche :
-Après avoir terminé ce tour d'horizon des principales tâches NLP, vous devriez :
+Après avoir terminé ce tour d'horizon des principales tâches de *NLP*, vous devriez :
* savoir quelles architectures (encodeur, décodeur ou encodeur-décodeur) sont les mieux adaptées à chaque tâche,
* comprendre la différence entre le pré-entraînement et le *finetuning* d'un modèle de langage,
@@ -14,4 +14,4 @@ Après avoir terminé ce tour d'horizon des principales tâches NLP, vous devrie
* comprendre la signification et les limites de métriques comme ROUGE et BLEU pour les tâches de génération de texte,
* savoir comment interagir avec vos modèles *finetunés*, à la fois sur le *Hub* et en utilisant la `pipeline` de 🤗 *Transformers*.
-Malgré toutes ces connaissances, il arrivera un moment où vous rencontrerez un bug difficile dans votre code ou aurez une question sur la façon de résoudre un problème NLP particulier. Heureusement, la communauté Hugging Face est là pour vous aider ! Dans le dernier chapitre de cette partie du cours, nous allons explorer comment vous pouvez déboguer vos *transformers* et demander de l'aide efficacement.
\ No newline at end of file
+Malgré toutes ces connaissances, il arrivera un moment où vous rencontrerez un *bug* difficile dans votre code ou aurez une question sur la façon de résoudre un problème de *NLP* particulier. Heureusement, la communauté d'*Hugging Face* est là pour vous aider ! Dans le dernier chapitre de cette partie du cours, nous allons explorer comment vous pouvez déboguer vos modèles et demander de l'aide efficacement.
\ No newline at end of file
diff --git a/chapters/fr/chapter7/9.mdx b/chapters/fr/chapter7/9.mdx
index 56cb887aa..ae063e9d0 100644
--- a/chapters/fr/chapter7/9.mdx
+++ b/chapters/fr/chapter7/9.mdx
@@ -6,42 +6,42 @@
Testons ce que vous avez appris dans ce chapitre !
-### 1. Laquelle des tâches suivantes peut être considérée comme un problème de classification de *tokens* ?
+### 1. Laquelle des tâches suivantes peut être considérée comme un problème de classification de
tokens ?
-### 2. Quelle partie du prétraitement pour la classification des *tokens* diffère des autres pipelines de prétraitement ?
+### 2. Quelle partie du prétraitement pour la classification de
tokens diffère des autres pipelines de prétraitement ?
padding.",
- explain: "En effet ! Mais ce n'est pas la seule différence.",
+ explain: "En effet mais ce n'est pas la seule différence.",
correct: true
}
]}
/>
-### 3. Quel problème se pose lorsque nous tokenisons les mots dans un problème de classification de *tokens* et que nous voulons étiqueter les *tokens* ?
+### 3. Quel problème se pose lorsque nous tokenisons les mots dans un problème de classification de tokens et que nous voulons étiqueter les tokens ?
tokenizer ajoute des tokens spéciaux et nous n'avons pas d'étiquettes pour eux.",
- explain: "Nous étiquetons ces -100
ils sont donc ignorés dans la perte."
+ explain: "Nous les étiquetons par -100
ils sont donc ignorés dans la perte."
},
{
text: "Chaque mot peut produire plusieurs tokens, ce qui fait que nous nous retrouvons avec plus de tokens que d'étiquettes.",
- explain: "C'est le problème principal, et nous devons aligner les étiquettes originales avec les tokens.",
+ explain: "C'est le problème principal et nous devons aligner les étiquettes originales avec les tokens.",
correct: true
},
{
text: "Les tokens ajoutés n'ont pas d'étiquettes, il n'y a donc pas de problème.",
- explain: "C'est incorrect. Nous avons besoin d'autant d'étiquettes que de tokens, sinon nos modèles se tromperont."
+ explain: "Nous avons besoin d'autant d'étiquettes que de tokens, sinon nos modèles se tromperont."
}
]}
/>
-### 4. Que signifie "adaptation au domaine" ?
+### 4. Que signifie « adaptation au domaine » ?
finetunons un modèle pré-entraîné sur un nouveau jeu de données et qu'il donne des prédictions qui sont plus adaptées à ce nouveau jeu de données.",
+ explain: "Le modèle a adapté ses connaissances au nouveau jeu de données.",
correct: true
},
{
text: "C'est lorsque nous ajoutons des échantillons mal classés à un jeu de données pour rendre notre modèle plus robuste.",
- explain: "C'est certainement quelque chose que vous devriez faire si vous réentraînez votre modèle régulièrement, mais ce n'est pas une adaptation au domaine.."
+ explain: "C'est certainement quelque chose que vous devriez faire si vous réentraînez votre modèle régulièrement, mais ce n'est pas une adaptation au domaine."
}
]}
/>
@@ -110,16 +110,16 @@ Testons ce que vous avez appris dans ce chapitre !
correct: true
},
{
- text: "Certains des