diff --git a/chapters/en/chapter3/3.mdx b/chapters/en/chapter3/3.mdx index 749cfd511..40cec5e78 100644 --- a/chapters/en/chapter3/3.mdx +++ b/chapters/en/chapter3/3.mdx @@ -162,7 +162,7 @@ This time, it will report the validation loss and metrics at the end of each epo The `Trainer` will work out of the box on multiple GPUs or TPUs and provides lots of options, like mixed-precision training (use `fp16 = True` in your training arguments). We will go over everything it supports in Chapter 10. -This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in Chapter 7, but for now let's look at how to do the same thing in pure PyTorch. +This concludes the introduction to fine-tuning using the `Trainer` API. An example of doing this for most common NLP tasks will be given in [Chapter 7](course/chapter7), but for now let's look at how to do the same thing in pure PyTorch. diff --git a/chapters/en/chapter3/3_tf.mdx b/chapters/en/chapter3/3_tf.mdx index f2dd7d6cb..3c72b30fb 100644 --- a/chapters/en/chapter3/3_tf.mdx +++ b/chapters/en/chapter3/3_tf.mdx @@ -196,4 +196,4 @@ metric.compute(predictions=class_preds, references=raw_datasets["validation"]["l The exact results you get may vary, as the random initialization of the model head might change the metrics it achieved. Here, we can see our model has an accuracy of 85.78% on the validation set and an F1 score of 89.97. Those are the two metrics used to evaluate results on the MRPC dataset for the GLUE benchmark. The table in the [BERT paper](https://arxiv.org/pdf/1810.04805.pdf) reported an F1 score of 88.9 for the base model. That was the `uncased` model while we are currently using the `cased` model, which explains the better result. -This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in Chapter 7. If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. +This concludes the introduction to fine-tuning using the Keras API. An example of doing this for most common NLP tasks will be given in [Chapter 7](course/chapter7). If you would like to hone your skills on the Keras API, try to fine-tune a model on the GLUE SST-2 dataset, using the data processing you did in section 2. diff --git a/chapters/en/chapter3/6.mdx b/chapters/en/chapter3/6.mdx index 94d02da24..63e6c7052 100644 --- a/chapters/en/chapter3/6.mdx +++ b/chapters/en/chapter3/6.mdx @@ -251,7 +251,7 @@ Test what you learned in this chapter! explain: "Almost! There are some small additional changes required. For example, you need to run everything in a TPUStrategy scope, including the initialization of the model." }, { - text: "You can leverage existing methods such as compile(), fit(), and predict().", + text: "You can leverage existing methods such as compile(), fit(), and predict().", explain: "Correct! Once you have the data, training on it requires very little work.", correct: true }, @@ -293,4 +293,4 @@ Test what you learned in this chapter! ]} /> -{/if} \ No newline at end of file +{/if} diff --git a/chapters/fr/_toctree.yml b/chapters/fr/_toctree.yml index e9052ae57..20f72bd85 100644 --- a/chapters/fr/_toctree.yml +++ b/chapters/fr/_toctree.yml @@ -2,20 +2,21 @@ sections: - local: chapter0/1 title: Introduction -- title: 1. Les modèles Transformers + +- title: 1. Les transformers sections: - local: chapter1/1 title: Introduction - local: chapter1/2 title: Traitement du langage naturel - local: chapter1/3 - title: Que peut-on faire avec les modèles Transformers? + title: Que peut-on faire avec les transformers ? - local: chapter1/4 - title: Comment fonctionnent les modèles Transformers? + title: Comment fonctionnent les transformers ? - local: chapter1/5 - title: Les modèles d'encodeur + title: Les modèles encodeur - local: chapter1/6 - title: Les modèles de décodeur + title: Les modèles décodeur - local: chapter1/7 title: Les modèles de séquence-à-séquence - local: chapter1/8 @@ -23,8 +24,9 @@ - local: chapter1/9 title: Résumé - local: chapter1/10 - title: Questionnaire de fin de chapitre + title: Quiz de fin de chapitre quiz: 1 + - title: 2. Utilisation de 🤗 Transformers sections: - local: chapter2/1 @@ -45,6 +47,35 @@ title: Quiz de fin de chapitre quiz: 2 +- title: 3. Finetuner un modèle pré-entraîné + sections: + - local: chapter3/3 + title: Finetuner un modèle avec l'API Trainer API ou Keras + local_fw: { pt: chapter3/3, tf: chapter3/3_tf } + - local: chapter3/4 + title: Un entraînement complet + - local: chapter3/5 + title: Finetuning, vérifié ! + - local: chapter3/6 + title: Quiz de fin de chapitre + quiz: 3 + +- title: 4. Partager des modèles et des tokenizers + sections: + - local: chapter4/1 + title: Le Hub d'Hugging Face + - local: chapter4/2 + title: Utilisation de modèles pré-entraînés + - local: chapter4/3 + title: Partager des modèles pré-entraînés + - local: chapter4/4 + title: Créer une carte de modèle + - local: chapter4/5 + title: Partie 1 terminée ! + - local: chapter4/6 + title: Quiz de fin de chapitre + quiz: 4 + - title: 5. La bibliothèque 🤗 Datasets sections: - local: chapter5/1 diff --git a/chapters/fr/chapter3/3.mdx b/chapters/fr/chapter3/3.mdx new file mode 100644 index 000000000..62a7962e9 --- /dev/null +++ b/chapters/fr/chapter3/3.mdx @@ -0,0 +1,171 @@ + + +# *Finetuner* un modèle avec l'API Trainer + + + + + +🤗 *Transformers* fournit une classe `Trainer` pour vous aider à *finetuner* n'importe lequel des modèles pré-entraînés qu'il fournit sur votre jeu de données. Une fois que vous avez fait tout le travail de prétraitement des données dans la dernière section, il ne vous reste que quelques étapes pour définir le `Trainer`. La partie la plus difficile sera probablement de préparer l'environnement pour exécuter `Trainer.train()`, car elle fonctionnera très lentement sur un CPU. Si vous n'avez pas de GPU, vous pouvez avoir accès à des GPUs ou TPUs gratuits sur [Google Colab](https://colab.research.google.com/). + +Les exemples de code ci-dessous supposent que vous avez déjà exécuté les exemples de la section précédente. Voici un bref résumé de ce dont vous avez besoin : + +```py +from datasets import load_dataset +from transformers import AutoTokenizer, DataCollatorWithPadding + +raw_datasets = load_dataset("glue", "mrpc") +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + + +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) + + +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) +``` + +### Entraînement + +La première étape avant de pouvoir définir notre `Trainer` est de définir une classe `TrainingArguments` qui contiendra tous les hyperparamètres que le `Trainer` utilisera pour l'entraînement et l'évaluation. Le seul argument que vous devez fournir est un répertoire où le modèle entraîné sera sauvegardé, ainsi que les *checkpoints*. Pour tout le reste, vous pouvez laisser les valeurs par défaut, qui devraient fonctionner assez bien pour un *finetuning* de base. + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments("test-trainer") +``` + + + +💡 Si vous voulez télécharger automatiquement votre modèle sur le *Hub* pendant l'entraînement, passez `push_to_hub=True` dans le `TrainingArguments`. Nous en apprendrons plus à ce sujet au [Chapitre 4](/course/fr/chapter4/3). + + + +La deuxième étape consiste à définir notre modèle. Comme dans le [chapitre précédent](/course/fr/chapter2), nous utiliserons la classe `AutoModelForSequenceClassification`, avec deux labels : + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +Vous remarquerez que contrairement au [Chapitre 2](/course/fr/chapter2), vous obtenez un message d'avertissement après l'instanciation de ce modèle pré-entraîné. C'est parce que BERT n'a pas été pré-entraîné à la classification de paires de phrases, donc la tête du modèle pré-entraîné a été supprimée et une nouvelle tête adaptée à la classification de séquences a été ajoutée à la place. Les messages d'avertissement indiquent que certains poids n'ont pas été utilisés (ceux correspondant à la tête de pré-entraînement abandonnée) et que d'autres ont été initialisés de manière aléatoire (ceux pour la nouvelle tête). Il conclut en vous encourageant à entraîner le modèle, ce qui est exactement ce que nous allons faire maintenant. + +Une fois que nous avons notre modèle, nous pouvons définir un `Trainer` en lui passant tous les objets construits jusqu'à présent : le `model`, le `training_args`, les jeux de données d'entraînement et de validation, notre `data_collator`, et notre `tokenizer` : + +```py +from transformers import Trainer + +trainer = Trainer( + model, + training_args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + tokenizer=tokenizer, +) +``` + +Notez que lorsque vous passez le `tokenizer` comme nous l'avons fait ici, le `data_collator` par défaut utilisé par le `Trainer` sera un `DataCollatorWithPadding` comme défini précédemment. Ainsi, vous pouvez sauter la ligne `data_collator=data_collator` dans cet appel. Il était quand même important de vous montrer cette partie du traitement dans la section 2 ! + +Pour *finetuner* le modèle sur notre jeu de données, il suffit d'appeler la méthode `train()` de notre `Trainer` : + +```py +trainer.train() +``` + +Cela lancera le *finetuning* (qui devrait prendre quelques minutes sur un GPU) et indiquera la perte d'entraînement tous les 500 pas. Cependant, elle ne vous dira pas si votre modèle fonctionne bien (ou mal). Ceci est dû au fait que : + +1. nous n'avons pas dit au `Trainer` d'évaluer pendant l'entraînement en réglant `evaluation_strategy` à soit `"steps"` (évaluer chaque `eval_steps`) ou `"epoch"` (évaluer à la fin de chaque epoch). +2. nous n'avons pas fourni au `Trainer` une fonction `compute_metrics()` pour calculer une métrique pendant ladite évaluation (sinon l'évaluation aurait juste affiché la perte, qui n'est pas un nombre très intuitif). + + +### Evaluation + +Voyons comment nous pouvons construire une fonction `compute_metrics()` utile et l'utiliser la prochaine fois que nous entraînons. La fonction doit prendre un objet `EvalPrediction` (qui est un *tuple* nommé avec un champ `predictions` et un champ `label_ids`) et retournera un dictionnaire de chaînes de caractères vers des flottants (les chaînes de caractères étant les noms des métriques retournées, et les flottants leurs valeurs). Pour obtenir des prédictions de notre modèle, nous pouvons utiliser la commande `Trainer.predict()` : + +```py +predictions = trainer.predict(tokenized_datasets["validation"]) +print(predictions.predictions.shape, predictions.label_ids.shape) +``` + +```python out +(408, 2) (408,) +``` + +La sortie de la méthode `predict()` est un autre *tuple* nommé avec trois champs : `predictions`, `label_ids`, et `metrics`. Le champ `metrics` contiendra juste la perte sur le jeu de données passé, ainsi que quelques mesures de temps (combien de temps il a fallu pour prédire, au total et en moyenne). Une fois que nous aurons complété notre fonction `compute_metrics()` et que nous l'aurons passé au `Trainer`, ce champ contiendra également les métriques retournées par `compute_metrics()`. + +Comme vous pouvez le voir, `predictions` est un tableau bidimensionnel de forme 408 x 2 (408 étant le nombre d'éléments dans le jeu de données que nous avons utilisé). Ce sont les logits pour chaque élément du jeu de données que nous avons passé à `predict()` (comme vous l'avez vu dans le [chapitre précédent](/course/fr/chapter2), tous les *transformers* retournent des logits). Pour les transformer en prédictions que nous pouvons comparer à nos étiquettes, nous devons prendre l'indice avec la valeur maximale sur le second axe : + +```py +import numpy as np + +preds = np.argmax(predictions.predictions, axis=-1) +``` + +Nous pouvons maintenant comparer ces `preds` aux étiquettes. Pour construire notre fonction `compute_metric()`, nous allons nous appuyer sur les métriques de la bibliothèque 🤗 *Datasets*. Nous pouvons charger les métriques associées au jeu de données MRPC aussi facilement que nous avons chargé le jeu de données, cette fois avec la fonction `load_metric()`. L'objet retourné possède une méthode `compute()` que nous pouvons utiliser pour effectuer le calcul de la métrique : + +```py +from datasets import load_metric + +metric = load_metric("glue", "mrpc") +metric.compute(predictions=preds, references=predictions.label_ids) +``` + +```python out +{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} +``` + +Les résultats exacts que vous obtiendrez peuvent varier, car l'initialisation aléatoire de la tête du modèle peut modifier les métriques obtenues. Ici, nous pouvons voir que notre modèle a une précision de 85,78% sur l'ensemble de validation et un score F1 de 89,97. Ce sont les deux métriques utilisées pour évaluer les résultats sur le jeu de données MRPC pour le benchmark GLUE. Le tableau du papier de [BERT](https://arxiv.org/pdf/1810.04805.pdf) indique un score F1 de 88,9 pour le modèle de base. Il s'agissait du modèle `uncased` alors que nous utilisons actuellement le modèle `cased`, ce qui explique le meilleur résultat. + +En regroupant le tout, nous obtenons notre fonction `compute_metrics()` : + +```py +def compute_metrics(eval_preds): + metric = load_metric("glue", "mrpc") + logits, labels = eval_preds + predictions = np.argmax(logits, axis=-1) + return metric.compute(predictions=predictions, references=labels) +``` + +Et pour le voir utilisé en action pour rapporter les métriques à la fin de chaque époque, voici comment nous définissons un nouveau `Trainer` avec cette fonction `compute_metrics()` : + +```py +training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch") +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) + +trainer = Trainer( + model, + training_args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + tokenizer=tokenizer, + compute_metrics=compute_metrics, +) +``` + +Notez que nous créons un nouveau `TrainingArguments` avec sa `evaluation_strategy` définie sur `"epoch"` et un nouveau modèle. Sinon, nous ne ferions que continuer l'entraînement du modèle que nous avons déjà entraîné. Pour lancer un nouveau cycle d'entraînement, nous exécutons : + +``` +trainer.train() +``` + +Cette fois, il indiquera la perte et les mesures de validation à la fin de chaque époque, en plus de la perte d'entraînement. Encore une fois, le score exact de précision/F1 que vous atteignez peut être un peu différent de ce que nous avons trouvé, en raison de l'initialisation aléatoire de la tête du modèle, mais il devrait être dans la même fourchette. + +Le `Trainer` fonctionnera sur plusieurs GPUs ou TPUs et fournit beaucoup d'options, comme l'entraînement en précision mixte (utilisez `fp16 = True` dans vos arguments d'entraînement). Nous passerons en revue tout ce qu'il supporte dans le chapitre 10. + +Ceci conclut l'introduction au *fine-tuning* en utilisant l'API `Trainer`. Un exemple d'utilisation pour les tâches de NLP les plus communes es donné dans le [Chapitre 7](/course/fr/chapter7), mais pour l'instant regardons comment faire la même chose en PyTorch pur. + + + +✏️ **Essayez** *Finetunez* un modèle sur le jeu de données GLUE SST-2, en utilisant le traitement des données que vous avez fait dans la section 2. + + \ No newline at end of file diff --git a/chapters/fr/chapter3/3_tf.mdx b/chapters/fr/chapter3/3_tf.mdx new file mode 100644 index 000000000..1fd969770 --- /dev/null +++ b/chapters/fr/chapter3/3_tf.mdx @@ -0,0 +1,190 @@ + + +# *Finetuner* un modèle avec Keras + + + +Une fois que vous avez fait tout le travail de prétraitement des données dans la dernière section, il ne vous reste que quelques étapes pour entraîner le modèle. Notez, cependant, que la commande `model.fit()` s'exécutera très lentement sur un CPU. Si vous n'avez pas de GPU, vous pouvez avoir accès à des GPUs ou TPUs gratuits sur [Google Colab] (https://colab.research.google.com/). + +Les exemples de code ci-dessous supposent que vous avez déjà exécuté les exemples de la section précédente. Voici un bref résumé de ce dont vous avez besoin : + +```py +from datasets import load_dataset +from transformers import AutoTokenizer, DataCollatorWithPadding +import numpy as np + +raw_datasets = load_dataset("glue", "mrpc") +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + + +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) + + +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) + +data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf") + +tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( + columns=["attention_mask", "input_ids", "token_type_ids"], + label_cols=["labels"], + shuffle=True, + collate_fn=data_collator, + batch_size=8, +) + +tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( + columns=["attention_mask", "input_ids", "token_type_ids"], + label_cols=["labels"], + shuffle=False, + collate_fn=data_collator, + batch_size=8, +) +``` + +### Entraînement + +Les modèles TensorFlow importés depuis 🤗 *Transformers* sont déjà des modèles Keras. Voici une courte introduction à Keras. + + + +Cela signifie qu'une fois que nous disposons de nos données, très peu de travail est nécessaire pour commencer à entraîner sur celles-ci. + + + +Comme dans le [chapitre précédent] (/course/fr/chapter2), nous allons utiliser la classe `TFAutoModelForSequenceClassification`, avec deux étiquettes : + +```py +from transformers import TFAutoModelForSequenceClassification + +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +Vous remarquerez que, contrairement au [Chapitre 2](/course/fr/chapter2), vous obtenez un message d'avertissement après l'instanciation de ce modèle pré-entraîné. Ceci est dû au fait que BERT n'a pas été pré-entraîné à la classification de paires de phrases, donc la tête du modèle pré-entraîné a été supprimée et une nouvelle tête adaptée à la classification de séquences a été insérée à la place. Les messages d'avertissement indiquent que certains poids n'ont pas été utilisés (ceux correspondant à la tête de pré-entraînement abandonnée) et que d'autres ont été initialisés de manière aléatoire (ceux pour la nouvelle tête). Il conclut en vous encourageant à entraîner le modèle, ce qui est exactement ce que nous allons faire maintenant. + +Pour *finetuner* le modèle sur notre jeu de données, nous devons simplement `compiler()` notre modèle et ensuite passer nos données à la méthode `fit()`. Cela va démarrer le processus de *finetuning* (qui devrait prendre quelques minutes sur un GPU) et rapporter la perte d'entraînement au fur et à mesure, plus la perte de validation à la fin de chaque époque. + + + +Notez que les modèles 🤗 *Transformers* ont une capacité spéciale que la plupart des modèles Keras n'ont pas. Ils peuvent automatiquement utiliser une perte appropriée qu'ils calculent en interne. Ils utiliseront cette perte par défaut si vous ne définissez pas un argument de perte dans `compile()`. Notez que pour utiliser la perte interne, vous devrez passer vos labels comme faisant partie de l'entrée, et non pas comme un label séparé, ce qui est la façon normale d'utiliser les labels avec les modèles Keras. Vous verrez des exemples de cela dans la partie 2 du cours, où la définition de la fonction de perte correcte peut être délicate. Pour la classification des séquences, cependant, une fonction de perte standard de Keras fonctionne bien, et c'est donc ce que nous utiliserons ici. + + + +```py +from tensorflow.keras.losses import SparseCategoricalCrossentropy + +model.compile( + optimizer="adam", + loss=SparseCategoricalCrossentropy(from_logits=True), + metrics=["accuracy"], +) +model.fit( + tf_train_dataset, + validation_data=tf_validation_dataset, +) +``` + + + +Notez un piège très commun ici. Vous *pouvez* simplement passer le nom de la perte comme une chaîne à Keras, mais par défaut Keras supposera que vous avez déjà appliqué une fonction softmax à vos sorties. Cependant, de nombreux modèles produisent les valeurs juste avant l'application de la softmax, que l'on appelle aussi les *logits*. Nous devons indiquer à la fonction de perte que c'est ce que fait notre modèle, et la seule façon de le faire est de l'appeler directement, plutôt que par son nom avec une chaîne. + + + + +### Améliorer les performances d'entraînement + + + +Si vous essayez le code ci-dessus, il fonctionne certainement, mais vous constaterez que la perte ne diminue que lentement ou sporadiquement. La cause principale est le *taux d'apprentissage*. Comme pour la perte, lorsque nous transmettons à Keras le nom d'un optimiseur sous forme de chaîne de caractères, Keras initialise cet optimiseur avec des valeurs par défaut pour tous les paramètres, y compris le taux d'apprentissage. Cependant, nous savons depuis longtemps que les *transformers* bénéficient d'un taux d'apprentissage beaucoup plus faible que celui par défaut d'Adam, qui est de 1e-3, également écrit comme 10 à la puissance -3, ou 0,001. 5e-5 (0,00005), qui est environ vingt fois inférieur, est un bien meilleur point de départ. + +En plus de réduire le taux d'apprentissage, nous avons une deuxième astuce dans notre manche : nous pouvons réduire lentement le taux d'apprentissage au cours de l'entraînement. Dans la littérature, on parle parfois de *décroissance* ou d' *annulation* du taux d'apprentissage.le taux d'apprentissage. Dans Keras, la meilleure façon de le faire est d'utiliser un *planificateur du taux d'apprentissage*. Un bon planificateur à utiliser est `PolynomialDecay`. Malgré son nom, avec les paramètres par défaut, il diminue simplement de façon linéaire le taux d'apprentissage de la valeur initiale à la valeur finale au cours de l'entraînement, ce qui est exactement ce que nous voulons. Afin d'utiliser correctement un planificateur, nous devons lui dire combien de temps l'entraînement va durer. Nous calculons cela comme `num_train_steps` ci-dessous. + +```py +from tensorflow.keras.optimizers.schedules import PolynomialDecay + +batch_size = 8 +num_epochs = 3 +# 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. 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. +num_train_steps = len(tf_train_dataset) * num_epochs +lr_scheduler = PolynomialDecay( + initial_learning_rate=5e-5, end_learning_rate=0.0, decay_steps=num_train_steps +) +from tensorflow.keras.optimizers import Adam + +opt = Adam(learning_rate=lr_scheduler) +``` + + + +La bibliothèque 🤗 *Transformers* possède également une fonction `create_optimizer()` qui créera un optimiseur `AdamW` avec un taux d'apprentissage décroissant. Il s'agit d'un raccourci pratique que vous verrez en détail dans les prochaines sections du cours. + + + +Nous avons maintenant notre tout nouvel optimiseur et nous pouvons essayer de nous entraîner avec lui. Tout d'abord, rechargeons le modèle pour réinitialiser les modifications apportées aux poids lors de l'entraînement que nous venons d'effectuer, puis nous pouvons le compiler avec le nouvel optimiseur : + +```py +import tensorflow as tf + +model = TFAutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) +model.compile(optimizer=opt, loss=loss, metrics=["accuracy"]) +``` + +Maintenant, on *fit* : + +```py +model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3) +``` + + + +💡 Si vous voulez télécharger automatiquement votre modèle sur le *Hub* pendant l'entraînement, vous pouvez passer un `PushToHubCallback` dans la méthode `model.fit()`. Nous en apprendrons davantage à ce sujet au [Chapitre 4](/course/fr/chapter4/3). + + + +### Prédictions du modèle + + + + +Entraîner et regarder la perte diminuer, c'est très bien, mais que faire si l'on veut réellement obtenir des résultats du modèle entraîné, soit pour calculer des métriques, soit pour utiliser le modèle en production ? Pour ce faire, nous pouvons simplement utiliser la méthode `predict()`. Ceci retournera les *logits* de la tête de sortie du modèle, un par classe. + +```py +preds = model.predict(tf_validation_dataset)["logits"] +``` + +Nous pouvons convertir ces logits en prédictions de classe du modèle en utilisant `argmax` pour trouver le logit le plus élevé, qui correspond à la classe la plus probable : + +```py +class_preds = np.argmax(preds, axis=1) +print(preds.shape, class_preds.shape) +``` + +```python out +(408, 2) (408,) +``` + +Maintenant, utilisons ces `preds` pour calculer des métriques ! Nous pouvons charger les métriques associées au jeu de données MRPC aussi facilement que nous avons chargé le jeu de données, cette fois avec la fonction `load_metric()`. L'objet retourné a une méthode `compute()` que nous pouvons utiliser pour faire le calcul de la métrique : + +```py +from datasets import load_metric + +metric = load_metric("glue", "mrpc") +metric.compute(predictions=class_preds, references=raw_datasets["validation"]["label"]) +``` + +```python out +{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} +``` + +Les résultats exacts que vous obtiendrez peuvent varier, car l'initialisation aléatoire de la tête du modèle peut modifier les métriques obtenues. Ici, nous pouvons voir que notre modèle a une précision de 85,78% sur l'ensemble de validation et un score F1 de 89,97. Ce sont les deux métriques utilisées pour évaluer les résultats sur le jeu de données MRPC pour le benchmark GLUE. Le tableau du papier de [BERT](https://arxiv.org/pdf/1810.04805.pdf) indique un score F1 de 88,9 pour le modèle de base. Il s'agissait du modèle `uncased` alors que nous utilisons actuellement le modèle `cased`, ce qui explique le meilleur résultat. + +Ceci conclut l'introduction à le *finetuning* en utilisant l'API Keras. Un exemple d'application de cette méthode aux tâches les plus courantes du traitement automatique des langues sera présenté au [Chapitre 7](/course/fr/chapter7). Si vous souhaitez affiner vos connaissances de l'API Keras, essayez *finetuner* un modèle sur le jeu de données GLUE SST-2, en utilisant le traitement des données que vous avez effectué dans la section 2. \ No newline at end of file diff --git a/chapters/fr/chapter3/4.mdx b/chapters/fr/chapter3/4.mdx new file mode 100644 index 000000000..fe3dfcc94 --- /dev/null +++ b/chapters/fr/chapter3/4.mdx @@ -0,0 +1,359 @@ +# Un entraînement complet + + + + + +Maintenant nous allons voir comment obtenir les mêmes résultats que dans la dernière section sans utiliser la classe `Trainer`. Encore une fois, nous supposons que vous avez fait le traitement des données dans la section 2. Voici un court résumé couvrant tout ce dont vous aurez besoin : + +```py +from datasets import load_dataset +from transformers import AutoTokenizer, DataCollatorWithPadding + +raw_datasets = load_dataset("glue", "mrpc") +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + + +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) + + +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) +``` + +### Préparer l'entraînement + +Avant d'écrire réellement notre boucle d'entraînement, nous devons définir quelques objets. Les premiers sont les *dataloaders* que nous utiliserons pour itérer sur les batchs. Mais avant de pouvoir définir ces chargeurs de données, nous devons appliquer un peu de post-traitement à nos `tokenized_datasets`, pour prendre soin de certaines choses que le `Trainer` fait pour nous automatiquement. Spécifiquement, nous devons : + +- supprimer les colonnes correspondant aux valeurs que le modèle n'attend pas (comme les colonnes `sentence1` et `sentence2`), +- renommer la colonne `label` en `labels` (parce que le modèle s'attend à ce que l'argument soit nommé `labels`), +- définir le format des jeux de données pour qu'ils retournent des tenseurs PyTorch au lieu de listes. + +Notre `tokenized_datasets` a une méthode pour chacune de ces étapes : + +```py +tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"]) +tokenized_datasets = tokenized_datasets.rename_column("label", "labels") +tokenized_datasets.set_format("torch") +tokenized_datasets["train"].column_names +``` + +Nous pouvons alors vérifier que le résultat ne comporte que des colonnes que notre modèle acceptera : + +```python +["attention_mask", "input_ids", "labels", "token_type_ids"] +``` + +Maintenant que cela est fait, nous pouvons facilement définir nos *dataloaders* : + +```py +from torch.utils.data import DataLoader + +train_dataloader = DataLoader( + tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator +) +``` + +Pour vérifier rapidement qu'il n'y a pas d'erreur dans le traitement des données, nous pouvons inspecter un batch comme celui-ci : + +```py +for batch in train_dataloader: + break +{k: v.shape for k, v in batch.items()} +``` + +```python out +{'attention_mask': torch.Size([8, 65]), + 'input_ids': torch.Size([8, 65]), + 'labels': torch.Size([8]), + 'token_type_ids': torch.Size([8, 65])} +``` + +Notez que les formes réelles seront probablement légèrement différentes pour vous puisque nous avons défini `shuffle=True` pour le chargeur de données d'entraînement et que nous *paddons* à la longueur maximale dans le lot. + +Maintenant que nous en avons terminé avec le prétraitement des données (un objectif satisfaisant mais difficile à atteindre pour tout praticien d'apprentissage automatique), passons au modèle. Nous l'instancions exactement comme nous l'avons fait dans la section précédente : + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +Pour s'assurer que tout se passera bien pendant l'entraînement, nous transmettons notre batch à ce modèle : + +```py +outputs = model(**batch) +print(outputs.loss, outputs.logits.shape) +``` + +```python out +tensor(0.5441, grad_fn=) torch.Size([8, 2]) +``` + +Tous les modèles 🤗 *Transformers* renvoient la perte lorsque les `labels` sont fournis. Nous obtenons également les logits (deux pour chaque entrée de notre batch, donc un tenseur de taille 8 x 2). + +Nous sommes presque prêts à écrire notre boucle d'entraînement ! Il nous manque juste deux choses : un optimiseur et un planificateur de taux d'apprentissage. Puisque nous essayons de reproduire à la main ce que fait la fonction `Trainer`, utilisons les mêmes paramètres par défaut. L'optimiseur utilisé par `Trainer` est `AdamW`, qui est le même qu'Adam, mais avec une torsion pour la régularisation par décroissance de poids (voir ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) par Ilya Loshchilov et Frank Hutter) : + +```py +from transformers import AdamW + +optimizer = AdamW(model.parameters(), lr=5e-5) +``` + +Enfin, le planificateur du taux d'apprentissage utilisé par défaut est juste une décroissance linéaire de la valeur maximale (5e-5) à 0. Pour le définir correctement, nous devons connaître le nombre d'étapes d'entraînement que nous prendrons, qui est le nombre d'époques que nous voulons exécuter multiplié par le nombre de lots d'entraînement (qui est la longueur de notre dataloader d'entraînement). Le `Trainer` utilise trois époques par défaut, nous allons donc suivre ça : + +```py +from transformers import get_scheduler + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dataloader) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +print(num_training_steps) +``` + +```python out +1377 +``` + +### La boucle d'entraînement + +Une dernière chose : nous voulons utiliser le GPU si nous en avons un (sur un CPU, l'entraînement peut prendre plusieurs heures au lieu de quelques minutes). Pour ce faire, nous définissons un `device` sur lequel nous allons placer notre modèle et nos batchs : + +```py +import torch + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +model.to(device) +device +``` + +```python out +device(type='cuda') +``` + +Nous sommes maintenant prêts à entraîner ! Pour avoir une idée du moment où l'entraînement sera terminé, nous ajoutons une barre de progression sur le nombre d'étapes d'entraînement, en utilisant la bibliothèque `tqdm` : + +```py +from tqdm.auto import tqdm + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss + loss.backward() + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +Vous pouvez voir que le cœur de la boucle d'entraînement ressemble beaucoup à celui de l'introduction. Nous n'avons pas demandé de rapport, donc cette boucle d'entraînement ne nous dira rien sur les résultats du modèle. Pour cela, nous devons ajouter une boucle d'évaluation. + + +### La boucle d'évaluation + +Comme nous l'avons fait précédemment, nous allons utiliser une métrique fournie par la bibliothèque 🤗 *Datasets*. Nous avons déjà vu la méthode `metric.compute()`, mais les métriques peuvent en fait accumuler des batchs pour nous au fur et à mesure que nous parcourons la boucle de prédiction avec la méthode `add_batch()`. Une fois que nous avons accumulé tous les batchs, nous pouvons obtenir le résultat final avec `metric.compute()`. Voici comment implémenter tout cela dans une boucle d'évaluation : + +```py +from datasets import load_metric + +metric = load_metric("glue", "mrpc") +model.eval() +for batch in eval_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + with torch.no_grad(): + outputs = model(**batch) + + logits = outputs.logits + predictions = torch.argmax(logits, dim=-1) + metric.add_batch(predictions=predictions, references=batch["labels"]) + +metric.compute() +``` + +```python out +{'accuracy': 0.8431372549019608, 'f1': 0.8907849829351535} +``` + +Une fois encore, vos résultats seront légèrement différents en raison du caractère aléatoire de l'initialisation de la tête du modèle et du mélange des données, mais ils devraient se situer dans la même fourchette. + + + +✏️ **Essayez** Modifiez la boucle d'entraînement précédente pour *finetuner* votre modèle sur le jeu de données SST-2. + + + +### Optimisez votre boucle d'entraînement avec 🤗 *Accelerate* + + + +La boucle d'entraînement que nous avons définie précédemment fonctionne bien sur un seul CPU ou GPU. Mais en utilisant la bibliothèque [🤗 *Accelerate*](https://github.com/huggingface/accelerate), il suffit de quelques ajustements pour permettre un entraînement distribué sur plusieurs GPUs ou TPUs. En partant de la création des *dataloaders* d'entraînement et de validation, voici à quoi ressemble notre boucle d'entraînement manuel : + +```py +from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +optimizer = AdamW(model.parameters(), lr=3e-5) + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +model.to(device) + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dataloader) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss + loss.backward() + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +Et voici les changements : + +```diff ++ from accelerate import Accelerator + from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + ++ accelerator = Accelerator() + + model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) + optimizer = AdamW(model.parameters(), lr=3e-5) + +- device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +- model.to(device) + ++ train_dataloader, eval_dataloader, model, optimizer = accelerator.prepare( ++ train_dataloader, eval_dataloader, model, optimizer ++ ) + + num_epochs = 3 + num_training_steps = num_epochs * len(train_dataloader) + lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps + ) + + progress_bar = tqdm(range(num_training_steps)) + + model.train() + for epoch in range(num_epochs): + for batch in train_dataloader: +- batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss +- loss.backward() ++ accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +La première ligne à ajouter est la ligne d'importation. La deuxième ligne instancie un objet `Accelerator` qui va regarder l'environnement et initialiser la bonne configuration distribuée. 🤗 *Accelerate* gère le placement des périphériques pour vous, donc vous pouvez enlever les lignes qui placent le modèle sur le périphérique (ou, si vous préférez, les changer pour utiliser `accelerator.device` au lieu de `device`). + +Ensuite, le gros du travail est fait dans la ligne qui envoie les *dataloaders*, le modèle, et l'optimiseur à `accelerator.prepare()`. Cela va envelopper ces objets dans le conteneur approprié pour s'assurer que votre entraînement distribué fonctionne comme prévu. Les changements restants à faire sont la suppression de la ligne qui met le batch sur le `device` (encore une fois, si vous voulez le garder, vous pouvez juste le changer pour utiliser `accelerator.device`) et le remplacement de `loss.backward()` par `accelerator.backward(loss)`. + + +⚠️ Afin de bénéficier de la rapidité offerte par les TPUs du Cloud, nous vous recommandons de rembourrer vos échantillons à une longueur fixe avec les arguments `padding="max_length"` et `max_length` du *tokenizer*. + + +Si vous souhaitez faire un copier-coller pour jouer, voici à quoi ressemble la boucle d'entraînement complète avec 🤗 *Accelerate* : + +```py +from accelerate import Accelerator +from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler + +accelerator = Accelerator() + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +optimizer = AdamW(model.parameters(), lr=3e-5) + +train_dl, eval_dl, model, optimizer = accelerator.prepare( + train_dataloader, eval_dataloader, model, optimizer +) + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dl) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dl: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +En plaçant ceci dans un script `train.py`, cela sera exécutable sur n'importe quel type d'installation distribuée. Pour l'essayer dans votre installation distribuée, exécutez la commande : + +```bash +accelerate config +``` + +qui vous demandera de répondre à quelques questions et enregistrera vos réponses dans un fichier de configuration utilisé par cette commande : + +``` +accelerate launch train.py +``` + +qui lancera l'entraînement distribué. + +Si vous voulez essayer ceci dans un *notebook* (par exemple, pour le tester avec des TPUs sur Colab), collez simplement le code dans une `training_function()` et lancez une dernière cellule avec : + +```python +from accelerate import notebook_launcher + +notebook_launcher(training_function) +``` + +Vous trouverez d'autres exemples dans le dépôt d'[🤗 *Accelerate*](https://github.com/huggingface/accelerate/tree/main/examples). \ No newline at end of file diff --git a/chapters/fr/chapter3/5.mdx b/chapters/fr/chapter3/5.mdx new file mode 100644 index 000000000..62f49c39d --- /dev/null +++ b/chapters/fr/chapter3/5.mdx @@ -0,0 +1,20 @@ + + +# *Finetuning*, vérifié ! + +C'était amusant ! Dans les deux premiers chapitres, vous avez appris à connaître les modèles et les *tokenizers*, et vous savez maintenant comment les *finetuner* pour vos propres données. Pour récapituler, dans ce chapitre vous : + +{#if fw === 'pt'} +* avez appris à connaître les jeux de données dans le [Hub](https://huggingface.co/datasets), +* avez appris à charger et à prétraiter des jeux de données, notamment en utilisant le remplissage dynamique et les assembleurs, +* avez implémenté votre propre *finetuning* et évaluation d'un modèle, +* avez implémenté une boucle d'entraînement de niveau inférieur, +* avez utilisé 🤗 *Accelerate* pour adapter facilement votre boucle d'entraînement afin qu'elle fonctionne pour plusieurs GPUs ou TPUs. + +{:else} +* avez appris à connaître les jeux de données dans le [Hub](https://huggingface.co/datasets), +* avez appris comment charger et prétraiter les jeux de données, +* avez appris comment *finetuner* et évaluer un modèle avec Keras, +* avez implémenté une métrique personnalisée. + +{/if} \ No newline at end of file diff --git a/chapters/fr/chapter3/6.mdx b/chapters/fr/chapter3/6.mdx new file mode 100644 index 000000000..3654b7181 --- /dev/null +++ b/chapters/fr/chapter3/6.mdx @@ -0,0 +1,296 @@ + + + + +# Quiz de fin de chapitre + +Testez ce que vous avez appris dans ce chapitre ! + +### 1. Le jeu de données `emotion` contient des messages Twitter étiquetés avec des émotions. Cherchez-le dans le [*Hub*](https://huggingface.co/datasets), et lisez la carte du jeu de données. Laquelle de ces émotions n'est pas une de ses émotions de base ? + + + +### 2. Cherchez le jeu de données `ar_sarcasme` dans le [*Hub*](https://huggingface.co/datasets). Quelle tâche prend-il en charge ? + +carte du jeu de données !" + }, + { + text: "Reconnaissance des entités nommées", + explain: "Ce n'est pas ça. Jetez un autre coup d'œil à la carte du jeu de données !" + }, + { + text: "Réponse aux questions", + explain: "Hélas, cette question n'a pas reçu de réponse correcte. Essayez à nouveau !" + } + ]} +/> + +### 3. Comment le modèle BERT attend-il qu'une paire de phrases soit traitée ? + +[SEP] est nécessaire pour séparer les deux phrases, mais ce n'est pas tout !" + }, + { + text: "[CLS] Tokens_de_la_phrase_1 Tokens_de_la_phrase_2", + explain: "Un jeton spécial [CLS] est requis au début, mais ce n'est pas la seule chose !" + }, + { + text: "[CLS] Tokens_de_la_phrase_1 [SEP] Tokens_de_la_phrase_2 [SEP]", + explain: "C'est exact !", + correct: true + }, + { + text: "[CLS] Tokens_de_la_phrase_1 [SEP] Tokens_de_la_phrase_2", + explain: "Un jeton spécial [CLS] est nécessaire au début, ainsi qu'un jeton spécial [SEP] pour séparer les deux phrases, mais ce n'est pas tout !" + } + ]} +/> + +{#if fw === 'pt'} +### 4. Quels sont les avantages de la méthode `Dataset.map()` ? + + + +### 5. Que signifie le remplissage (*padding*) dynamique ? + +tokens que la précédente dans le jeu de données.", + explain: "C'est incorrect, et cela n'a pas de sens de regarder l'ordre dans le jeu de données puisque nous le mélangeons pendant l'entraînement." + }, + ]} +/> + +### 6. Quel est le but d'une fonction de collecte ? + +DataCollatorWithPadding." + }, + { + text: "Elle rassemble tous les échantillons dans un batch.", + explain: "Correct ! Vous pouvez passer la fonction de collecte comme argument d'une fonction DataLoader. Nous avons utilisé la fonction DataCollatorWithPadding qui remplit tous les éléments d'un batch pour qu'ils aient la même longueur.", + correct: true + }, + { + text: "Elle pré-traite tout le jeu de données.", + explain: "Ce serait une fonction de prétraitement, pas une fonction de collecte." + }, + { + text: "Elle tronque les séquences dans le jeu de données.", + explain: "Une fonction de collecte est impliquée dans le traitement des batchs individuels, et non de tout le jeu de données. Si vous êtes intéressé par la troncature, vous pouvez utiliser la fonction truncate en argument du tokenizer." + } + ]} +/> + +### 7. Que se passe-t-il lorsque vous instanciez une des classes `AutoModelForXxx` avec un modèle de langage pré-entraîné (tel que `bert-base-uncased`) qui correspond à une tâche différente de celle pour laquelle il a été entraîné ? + +AutoModelForSequenceClassification avec bert-base-uncased, nous avons eu des messages d'avertissement lors de l'instanciation du modèle. La tête pré-entraînée n'est pas utilisée pour la tâche de classification de séquences, elle est donc supprimée et une nouvelle tête est instanciée avec des poids aléatoires..", + correct: true + }, + { + text: "La tête du modèle pré-entraîné est supprimée.", + explain: "Quelque chose d'autre doit se produire. Essayez encore !" + }, + { + text: "Rien, puisque le modèle peut encore être finetuné pour les différentes tâches.", + explain: "La tête du modèle pré-entraîné n'a pas été entraînée à résoudre cette tâche, nous devons donc la supprimer !" + } + ]} +/> + +### 8. Quel est le but de `TrainingArguments` ? + +Trainer.", + explain: "Correct !", + correct: true + }, + { + text: "Préciser la taille du modèle.", + explain: "La taille du modèle est définie par la configuration du modèle, et non par la classe TrainingArguments." + }, + { + text: "Juste contenir les hyperparamètres utilisés pour l'évaluation..", + explain: "Dans l'exemple, nous avons spécifié où le modèle et ses checkpoints seront sauvegardés. Essayez à nouveau !" + }, + { + text: "Contenir seulement les hyperparamètres utilisés pour l'entraînement.", + explain: "Dans l'exemple, nous avons utilisé une evaluation_strategy également, ce qui a un impact sur l'évaluation. Essayez à nouveau !" + } + ]} +/> + +### 9. Pourquoi devriez-vous utiliser la librairie 🤗 *Accelerate* ? + +Trainer mais pas avec la librairie 🤗 *Accelerate*. Essayez à nouveau !" + }, + { + text: "Elle permet à nos boucles d'entraînement de fonctionner avec des stratégies distribuées.", + explain: "Correct ! Avec 🤗 *Accelerate*, vos boucles d'entraînement fonctionneront pour plusieurs GPUs et TPUs..", + correct: true + }, + { + text: "Elle offre davantage de fonctions d'optimisation.", + explain: "Non, la librairie 🤗 *Accelerate* ne fournit pas de fonctions d'optimisation." + } + ]} +/> + +{:else} +### 4. Que se passe-t-il lorsque vous instanciez une des classes `TFAutoModelForXxx` avec un modèle de langage pré-entraîné (tel que `bert-base-uncased`) qui correspond à une tâche différente de celle pour laquelle il a été entraîné ? + +TFAutoModelForSequenceClassification avec bert-base-uncased, nous avons eu des messages d'avertissement lors de l'instanciation du modèle. La tête pré-entraînée n'est pas utilisée pour la tâche de classification de séquences, elle est donc supprimée et une nouvelle tête est instanciée avec des poids aléatoires..", + correct: true + }, + { + text: "La tête du modèle pré-entraîné est supprimée.", + explain: "Quelque chose d'autre doit se produire. Essayez encore !" + }, + { + text: "Rien, puisque le modèle peut encore être finetuné pour les différentes tâches.", + explain: "La tête du modèle pré-entraîné n'a pas été entraînée à résoudre cette tâche, nous devons donc la supprimer !" + } + ]} +/> + +### 5. Les modèles TensorFlow de `transformers` sont déjà des modèles Keras. Quel avantage cela offre-t-il ? + +TPUStrategy, y compris l'initialisation du modèle." + }, + { + text: "Vous pouvez tirer parti des méthodes existantes telles que compile(), fit() et predict().", + explain: "Correct ! Une fois que vous disposez des données, l'entraînement sur celles-ci ne demande que très peu de travail.", + correct: true + }, + { + text: "Vous apprendrez à connaître Keras ainsi que transformers.", + explain: "Correct, mais nous cherchons quelque chose d'autre :)", + correct: true + }, + { + text: "Vous pouvez facilement calculer les métriques liées au jeu de données.", + explain: "Keras nous aide à entraîner et à évaluer le modèle, et non à calculer les paramètres liés aux jeux de données." + } + ]} +/> + +### 6. Comment pouvez-vous définir votre propre métrique personnalisée ? + +tf.keras.metrics.Metric.", + explain: "Excellent !", + correct: true + }, + { + text: "Utilisation de l'API fonctionnelle de Keras.", + explain: "Essayez à nouveau !" + }, + { + text: "En utilisant un callable avec la signature metric_fn(y_true, y_pred).", + explain: "Correct !", + correct: true + }, + { + text: "En le googlant.", + explain: "Ce n'est pas la réponse que nous cherchons, mais cela devrait vous aider à la trouver..", + correct: true + } + ]} +/> + +{/if} \ No newline at end of file diff --git a/chapters/fr/chapter4/1.mdx b/chapters/fr/chapter4/1.mdx new file mode 100644 index 000000000..8c98a16b5 --- /dev/null +++ b/chapters/fr/chapter4/1.mdx @@ -0,0 +1,17 @@ +# Le *Hub* d'Hugging Face + +Le [*Hub* d'Hugging Face](https://huggingface.co/), notre site internet principal, est une plateforme centrale qui permet à quiconque de découvrir, d'utiliser et de contribuer à de nouveaux modèles et jeux de données de pointe. Il héberge une grande variété de modèles, dont plus de 10 000 sont accessibles au public. Nous nous concentrerons sur les modèles dans ce chapitre, et nous examinerons les jeux de données au chapitre 5. + +Les modèles présents dans le *Hub* ne sont pas limités à 🤗 *Transformers* ou même au NLP. Il existe des modèles de [Flair](https://github.com/flairNLP/flair) et [AllenNLP](https://github.com/allenai/allennlp) pour le NLP, [Asteroid](https://github.com/asteroid-team/asteroid) et [pyannote](https://github.com/pyannote/pyannote-audio) pour l'audio, et [timm](https://github.com/rwightman/pytorch-image-models) pour la vision, pour n'en citer que quelques-uns. + +Chacun de ces modèles est hébergé sous forme de dépôt Git, ce qui permet le suivi des versions et la reproductibilité. Partager un modèle sur le *Hub*, c'est l'ouvrir à la communauté et le rendre accessible à tous ceux qui souhaitent l'utiliser facilement, ce qui leur évite d'avoir à entraîner eux-mêmes un modèle et simplifie le partage et l'utilisation. + +En outre, le partage d'un modèle sur le *Hub* déploie automatiquement une API d'inférence hébergée pour ce modèle. Toute personne de la communauté est libre de la tester directement sur la page du modèle, avec des entrées personnalisées et des *widgets* appropriés. + +La meilleure partie est que le partage ainsi que l'utilisation de n'importe quel modèle public sur le *Hub* sont totalement gratuits ! [Des plans payants](https://huggingface.co/pricing) existent également si vous souhaitez partager des modèles en privé. + +La vidéo ci-dessous montre comment naviguer sur le *Hub* : + + + +Avoir un compte huggingface.co est nécessaire pour suivre cette partie car nous allons créer et gérer des répertoires sur le *Hub* : [créer un compte](https://huggingface.co/join) \ No newline at end of file diff --git a/chapters/fr/chapter4/2.mdx b/chapters/fr/chapter4/2.mdx new file mode 100644 index 000000000..1d1ecb387 --- /dev/null +++ b/chapters/fr/chapter4/2.mdx @@ -0,0 +1,97 @@ + + +# Utilisation de modèles pré-entraînés + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Le *Hub* simplifie la sélection du modèle approprié, de sorte que son utilisation dans toute bibliothèque en aval peut se faire en quelques lignes de code. Voyons comment utiliser concrètement l'un de ces modèles et comment contribuer à la communauté. + +Supposons que nous recherchions un modèle basé sur le français, capable de remplir des masques. + +
+Selecting the Camembert model. +
+ +Nous choisissons le *checkpoint* `camembert-base` pour essayer. L'identifiant `camembert-base` est tout ce dont nous avons besoin pour commencer à utiliser le modèle ! Comme vous l'avez vu dans les chapitres précédents, nous pouvons l'instancier en utilisant la fonction `pipeline()` : + +```py +from transformers import pipeline + +camembert_fill_mask = pipeline("fill-mask", model="camembert-base") +results = camembert_fill_mask("Le camembert est :)") +``` + +```python out +[ + {'sequence': 'Le camembert est délicieux :)', 'score': 0.49091005325317383, 'token': 7200, 'token_str': 'délicieux'}, + {'sequence': 'Le camembert est excellent :)', 'score': 0.1055697426199913, 'token': 2183, 'token_str': 'excellent'}, + {'sequence': 'Le camembert est succulent :)', 'score': 0.03453313186764717, 'token': 26202, 'token_str': 'succulent'}, + {'sequence': 'Le camembert est meilleur :)', 'score': 0.0330314114689827, 'token': 528, 'token_str': 'meilleur'}, + {'sequence': 'Le camembert est parfait :)', 'score': 0.03007650189101696, 'token': 1654, 'token_str': 'parfait'} +] +``` + +Comme vous pouvez le constater, le chargement d'un modèle dans un pipeline est extrêmement simple. La seule chose à laquelle vous devez faire attention est que le *checkpoint* choisi soit adapté à la tâche pour laquelle il va être utilisé. Par exemple, ici nous chargeons le *checkpoint* `camembert-base` dans le pipeline `fill-mask`, ce qui est tout à fait correct. Mais si nous chargeions ce *checkpoint* dans le pipeline `text-classification`, les résultats n'auraient aucun sens car la tête de `camembert-base` n'est pas adaptée à cette tâche ! Nous recommandons d'utiliser le sélecteur de tâche dans l'interface du *Hub* afin de sélectionner les *checkpoints* appropriés : + +
+The task selector on the web interface. +
+ +Vous pouvez également instancier le *checkpoint* en utilisant directement l'architecture du modèle : + +{#if fw === 'pt'} +```py +from transformers import CamembertTokenizer, CamembertForMaskedLM + +tokenizer = CamembertTokenizer.from_pretrained("camembert-base") +model = CamembertForMaskedLM.from_pretrained("camembert-base") +``` + +Cependant, nous recommandons d'utiliser les classes [`Auto*`](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) à la place, car elles sont par conception indépendantes de l'architecture. Alors que l'exemple de code précédent limite les utilisateurs aux *checkpoints* chargeables dans l'architecture CamemBERT, l'utilisation des classes `Auto*` facilite le changement de *checkpoint* : + +```py +from transformers import AutoTokenizer, AutoModelForMaskedLM + +tokenizer = AutoTokenizer.from_pretrained("camembert-base") +model = AutoModelForMaskedLM.from_pretrained("camembert-base") +``` +{:else} +```py +from transformers import CamembertTokenizer, TFCamembertForMaskedLM + +tokenizer = CamembertTokenizer.from_pretrained("camembert-base") +model = TFCamembertForMaskedLM.from_pretrained("camembert-base") +``` + +Cependant, nous recommandons d'utiliser les classes [`TFAuto*`](https://huggingface.co/transformers/model_doc/auto.html?highlight=auto#auto-classes) à la place, car elles sont par conception indépendantes de l'architecture. Alors que l'exemple de code précédent limite les utilisateurs aux *checkpoints* chargeables dans l'architecture CamemBERT, l'utilisation des classes `TFAuto*` facilite le changement de *checkpoint* : + + +```py +from transformers import AutoTokenizer, TFAutoModelForMaskedLM + +tokenizer = AutoTokenizer.from_pretrained("camembert-base") +model = TFAutoModelForMaskedLM.from_pretrained("camembert-base") +``` +{/if} + + +Lorsque vous utilisez un modèle pré-entraîné, assurez-vous de vérifier comment il a été entraîné, sur quels jeux de données, ses limites et ses biais. Toutes ces informations doivent être indiquées dans sa carte. + diff --git a/chapters/fr/chapter4/3.mdx b/chapters/fr/chapter4/3.mdx new file mode 100644 index 000000000..95b5d420b --- /dev/null +++ b/chapters/fr/chapter4/3.mdx @@ -0,0 +1,638 @@ + + +# Partage de modèles pré-entraînés + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Dans les étapes ci-dessous, nous allons examiner les moyens les plus simples de partager des modèles pré-entraînés sur le 🤗 *Hub*. Il existe des outils et des services disponibles qui permettent de simplifier le partage et la mise à jour des modèles directement sur le *Hub*, que nous allons explorer ci-dessous. + + + +Nous encourageons tous les utilisateurs qui entraînent des modèles à contribuer en les partageant avec la communauté. Le partage des modèles, même s'ils ont été entraînés sur des jeux de données très spécifiques, aidera les autres, en leur faisant gagner du temps, des ressources de calcul et en leur donnant accès à des artefacts entraînés utiles. À votre tour, vous pourrez bénéficier du travail effectué par les autres ! + +Il y a trois façons de créer de nouveaux dépôts de modèles : + +- en utilisant l'API `push_to_hub`, +- en utilisant la bibliothèque Python `huggingface_hub`, +- en utilisant l'interface web. + +Une fois que vous avez créé un dépôt, vous pouvez y charger des fichiers via git et git-lfs. Nous allons vous guider dans la création de dépôts de modèles et le téléchargement de fichiers dans les sections suivantes. + + +## Utilisation de l'API `push_to_hub` + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +La façon la plus simple de télécharger des fichiers vers le *Hub* est d'utiliser l'API `push_to_hub`. + +Avant d'aller plus loin, vous devrez générer un jeton d'authentification afin que l'API `huggingface_hub` sache qui vous êtes et à quels espaces de noms vous avez accès en écriture. Assurez-vous que vous êtes dans un environnement où vous avez installé `transformers` (voir la [Configuration](/course/fr/chapter0)). Si vous êtes dans un *notebook*, vous pouvez utiliser la fonction suivante pour vous connecter : + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +Dans un terminal, vous pouvez exécuter : + +```bash +huggingface-cli login +``` + +Dans les deux cas, vous serez invité à saisir votre nom d'utilisateur et votre mot de passe, qui sont les mêmes que ceux que vous utilisez pour vous connecter au *Hub*. Si vous n'avez pas encore de profil pour le Hub, vous devez en créer un [ici](https://huggingface.co/join). + +Super ! Votre jeton d'authentification est maintenant stocké dans votre dossier de cache. Créons quelques référentiels ! + +{#if fw === 'pt'} + +Si vous avez joué avec l'API `Trainer` pour entraîner un modèle, le moyen le plus simple de le télécharger sur le *Hub* est de définir `push_to_hub=True` lorsque vous définissez vos `TrainingArguments` : + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments( + "bert-finetuned-mrpc", save_strategy="epoch", push_to_hub=True +) +``` + +Lorsque vous appelez `trainer.train()`, le `Trainer` téléchargera alors votre modèle vers le *Hub* à chaque fois qu'il sera sauvegardé (ici à chaque époque) dans un dépôt dans votre espace personnel. Ce dépôt sera nommé comme le répertoire de sortie que vous avez choisi (ici `bert-finetuned-mrpc`) mais vous pouvez choisir un nom différent avec `hub_model_id = "a_different_name"`. + +Pour télécharger votre modèle vers une organisation dont vous êtes membre, passez-le simplement avec `hub_model_id = "my_organization/my_repo_name"`. + +Une fois que votre entraînement est terminé, vous devriez faire un dernier `trainer.push_to_hub()` pour télécharger la dernière version de votre modèle. Cela générera également une carte pour le modèle avec toutes les métadonnées pertinentes, rapportant les hyperparamètres utilisés et les résultats d'évaluation ! Voici un exemple du contenu que vous pourriez trouver dans une telle carte de modèle : +
+ An example of an auto-generated model card. +
+ +{:else} + +Si vous utilisez Keras pour entraîner votre modèle, le moyen le plus simple de le télécharger sur le *Hub* est de passer un `PushToHubCallback` lorsque vous appelez `model.fit()` : + +```py +from transformers import PushToHubCallback + +callback = PushToHubCallback( + "bert-finetuned-mrpc", save_strategy="epoch", tokenizer=tokenizer +) +``` + +Ensuite, vous devez ajouter `callbacks=[callback]` dans votre appel à `model.fit()`. La *callback* téléchargera alors votre modèle vers le *Hub* à chaque fois qu'il sera sauvegardé (ici à chaque époque) dans un référentiel dans votre espace de noms. Ce dépôt sera nommé comme le répertoire de sortie que vous avez choisi (ici `bert-finetuned-mrpc`) mais vous pouvez choisir un nom différent avec `hub_model_id = "a_different_name"`. + +Pour télécharger votre modèle dans une organisation dont vous êtes membre, passez-le simplement avec `hub_model_id = "my_organization/my_repo_name"`. + +{/if} + +A un niveau inférieur, l'accès au *Hub* peut être fait directement sur les modèles, les *tokenizers* et les objets de configuration via leur méthode `push_to_hub()`. Cette méthode s'occupe à la fois de la création du dépôt et de l'envoi les fichiers du modèle et du *tokenizer* directement dans le dépôt. Aucune manipulation manuelle n'est nécessaire, contrairement à l'API que nous verrons plus loin. + +Pour avoir une idée de son fonctionnement, commençons par initialiser un modèle et un *tokenizer* : + +{#if fw === 'pt'} +```py +from transformers import AutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = AutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` +{:else} +```py +from transformers import TFAutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = TFAutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` +{/if} + +Vous êtes libre de faire ce que vous voulez avec ces objets : ajouter des *tokens* au *tokenizer*, entraîner le modèle, le *finetuner*. Une fois que vous êtes satisfait du modèle, des poids et du *tokenizer* obtenus, vous pouvez utiliser la méthode `push_to_hub()` directement disponible sur l'objet `model` : + +```py +model.push_to_hub("dummy-model") +``` + +Cela va créer le nouveau dépôt `dummy-model` dans votre profil et le remplir avec les fichiers du modèle. +Faites la même chose avec le *tokenizer*, de sorte que tous les fichiers sont maintenant disponibles dans ce dépôt : + +```py +tokenizer.push_to_hub("dummy-model") +``` + +Si vous appartenez à une organisation, il suffit de spécifier l'argument `organization` pour télécharger dans l'espace de cette organisation : + +```py +tokenizer.push_to_hub("dummy-model", organization="huggingface") +``` + +Si vous souhaitez utiliser un jeton Hugging Face spécifique, vous pouvez également le spécifier à la méthode `push_to_hub()` : + +```py +tokenizer.push_to_hub("dummy-model", organization="huggingface", use_auth_token="") +``` + +Maintenant, dirigez-vous sur *Hub* pour trouver votre modèle nouvellement téléchargé : *https://huggingface.co/user-or-organization/dummy-model*. + +Cliquez sur l'onglet « Fichiers et versions » et vous devriez voir les fichiers visibles dans la capture d'écran suivante : + +{#if fw === 'pt'} +
+Dummy model containing both the tokenizer and model files. +
+{:else} +
+Dummy model containing both the tokenizer and model files. +
+{/if} + + + +✏️ **Essayez** Prenez le modèle et le *tokenizer* associés au *checkpoint* `bert-base-cased` et téléchargez-les vers un dépôt dans votre espace en utilisant la méthode `push_to_hub()`. Vérifiez que le dépôt apparaît correctement sur votre page avant de le supprimer. + + + +Comme vous l'avez vu, la méthode `push_to_hub()` accepte plusieurs arguments, ce qui permet de télécharger vers un dépôt ou un espace d'organisation spécifique, ou d'utiliser un jeton d'API différent. Nous vous recommandons de jeter un coup d'œil à la spécification de la méthode disponible directement dans la documentation de [🤗 *Transformers*](https://huggingface.co/transformers/model_sharing.html) pour avoir une idée de ce qui est possible. + +La méthode `push_to_hub()` est soutenue par le paquet Python [`huggingface_hub`](https://github.com/huggingface/huggingface_hub), qui offre une API directe au *Hub*. C'est intégré à 🤗 *Transformers* et à plusieurs autres bibliothèques d'apprentissage automatique, comme [`allenlp`](https://github.com/allenai/allennlp). Bien que nous nous concentrions sur l'intégration via 🤗 *Transformers* dans ce chapitre, son intégration dans votre propre code ou bibliothèque est simple. + +Passez à la dernière section pour voir comment télécharger des fichiers dans votre dépôt nouvellement créé ! + +## Utilisation de la bibliothèque Python `huggingface_hub` + +La bibliothèque Python `huggingface_hub` est un *package* qui offre un ensemble d'outils pour les hubs des modèles et des jeux de données. Elle fournit des méthodes et des classes simples pour des tâches courantes telles qu'obtenir et gérer des informations à propos des dépôts sur le *Hub*. Elle fournit des APIs simples qui fonctionnent au-dessus de git pour gérer le contenu de ces dépôts et pour intégrer le *Hub* dans vos projets et bibliothèques. + +De la même manière que pour l'utilisation de l'API `push_to_hub`, vous devrez avoir votre jeton d'API enregistré dans votre cache. Pour ce faire, vous devrez utiliser la commande `login` de la CLI, comme mentionné dans la section précédente (encore une fois, assurez-vous de faire précéder ces commandes du caractère `!` si vous les exécutez dans Google Colab) : + +```bash +huggingface-cli login +``` + +Le *package* `huggingface_hub` offre plusieurs méthodes et classes qui sont utiles pour notre objectif. Tout d'abord, il y a quelques méthodes pour gérer la création, la suppression des dépôts, et autres : + +```python no-format +from huggingface_hub import ( + # User management + login, + logout, + whoami, + + # Repository creation and management + create_repo, + delete_repo, + update_repo_visibility, + + # And some methods to retrieve/change information about the content + list_models, + list_datasets, + list_metrics, + list_repo_files, + upload_file, + delete_file, +) +``` + + +De plus, elle offre la très puissante classe `Repository` pour gérer un dépôt local. Nous allons explorer ces méthodes et cette classe dans les prochaines sections pour comprendre comment les exploiter. + +La méthode `create_repo` peut être utilisée pour créer un nouveau dépôt sur le *Hub* : + +```py +from huggingface_hub import create_repo + +create_repo("dummy-model") +``` + +Ceci créera le dépôt `dummy-model` dans votre espace. Si vous le souhaitez, vous pouvez spécifier à quelle organisation le dépôt doit appartenir en utilisant l'argument `organization` : + +```py +from huggingface_hub import create_repo + +create_repo("dummy-model", organization="huggingface") +``` + +Cela créera le dépôt `dummy-model` dans l'espace de nom `huggingface`, en supposant que vous appartenez à cette organisation. +D'autres arguments qui peuvent être utiles sont : + +- `private`, afin de spécifier si le référentiel doit être visible des autres ou non, +- `token`, si vous voulez remplacer le jeton stocké dans votre cache par un jeton donné, +- `repo_type`, si vous souhaitez créer un `dataset` ou un `space` au lieu d'un modèle. Les valeurs acceptées sont `"dataset"` et `"space"`. + +Une fois que le dépôt est créé, nous devons y ajouter des fichiers ! Passez à la section suivante pour voir les trois façons dont cela peut être géré. + + +## Utilisation de l'interface web + +L'interface web offre des outils pour gérer les dépôts directement dans le *Hub*. En utilisant l'interface, vous pouvez facilement créer des dépôts, ajouter des fichiers (même de grande taille !), explorer des modèles, visualiser les différences, et bien plus encore. + +Pour créer un nouveau dépôt, visitez [huggingface.co/new](https://huggingface.co/new) : + +
+Page showcasing the model used for the creation of a new model repository. +
+ +Tout d'abord, indiquez le propriétaire du dépôt : il peut s'agir de vous ou de l'une des organisations auxquelles vous êtes affilié. Si vous choisissez une organisation, le modèle sera présenté sur la page de l'organisation et chaque membre de l'organisation aura la possibilité de contribuer au référentiel. + +Ensuite, saisissez le nom de votre modèle. Ce sera également le nom du dépôt. Enfin, vous pouvez préciser si vous souhaitez que votre modèle soit public ou privé. Les modèles privés sont cachés de la vue du public. + +Après avoir créé votre dépôt de modèles, vous devriez voir une page comme celle-ci : + +
+An empty model page after creating a new repository. +
+ +C'est là que votre modèle sera hébergé. Pour commencer à le remplir, vous pouvez ajouter un fichier README directement depuis l'interface web. + +
+The README file showing the Markdown capabilities. +
+ +Le fichier README est en Markdown. N'hésitez pas à vous lâcher avec lui ! La troisième partie de ce chapitre est consacrée à la construction d'une carte de modèle. Celles-ci sont d'une importance capitale pour valoriser votre modèle, car c'est par elles que vous indiquez aux autres ce qu'il peut faire. + +Si vous regardez l'onglet « Fichiers et versions », vous verrez qu'il n'y a pas encore beaucoup de fichiers : juste le *README.md* que vous venez de créer et le fichier *.gitattributes* qui garde la trace des gros fichiers. + +
+The 'Files and versions' tab only shows the .gitattributes and README.md files. +
+ +Nous allons maintenant voir comment ajouter de nouveaux fichiers. + +## Téléchargement des fichiers du modèle + +Le système de gestion des fichiers sur le *Hub* est basé sur git pour les fichiers ordinaires et git-lfs (qui signifie [Git Large File Storage](https://git-lfs.github.com/)) pour les fichiers plus importants. + +Dans la section suivante, nous passons en revue trois façons différentes de télécharger des fichiers sur le *Hub* : par `huggingface_hub` et par des commandes git. + +### L'approche `upload_file' + +L'utilisation de `upload_file` ne nécessite pas que git et git-lfs soient installés sur votre système. Il pousse les fichiers directement vers le 🤗 *Hub* en utilisant des requêtes HTTP POST. Une limitation de cette approche est qu'elle ne gère pas les fichiers dont la taille est supérieure à 5 Go. +Si vos fichiers ont une taille supérieure à 5 Go, veuillez suivre les deux autres méthodes détaillées ci-dessous. + +L'API peut être utilisée comme suit : + +```py +from huggingface_hub import upload_file + +upload_file( + "/config.json", + path_in_repo="config.json", + repo_id="/dummy-model", +) +``` + +Ceci téléchargera le fichier `config.json` disponible à `` à la racine du dépôt en tant que `config.json`, vers le dépôt `dummy-model`. +D'autres arguments qui peuvent être utiles sont : + +- `token`, si vous souhaitez remplacer le jeton stocké dans votre cache par un jeton donné, +- `repo_type`, si vous souhaitez télécharger vers un `dataset` ou un `space` au lieu d'un modèle. Les valeurs acceptées sont `"dataset"` et `"space"`. + + +### La classe `Repository` + +La classe `Repository` gère un dépôt local d'une manière similaire à git. Elle abstrait la plupart des problèmes que l'on peut rencontrer avec git pour fournir toutes les fonctionnalités dont nous avons besoin. + +L'utilisation de cette classe nécessite l'installation de git et de git-lfs, donc assurez-vous que git-lfs est installé (voir [ici](https://git-lfs.github.com/) pour les instructions d'installation) et configuré avant de commencer. + +Afin de commencer à jouer avec le dépôt que nous venons de créer, nous pouvons commencer par l'initialiser dans un dossier local en clonant le dépôt distant : + +```py +from huggingface_hub import Repository + +repo = Repository("", clone_from="/dummy-model") +``` + +Cela a créé le dossier `` dans notre répertoire de travail. Ce dossier ne contient que le fichier `.gitattributes` car c'est le seul fichier créé lors de l'instanciation du dépôt par `create_repo`. + +A partir de maintenant, nous pouvons utiliser plusieurs des méthodes traditionnelles de git : + +```py +repo.git_pull() +repo.git_add() +repo.git_commit() +repo.git_push() +repo.git_tag() +``` + +Et d'autres encore ! Nous vous recommandons de jeter un coup d'oeil à la documentation de `Repository` disponible [ici](https://github.com/huggingface/huggingface_hub/tree/main/src/huggingface_hub#advanced-programmatic-repository-management) pour une vue d'ensemble de toutes les méthodes disponibles. + +Actuellement, nous avons un modèle et un *tokenizer* que nous voulons pousser vers le *Hub*. Nous avons réussi à cloner le dépôt, nous pouvons donc enregistrer les fichiers dans ce dépôt. + +Nous nous assurons d'abord que notre clone local est à jour en récupérant les dernières modifications : + +```py +repo.git_pull() +``` + +Une fois que c'est fait, nous sauvegardons les fichiers du modèle et du *tokenizer* : + +```py +model.save_pretrained("") +tokenizer.save_pretrained("") +``` + +Le `` contient maintenant tous les fichiers du modèle et du *tokenizer*. Nous suivons le flux de travail git habituel en ajoutant des fichiers à la zone de transit, en les validant et en les poussant vers le *Hub* : + +```py +repo.git_add() +repo.git_commit("Add model and tokenizer files") +repo.git_push() +``` + +Félicitations ! Vous venez de pousser vos premiers fichiers sur le *Hub*. + +### L'approche basée sur git + +Il s'agit de l'approche la plus basique pour télécharger des fichiers : nous le ferons directement avec git et git-lfs. La plupart des difficultés sont abstraites par les approches précédentes, mais il y a quelques réserves avec la méthode suivante, nous allons donc suivre un cas d'utilisation plus complexe. + +L'utilisation de cette classe nécessite l'installation de git et de git-lfs, donc assurez-vous d'avoir [git-lfs](https://git-lfs.github.com/) installé et configuré avant de commencer. + +Commencez par initialiser git-lfs : + +```bash +git lfs install +``` + +```bash +Updated git hooks. +Git LFS initialized. +``` + +Une fois que c'est fait, la première étape consiste à cloner votre dépôt de modèles : + +```bash +git clone https://huggingface.co// +``` + +Mon nom d'utilisateur est `lysandre` et j'ai utilisé le nom de modèle `dummy`, donc pour moi la commande ressemble à ce qui suit : + +``` +git clone https://huggingface.co/lysandre/dummy +``` + +J'ai maintenant un dossier nommé *dummy* dans mon répertoire de travail. Je peux `cd` dans ce dossier et jeter un coup d'oeil à son contenu : + +```bash +cd dummy && ls +``` + +```bash +README.md +``` + +Si vous venez de créer votre dépôt en utilisant la méthode `create_repo` du *Hub*, ce dossier devrait seulement contenir un fichier caché `.gitattributes`. Si vous avez suivi les instructions de la section précédente pour créer un dépôt en utilisant l'interface web, le dossier devrait contenir un seul fichier *README.md* à côté du fichier caché `.gitattributes`, comme indiqué ici. + +L'ajout d'un fichier de taille normale, comme un fichier de configuration, un fichier de vocabulaire, ou tout autre fichier de moins de quelques mégaoctets, est fait exactement comme on le ferait dans n'importe quel système basé sur git. Cependant, les fichiers plus volumineux doivent être enregistrés via git-lfs afin de les pousser vers *huggingface.co*. + +Revenons un peu à Python pour générer un modèle et un *tokenizer* que nous souhaitons commiter dans notre dépôt fictif : + +{#if fw === 'pt'} +```py +from transformers import AutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = AutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +# Faites ce que vous voulez avec le modèle, entraînez-le, finetunez-le... + +model.save_pretrained("") +tokenizer.save_pretrained("") +``` +{:else} +```py +from transformers import TFAutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = TFAutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +# Faites ce que vous voulez avec le modèle, entraînez-le, finetunez-le... + +model.save_pretrained("") +tokenizer.save_pretrained("") +``` +{/if} + +Maintenant que nous avons sauvegardé quelques artefacts de modèle et de *tokenizer*, regardons à nouveau le dossier *dummy* : + +```bash +ls +``` + +{#if fw === 'pt'} +```bash +config.json pytorch_model.bin README.md sentencepiece.bpe.model special_tokens_map.json tokenizer_config.json tokenizer.json +``` + +Si vous regardez la taille des fichiers (par exemple, avec `ls -lh`), vous devriez voir que le fichier d'état du modèle (*pytorch_model.bin*) est la seule exception, avec plus de 400 Mo. + +{:else} +```bash +config.json README.md sentencepiece.bpe.model special_tokens_map.json tf_model.h5 tokenizer_config.json tokenizer.json +``` + +Si vous regardez la taille des fichiers (par exemple, avec `ls -lh`), vous devriez voir que le fichier dict de l'état du modèle (*t5_model.h5*) est la seule aberration, avec plus de 400 Mo. + +{/if} + + +✏️ Lors de la création du dépôt à partir de l'interface web, le fichier *.gitattributes* est automatiquement configuré pour considérer les fichiers avec certaines extensions, comme *.bin* et *.h5*, comme des fichiers volumineux, et git-lfs les suivra sans aucune configuration nécessaire de votre part. + + +Nous pouvons maintenant aller de l'avant et procéder comme nous le ferions habituellement avec des dépôts Git traditionnels. Nous pouvons ajouter tous les fichiers à l'environnement staging de Git en utilisant la commande `git add` : + +```bash +git add . +``` + +Nous pouvons alors jeter un coup d'œil aux fichiers : + +```bash +git status +``` + +{#if fw === 'pt'} +```bash +On branch main +Your branch is up to date with 'origin/main'. + +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: .gitattributes + new file: config.json + new file: pytorch_model.bin + new file: sentencepiece.bpe.model + new file: special_tokens_map.json + new file: tokenizer.json + new file: tokenizer_config.json +``` +{:else} +```bash +On branch main +Your branch is up to date with 'origin/main'. + +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: .gitattributes + new file: config.json + new file: sentencepiece.bpe.model + new file: special_tokens_map.json + new file: tf_model.h5 + new file: tokenizer.json + new file: tokenizer_config.json +``` +{/if} + +De même, nous pouvons nous assurer que git-lfs suit les bons fichiers en utilisant sa commande `status` : + +```bash +git lfs status +``` + +{#if fw === 'pt'} +```bash +On branch main +Objects to be pushed to origin/main: + + +Objects to be committed: + + config.json (Git: bc20ff2) + pytorch_model.bin (LFS: 35686c2) + sentencepiece.bpe.model (LFS: 988bc5a) + special_tokens_map.json (Git: cb23931) + tokenizer.json (Git: 851ff3e) + tokenizer_config.json (Git: f0f7783) + +Objects not staged for commit: + + +``` + +Nous pouvons voir que tous les fichiers ont `Git` comme gestionnaire, sauf *pytorch_model.bin* et *sentencepiece.bpe.model*, qui ont `LFS`. Super ! + +{:else} +```bash +On branch main +Objects to be pushed to origin/main: + + +Objects to be committed: + + config.json (Git: bc20ff2) + sentencepiece.bpe.model (LFS: 988bc5a) + special_tokens_map.json (Git: cb23931) + tf_model.h5 (LFS: 86fce29) + tokenizer.json (Git: 851ff3e) + tokenizer_config.json (Git: f0f7783) + +Objects not staged for commit: + + +``` + +Nous pouvons voir que tous les fichiers ont `Git` comme gestionnaire, sauf *t5_model.h5* qui a `LFS`. Super ! + +{/if} + +Passons aux étapes finales, *committing* et *pushing* vers le dépôt distant *huggingface.co* : + +```bash +git commit -m "First model version" +``` + +{#if fw === 'pt'} +```bash +[main b08aab1] First model version + 7 files changed, 29027 insertions(+) + 6 files changed, 36 insertions(+) + create mode 100644 config.json + create mode 100644 pytorch_model.bin + create mode 100644 sentencepiece.bpe.model + create mode 100644 special_tokens_map.json + create mode 100644 tokenizer.json + create mode 100644 tokenizer_config.json +``` +{:else} +```bash +[main b08aab1] First model version + 6 files changed, 36 insertions(+) + create mode 100644 config.json + create mode 100644 sentencepiece.bpe.model + create mode 100644 special_tokens_map.json + create mode 100644 tf_model.h5 + create mode 100644 tokenizer.json + create mode 100644 tokenizer_config.json +``` +{/if} + +Le chargement peut prendre un peu de temps, en fonction de la vitesse de votre connexion Internet et de la taille de vos fichiers : + +```bash +git push +``` + +```bash +Uploading LFS objects: 100% (1/1), 433 MB | 1.3 MB/s, done. +Enumerating objects: 11, done. +Counting objects: 100% (11/11), done. +Delta compression using up to 12 threads +Compressing objects: 100% (9/9), done. +Writing objects: 100% (9/9), 288.27 KiB | 6.27 MiB/s, done. +Total 9 (delta 1), reused 0 (delta 0), pack-reused 0 +To https://huggingface.co/lysandre/dummy + 891b41d..b08aab1 main -> main +``` + +{#if fw === 'pt'} +Si nous jetons un coup d'œil au dépôt du modèle, lorsque cette opération est terminée, nous pouvons voir tous les fichiers récemment ajoutés : + +
+The 'Files and versions' tab now contains all the recently uploaded files. +
+ +L'interface utilisateur vous permet d'explorer les fichiers du modèle et les *commits* et de voir la différence introduite par chaque *commit* : + +
+The diff introduced by the recent commit. +
+{:else} +Si nous jetons un coup d'œil au dépôt du modèle, lorsque cette opération est terminée, nous pouvons voir tous les fichiers récemment ajoutés : + +
+The 'Files and versions' tab now contains all the recently uploaded files. +
+ +L'interface utilisateur vous permet d'explorer les fichiers du modèle et les *commits* et de voir la différence introduite par chaque *commit* : + +
+The diff introduced by the recent commit. +
+{/if} diff --git a/chapters/fr/chapter4/4.mdx b/chapters/fr/chapter4/4.mdx new file mode 100644 index 000000000..d3a574cf2 --- /dev/null +++ b/chapters/fr/chapter4/4.mdx @@ -0,0 +1,84 @@ +# Construire une carte de modèle + +La carte de modèle est un fichier qui est sans doute aussi important que les fichiers du modèle et du *tokenizer* dans un dépôt de modèles. Il s'agit de la définition centrale du modèle, qui garantit la réutilisation par les autres membres de la communauté, la reproductibilité des résultats, et une plateforme sur laquelle les autres membres peuvent construire leurs artefacts. + +Documenter le processus d'entraînement et d'évaluation aide les autres à comprendre ce qu'ils peuvent attendre d'un modèle. Fournir suffisamment d'informations concernant les données utilisées, les prétraitements et post-traitements effectués permet d'identifier et de comprendre les limites, les biais et les contextes dans lesquels le modèle est ou n'est pas utile. + +Par conséquent, la création d'une carte de modèle définissant clairement votre modèle est une étape très importante. Nous vous donnons ici quelques conseils qui vous aideront à le faire. La création de la fiche de modèle se fait par le biais du fichier *README.md* que vous avez vu précédemment, qui est un fichier Markdown. + +Le concept de carte de modèle provient d'une direction de recherche de Google, partagée pour la première fois dans l'article ["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993) par Margaret Mitchell et al. De nombreuses informations contenues dans ce document sont basées sur cet article et nous vous recommandons d'y jeter un coup d'œil pour comprendre pourquoi les cartes de modèles sont si importantes dans un monde qui valorise la reproductibilité, la réutilisation et l'équité. + +La carte de modèle commence généralement par une très brève présentation de haut niveau de l'objet du modèle, suivie de détails supplémentaires dans les sections suivantes : + +- description du modèle +- utilisations et limites prévues +- comment utiliser le modèle +- limites et biais +- données d'entraînement +- procédure d'entraînement +- résultats de l'évaluation + +Voyons ce que chacune de ces sections doit contenir. + + +### Description du modèle + +La description du modèle fournit des détails de base sur le modèle. Cela inclut l'architecture, la version, s'il a été présenté dans un article, si une implémentation originale est disponible, l'auteur et des informations générales sur le modèle. Tout droit d'auteur doit être attribué ici. Des informations générales sur les procédures d'entraînement, les paramètres et les avertissements importants peuvent également être mentionnés dans cette section. + +### Utilisations et limitations prévues + +Vous décrivez ici les cas d'utilisation auxquels le modèle est destiné, y compris les langues, les domaines et les champs où il peut être appliqué. Cette section de la fiche de modèle peut également documenter les domaines qui sont connus pour être hors de portée du modèle, ou dans lesquels il est susceptible de fonctionner de manière sous-optimale. + +### Comment utiliser + +Cette section doit inclure des exemples d'utilisation du modèle. Cela peut montrer l'utilisation de la fonction `pipeline()`, l'utilisation des classes du modèle et du *tokenizer*, et tout autre code que vous pensez être utile. + +### Données d'entraînement + +Cette partie doit indiquer sur quel(s) jeu(x) de données le modèle a été entraîné. Une brève description du ou des jeux de données est également la bienvenue. + +### Procédure d'entraînement + +Dans cette section, vous devez décrire tous les aspects pertinents de l'entraînement qui sont utiles du point de vue de la reproductibilité. Cela inclut tout prétraitement et post-traitement effectué sur les données, ainsi que des détails tels que le nombre d'époques pour lesquelles le modèle a été entraîné, la taille du batch, le taux d'apprentissage, etc. + +### Variable et métriques + +Décrivez ici les métriques que vous utilisez pour l'évaluation et les différents facteurs que vous mesurez. En mentionnant la ou les métriques utilisées, sur quel jeu de données et quelle division du jeu de données, il est plus facile de comparer les performances de votre modèle à celles d'autres modèles. Les sections précédentes, telles que les utilisateurs prévus et les cas d'utilisation, doivent être prises en compte. + +### Résultats de l'évaluation + +Enfin, fournissez une indication de la performance du modèle sur l'ensemble de données d'évaluation. Si le modèle utilise un seuil de décision, indiquez le seuil de décision utilisé dans l'évaluation ou fournissez des détails sur l'évaluation à différents seuils pour les utilisations prévues. + + +## Exemple + +Voici quelques exemples de cartes de modèles bien conçues : + +- [`bert-base-case`](https://huggingface.co/bert-base-cased) +- [`gpt2`](https://huggingface.co/gpt2) +- [`distilbert`](https://huggingface.co/distilbert-base-uncased) + +D'autres exemples provenant de différentes organisations et entreprises sont disponibles [ici](https://github.com/huggingface/model_card/blob/master/examples.md). + +## Note + +Les fiches de modèle ne sont pas une exigence lors de la publication de modèles, et vous n'avez pas besoin d'inclure toutes les sections décrites ci-dessus lorsque vous en faites une. Cependant, une documentation explicite du modèle ne peut qu'être bénéfique aux futurs utilisateurs. Nous vous recommandons donc de remplir autant de sections que possible, au mieux de vos connaissances et de vos capacités. + +## Métadonnées de la carte de modèle + +Si vous avez exploré un peu le *Hub*, vous devriez avoir vu que certains modèles appartiennent à certaines catégories : vous pouvez les filtrer par tâches, langues, bibliothèques, et plus encore. Les catégories auxquelles appartient un modèle sont identifiées en fonction des métadonnées que vous ajoutez dans l'en-tête de la fiche du modèle. + +Par exemple, si vous regardez la fiche de modèle de [`camembert-base`](https://huggingface.co/camembert-base/blob/main/README.md), vous devriez voir les lignes suivantes dans l'en-tête de la fiche de modèle : + +``` +--- +language: fr +license: mit +datasets: +- oscar +--- +``` + +Ces métadonnées sont analysées par le *Hub* qui identifie alors ce modèle comme étant un modèle français, avec une licence MIT, entraîné sur le jeu de données Oscar. + +La [spécification complète de la carte du modèle](https://github.com/huggingface/hub-docs/blame/main/modelcard.md) permet de spécifier les langues, les licences, les balises, les jeux de données, les mesures, ainsi que les résultats d'évaluation obtenus par le modèle lors de l'entraînement. \ No newline at end of file diff --git a/chapters/fr/chapter4/5.mdx b/chapters/fr/chapter4/5.mdx new file mode 100644 index 000000000..1cab384bc --- /dev/null +++ b/chapters/fr/chapter4/5.mdx @@ -0,0 +1,7 @@ +# Fin de la première partie du cours ! + +C'est la fin de la première partie du cours ! La partie 2 sera publiée le 15 novembre 2021 avec un grand événement communautaire, pour plus d'informations voir [ici](https://huggingface.co/blog/course-launch-event). + +Vous devriez maintenant être capable de *finetuner* un modèle pré-entraîné sur un problème de classification de texte (phrases simples ou paires de phrases) et de télécharger le résultat sur le *Hub*. Pour vous assurer que vous maîtrisez cette première section, vous devriez refaire ça sur un problème qui vous intéresse (et pas nécessairement en anglais si vous parlez une autre langue) ! Vous pouvez trouver de l'aide dans les [forums Hugging Face](https://discuss.huggingface.co/) et partager votre projet dans [ce sujet](https://discuss.huggingface.co/t/share-your-projects/6803) une fois que vous avez terminé. + +Nous sommes impatients de voir ce que vous allez construire avec cet outil ! \ No newline at end of file diff --git a/chapters/fr/chapter4/6.mdx b/chapters/fr/chapter4/6.mdx new file mode 100644 index 000000000..5e00bbdc1 --- /dev/null +++ b/chapters/fr/chapter4/6.mdx @@ -0,0 +1,223 @@ + + + + +# Quiz de fin de chapitre + +Testons ce que vous avez appris dans ce chapitre ! + +### 1. A quoi sont limités les modèles du *Hub* ? + +Transformers.", + explain: "Si les modèles de la bibliothèque 🤗 Transformers sont pris en charge sur le Hub, ils ne sont pas les seuls !" + }, + { + text: "Tous les modèles avec une interface similaire à 🤗 Transformers.", + explain: "Aucune exigence d'interface n'est fixée lors du téléchargement de modèles vers le Hub." + }, + { + text: "Il n'y a pas de limites.", + explain: "C'est vrai ! Il n'y a pas de limites au téléchargement de modèles sur le Hub.", + correct: true + }, + { + text: "Des modèles qui sont d'une certaine manière liés au NLP.", + explain: "Aucune exigence n'est fixée concernant le domaine d'application !" + } + ]} +/> + +### 2. Comment pouvez-vous gérer les modèles sur le *Hub* ? + +Hub sont de simples dépôts Git exploitant git-lfs pour les fichiers volumineux.", + correct: true + } + ]} +/> + +### 3. Que pouvez-vous faire en utilisant l'interface web du *Hub* ? + +Forker un dépôt existant.", + explain: "Forking un dépôt n'est pas possible sur le Hub." + }, + { + text: "Créer un nouveau dépôt de modèles.", + explain: "Correct ! Ce n'est pas tout ce que vous pouvez faire, cependant.", + correct: true + }, + { + text: "Gérer et modifier des fichiers.", + explain: "Correct ! Ce n'est pas la seule bonne réponse, cependant..", + correct: true + }, + { + text: "Télécharger des fichiers.", + explain: "C'est vrai ! Mais ce n'est pas tout.", + correct: true + }, + { + text: "Voir les différences entre les versions.", + explain: "Correct ! Ce n'est pas tout ce que vous pouvez faire.", + correct: true + } + ]} +/> + +### 4. Qu'est-ce qu'une carte de modèle ? + +tokenizer.", + explain: "It is indeed a description of the model, but it's an important piece: if it's incomplete or absent the model's utility is drastically reduced." + }, + { + text: "A way to ensure reproducibility, reusability, and fairness.", + explain: "Correct! Sharing the right information in the model card will help users leverage your model and be aware of its limits and biases. ", + correct: true + }, + { + text: "A Python file that can be run to retrieve information about the model.", + explain: "Model cards are simple Markdown files." + } + ]} +/> + +### 5. Lesquels de ces objets de la bibliothèque 🤗 *Transformers* peuvent être directement partagés sur le Hub avec `push_to_hub()` ? + +{#if fw === 'pt'} +tokenizer", + explain: "Correct ! Tous les tokenizers ont la méthode push_to_hub et l'utiliser poussera tous les fichiers du tokenizer (vocabulaire, architecture du tokenizer, etc.) vers un dépôt donné. Ce n'est pas la seule bonne réponse, cependant !", + correct: true + }, + { + text: "Une configuration de modèle", + explain: "C'est vrai ! Toutes les configurations de modèles ont la méthode push_to_hub et son utilisation les poussera vers un dépôt donné. Que pouvez-vous partager d'autre ?", + correct: true + }, + { + text: "Un modèle", + explain: "Correct ! Tous les modèles ont la méthode push_to_hub qui le pushra ainsi que leurs fichiers de configuration, vers un dépôt donné. Ce n'est pas tout ce que vous pouvez partager, cependant.", + correct: true + }, + { + text: "Trainer", + explain: "C'est exact. Le Trainer implémente aussi la méthode push_to_hub. L'utiliser téléchargera le modèle, sa configuration, le tokenizer et une ébauche de carte de modèle vers un dépôt donné. Essayez une autre réponse !", + correct: true + } + ]} +/> +{:else} +tokenizer", + explain: "C'est vrai ! Toutes les configurations de modèles ont la méthode push_to_hub et son utilisation les poussera vers un dépôt donné. Que pouvez-vous partager d'autre ?", + correct: true + }, + { + text: "Une configuration de modèle", + explain: "C'est vrai ! Toutes les configurations de modèles ont la méthode push_to_hub et son utilisation les poussera vers un dépôt donné. Que pouvez-vous partager d'autre ?", + correct: true + }, + { + text: "Un modèle", + explain: "Correct ! Tous les modèles ont la méthode push_to_hub qui le pushra ainsi que leurs fichiers de configuration, vers un dépôt donné. Ce n'est pas tout ce que vous pouvez partager, cependant.", + correct: true + }, + { + text: "Tout ce qui précède avec un callback dédié", + explain: "C'est exact. Le PushToHubCallback enverra régulièrement tous ces objets à un dépôt pendant l'entraînement.", + correct: true + } + ]} +/> +{/if} + +### 6. Quelle est la première étape lorsqu'on utilise la méthode `push_to_hub()` ou les outils CLI ? + +notebook.", + explain: "Correct ! Cela affichera un widget pour vous permettre de vous authentifier.", + correct: true + }, + ]} +/> + +### 7. Vous utilisez un modèle et un *tokenizer*, comment pouvez-vous les télécharger sur le *Hub* ? + +tokenizer.", + explain: "Correct !", + correct: true + }, + { + text: "Au sein du moteur d'exécution Python, en les enveloppant dans une balise huggingface_hub.", + explain: "Les modèles et les tokenizers bénéficient déjà de huggingface_hub : pas besoin d'emballage supplémentaire !" + }, + { + text: "En les sauvegardant sur le disque et en appelant transformers-cli upload-model.", + explain: "La commande upload-model n'existe pas." + } + ]} +/> + +### 8. Quelles opérations git pouvez-vous faire avec la classe `Repository` ? + +commit.", + explain: "Correct, la méthode git_commit() est là pour ça.", + correct: true + }, + { + text: "Un pull.", + explain: "C'est le but de la méthode git_pull().", + correct: true + }, + { + text: "Un push.", + explain: "La méthode git_push() fait ça.", + correct: true + }, + { + text: "Un merge.", + explain: "Non, cette opération ne sera jamais possible avec cette API." + } + ]} +/> \ No newline at end of file