ПРОЛОГ

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

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

Эти методы заключаются в следующем:

1. BERT (глубокие двунаправленные преобразователи для понимания языка)
2. Fastai ULMFiT (точная настройка универсальной языковой модели для классификации текста)

Обе эти техники являются очень продвинутыми и новейшими техниками НЛП (BERT был представлен Google в 2018 году, а Джереми Ховард и Себастьян Рудер представили ULMFiT в 2017–2018 годах). Оба они включают в себя методы трансферного обучения, что довольно круто и предварительно обучено на больших корпусах Википедии и связанных статей. Я хотел сравнить общую производительность этих двух методов.

Мне очень нравится использовать Fastai для своих проектов глубокого обучения, и я не могу поблагодарить замечательное сообщество Fastai, а также наших наставников и инструкторов - Джереми Ховарда и Рэйчел Томас за разработку нескольких из самых замечательных курсов по вопросам, относящимся к глубокому обучению. Однако до настоящего времени BERT не реализован в Fastai.

Таким образом, одной из моих целей в работе над этим проектом была интеграция BERT с Fastai. Это означает, что мощность BERT сочетается с простотой Fastai, а затем сравниваются их соответствующие характеристики. Это была непростая задача, особенно реализация методики Discriminative Learning Rate Fastai в моделировании BERT.

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

Https://mlexplained.com/2019/05/13/a-tutorial-to-fine-tuning-bert-with-fast-ai/

ДАННЫЕ

Мы будем работать над старым набором данных о соревнованиях Kaggle, который можно найти здесь:



Это задача классификации текста с несколькими метками, в которой нам нужно классифицировать заданную строку текста на следующие классы:

  1. Токсичный
  2. Сильно токсичен
  3. Непристойный
  4. Угроза
  5. Оскорблять
  6. Личность Ненависть

БИБЛИОТЕКИ И ОСНОВНЫЕ ЗАВИСИМОСТИ

  1. Kaggle Kernel для использования GPU
  2. Fastai v 1.0.52
  3. Предварительно обученные модели pytorch от Huggingface для BERT


Huggingface - это великолепное хранилище нескольких удивительных современных предварительно обученных моделей для НЛП. Недавно его переименовали (и обновили) в Pytorch-Transformers.

МЕТОДЫ ИНТЕГРАЦИИ

В основном я использовал следующие техники (с помощью средней статьи, ссылка на которую приведена выше):

  1. Использование токенизатора BERT
  2. Использование словаря BERT
  3. Отключение include_bos и include_eos по умолчанию Fastai как False
  4. Введение [CLS] и [SEP] в начало и конец каждого токена BERT соответственно
  5. Метод разделения модели для применения дискриминационного обучения (новый метод, который преподается на лекциях Fastai, так что разные уровни скорости обучения и уменьшения веса могут быть введены в разные части архитектуры модели)

Итак, давайте посмотрим, как можно применить эти методы:

Сначала мы импортируем токенизатор BERT из предварительно обученной модели BERT Huggingface:

from pytorch_pretrained_bert import BertTokenizer
bert_tok = BertTokenizer.from_pretrained(
 “bert-base-uncased”,
)

Есть много методов токенизатора, которые мы можем импортировать, но мы будем использовать самый простой и самый распространенный из них - «bert-base-uncased»

Затем мы определим функцию для создания токенизатора в зависимости от указанной выше модели токенизатора, которая может быть совместима с fastai:

class FastAiBertTokenizer(BaseTokenizer):
 “””Wrapper around BertTokenizer to be compatible with fast.ai”””
 def __init__(self, tokenizer: BertTokenizer, max_seq_len: int=128, **kwargs):
 self._pretrained_tokenizer = tokenizer
 self.max_seq_len = max_seq_len
def __call__(self, *args, **kwargs):
 return self
def tokenizer(self, t:str) -> List[str]:
 “””Limits the maximum sequence length”””
 return [“[CLS]”] + self._pretrained_tokenizer.tokenize(t)[:self.max_seq_len — 2] + [“[SEP]”]

Здесь вы можете видеть, что каждый токен должен начинаться с [CLS] и заканчиваться на [SEP].

После этого мы создадим функцию словаря:

fastai_bert_vocab = Vocab(list(bert_tok.vocab.keys()))

и после этого нам нужно обернуть созданную выше функцию токенизатора в fastai:

fastai_tokenizer = Tokenizer(tok_func=FastAiBertTokenizer(bert_tok, max_seq_len=256), pre_rules=[], post_rules=[])

