Как обучить BERT для задач маскированного моделирования языка

Как эффективно обучить BERT для задач маскированного моделирования языка

Практическое руководство по созданию языковой модели для задач MLM с нуля с использованием Python и библиотеки Transformers

Введение

В последние годы большое внимание машинного обучения привлекли большие языковые модели (LLM). Перед появлением LLM мы провели важный исследовательский этап по различным методикам языкового моделирования, включая маскированное языковое моделирование, причинное языковое моделирование и языковое моделирование последовательностей.

Из перечисленных выше методик особенно полезными стали маскированные языковые модели, такие как BERT, в задачах обработки естественного языка, таких как классификация и кластеризация. Благодаря библиотекам, таким как Transformers от Hugging Face, адаптация этих моделей для задач стала более доступной и управляемой. Кроме того, благодаря сообществу с открытым исходным кодом, у нас есть множество языковых моделей на выбор, охватывающих широко используемые языки и области.

Настроить или создать с нуля?

При адаптации существующих языковых моделей под свои конкретные случаи использования иногда можно использовать существующие модели без дополнительной настройки (так называемая тонкая настройка). Например, если вам нужна модель английского языка для определения настроения/намерения, вы можете перейти на HuggingFace.co и найти подходящую модель для своего случая использования.

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

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

Архитектура BERT

Не смотря на то, что описание архитектуры BERT выходит за рамки данного урока, давайте очень кратко рассмотрим ее для большей ясности. BERT, или Bидирикционные Eнкодер Rепрезентации от Tрансформеров, относится к семейству энкодеров-трансформеров. Он был представлен в 2018 году исследователями из Google.

Краткое описание статьи:

Мы представляем новую модель представления языка, называемую BERT, что означает Бидирекционные Репрезентации Энкодера от Трансформеров. В отличие от недавних моделей представления языка, BERT предназначен для предварительного обучения глубоких бидирекционных представлений на неразмеченном тексте совместно на обоих сторонах контекста во всех слоях. В результате, предварительно обученную модель BERT можно довести до состояния передовых моделей для широкого спектра задач, таких как ответы на вопросы и выводы на естественном языке, без существенных изменений архитектуры, специфичных для задачи. BERT концептуально прост и эмпирически мощен. Он достигает новых передовых результатов на одиннадцати задачах обработки естественного языка, включая улучшение показателя GLUE до 80,5% (абсолютное улучшение на 7,7% пункта), увеличение точности на MultiNLI до 86,7% (абсолютное улучшение на 4,6%), улучшение показателя F1 на вопросы и ответы SQuAD v1.1 до 93,2 (абсолютное улучшение на 1,5 пункта) и улучшение показателя F1 на вопросы и ответы SQuAD v2.0 до 83,1 (абсолютное улучшение на 5,1 пункта). Статья: https://arxiv.org/abs/1810.04805

В приведенном выше тексте можно увидеть интересное ключевое слово – Бидирекционные. Бидирекциональная природа придает BERT человекоподобную мощь. Предположим, у вас есть задача заполнить пропуск в предложении, подобный следующему:

«Война иногда может быть необходимым злом. Но любая война всегда – это __________________, никогда не хорошее».

Чтобы угадать слово, которое должно находиться на месте пропуска, вам нужно учесть несколько вещей: слова перед пропуском, слова после пропуска и общий контекст предложения. BERT работает аналогичным образом. Во время обучения мы скрываем некоторые слова и просим BERT попытаться предсказать их. После обучения BERT может предсказывать токены на основе их предшествующих и последующих слов. Для этого модель должна распределить различное внимание на слова, представленные во входной последовательности, что может существенно повлиять на предсказание скрытых токенов.

Image by Author via https://huggingface.co/spaces/exbert-project/exbert

Как видно здесь, модель видит подходящее слово для скрытой позиции как зло и первое слово “зло” предложения как необходимое для этого прогноза. Это заметный момент и подразумевает, что модель понимает контекст входной последовательности. Это осознание контекста позволяет BERT генерировать значимые вложения предложений для заданных задач. Кроме того, эти вложения могут использоваться в последующих задачах, таких как кластеризация и классификация. Хватит о BERT, давайте создадим его с нуля.

Определение модели BERT

Обычно у нас есть BERT (base) и BERT (large). У обоих по 64 размерности на голову. Вариант large содержит 24 слоя кодировщика, тогда как базовый вариант имеет только 12. Однако мы не ограничены этими конфигурациями. Удивительно, но мы полностью контролируем определение модели с помощью библиотеки Hugging Face Transformers. Все, что нужно сделать, это определить желаемые конфигурации модели с использованием класса BertConfig.

Я выбрал 6 голов и общую размерность модели 384, чтобы соответствовать оригинальной реализации. Таким образом, каждая голова имеет 64 размерности, аналогично оригинальной реализации. Давайте инициализируем нашу модель BERT.

from transformers import BertConfig, BertForMaskedLMconfig = BertConfig(    hidden_size = 384,    vocab_size= tokenizer.vocab_size,    num_hidden_layers = 6,    num_attention_heads = 6,    intermediate_size = 1024,    max_position_embeddings = 256)model = BertForMaskedLM(config=config)print(model.num_parameters()) #10457864

Обучение токенизатора

Здесь я не буду описывать, как работает токенизация внутри. Вместо этого давайте обучим ее с нуля, используя библиотеку Hugging Face tokenizers. Обратите внимание, что токенизатор, используемый в оригинальной реализации BERT, – это токенизатор WordPiece, еще один метод токенизации на основе подслов. Вы можете узнать больше о этой токенизации с использованием ресурса HuggingFace ниже.

