Вопрос или проблема
У меня есть набор данных онлайн-отзывов (X) с соответствующими темами (тема1 до тема5), и каждая тема может иметь 5 значений (подробная оценка настроений от 1 до 5). Итак, у меня есть один X и 5 Y колонок. Я хотел бы узнать, как я могу использовать Bert и Pytorch для обучения модели, которая получает текстовые данные и выдает результат, например, ([2,3,1,5,4], что означает тема1: 2, тема2: 3 и так далее). В настоящее время моё решение выглядит так, но мои метрики не хорошие. Я был бы признателен, если бы вы помогли мне справиться с ситуацией несбалансированности, поскольку для каждой темы оценки 1 и 2 очень небольшие.
class SentimentClassifier(nn.Module):
def __init__(self, n_classes):
super(SentimentClassifier, self).__init__()
self.bert = BertModel.from_pretrained(PRE_TRAINED_MODEL_NAME)
self.drop = nn.Dropout(p=0.1)
self.out = nn.Linear(self.bert.config.hidden_size, n_classes)
def forward(self, input_ids, attention_mask):
_, pooled_output = self.bert(
input_ids=input_ids,
attention_mask=attention_mask, return_dict=False
)
output = self.drop(pooled_output)
output_1 = self.out(output)
output_2 = self.out(output)
output_3 = self.out(output)
output_4 = self.out(output)
output_5 = self.out(output)
return output_1 ,output_2 ,output_3 ,output_4 ,output_5
torch.cuda.manual_seed(3447)
def train_epoch(
model,
data_loader,
loss_fn,
optimizer,
device,
scheduler
):
model = model.train()
losses = []
acc = []
f1 = []
for d in data_loader:
input_ids = d["input_ids"].to(device)
attention_mask = d["attention_mask"].to(device)
target_1 = d["targets"][:,0].to(device)
target_2 = d["targets"][:,1].to(device)
target_3 = d["targets"][:,2].to(device)
target_4 = d["targets"][:,3].to(device)
target_5 = d["targets"][:,4].to(device)
output_1 ,output_2 ,output_3 ,output_4 ,output_5 = model(
input_ids=input_ids,
attention_mask=attention_mask
)
preds_1 = torch.argmax(output_1 , dim=1)
preds_2 = torch.argmax(output_2 , dim=1)
preds_3 = torch.argmax(output_3 , dim=1)
preds_4 = torch.argmax(output_4 , dim=1)
preds_5 = torch.argmax(output_5 , dim=1)
loss_1 = loss_fn(output_1 , target_1 -1)
loss_2 = loss_fn(output_2 , target_2 -1)
loss_3 = loss_fn(output_3 , target_3 -1)
loss_4 = loss_fn(output_4 , target_4 -1)
loss_5 = loss_fn(output_5 , target_5 -1)
loss = loss_1 + loss_2 + loss_3 + loss_4 + loss_5
acc_1 = accuracy_score(preds_1 ,target_1 -1).item()
f1_1 = f1_score(preds_1 ,target_1 -1).item()
....(для других Ys)
acc_total = (acc_1 + acc_2 + acc_3 + acc_4 + acc_5) / 5
f1_total = (f1_1 + f1_2 + f1_3 + f1_4 + f1_5) / 5
losses.append(loss.item())
acc.append(acc_total)
f1.append(f1_total)
loss.backward()
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
scheduler.step()
optimizer.zero_grad()
gc.collect()
torch.cuda.empty_cache()
return np.mean(losses), np.mean(acc), np.mean(f1)
Думаете, мой подход в порядке? Я рассматриваю проблему как многовыходную классификацию (5 многоклассовых проблем), поэтому я использовал 5-головку на выходе для архитектуры глубокого обучения. Я буду очень благодарен за любую помощь, комментарии и ресурсы для улучшения модели. Большое спасибо!
Добавьте плотный слой поверх объединенного вывода и напишите softmax с 5 единицами в нем.
Также, можете распечатать сводку вашей модели и поделиться ею, пожалуйста!
Ответ или решение
Аспектно-основанный анализ настроений с использованием BERT и PyTorch
Ваша задача по аспектно-основанному анализу настроений представляет собой интересный пример многозадачной классификации, где необходимо предсказать тональность по пяти различным темам на основе текстовых данных. Давайте рассмотрим, как можно улучшить вашу текущую модель, а также как справиться с проблемами, связанными с дисбалансом классов.
Архитектура модели
Вы правильно выбрали архитектуру с несколькими выходами, которая позволяет решить вашу задачу многоклассовой классификации для каждой из пяти тем. Однако, есть несколько аспектов, которые требуют улучшения.
1. Использование Dense Layer:
Добавление плотного слоя (Dense Layer) перед выходным слоем может помочь в извлечении более высокоуровневых признаков из выходного слоя BERT. Это может улучшить качество предсказания, так как модель сможет лучше обработать представление текста перед тем, как перейти к финальным выводам.
Ассортимент выходного слоя для каждой задачи также поможет вашему слою вывода лучше адаптироваться к данным. Пример модификации вашего класса может выглядеть следующим образом:
class SentimentClassifier(nn.Module):
def __init__(self, n_classes):
super(SentimentClassifier, self).__init__()
self.bert = BertModel.from_pretrained(PRE_TRAINED_MODEL_NAME)
self.drop = nn.Dropout(p=0.1)
self.dense = nn.Linear(self.bert.config.hidden_size, 128) # Добавление dense слоя
self.out = nn.Linear(128, n_classes) # Выходной слой
def forward(self, input_ids, attention_mask):
_, pooled_output = self.bert(input_ids=input_ids, attention_mask=attention_mask, return_dict=False)
output = self.drop(pooled_output)
output = self.dense(output) # Пропускание через dense слой
output = self.drop(output) # Дополнительный dropout
return [self.out(output) for _ in range(5)] # Возврат списка выходов
# Теперь ваш метод train_epoch должен будет немного измениться для работы с одним выходом,
# который будет отправлен на все 5 тем.
2. Обработка несбалансированных данных:
Ваша задача сталкивается с проблемой несбалансированных данных, так как классы с оценками 1 и 2 встречаются реже. Вот несколько стратегий, которые могут помочь:
- Обработка весов классов: Определите веса для каждого класса и передайте их в функцию потерь. Это поможет модели уделять больше внимания слабым классам.
class_weights = torch.tensor([weight1, weight2, weight3, weight4, weight5]).to(device) # Определите ваши веса
loss_fn = nn.CrossEntropyLoss(weight=class_weights)
-
Аугментация данных: Рассмотрите возможность увеличения данных с использованием методов аугментации, таких как парафразирование текстов, синонимизация и т.д.
-
Генерация новых примеров: Используйте алгоритмы, такие как SMOTE (Synthetic Minority Over-sampling Technique), для генерации новых примеров для менее представленных классов.
Оценка модели
Ваш текущий код для оценки модели выглядит хорошо, но убедитесь, что вы используете метрики, которые учитывают дисбаланс классов, например, F1-меру, которая дает более полное представление о модели с точки зрения точности и полноты.
Добавьте также дополнительные метрики, такие как ROC AUC и confusion matrix, для лучшей оценки производительности вашей модели.
Пример вывода модели:
Чтобы получить удобоваримый вывод о вашей модели, вы можете использовать summary
от пакета torchsummary
. Однако, если вы хотите просто вывести структуру модели, можно использовать:
model = SentimentClassifier(n_classes=5)
print(model)
Эта команда покажет структуру вашей модели, включая слои и параметры, что поможет при отладке и оптимизации.
Заключение
Таким образом, улучшение вашей модели для аспектно-основанного анализа настроений с помощью BERT и PyTorch требует использования дополнительных слоев для извлечения более качественных признаков, а также противодействия проблеме несбалансированности классов через соответствующие методы. Регулярное тестирование и экспериментирование с гиперпараметрами помогут вам в дальнейшем повысить эффективность решения задачи. Удачи в ваших дальнейших разработках!