Это все, что касается создания токенов BERT и словаря, совместимых с библиотекой Fastai.

Теперь мы можем создать нашу Databunch следующим образом:

label_cols = [“toxic”, “severe_toxic”, “obscene”, “threat”, “insult”, “identity_hate”]
databunch_1 = TextDataBunch.from_df(“.”, train, val, 
 tokenizer=fastai_tokenizer,
 vocab=fastai_bert_vocab,
 include_bos=False,
 include_eos=False,
 text_cols=”comment_text”,
 label_cols=label_cols,
 bs=32,
 collate_fn=partial(pad_collate, pad_first=False, pad_idx=0),
 )

При создании панели данных выше обратите внимание, что мы установили для include_bos и include_eos значение False. Мы делаем это, потому что это каким-то образом мешает методам [CLS] и [SEP] BERT.

Я проигнорировал предоставление здесь кодов для создания набора данных поезда и проверки, но их можно найти в моей учетной записи GitHub (ссылка будет приведена ниже)

Наконец, для разборчивой техники обучения нам необходимо разделить архитектуру модели, и это можно сделать следующим образом:

def bert_clas_split(self) -> List[nn.Module]:
 
 bert = model.bert
 embedder = bert.embeddings
 pooler = bert.pooler
 encoder = bert.encoder
 classifier = [model.dropout, model.classifier]
 n = len(encoder.layer)//3
 print(n)
 groups = [[embedder], list(encoder.layer[:n]), list(encoder.layer[n+1:2*n]), list(encoder.layer[(2*n)+1:]), [pooler], classifier]
 return groups

Здесь модель BERT можно импортировать следующим образом:

from pytorch_pretrained_bert.modeling import BertConfig, BertForSequenceClassification, BertForNextSentencePrediction, BertForMaskedLM
bert_model_class = BertForSequenceClassification.from_pretrained(‘bert-base-uncased’, num_labels=6)
model = bert_model_class

Для моделирования мы будем использовать следующую функцию потерь и метрики:

  1. Функция потерь = бинарная кросс-энтропия с логистическими потерями
  2. Метрика = точность с порогом (с порогом 25%), учитывая, что мы не можем использовать здесь простую точность в качестве метрики, поскольку это задача классификации с несколькими метками.

Наконец, это наша обучающая функция:

from fastai.callbacks import *
learner = Learner(
 databunch_1, model,
 loss_func=loss_func, model_dir=’/temp/model’, metrics=acc_02,
)

Мы можем использовать указанную выше функцию, чтобы разделить модель следующим образом:

x = bert_clas_split(model)
learner.split([x[0], x[1], x[2], x[3], x[5]])

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

Для задач НЛП, как упоминал Джереми в своих лекциях, в отличие от задач классификации / регрессии изображений, мы будем постепенно размораживать слои.

Я не буду вдаваться в подробности процедур обучения как для моделей BERT, так и для ULMFiT. Это те же техники, которым обучают в классах Джереми, и их там можно изучить гораздо лучше.

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

РАБОЧИЕ ХАРАКТЕРИСТИКИ МОДЕЛИ

Показатели BERT (после 2-х периодов обучения):

Это отличный спектакль! Точность 98,27% всего за 2 эпохи обучения.

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

Показатели Fastai ULMFiT (после 2 эпох обучения):

Производительность ULMFiT Fastai также великолепна (точность около 97,2%). Это можно было бы улучшить еще больше, если бы мы могли запустить еще несколько эпох, поскольку ошибка обучения все еще выше, чем ошибка проверки.

Теперь давайте посмотрим, как он предсказывал те же два фрагмента текста:

ЗАКЛЮЧЕНИЕ

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

Обе модели отлично справились с этой задачей классификации текста с несколькими метками.

Следует отметить несколько важных моментов:

  1. Токенизатор и словарь BERT должны быть тщательно интегрированы с Fastai.
  2. [CLS] и [SEP] необходимо аккуратно вставлять в каждый токен.
  3. Разделение архитектуры модели необходимо, если мы хотим воспользоваться преимуществом различительного обучения, которое преподается в Fastai.

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



То же самое можно найти и в моем ядре Kaggle:

Https://www.kaggle.com/abhikjha/jigsaw-toxicity-bert-with-fastai-and-fastai/notebook

Если вам понравилась моя статья, прошу вас поделиться ею и аплодировать :)