часть 4 БЕРТ

ссылка на мой Github для получения дополнительного кода: https://github.com/charliezcr/Sentiment-Analysis-of-Movie-Reviews/blob/main/sa_p4.ipynb

В части 1, 2, 3 этого исследования анализа настроений в обзорах фильмов IMDb я использовал классические методы обучения с учителем. В этой части я буду использовать трансферное обучение с моделью BERT.

Трансферное обучение

В отличие от моделей, обученных мной в частях 1–3, трансферное обучение — это метод использования уже существующих предварительно обученных моделей для решения конкретной задачи. Модель на этот раз, BERT, представляет собой современную модель глубокого обучения для различных целей в области понимания естественного языка, изобретенную исследователями Google. Путем точной настройки BERT для этого набора данных обзоров фильмов IMDb мне не нужно обучать свою собственную модель, а нужно использовать переданную модель для этой конкретной задачи прогнозирования настроений для обзоров фильмов. Образно говоря, обучение модели контролируемого обучения похоже на самостоятельную сборку автомобиля; тонкая настройка модели трансферного обучения похожа на настройку автомобиля: покупка автомобиля и его модификация.

Pytorch и CUDA

Прочитав все данные, я буду использовать Pytorch, пакет для глубокого обучения. CUDA в Pytorch — это набор инструментов, который позволяет использовать GPU для параллельных вычислений (но на самом деле у меня нет GPU на моем локальном компьютере, поэтому я все равно буду использовать CPU). Чтобы объяснить это образно. Когда вы что-то доставляете, использование процессора похоже на вождение быстрой машины для перевозки небольшого количества груза; использование графического процессора похоже на одновременное вождение нескольких пикапов для перевозки большого количества груза. Поскольку в глубоком обучении расчет представляет собой большое количество матричных умножений, использование графического процессора ускорит процесс.

При токенизации предложений максимальная длина будет установлена ​​на 128. Таким образом, предложения с более чем 126 токенами (двумя другими токенами являются «cls» и «sep», что означает начало и конец предложения) будут усечены. Предложение, в котором меньше 126 слов, имеет нулевой отступ в конце.

Токенизация

В Части 1 я использовал TF-IDF для преобразования предложения в вектор, предложения в матрицу. В этой части я буду напрямую использовать токенизатор BERT для преобразования предложений в кодировки, состоящие из входных идентификаторов и масок внимания. Входные идентификаторы — это токены для BERT, преобразованные из слов в предложении. Маски внимания показывают, сколько внимания нужно каждому токену в предложении.

Например, в предложении Есть две птицы. Если слово «там» привлекает наибольшее внимание, мы знаем, что птицы там, а не здесь. Если наибольшее внимание уделяется «двум», мы знаем, что птиц больше 1, меньше 3. Если «птицы», то мы знаем, что существа есть птицы, а не что-то другое.

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

При токенизации предложений максимальная длина будет установлена ​​на 128. Таким образом, предложения с более чем 126 токенами (двумя другими токенами являются «cls» и «sep», что означает начало и конец предложения) будут усечены. Предложение, в котором меньше 126 слов, имеет нулевой отступ в конце.

from transformers import BertTokenizer
# load bert tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)
# setting the maximum length of encodings to 128, so that encodings will not be too long
encodings = tokenizer(reviews, truncation=True, padding='max_length', return_tensors='pt', max_length=128)
input_ids = encodings['input_ids']
attention_masks = encodings['attention_mask']

Набор данных и загрузчик данных

После кодирования предложений входные идентификаторы, маски внимания и метки будут сохранены в тензорной форме в TensorDataset и разделены на обучающий и тестовый наборы. Затем загрузчики данных оборачивают итерируемые объекты в наборы данных и поддерживают автоматическую пакетную обработку, выборку, перемешивание и многопроцессорную загрузку данных.

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

from torch.utils.data import TensorDataset, random_split, DataLoader
# splitting traing and validation dataset
dataset = TensorDataset(input_ids, attention_masks, torch.tensor(labels))
train_size = int(df.shape[0] * 0.8)
val_size = df.shape[0] - train_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
# load datasets into dataloaders
train_dataloader = DataLoader(train_dataset, shuffle=True, batch_size=16)
eval_dataloader = DataLoader(val_dataset, batch_size=16)

Обучение

Эпохи означают, сколько раз тренировочный набор будет отправлен модели в процессе обучения. Для обучения я установлю количество эпох равным 3. Обычно рекомендуемое количество эпох — 2–4. Я буду использовать ADAM в качестве оптимизатора градиентного спуска.

from transformers import BertForSequenceClassification, AdamW, get_scheduler
# setting the model
model = BertForSequenceClassification.from_pretrained(
"bert-base-uncased",  # Use the 12-layer BERT model, with an uncased vocab.
num_labels=2,  # The number of output labels--2 for binary classification.
output_attentions=False,  # Whether the model returns attentions weights.
output_hidden_states=False,  # Whether the model returns all hidden-states.)

# setting the epochs
num_epochs = 3
# setting for gradient descent
optimizer = AdamW(model.parameters(), lr=5e-5)
num_training_steps = num_epochs * len(train_dataloader)
lr_scheduler = get_scheduler("linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps)
model.train()
for epoch in range(num_epochs):
for batch in train_dataloader:
# send batches to device (cpu or gpu)
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
outputs = model(b_input_ids, token_type_ids=None, attention_mask=b_input_mask, labels=b_labels, return_dict=True)
loss = outputs.loss
loss.backward()
optimizer.step()
lr_scheduler.step()
optimizer.zero_grad()

Оценка

In [30]:

from sklearn.metrics import accuracy_score
y_pred = []
y_true = []
model.eval()
for batch in eval_dataloader:
b_input_ids = batch[0].to(device)
b_input_mask = batch[1].to(device)
b_labels = batch[2].to(device)
# set gradient to zero at the start of every batch
with torch.no_grad():
outputs = model(b_input_ids, token_type_ids=None, attention_mask=b_input_mask, labels=b_labels, return_dict=True)
logits = outputs.logits
predictions = torch.argmax(logits, dim=-1)
y_pred.extend(predictions.tolist())
y_true.extend(b_labels.tolist())
print(f'Accuracy: {accuracy_score(y_pred, y_true)}')

Точность: 0,905

Мы видим, что точность выше 90%, что также лучше, чем у классического обучения с учителем в частях 1–3, что доказывает, что BERT — более продвинутая модель для анализа настроений.