项目实战之评论情感分析模型——基于Bert(含任务头)
目录
BERT 是谷歌于 2018 年提出的基于 Transformer 编码器结构的预训练语言模型。本文基于 BERT 架构,完成从预处理、微调训练到效果评估的全流程实验,经过多轮迭代优化,模型在情感分析任务上精确率达到 98.7%,相比 LSTM 模型精确率提高108%。

github项目地址:zhanghong203/bert_based_emotion_analysis at master
一、项目流程
实验配置:
显卡: NVIDIA GeForce RTX 3050 LAPTOP GP
模型:google-bert/bert-base-chinese · Hugging Face
数据:评论情感分析数据集
1.1 加载预训练模型Bert
Bert模型 通过官方链接或者代码方式下载:
from transformers import AutoTokenizer, AutoModelForMaskedLM
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
model = AutoModelForMaskedLM.from_pretrained("bert-base-chinese")
默认huggingface安装目录 ~/.cache/huggingface/hub,可以通过配置环境变量修改

完成Bert模型加载后,通过from_pretrained方法可以从huggingface缓存中读取,同时也可以把模型放置在项目目录下,通过读取绝对路径方式加载。
关于from_pretrained()方法,详细介绍参考链接
1.2 数据预处理
该过程主要完成数据清洗、对接Bert输入的任务。数据清洗过滤无用列,去除不符合的行。
# 过滤数据
dataset = dataset.remove_columns(['cat'])
dataset = dataset.filter(lambda x: x['review'] is not None)
dataset = dataset.cast_column('label', ClassLabel(names=['negative', 'positive']))
Bert一般接收参数:(input_ids, token_type_ids,attention_mask,Optional [labels])
def batch_encode(batch):
inputs = tokenizer(batch['review'], truncation=True, padding='max_length', max_length=config.MAX_LENGTH)
inputs['labels'] = batch['label']
return inputs
dataset_dict = dataset_dict.map(batch_encode, batched=True, remove_columns=['review', 'label'])
调用tokenizer()获取前三个字段,为了保证批处理,需要做填充和截断操作。针对带句子分类任务头的Bert还需要labels字段。在后续过程中,为了方便解构,提前将label字段转化成labels,后续添加任务头,不需要再做预处理。
1.3 模型定义
首先,明确设计的任务是对评论进行情感分析,属于二分类任务。通过Bert前向传播,即通过12层隐藏层,只需要将最后一层last_hidden_state(batch_size, sequence_length, hidden_size)(Bert模型第一个token蕴含的向量信息是整个句子信息)接一个线性层。默认hidden_size是768,线性层输出维度设为1。
def forward(self, input_ids, attention_mask, token_type_ids):
output = self.bert(input_ids, attention_mask, token_type_ids)
last_hidden_state = output.last_hidden_state
cls_hidden_state = last_hidden_state[:, 0, :]
output = self.linear(cls_hidden_state).squeeze(-1)
return output
1.4 模型训练
对于不带任务头的Bert,传入参数不需要携带labels,并且在进行训练时,需要再多一步计算损失;然而针对句子分类任务的Bert,输出包含loss字段。
# 含任务头
model = AutoModelForSequenceClassification.from_pretrained('google-bert/bert-base-chinese').to(device)
训练代码如下:
def train_one_epoch(model, dataloader, loss_fn, optimizer, device):
total_loss = 0
model.train()
for batch in tqdm(dataloader, desc='训练'):
inputs = {k: v.to(device) for k, v in batch.items()}
labels = inputs.pop('labels').to(dtype=torch.float)
outputs = model(**inputs)
loss = loss_fn(outputs, labels)
loss.backward()
optimizer.step()
optimizer.zero_grad()
total_loss += loss.item()
return total_loss / len(dataloader)
def train():
# 1.设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)
# 2.数据
dataloader = get_loader()
# 3.分词器
tokenizer = AutoTokenizer.from_pretrained('google-bert/bert-base-chinese')
# 4.模型
model = ReviewAnalyzeModel().to(device)
# 5.损失函数
loss_fn = torch.nn.BCEWithLogitsLoss()
# 6.优化器
optimizer = torch.optim.Adam(model.parameters(), lr=config.LEARNING_RATE)
# train
best_loss = float('inf')
for epoch in range(config.EPOCHS):
print(f'Epoch: {epoch + 1}')
loss = train_one_epoch(model, dataloader, loss_fn, optimizer, device)
print(f'Loss: {loss:.4f}')
# 保存模型
if loss < best_loss:
best_loss = loss
torch.save(model.state_dict(), config.MODELS_DIR / 'best.pt')
print("保存模型")
BertForSequenceClassification模型介绍
1.5 模型预测
1.3小节中的模型,是通过一个线性层得到一个结果,通过sigmoid映射到[0,1];含任务头的Bert模型,输出包含一个logit字段((batch_size, config.num_labels))在预测阶段,logit的形状是(1, 2),可以使用argmax完成标签映射。
# 含任务头
def predict_batch(model, inputs):
model.eval()
with torch.no_grad():
output = model(**inputs)
logits = output.logits
# (batch_size, config.num_labels)
result = torch.argmax(logits, dim=1)
return result.tolist()
-------------------------------------------
# 不含任务头
def predict_batch(model, inputs):
model.eval()
with torch.no_grad():
output = model(**inputs)
# output.shape (batch_size)
batch_result = torch.sigmoid(output)
return batch_result.tolist()
二、总结
本文基于Bert完成从数据预处理到模型预测的全流程,在项目过程中免不了Bert文档的查看,笔者在每个小节都添加了相关API,便于读者理解。此外,下载Bert以及训练有一些小问题没有列举出来,比如访问huggingface超时、GPU显存利用率过高训练效率很低等问题。上述内容如果有错误的地方,希望大佬们可以指正。我一直在学习的路上,您的帮助使我收获更大!觉得对您有帮助的话,还请点赞支持!我也会不断更新文章!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)