Начало путешествия по языковой стране

Мой интерес к области НЛП начался, когда я решил участвовать в одном из продолжающихся соревнований по определению того, является ли данный твит о какой-либо катастрофе или нет. У меня не было никакого опыта в области языковой обработки, и после нескольких поисков в Интернете я узнал о некоторой предварительной обработке текста данных, такой как токенизация и лемматизация, с использованием TfidfTransformer и TfidfVectorizer для извлечения признаков, а затем просто использовал Наивный байесовский для классификации (оценка = 0,77). Тем временем я прошел курс специализации по глубокому обучению, узнал о RNN и решил использовать модель LTSM для этой задачи и получил лучшие результаты (оценка = 0,79987 , Верхние 40%). В этом курсе упоминалось о трансфертном обучении и о том, что оно может стать мощным инструментом для решения любых задач. Я подумал, почему бы не попробовать это с набором данных, который у меня есть прямо сейчас.

Открытие BERT

Я искал разные фреймворки в НЛП и узнал о BERT. Говорят, что это одна из самых мощных и влиятельных моделей в области НЛП от Google, обученная на большом немаркированном наборе данных для достижения самых современных результатов по 11 отдельным задачам НЛП. Его можно настроить в соответствии с вашими потребностями, что сделает его еще более мощным. Я решил использовать этот фреймворк и настроить его в соответствии с моим набором данных. Я искал, как использовать этот фреймворк, и наткнулся на Трансформаторы обнимающего лица, которые предоставляют архитектуры общего назначения (BERT, GPT-2, RoBERTa, XLM, DistilBert, XLNet…) для понимания естественного языка. (NLU) и Natural Language Generation (NLG) с более чем 32+ предварительно обученными моделями на более чем 100 языках и глубоким взаимодействием между TensorFlow 2.0 и PyTorch.

После множества экспериментов и чтения документации мне удалось отрегулировать эту модель, и я надеюсь, что этот опыт также может помочь вам в какой-то мере.

Давайте начнем

Во-первых, давайте посмотрим на предоставленные данные

data = pd.read('train.csv')
data.head()

data.describe(include = 'all')

Точно так же есть "test.csv", твиты которого мы должны предсказывать. Мы можем объединить оба набора данных и проделать с ними некоторые необходимые операции. Мы можем опустить столбец ключевых слов и местоположения, чтобы делать прогнозы только на основе заданных твитов.

df1 = pd.read_csv('content/drive/My Drive/disaster tweets/train.csv')
df2 = pd.read_csv('content/drive/My Drive/disaster tweets/test.csv')
combined = pd.concat([df1,df2], axis=0)
combined = combined.drop(['keyword','location'], axis=1)

Я не выполнял предварительную обработку и очистку данных (например, удаление знаков препинания или удаление тегов HTML и т. Д.), Так как просто хотел посмотреть, как работать с фреймворком. Я уверен, что очистка и работа с данными в дальнейшем даст лучшие результаты.

from transformers import BertForSequenceClassification, AdamW    #importing appropriate class for classification
import numpy as np
import pandas as pd
import torch
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')   #Importing the bert model
model.train()     #tell model its in training mode so that some
layers(dropout,batchnorm) behave accordingly

Токенизация и кодирование

Для использования модели BERT мы должны сначала токенизировать и закодировать наш текст, а токенизатор BERT предоставляется в трансформаторе обнимающего лица.

from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained(‘bert-base-uncased’)
encoded = tokenizer(combined.text.values.tolist(), padding=True, truncation=True, return_tensors='pt')

Кодировщик выдает три тензора для одного твита в виде словаря («input_ids», «Внимание_mask», «token_type_ids»), который используется моделью.

Теперь давайте разделим тензоры на разные переменные (нам нужны только «input_ids» и «Внимание_mask») и снова разберем объединенные данные в формате теста и обучения.

input_id = encoded['input_ids']
attention_mask = encoded['attention_mask']
train_id = input_id[:len(df1)]
train_am = attention_mask[:len(df1)]
test_id = input_id[len(df1):]
test_am = attention_mask[len(df1):]
train = combined.iloc[:len(df1)]
test = combined.iloc[len(df1):]

