项目实战之评论情感分析模型——基于Bert(含任务头)

目录

一、项目流程

[1.1 加载预训练模型Bert](#1.1 加载预训练模型Bert)

[1.2 数据预处理](#1.2 数据预处理)

[1.3 模型定义](#1.3 模型定义)

[1.4 模型训练](#1.4 模型训练)

[1.5 模型预测](#1.5 模型预测)

二、总结


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

github项目地址:zhanghong203/bert_based_emotion_analysis at master

LSTM项目地址:zhanghong203/emotion_analyse_lm: 基于LSTM的情感分析模型


一、项目流程

实验配置:

显卡: NVIDIA GeForce RTX 3050 LAPTOP GP

模型:google-bert/bert-base-chinese · Hugging Face

数据:评论情感分析数据集

1.1 加载预训练模型Bert

Bert模型 通过官方链接或者代码方式下载:

python 复制代码
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()方法,详细介绍参考链接

from_pretrained 做了啥_from pretrained-CSDN博客


1.2 数据预处理

该过程主要完成数据清洗、对接Bert输入的任务。数据清洗过滤无用列,去除不符合的行。

python 复制代码
# 过滤数据
	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])

python 复制代码
	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,后续添加任务头,不需要再做预处理。

tokenizer方法参考链接


1.3 模型定义

首先,明确设计的任务是对评论进行情感分析,属于二分类任务。通过Bert前向传播,即通过12层隐藏层,只需要将最后一层last_hidden_state(batch_size, sequence_length, hidden_size)(Bert模型第一个token蕴含的向量信息是整个句子信息)接一个线性层。默认hidden_size是768,线性层输出维度设为1。

python 复制代码
	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

Bert输出结构参考链接


1.4 模型训练

对于不带任务头的Bert,传入参数不需要携带labels,并且在进行训练时,需要再多一步计算损失;然而针对句子分类任务的Bert,输出包含loss字段。

python 复制代码
# 含任务头
model = AutoModelForSequenceClassification.from_pretrained('google-bert/bert-base-chinese').to(device)

训练代码如下:

python 复制代码
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完成标签映射。

python 复制代码
# 含任务头
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显存利用率过高训练效率很低等问题。上述内容如果有错误的地方,希望大佬们可以指正。我一直在学习的路上,您的帮助使我收获更大!觉得对您有帮助的话,还请点赞支持!我也会不断更新文章!

相关推荐
bryant_meng4 分钟前
【Hung-yi Lee】《Introduction to Generative Artificial Intelligence》(11)
人工智能·深度学习·llm·speculative·预言家
OriginHub_元枢智汇4 分钟前
知识图谱的检索增强:图结构与向量化技术的融合实践
人工智能·知识图谱
人工智能AI技术6 分钟前
Python 有序字典与普通字典基础区别
人工智能
胡耀超6 分钟前
从逻辑思维到方法论(DMBOK2)并以知识图谱实践指导:构建企业级思维与执行框架
大数据·人工智能·dama·知识图谱·方法论·逻辑学·思维框架
小敬爱吃饭10 分钟前
知识图谱实战第一章:知识图谱全景解析其定义、技术演进与十大应用场景
人工智能·python·目标检测·自然语言处理·flask·nlp·知识图谱
Jump 不二10 分钟前
揭秘腾讯 Ima 知识库架构:从开源 WeKnora 看 RAG + 知识图谱落地实践
人工智能·语言模型·架构·机器人·开源·知识图谱
武汉知识图谱科技11 分钟前
神经符号AI+知识图谱:可信认知智能新纪元
人工智能
鹏子训13 分钟前
六个典型热门AI记忆架构对比:Mem0,Letta,MemoryLake,ZenBrain,MIA,MSA 助你快速选型
人工智能·架构·长短时记忆网络
xier_ran13 分钟前
知识图谱(Knowledge Graph)详解
人工智能·知识图谱
P-ShineBeam13 分钟前
知识图谱-基本知识图谱知识概览
人工智能·自然语言处理·知识图谱