# Choix multiples

Une tâche à choix multiples est similaire à la réponse à des questions, à l’exception près que plusieurs réponses candidates sont fournies avec un contexte et que le modèle est entraîné à sélectionner la bonne réponse.

Ce guide vous montre comment :

1. Effectuer l’ajustement fin de [BERT](https://huggingface.co/google-bert/bert-base-uncased) sur la configuration `regular` du jeu de données [SWAG](https://huggingface.co/datasets/allenai/swag) afin de sélectionner la meilleure réponse parmi plusieurs options et un certain contexte.
2. Utilisez votre modèle affiné pour l'inférence.

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

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

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 SWAG

Commencez par charger la configuration `regular` du jeu de données SWAG à partir de la bibliothèque 🤗 Datasets :

```py
>>> from datasets import load_dataset

>>> swag = load_dataset("allenai/swag", "regular")
```

Puis, jetez un œil à un exemple :

```py
>>> swag["train"][0]
{'ending0': 'passes by walking down the street playing their instruments.',
 'ending1': 'has heard approaching them.',
 'ending2': "arrives and they're outside dancing and asleep.",
 'ending3': 'turns the lead singer watches the performance.',
 'fold-ind': '3416',
 'gold-source': 'gold',
 'label': 0,
 'sent1': 'Members of the procession walk down the street holding small horn brass instruments.',
 'sent2': 'A drum line',
 'startphrase': 'Members of the procession walk down the street holding small horn brass instruments. A drum line',
 'video-id': 'anetv_jkn6uvmqwh4'}
```

Bien qu’il semble y avoir beaucoup de champs ici, c’est en réalité assez simple :

- `sent1` et `sent2` : ces champs indiquent comment une phrase commence, et si vous les combinez, vous obtenez le champ `startphrase`.
- `ending` : suggère une fin possible pour la façon dont une phrase peut se terminer, mais seule l'une d'entre elles est correcte.
- `label` : identifie la fin de phrase correcte.

## Prétraitement

L'étape suivante consiste à charger un tokenizer BERT pour traiter le début de la phrase et les quatre fins possibles :

```py
>>> from transformers import AutoTokenizer

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

La fonction de prétraitement que vous souhaitez créer doit :

1. Créez quatre copies du champ `sent1` et combinez chacune d'elles avec `sent2` pour recréer le début d'une phrase.
2. Combiner `sent2` avec chacune des quatre fins de phrase possibles.
3. Aplatir ces deux listes pour pouvoir les tokeniser, puis les dé-aplatir ensuite afin que chaque exemple possède un champ `input_ids`, `attention_mask` et `labels` correspondant.

```py
>>> ending_names = ["ending0", "ending1", "ending2", "ending3"]

>>> def preprocess_function(examples):
...     first_sentences = [[context] * 4 for context in examples["sent1"]]
...     question_headers = examples["sent2"]
...     second_sentences = [
...         [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers)
...     ]

...     first_sentences = sum(first_sentences, [])
...     second_sentences = sum(second_sentences, [])

...     tokenized_examples = tokenizer(first_sentences, second_sentences, truncation=True)
...     return {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()}
```

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

```py
>>> tokenized_swag = swag.map(preprocess_function, batched=True)
```

Pour créer un lot d'exemples, il est plus efficace de *rembourrer dynamiquement* les phrases jusqu'à la longueur maximale du lot lors de la collation, plutôt que de rembourrer l'ensemble du jeu de données jusqu'à la longueur maximale. [DataCollatorForMultipleChoice](/docs/transformers/v5.23.0/fr/main_classes/data_collator#transformers.DataCollatorForMultipleChoice) aplatit toutes les entrées du modèle, applique le rembourrage, puis rétablit la structure d'origine des résultats.

```py
>>> from transformers import DataCollatorForMultipleChoice
>>> collator = DataCollatorForMultipleChoice(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/v0.4.6/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

Si vous n'êtes pas familier avec l'ajustement fin d'un modèle à l'aide du [Trainer](/docs/transformers/v5.23.0/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 BERT avec [AutoModelForMultipleChoice](/docs/transformers/v5.23.0/fr/model_doc/auto#transformers.AutoModelForMultipleChoice) :

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

>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
```

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

1. Définissez vos hyperparamètres d'entraînement dans [TrainingArguments](/docs/transformers/v5.23.0/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/v5.23.0/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/v5.23.0/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/v5.23.0/fr/main_classes/trainer#transformers.Trainer.train) pour l’ajustement fin de votre modèle.

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

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

>>> trainer.train()
```

Une fois l’entraînement terminé, partagez votre modèle sur le Hub à l’aide de la méthode [push_to_hub()](/docs/transformers/v5.23.0/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 un choix multiple, consultez le [notebook PyTorch](https://colab.research.google.com/github/huggingface/notebooks/blob/main/examples/multiple_choice.ipynb) correspondant.

## Inférence

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

Proposez un texte et deux réponses candidates :

```py
>>> prompt = "France has a bread law, Le Décret Pain, with strict rules on what is allowed in a traditional baguette."
>>> candidate1 = "The law does not apply to croissants and brioche."
>>> candidate2 = "The law applies to baguettes."
```

Tokenisez chaque paire de prompt et de réponse candidate et renvoyez des tenseurs PyTorch. Vous devez également créer des `labels` :

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_swag_model")
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="pt", padding=True)
>>> labels = torch.tensor(0).unsqueeze(0)
```

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

```py
>>> from transformers import AutoModelForMultipleChoice

>>> model = AutoModelForMultipleChoice.from_pretrained("username/my_awesome_swag_model")
>>> outputs = model(**{k: v.unsqueeze(0) for k, v in inputs.items()}, labels=labels)
>>> logits = outputs.logits
```

Obtenir la classe ayant la probabilité la plus élevée :

```py
>>> predicted_class = logits.argmax().item()
>>> predicted_class
0
```

