часть 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 — более продвинутая модель для анализа настроений.