В целях обучения и тестирования давайте разделим данные поезда на две части для обучения и тестирования модели.

Xtrain = train.iloc[:6800]
Xtest =  train.iloc[6800:]
Xtrain_id = train_id[:6800]
Xtrain_am = train_am[:6800]
Xtest_id = train_id[6800:]
Xtest_am = train_am[6800:]
labels = torch.tensor(Xtrain.target.values.tolist())
labels = labels.type(torch.LongTensor)
labels.shape

Точная настройка модели

Теперь давайте сосредоточимся на модели. Мы будем использовать PyTorch для обучения модели (также можно использовать TensorFlow). Сначала мы настроим наш оптимизатор (Адам), а затем обучим нашу модель в пакетном режиме, чтобы наша машина (ЦП, ГП) не зависала.

optimizer = AdamW(model.parameters(), lr=1e-5)
n_epochs = 1 
batch_size = 32 

for epoch in range(n_epochs):

    permutation = torch.randperm(Xtrain_id.size()[0])

    for i in range(0,Xtrain_id.size()[0], batch_size):
        optimizer.zero_grad()

        indices = permutation[i:i+batch_size]
        batch_x, batch_y,batch_am = Xtrain_id[indices],   labels[indices], Xtrain_am[indices]

        outputs = model(batch_x, attention_mask=batch_am, labels=batch_y)
        loss = outputs[0]
        loss.backward()
        optimizer.step()

Здесь выходы дают нам кортеж, содержащий потерю кросс-энтропии и окончательную активацию модели. Например, вот результат двух тензоров

Мы можем использовать эти активации для классификации твитов о катастрофах с помощью функции активации softmax.

Теперь давайте протестируем модель с помощью оставшихся данных в обучающем наборе. Сначала мы должны перевести модель в тестовый режим, а затем получить выходные данные из модели.

model.eval()     #model in testing mode
batch_size = 32
permutation = torch.randperm(Xtest_id.size()[0])

for i in range(0,Xtest_id.size()[0], batch_size):

  indices = permutation[i:i+batch_size]
  batch_x, batch_y, batch_am = Xtest_id[indices], labels[indices], Xtest_am[indices]

        
  outputs = model(batch_x, attention_mask=batch_am, labels=batch_y)
  loss = outputs[0]
  print('Loss:' ,loss)

Вы также можете получить показатель точности, сравнив вывод с меткой и вычислив (правильный прогноз) / (общее количество твитов) * 100.

Теперь давайте предскажем наши фактические тестовые данные, результат которых нам нужно найти.

import torch.nn.functional as F  #for softmax function    
batch_size = 32
prediction = np.empty((0,2)) #empty numpy for appending our output
ids = torch.tensor(range(original_test_id.size()[0]))
for i in range(0,original_test_id.size()[0], batch_size):
  indices = ids[i:i+batch_size]
  batch_x1, batch_am1 = original_test_id[indices], original_test_am[indices]
  pred = model(batch_x1, batch_am1) #Here only activation is given as output
  pt_predictions = F.softmax(pred[0], dim=-1)  #applying softmax activation function
  prediction = np.append(prediction, pt_predictions.detach().numpy(), axis=0) #appending the prediction

Как мы видим, в прогнозе есть два столбца, прогноз [:, 0] дает вероятность наличия метки 0, а прогноз [:, 1] дает вероятность наличия метки 1. Мы можем использовать функцию argmax, чтобы найти подходящую метку.

sub = np.argmax(prediction, axis=1)

Затем, расположив эти метки с правильным идентификатором, мы можем получить наши прогнозы.

submission = pd.DataFrame({'id': test.id.values, 'target':sub})

Используя эту модель, я получил оценку 0,83695 и попал в топ-12%, даже не очищая и не обрабатывая данные. Итак, мы видим, насколько мощна эта структура, как ее можно использовать для различных целей. Вы также можете увидеть код здесь.

Я надеюсь, что мой опыт может помочь вам в некоторой степени, а также даст мне знать, что еще можно сделать для улучшения производительности (поскольку я также новичок в НЛП: P).