Transformers documentation

Выбор из нескольких вариантов

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Выбор из нескольких вариантов

Задача с множественным выбором похожа на задачу по ответам на вопросы, за исключением того, что вместе с контекстом предоставляется несколько вариантов ответа, а модель обучается выбирать правильный.

В этом руководстве показано, как:

  1. Настройте BERT на конфигурации regular набора данных SWAG, чтобы выбирать лучший ответ из нескольких вариантов с учётом контекста.
  2. Используйте вашу дообученную модель для инференса.

Прежде чем начать, убедитесь, что у вас установлены все необходимые библиотеки:

pip install transformers datasets evaluate

Мы рекомендуем вам войти в свой аккаунт Hugging Face, чтобы вы могли загрузить свою модель и поделиться ею с сообществом. При появлении запроса введите токен для входа:

>>> from huggingface_hub import notebook_login

>>> notebook_login()

Загрузка набора данных SWAG

Начните с загрузки конфигурации regular набора данных SWAG из библиотеки 🤗 Datasets:

>>> from datasets import load_dataset

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

Теперь рассмотрим пример:

>>> 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'}

Хотя здесь много полей, на самом деле всё довольно просто:

  • sent1 и sent2: эти поля показывают, как начинается предложение, а если объединить их, получится поле startphrase.
  • ending: предлагает возможный вариант окончания предложения, но только один из них является правильным.
  • label: определяет правильный конец предложения.

Предобработка

Следующий шаг — загрузить токенизатор BERT для обработки начала предложения и четырёх возможных концов:

>>> from transformers import AutoTokenizer

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

Функция предобработки, которую вы хотите создать, должна:

  1. Создайте четыре копии поля sent1 и объедините каждую из них с sent2, чтобы воссоздать начало предложения.
  2. Соедините sent2 с каждым из четырёх возможных окончаний предложения.
  3. Выровняйте эти два списка, чтобы токенизировать их, а затем верните исходную структуру, чтобы у каждого примера были соответствующие поля input_ids, attention_mask и labels.
>>> 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()}

Чтобы применить функцию предобработки ко всему набору данных, используйте метод map библиотеки 🤗 Datasets. Вы можете ускорить работу функции map, установив batched=True, чтобы обрабатывать несколько элементов набора данных одновременно:

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

Чтобы создать батч примеров, эффективнее динамически дополнять предложения до максимальной длины в батче на этапе collation, чем дополнять весь датасет до максимальной длины. DataCollatorForMultipleChoice разворачивает все входные данные модели, применяет padding, а затем сворачивает результаты обратно.

>>> from transformers import DataCollatorForMultipleChoice
>>> collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)

Оценка

Добавление метрики в процесс обучения часто помогает оценить качество модели. Вы можете быстро загрузить метод оценки с помощью библиотеки 🤗 Evaluate. Для этой задачи загрузите метрику accuracy (ознакомьтесь с быстрым обзором 🤗 Evaluate, чтобы узнать, как загружать и вычислять метрики):

>>> import evaluate

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

Затем создайте функцию, которая передаёт ваши предсказания и метки в compute для вычисления точности:

>>> 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)

Ваша функция compute_metrics готова, и вы вернётесь к ней при настройке обучения.

Обучение

Если вы не знакомы с дообучением модели с помощью Trainer, загляните в базовое руководство здесь!

Теперь вы готовы приступить к обучению модели! Загрузите BERT с помощью AutoModelForMultipleChoice:

>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer

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

На этом этапе осталось выполнить только три шага:

  1. Определите гиперпараметры обучения в TrainingArguments. Единственный обязательный параметр — output_dir, который указывает, куда сохранять модель. Чтобы загрузить модель на Hub, установите push_to_hub=True (для загрузки модели необходимо войти в аккаунт Hugging Face). В конце каждой эпохи Trainer оценивает точность и сохраняет контрольную точку обучения.
  2. Передайте аргументы обучения в Trainer вместе с моделью, набором данных, токенизатором, data collator и функцией compute_metrics.
  3. Вызовите train(), чтобы дообучить модель.
>>> 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()

После завершения обучения используйте метод push_to_hub(), чтобы опубликовать модель на Hub и дать всем возможность её использовать:

>>> trainer.push_to_hub()

Более подробный пример того, как дообучить модель для задачи с множественным выбором, можно найти в соответствующем ноутбуке PyTorch.

Вывод

Отлично, теперь, когда вы дообучили модель, вы можете использовать её для инференса!

Придумайте какой-либо текст и два варианта ответа:

>>> 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."

Токенизируйте каждую пару «запрос — ответ» и верните тензоры PyTorch. Также необходимо создать некоторые labels:

>>> 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)

Передайте входные данные и метки в модель и верните logits:

>>> 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

Получите класс с наибольшей вероятностью:

>>> predicted_class = logits.argmax().item()
>>> predicted_class
0
Update on GitHub