Токенизация WordPiece – курс Hugging Face NLP

Мы на пути к развитию и демократизации искусственного интеллекта через открытые исходники и открытую науку.

huggingface.co

В этом случае используется набор данных Sinhala-400M (под лицензией Apache-2.0). Вы можете продолжить то же самое с любым набором данных, которым располагаете.

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

Сначала импортируем необходимые модули. Хорошая вещь заключается в том, что при обучении токенизаторов с использованием библиотеки Hugging Face Tokenizers мы можем использовать существующие токенизаторы и заменить только словарь (и объединить, где это применимо) согласно нашему корпусу для обучения. Это означает, что шаги токенизации, такие как предварительная токенизация и пост-токенизация, будут сохранены. Для этого мы можем использовать метод train_new_from_iterator класса BertTokenizer.

from tokenizers.implementations import ByteLevelBPETokenizerfrom tokenizers.processors import BertProcessingfrom transformers import AutoTokenizerfrom datasets import Datasetimport pandas as pd# загрузить базовый токенизатор для обучения на наборе данныхtokenizer_base = AutoTokenizer.from_pretrained("bert-base-cased")# преобразовать набор данных pandas в набор данных HFdataset = Dataset.from_pandas(df.rename(columns={"comment":'text'}))# определить итераторtraining_corpus = (    dataset[i : i + 1000]["text"]    for i in range(0, len(dataset), 1000))# обучить новый токенизатор для набора данныхtokenizer = tokenizer_base.train_new_from_iterator(training_corpus, 5000)#проверить обученный токенизатор для примерного текстатекст = dataset['text'][123]print(text)

# проверим процесс токенизацииinput_ids = tokenizer(text).input_idssubword_view = [tokenizer.convert_ids_to_tokens(id) for id in input_ids]np.array(subword_view)

Вы можете видеть слова, такие как ‘cricketer’, разложенные на cricket и ##er, что указывает на то, что токенизатор правильно обучен. Однако попробуйте использовать различные размеры словаря; у меня он составляет 5000, что является относительно небольшим, но подходящим для этого примера.

Наконец, мы можем сохранить обученный токенизатор в наш каталог.

tokenizer.save_pretrained("tokenizer/sinhala-wordpiece-yt-comments")

Определите коллектор данных и токенизируйте набор данных.

Давайте определим коллектор для задач MLM. Здесь мы будем маскировать 15% токенов. В любом случае, мы можем установить разные вероятности маскирования.

from transformers import DataCollatorForLanguageModelingdata_collator = DataCollatorForLanguageModeling(    tokenizer=tokenizer, mlm=True, mlm_probability=0.15)

Давайте токенизируем набор данных, используя ранее созданный токенизатор. Я заменяю оригинальный LineByLineTextDataset моим собственным классом, использующим Hugging Face accelerate.

import torchfrom torch.utils.data import Datasetfrom accelerate import Accelerator, DistributedTypeclass LineByLineTextDataset(Dataset):    def __init__(self, tokenizer, raw_datasets, max_length: int):        self.padding = "max_length"        self.text_column_name = 'text'        self.max_length = max_length        self.accelerator = Accelerator(gradient_accumulation_steps=1)        self.tokenizer = tokenizer        with self.accelerator.main_process_first():            self.tokenized_datasets = raw_datasets.map(                self.tokenize_function,                batched=True,                num_proc=4,                remove_columns=[self.text_column_name],                desc="Running tokenizer on dataset line_by_line",            )            self.tokenized_datasets.set_format('torch',columns=['input_ids'],dtype=torch.long)                def tokenize_function(self,examples):        examples[self.text_column_name] = [            line for line in examples[self.text_column_name] if len(line[0]) > 0 and not line[0].isspace()        ]        return self.tokenizer(            examples[self.text_column_name],            padding=self.padding,            truncation=True,            max_length=self.max_length,            return_special_tokens_mask=True,        )    def __len__(self):        return len(self.tokenized_datasets)    def __getitem__(self, i):        return self.tokenized_datasets[i]

Давайте токенизируем набор данных.

tokenized_dataset_train = LineByLineTextDataset(    tokenizer= tokenizer,    raw_datasets = dataset,    max_length=256,)

Хорошо, давайте закодируем нашу тренировочную петлю.

from transformers import Trainer, TrainingArgumentstraining_args = TrainingArguments(    output_dir="./model",    overwrite_output_dir=True,    push_to_hub=True,    hub_model_id="Ransaka/sinhala-bert-yt-comments",    num_train_epochs=2,    per_device_train_batch_size=32,    save_steps=5_000,    logging_steps = 1000,    save_total_limit=2,    use_mps_device = True, # отключите это, если вы запускаете среду, отличную от macOS    hub_private_repo = False, # установите true, если хотите сохранить модель приватно    save_safetensors= True,    learning_rate = 1e-4,    report_to='wandb')trainer = Trainer(    model=model,    args=training_args,    data_collator=data_collator,    train_dataset=tokenized_dataset_train)trainer.train()

Мы можем вызвать тренера, используя его метод train().

trainer.train()

После достаточной тренировки нашу модель можно использовать для задач нулевой классификации и кластеризации. Вы можете найти пример использования этого пространства Hugging Face для получения более подробной информации.

Sinhala Embedding Space – пространство Hugging Face от Ransaka

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

huggingface.co

Вывод

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

В этой статье все изображения, если не указано иное, принадлежат автору.

Ссылки

  1. Приложение Explorable BERT — https://huggingface.co/spaces/exbert-project/exbert
  2. Статья о BERT — https://arxiv.org/abs/1810.04805
  3. Набор данных — https://huggingface.co/datasets/Ransaka/Sinhala-400M