Начало путешествия по языковой стране
Мой интерес к области НЛП начался, когда я решил участвовать в одном из продолжающихся соревнований по определению того, является ли данный твит о какой-либо катастрофе или нет. У меня не было никакого опыта в области языковой обработки, и после нескольких поисков в Интернете я узнал о некоторой предварительной обработке текста данных, такой как токенизация и лемматизация, с использованием 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).