当前位置:   article > 正文

使用huggingface实现BERT+BILSTM情感3分类(附数据集源代码)_bert + lstm文本识别三分类

bert + lstm文本识别三分类

一、前言

        最近在学习自然语言处理和大模型实战,通过实战来总结一下学习内容,顺便将学的一些东西发表在博客上,希望能对看到文章的您有帮助,有任何问题也可以发表讨论或联系作者。

        GitHub源代码:Befineyou/bert-bilstm-in-Sentiment-classification: The author applies BERT+BILSTM to emotion classification (github.com)

        本次实战讲解围绕BERT+BILSTM模型开展情感3分类进行,介绍在huggingface框架下使得我们具有方便的模型训练方法。

二、huggingface 下载

        本文使用的是中文bert,需要提前从huggingface官网中将预训练好的模型组件下载下来,下载网站来自:bert-base-chinese at main (huggingface.co)

三、数据集介绍

        数据集来源:疫情期间网民情绪识别 竞赛 - DataFountain

        看到了一位博主的数据处理讲解代码,讲的很不错,大家可以去看一下这个博主的处理方法:【NLP实战】基于Bert和双向LSTM的情感分类【上篇】_bert-lstm-CSDN博客

四、模型搭建

4.1 确定编码工具 

        编码工具是为了将抽象文本数据转化为词典后的数据。

  1. from transformers import BertTokenizer
  2. token = BertTokenizer.from_pretrained('bert-base-chinese')
  3. print(token)

4.2 自定义数据集

        huggingface的一大好处就是该社区集成了大量的数据集和模型,可以直接调用,但当处理自己的数据集(csv)的形式,需要将csv转化为huggingface的dataset类型,从而进行构建,注意在我的示例数据集中,已经默认text列为文本内容列,label为文本标签列。

  1. train_data = pd.read_csv('data/train_clean.csv')
  2. train_dataset = Dataset.from_pandas(train_data)
  3. class Dataset(torch.utils.data.Dataset):
  4. def __init__(self):
  5. self.dataset = train_dataset
  6. def __len__(self):
  7. return len(self.dataset)
  8. def __getitem__(self, item):
  9. text = self.dataset[item]['text']
  10. label = self.dataset[item]['label']
  11. return text, label
  12. train_dataset = Dataset()

4.3 定义数据整理函数以及数据集加载器

         训练时要将数据打包成loader的形式,需要将抽象的文本数据转换为编码后的数据,这时就用到了之前定义好的编码工具

input_ids 代表句子中每个字的词典编号

attention_mask 只有0或1,0代表空,也就是PAD

token_type_ids 只有0或1,0代表第一个句子和特殊符号,1代表第二个句子

注意,在编码时的句子已经被修改,一般在句首加CLS,句尾加PAD,根据max_length选择对句子截断或者加PAD

  1. def collate_fn(data):
  2. sents = [i[0] for i in data]
  3. labels = [i[1] for i in data]
  4. data = token.batch_encode_plus(batch_text_or_text_pairs=sents,
  5. truncation=True,
  6. padding='max_length',
  7. max_length=500,
  8. return_tensors='pt',
  9. return_length=True)
  10. input_ids = data['input_ids']
  11. attention_mask = data['attention_mask']
  12. token_type_ids = data['token_type_ids']
  13. #labels = torch.LongTensor(labels)
  14. # labels = torch.tensor(labels).long()
  15. labels = torch.tensor([label if label != -1 else 0 for label in labels]).long()
  16. return input_ids, attention_mask, token_type_ids, labels
  1. train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
  2. batch_size=16,
  3. collate_fn=collate_fn,
  4. shuffle=True,
  5. drop_last=True)

 4.4 定义预训练模型

        首先要将BERT预训练模型添加进来

  1. from transformers import BertModel
  2. pretrained = BertModel.from_pretrained('bert-base-chinese')
  3. for param in pretrained.parameters():
  4. param.requires_grad_(False)

        之后就是定义Bert+BILSTM的模型

  1. class BertBiLSTMClassifier(nn.Module):
  2. def __init__(self, num_classes, hidden_size=768, lstm_hidden_size=128, lstm_layers=1):
  3. super(BertBiLSTMClassifier, self).__init__()
  4. # BiLSTM层
  5. self.lstm = nn.LSTM(input_size=hidden_size, hidden_size=lstm_hidden_size, num_layers=lstm_layers,
  6. batch_first=True, bidirectional=True)
  7. # 全连接层用于分类
  8. self.fc = nn.Linear(lstm_hidden_size * 2, num_classes)
  9. def forward(self, input_ids, attention_mask, token_type_ids):
  10. # BERT的前向传播
  11. with torch.no_grad():
  12. outputs = pretrained(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  13. #pooled_output = outputs.pooler_output
  14. last_hidden_state = outputs.last_hidden_state
  15. # 将BERT输出输入BiLSTM
  16. lstm_out, _ = self.lstm(last_hidden_state)
  17. # 提取BiLSTM的最后一层输出
  18. lstm_out = lstm_out[:, -1, :]
  19. # 全连接层分类
  20. logits = self.fc(lstm_out)
  21. return logits
model = BertBiLSTMClassifier(num_classes)

 4.5 训练模型

  1. def train():
  2. optimizer = AdamW(model.parameters(), lr=5e-4)
  3. criterion = torch.nn.CrossEntropyLoss()
  4. scheduler = get_scheduler(name='linear',
  5. num_warmup_steps=0,
  6. num_training_steps=len(loader),
  7. optimizer=optimizer)
  8. model.train()
  9. for i, (input_ids, attention_mask, token_type_ids, labels) in enumerate(loader):
  10. out = model(input_ids=input_ids, attention_mask=attention_mask, token_type_ids=token_type_ids)
  11. loss = criterion(out, labels)
  12. loss.backward()
  13. optimizer.step()
  14. scheduler.step()
  15. optimizer.zero_grad()
  16. if i % 10 == 0:
  17. out = out.argmax(dim=1)
  18. accuracy = (out == labels).sum().item() / len(labels)
  19. lr = optimizer.state_dict()['param_groups'][0]['lr']
  20. print(i, loss.item(), lr, accuracy)
  21. if i % 90 == 0:
  22. torch.save(model.state_dict(), f'bert_cnn_model_epoch_{i}.pth')

 4.6 测试模型

  1. def test():
  2. loader_test = torch.utils.data.DataLoader(dataset=test_dataset,
  3. batch_size=32,
  4. collate_fn=collate_fn,
  5. shuffle=True,
  6. drop_last=True)
  7. model.eval()
  8. correct = 0
  9. total = 0
  10. for i,(input_ids,attention_mask,token_type_ids,labels) in enumerate(loader_test):
  11. if i==5:
  12. break
  13. print(i)
  14. with torch.no_grad():
  15. out = model(input_ids=input_ids,
  16. attention_mask=attention_mask,
  17. token_type_ids = token_type_ids)
  18. #out = out.argmax(dim=1)
  19. out = torch.argmax(out, dim=1)
  20. correct +=(out==labels).sum().item()
  21. total +=len(labels)
  22. print(correct/total)
  23. test()

 这样一个简单的BERT+BILSTM实战模型便可以应用了。

五、总结

如有疑问,可以联系作者。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/353309
推荐阅读
相关标签
  

闽ICP备14008679号