# Classification de texte

La classification de texte est une tâche courante en NLP qui consiste à attribuer un libellé ou une classe à un texte. Certaines des plus grandes entreprises exploitent la classification de texte en production pour une large gamme d'applications pratiques. L'une des formes les plus populaires de classification de texte est l'analyse de sentiments, qui attribue un libellé tel que 🙂 positif, 🙁 négatif ou 😐 neutre à une séquence de texte.

Ce guide vous montre comment :

1. Effectuer le fine-tuning de [DistilBERT](https://huggingface.co/distilbert/distilbert-base-uncased) sur le jeu de données [IMDb](https://huggingface.co/datasets/stanfordnlp/imdb) afin de déterminer si une critique de film est positive ou négative.
2. Utilisez votre modèle affiné pour l'inférence.

Pour consulter toutes les architectures et points de contrôle compatibles avec cette tâche, nous vous recommandons de consulter la [page de la tâche](https://huggingface.co/tasks/text-classification).

Avant de commencer, assurez-vous d'avoir installé toutes les bibliothèques nécessaires :

```bash
pip install transformers datasets evaluate accelerate
```

Nous vous encourage à vous connecter à votre compte Hugging Face afin de pouvoir téléverser et partager votre modèle avec la communauté. Lorsque cela vous est demandé, saisissez votre jeton pour vous connecter :

```py
>>> from huggingface_hub import notebook_login

>>> notebook_login()
```

## Charger le jeu de données IMDb

Commencez par charger le jeu de données IMDb à partir de la bibliothèque 🤗 Datasets :

```py
>>> from datasets import load_dataset

>>> imdb = load_dataset("stanfordnlp/imdb")
```

Puis, jetez un œil à un exemple :

```py
>>> imdb["test"][0]
{
    "label": 0,
    "text": "I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded, under-appreciated and misunderstood. I tried to like this, I really did, but it is to good TV sci-fi as Babylon 5 is to Star Trek (the original). Silly prosthetics, cheap cardboard sets, stilted dialogues, CG that doesn't match the background, and painfully one-dimensional characters cannot be overcome with a 'sci-fi' setting. (I'm sure there are those of you out there who think Babylon 5 is good sci-fi TV. It's not. It's clichéd and uninspiring.) While US viewers might like emotion and character development, sci-fi is a genre that does not take itself seriously (cf. Star Trek). It may treat important issues, yet not as a serious philosophy. It's really difficult to care about the characters here as they are not simply foolish, just missing a spark of life. Their actions and reactions are wooden and predictable, often painful to watch. The makers of Earth KNOW it's rubbish as they have to always say \"Gene Roddenberry's Earth...\" otherwise people would not continue watching. Roddenberry's ashes must be turning in their orbit as this dull, cheap, poorly edited (watching it without advert breaks really brings this home) trudging Trabant of a show lumbers into space. Spoiler. So, kill off a main character. And then bring him back as another actor. Jeeez! Dallas all over again.",
}
```

Ce jeu de données comporte deux champs :

- `text` : le texte de la critique de film.
- `label` : une valeur qui est soit `0` pour une critique négative, soit `1` pour une critique positive.

## Prétraitement

L'étape suivante consiste à charger un tokenizer DistilBERT pour prétraiter le champ `text` :

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("distilbert/distilbert-base-uncased")
```

Créez une fonction de prétraitement pour tokeniser `text` et tronquer les séquences afin qu’elles ne dépassent pas la longueur d’entrée maximale de DistilBERT :

```py
>>> def preprocess_function(examples):
...     return tokenizer(examples["text"], truncation=True)
```

Pour appliquer la fonction de prétraitement à l'ensemble du jeu de données, utilisez la fonction [map](https://huggingface.co/docs/datasets/main/en/package_reference/main_classes#datasets.Dataset.map) de 🤗 Datasets. Vous pouvez accélérer `map` en définissant `batched=True` afin de traiter plusieurs éléments du jeu de données à la fois :

```py
tokenized_imdb = imdb.map(preprocess_function, batched=True)
```

Créez maintenant un lot d'exemples à l'aide de [DataCollatorWithPadding](/docs/transformers/main/fr/main_classes/data_collator#transformers.DataCollatorWithPadding). Il est plus efficace de *rembourrer dynamiquement* les phrases à la longueur maximale du lot lors de la collation, plutôt que de rembourrer l'ensemble du jeu de données à la longueur maximale.

```py
>>> from transformers import DataCollatorWithPadding

>>> data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```

## Évaluer

Inclure une métrique pendant l’entraînement est souvent utile pour évaluer les performances de votre modèle. Vous pouvez charger rapidement une méthode d’évaluation avec la bibliothèque 🤗 [Evaluate](https://huggingface.co/docs/evaluate/index). Pour cette tâche, chargez la métrique [accuracy](https://huggingface.co/spaces/evaluate-metric/accuracy) (consultez le [quick tour](https://huggingface.co/docs/evaluate/a_quick_tour) de 🤗 Evaluate pour en savoir plus sur la façon de charger et de calculer une métrique) :

```py
>>> import evaluate

>>> accuracy = evaluate.load("accuracy")
```

Créez ensuite une fonction qui transmet vos prédictions et vos étiquettes à [compute](https://huggingface.co/docs/evaluate/main/en/package_reference/main_classes#evaluate.EvaluationModule.compute) pour calculer la précision :

```py
>>> import numpy as np

>>> def compute_metrics(eval_pred):
...     predictions, labels = eval_pred
...     predictions = np.argmax(predictions, axis=1)
...     return accuracy.compute(predictions=predictions, references=labels)
```

Votre fonction `compute_metrics` est prête, et vous y reviendrez lors de la configuration de l’entraînement.

## Entraînement

Avant de commencer l'entraînement de votre modèle, créez une correspondance entre les ids attendus et leurs libellés à l'aide de `id2label` et `label2id` :

```py
>>> id2label = {0: "NEGATIVE", 1: "POSITIVE"}
>>> label2id = {"NEGATIVE": 0, "POSITIVE": 1}
```

Si vous n'êtes pas familier avec l'ajustement fin d'un modèle à l'aide du [Trainer](/docs/transformers/main/fr/main_classes/trainer#transformers.Trainer), consultez le tutoriel de base [ici](../training) !

Vous êtes prêt à commencer l’entraînement de votre modèle ! Chargez DistilBERT avec [AutoModelForSequenceClassification](/docs/transformers/main/fr/model_doc/auto#transformers.AutoModelForSequenceClassification), en précisant le nombre de classes attendues ainsi que les correspondances des étiquettes :

```py
>>> from transformers import AutoModelForSequenceClassification, TrainingArguments, Trainer

>>> model = AutoModelForSequenceClassification.from_pretrained(
...     "distilbert/distilbert-base-uncased", num_labels=2, id2label=id2label, label2id=label2id
... )
```

À ce stade, il ne reste que trois étapes :

1. Définissez vos hyperparamètres d'entraînement dans [TrainingArguments](/docs/transformers/main/fr/main_classes/trainer#transformers.TrainingArguments). Le seul paramètre obligatoire est `output_dir`, qui spécifie l'emplacement de sauvegarde de votre modèle. Vous publierez ce modèle sur le Hub en définissant `push_to_hub=True` (vous devez être connecté à Hugging Face pour téléverser votre modèle). À la fin de chaque époque, le [Trainer](/docs/transformers/main/fr/main_classes/trainer#transformers.Trainer) évaluera la précision et sauvegardera le point de contrôle d'entraînement.
2. Transmettez les arguments d’entraînement à [Trainer](/docs/transformers/main/fr/main_classes/trainer#transformers.Trainer) en même temps que le modèle, le jeu de données, le tokenizer, le data collator et la fonction `compute_metrics`.
3. Appel de [train()](/docs/transformers/main/fr/main_classes/trainer#transformers.Trainer.train) pour l’ajustement fin de votre modèle.

```py
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_model",
...     learning_rate=2e-5,
...     per_device_train_batch_size=16,
...     per_device_eval_batch_size=16,
...     num_train_epochs=2,
...     weight_decay=0.01,
...     eval_strategy="epoch",
...     save_strategy="epoch",
...     load_best_model_at_end=True,
...     push_to_hub=True,
... )

>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=tokenized_imdb["train"],
...     eval_dataset=tokenized_imdb["test"],
...     processing_class=tokenizer,
...     data_collator=data_collator,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()
```

[Trainer](/docs/transformers/main/fr/main_classes/trainer#transformers.Trainer) applique un rembourrage dynamique par défaut lorsque vous lui passez `tokenizer`. Dans ce cas, vous n'avez pas besoin de spécifier explicitement un collateur de données.

Une fois l’entraînement terminé, partagez votre modèle sur le Hub à l’aide de la méthode [push_to_hub()](/docs/transformers/main/fr/main_classes/trainer#transformers.Trainer.push_to_hub) afin que chacun puisse l’utiliser :

```py
>>> trainer.push_to_hub()
```

Pour un exemple plus approfondi sur la façon d’affiner un modèle pour la classification de texte, consultez le [notebook PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/text_classification.ipynb) correspondant.

## Inférence

Parfait, maintenant que vous avez affiné un modèle, vous pouvez l'utiliser pour l'inférence !

Récupérez du texte sur lequel vous souhaitez effectuer une inférence :

```py
>>> text = "This was a masterpiece. Not completely faithful to the books, but enthralling from beginning to end. Might be my favorite of the three."
```

La manière la plus simple de tester votre modèle finement ajusté pour l’inférence est de l’utiliser dans un [pipeline()](/docs/transformers/main/fr/main_classes/pipelines#transformers.pipeline). Instanciez un `pipeline` pour l’analyse de sentiments avec votre modèle, puis transmettez-lui votre texte :

```py
>>> from transformers import pipeline

>>> classifier = pipeline("sentiment-analysis", model="stevhliu/my_awesome_model")
>>> classifier(text)
[{'label': 'POSITIVE', 'score': 0.9994940757751465}]
```

Vous pouvez également reproduire manuellement les résultats de `pipeline` si vous le souhaitez :

Tokeniser le texte et retourner des tenseurs PyTorch :

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("stevhliu/my_awesome_model")
>>> inputs = tokenizer(text, return_tensors="pt")
```

Transmettez vos entrées au modèle et renvoyez les `logits` :

```py
>>> import torch
>>> from transformers import AutoModelForSequenceClassification

>>> model = AutoModelForSequenceClassification.from_pretrained("stevhliu/my_awesome_model")
>>> with torch.no_grad():
...     logits = model(**inputs).logits
```

Obtenez la classe ayant la probabilité la plus élevée, puis utilisez le mapping `id2label` du modèle pour la convertir en libellé texte :

```py
>>> predicted_class_id = logits.argmax().item()
>>> model.config.id2label[predicted_class_id]
'POSITIVE'
```

