python实战(八)——情感识别(多分类)

一、任务目标

        本文使用的是来自Kaggle的一个情感识别数据集,这个数据集的总数据量是5934条,标签为anger、fear、joy三种情感的其中一种,很明显是一个多分类任务。这里,我们将使用微调技巧进行深度学习建模,同时我们会比较不微调和微调之间的模型表现差距,以便于我们理解微调的优势。

二、数据集处理

        首先,我们加载数据集看看:

import pandas as pd
df = pd.read_csv('./data/Emotion_classify_Data.csv')
print(df.info())
print(df.head())

       

        可以看到,数据集没有出现空值,但标签是文本类型,为了便于后续建模,我们将它转换为索引:

print(list(set(df['Emotion'])))
# 根据打印出来的标签类别,逐个编上编号索引
label_idx = {'anger':0, 'joy':1, 'fear':2}
df['Emotion'] = df['Emotion'].apply(lambda x: label_idx[x])
print(df.head())

        为了便于后面对比不微调和微调的模型表现差别,我们提前划分训练集和测试集:

X_train, X_test, y_train, y_test = train_test_split(df['Comment'].tolist(), df['Emotion'].tolist(), stratify=df['Emotion'].tolist(), test_size=0.3, random_state=2024)

三、模型框架构建

1、定义数据集类

        首先我们自定义一个Dataset类,便于进行数据的转换:

from torch.utils.data import Datasetclass SentimentDataset(Dataset):def __init__(self,text,target):self.text=textself.target=targetself.tokenizer=transformers.BertTokenizer.from_pretrained(config['model_path'],do_lower_case=True)def __len__(self):return len(self.text)def __getitem__(self,index):text=str(self.text[index])text=" ".join(text.split())target=self.target[index]input=self.tokenizer.encode_plus(text,None,max_length=config['max_len'],truncation=True,pad_to_max_length=True,)ids=input['input_ids']mask=input['attention_mask']token_type_ids=input['token_type_ids']return {"ids":torch.tensor(ids,dtype=torch.long),"masks":torch.tensor(mask,dtype=torch.long),"token_type_ids":torch.tensor(token_type_ids,dtype=torch.long),"target":torch.tensor(target,dtype=torch.float)}

2、定义模型类

        现在,我们定义一个模型类,这里上游模型是Bert,下游模型为全连接层,即MLP。

class Bertmodel(nn.Module):def __init__(self):super(Bertmodel,self).__init__()self.bert=transformers.BertModel.from_pretrained(config['model_path'])self.dropout=nn.Dropout(0.3)self.fc1=nn.Linear(768,128)self.fc2 = nn.Linear(128, 64)self.fc3 = nn.Linear(64, 3)def forward(self,ids,mask,token_type):_,x=self.bert(ids,attention_mask=mask,token_type_ids=token_type,return_dict=False)x=self.dropout(x)x=self.fc1(x)x=self.dropout(x)x=self.fc2(x)x = self.fc3(x)return x

3、定义训练和测试函数

def train_fn(data_loader,model,optimizer,device,scheduler):model.train()for step,data  in enumerate(data_loader):ids=data['ids']masks=data['masks']token_type=data['token_type_ids']target=data['target']ids=ids.to(device,dtype=torch.long)masks=masks.to(device,dtype=torch.long)token_type=token_type.to(device,dtype=torch.long)target=target.to(device,dtype=torch.long)optimizer.zero_grad()preds=model(ids,masks,token_type)loss=loss_fn(preds,target)loss.backward()optimizer.step()# scheduler.step()return loss.item()def eval_fn(data_loader,model,device):fin_targets=[]fin_outputs=[]model.eval()with torch.no_grad():for data in data_loader:ids=data['ids']masks=data['masks']token_type=data['token_type_ids']target=data['target']ids=ids.to(device,dtype=torch.long)masks=masks.to(device,dtype=torch.long)token_type=token_type.to(device,dtype=torch.long)target=target.to(device, dtype=torch.long)preds=model(ids,masks,token_type)loss=loss_fn(preds,target)target=target.cpu().detach()fin_targets.extend(target.numpy().tolist())outputs=torch.argmax(preds, dim=1).cpu().detach()fin_outputs.extend(outputs.numpy().tolist())return fin_outputs,fin_targets

4、定义损失函数和优化器

criterion = nn.CrossEntropyLoss()
def loss_fn(output,target):loss=criterion(output,target)return lossdef train(X_train, y_train):train_dataset=SentimentDataset(X_train, y_train)train_loader=torch.utils.data.DataLoader(train_dataset,batch_size=config['train_batch'],num_workers=1)num_train_steps=int(len(X_train)/config['train_batch']*config['epochs'])optimizer=AdamW([param for param in model.parameters() if param.requires_grad], lr=5e-5)scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.1)best_precision=0for epoch in range(config['epochs']):loss=train_fn(train_loader,model,optimizer,device,scheduler)print(f"Epoch_{epoch}, Train_Loss-->>{loss}")

5、训练模型

        在这里,我们初始化模型并确定哪些模型的参数需要参与训练。首先对于不微调预训练模型Bert的过程,我们仅解冻fc层参数,而微调版本则仅解冻Bert最后一层的output子层参数

device=torch.device("cuda")
model=Bertmodel()
model.to(device)# 微调预训练模型版本
# unfreeze_layers = ['layer.11.output', 'fc']# 不微调预训练模型版本,相当于仅训练MLP
unfreeze_layers = ['fc']for name ,param in model.named_parameters():param.requires_grad = Falsefor ele in unfreeze_layers:if ele in name:param.requires_grad = Truebreak
for name, param in model.named_parameters():if param.requires_grad:print(name,param.size())train(X_train, y_train)

6、测试模型表现

        评估模型表现:

from sklearn.metrics import precision_score, recall_score, f1_scoretest_dataset=SentimentDataset(X_test, y_test)
test_loader=torch.utils.data.DataLoader(test_dataset,batch_size=16)
total_preds=[]
with torch.no_grad():for data in test_loader:ids=data["ids"].to(device,dtype=torch.long)mask=data["masks"].to(device,dtype=torch.long)token_type=data['token_type_ids'].to(device,dtype=torch.long)output=model(ids,mask,token_type)preds=torch.argmax(output, dim=1).cpu().detach()preds=preds.numpy().tolist()total_preds.extend(preds)print('Precision', precision_score(y_test, total_preds, average='macro'))
print('Recall', recall_score(y_test, total_preds, average='macro'))
print('F1', f1_score(y_test, total_preds, average='macro'))

        下面这是不微调Bert模型,仅训练MLP的效果:

        下面是微调Bert,并训练MLP的效果,可以看到模型的效果大幅提升,即便我们都是只训练了10个epoch

四、完整代码

import logging
logging.basicConfig(level='ERROR')
import transformers
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import torch
import torch.nn as nn
from sklearn import metrics
from sklearn.model_selection import train_test_split
from transformers import AdamW
from transformers import get_linear_schedule_with_warmup
from torch.utils.data import Dataset
from sklearn.metrics import precision_score, recall_score, f1_score
import warnings
warnings.filterwarnings("ignore")config={"max_len":512,"train_batch":16,"valid_batch":16,"epochs":10,"model_path":"bert-base-uncased"
}class SentimentDataset(Dataset):def __init__(self,text,target):self.text=textself.target=targetself.tokenizer=transformers.BertTokenizer.from_pretrained(config['model_path'],do_lower_case=True)def __len__(self):return len(self.text)def __getitem__(self,index):text=str(self.text[index])text=" ".join(text.split())target=self.target[index]input=self.tokenizer.encode_plus(text,None,max_length=config['max_len'],truncation=True,pad_to_max_length=True,)ids=input['input_ids']mask=input['attention_mask']token_type_ids=input['token_type_ids']return {"ids":torch.tensor(ids,dtype=torch.long),"masks":torch.tensor(mask,dtype=torch.long),"token_type_ids":torch.tensor(token_type_ids,dtype=torch.long),"target":torch.tensor(target,dtype=torch.float)}class Bertmodel(nn.Module):def __init__(self):super(Bertmodel,self).__init__()self.bert=transformers.BertModel.from_pretrained(config['model_path'])self.dropout=nn.Dropout(0.3)self.fc1=nn.Linear(768,128)self.fc2 = nn.Linear(128, 64)self.fc3 = nn.Linear(64, 3)def forward(self,ids,mask,token_type):_,x=self.bert(ids,attention_mask=mask,token_type_ids=token_type,return_dict=False)x=self.dropout(x)x=self.fc1(x)x=self.dropout(x)x=self.fc2(x)x = self.fc3(x)return xdef train_fn(data_loader,model,optimizer,device,scheduler):model.train()for step,data  in enumerate(data_loader):ids=data['ids']masks=data['masks']token_type=data['token_type_ids']target=data['target']ids=ids.to(device,dtype=torch.long)masks=masks.to(device,dtype=torch.long)token_type=token_type.to(device,dtype=torch.long)target=target.to(device,dtype=torch.long)optimizer.zero_grad()preds=model(ids,masks,token_type)loss=loss_fn(preds,target)loss.backward()optimizer.step()# scheduler.step()return loss.item()def eval_fn(data_loader,model,device):fin_targets=[]fin_outputs=[]model.eval()with torch.no_grad():for data in data_loader:ids=data['ids']masks=data['masks']token_type=data['token_type_ids']target=data['target']ids=ids.to(device,dtype=torch.long)masks=masks.to(device,dtype=torch.long)token_type=token_type.to(device,dtype=torch.long)target=target.to(device, dtype=torch.long)preds=model(ids,masks,token_type)loss=loss_fn(preds,target)target=target.cpu().detach()fin_targets.extend(target.numpy().tolist())outputs=torch.argmax(preds, dim=1).cpu().detach()fin_outputs.extend(outputs.numpy().tolist())return fin_outputs,fin_targetscriterion = nn.CrossEntropyLoss()
def loss_fn(output,target):loss=criterion(output,target)return lossdef train(X_train, y_train):train_dataset=SentimentDataset(X_train, y_train)train_loader=torch.utils.data.DataLoader(train_dataset,batch_size=config['train_batch'],num_workers=1)num_train_steps=int(len(X_train)/config['train_batch']*config['epochs'])optimizer=AdamW([param for param in model.parameters() if param.requires_grad], lr=5e-5)scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1, gamma=0.1)best_precision=0for epoch in range(config['epochs']):loss=train_fn(train_loader,model,optimizer,device,scheduler)print(f"Epoch_{epoch}, Train_Loss-->>{loss}")device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model=Bertmodel()
model.to(device)# 微调预训练模型版本
# unfreeze_layers = ['layer.11.output', 'fc']# 不微调预训练模型版本,相当于仅训练MLP
unfreeze_layers = ['fc']for name ,param in model.named_parameters():param.requires_grad = Falsefor ele in unfreeze_layers:if ele in name:param.requires_grad = Truebreak
for name, param in model.named_parameters():if param.requires_grad:print(name,param.size())train(X_train, y_train)test_dataset=SentimentDataset(X_test, y_test)
test_loader=torch.utils.data.DataLoader(test_dataset,batch_size=16)
total_preds=[]
with torch.no_grad():for data in test_loader:ids=data["ids"].to(device,dtype=torch.long)mask=data["masks"].to(device,dtype=torch.long)token_type=data['token_type_ids'].to(device,dtype=torch.long)output=model(ids,mask,token_type)preds=torch.argmax(output, dim=1).cpu().detach()preds=preds.numpy().tolist()total_preds.extend(preds)print('Precision', precision_score(y_test, total_preds, average='macro'))
print('Recall', recall_score(y_test, total_preds, average='macro'))
print('F1', f1_score(y_test, total_preds, average='macro'))

五、总结

        可以看到,如果仅仅是应用预训练模型的embeddings,任务建模的效果有限,这是由于预训练的过程中学习到的大都是通用知识。经过微调之后,预训练模型更有效地理解了任务的需求并能够生成更为有效的文本表示,从而大大提升建模效果,这就是微调的魅力。但是微调并不是在任何情况下都能够取得更好效果的,这受到解冻层数、参数量的选取,以及学习率等超参数的设置等多方因素的影响,需要我们根据经验调整到最优状态,否则微调的效果可能还不如不微调。本文并未对建模过程中的代码设计展开详细的介绍,这将在下一篇博文中重点讲解,敬请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/470392.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习笔记】数据结构(七)

图 文章目录 图7.1 图的定义和术语7.2 图的存储结构7.2.1 数组表示法 - 邻接矩阵(Adjacency Matrix)7.2.2 邻接表 -(链式)表示法(Adjacency List)7.2.3 十字链表(Orthogonal List)7.2.4 邻接多重表(Adjacent MultiList) 7.3 图的遍…

scrapy爬取中信证券销售金融产品信息

import scrapyclass CsProductSpider(scrapy.Spider):name "cs_product"allowed_domains ["www.cs.ecitic.com"]start_urls ["http://www.cs.ecitic.com/newsite/cpzx/jrcpxxgs/zgcp/index.html"]def parse(self, response):# 提取数据的逻辑…

power bi中的related函数解析

在Power BI中,RELATED函数是一种用于检索相关表中数据的函数。它用于在一个表中检索与当前行相关联的另一个表中的数据。 销售成本 [销售数量]*related(商品表[进价])

Ollama的安装以及大模型下载教程

简介 Ollama是一个开源的大型语言模型服务工具,它帮助用户快速在本地运行大模型。通过简单的安装指令,用户可以执行一条命令就在本地运行开源大型语言模型, Ollama极大地简化了在Docker容器内部署和管理LLM的过程,使得用户能够快…

算法演练----24点游戏

给定4个整数,数字范围在1~13之间任意使用-*/(),构造出一个表达式,使得最终结果为24, 方法一 算法分析:加括号和取出重复表达式 # 导入精确除法模块,使得在Python2中除法运算的行为更…

YUM 的使用

YUM 是一个用于 Fedora 和 Red Hat 以及 CentOS 操作系统的前端软件包管理器,它可以自动处理依赖关系并一次性安装所有必需的软件包。 镜像站点选择 1. 备份原有的镜像源配置文件 系统默认的 yum 镜像源配置文件存储在 /etc/yum.repos.d/ 目录下,可以…

第三十六章 Vue之路由重定向/404页面设置/路径模式设置

目录 一、路由重定向 1.1. 使用方式 1.2. 完整代码 1.2.1. main.js 1.2.2. App.vue 1.2.3. index.js 1.2.4. Search.vue 1.2.5. Home.vue 1.3. 运行效果 二、设定404错误页面 2.1. 使用方式 2.2. 完整代码 2.2.1. index.js 2.2.2. NotFound.vue 2.2.3. 运行效…

鸿蒙进阶篇-属性动画-animateTo转场动画

大家好啊,这里是鸿蒙开天组,今天我们来学习属性动画-animateTo&转场动画,咱们先来学习属性动画-animateTo 属性动画-animateTo 属性动画 animation是作为属性使用,而animateTo显示动画是一个系统的内置函数,可以…

[CKS] K8S ServiceAccount Set Up

最近准备花一周的时间准备CKS考试,在准备考试中发现有一个题目关于Rolebinding的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Netwo…

Autosar CP DDS规范导读

Autosar CP DDS 主要用途 数据通信 中间件协议:作为一种中间件协议,DDS实现了应用程序之间的高效数据通信,能够在不同的软件组件和ECU之间传输数据,确保数据的实时性和可靠性。跨平台通信:支持在AUTOSAR CP平台上的不同…

wafw00f源码详细解析

声明 本人菜鸟一枚,为了完成作业,发现网上所有的关于wafw00f的源码解析都是这抄那那抄这的,没有新东西,所以这里给出一个详细的源码解析,可能有错误,如果有大佬发现错误,可以在评论区平和的指出…

字节、快手、Vidu“打野”升级,AI视频小步快跑

文|白 鸽 编|王一粟 继9月份版本更新之后,光锥智能从生数科技联合创始人兼CEO唐家渝朋友圈获悉,Vidu大模型将于本周再次进行版本升级,Vidu-1.5版本即将上线。 此版本更新方向仍是重点延伸大模型的泛化能力和主体…

LeetCode【0036】有效的数独

本文目录 1 中文题目2 求解方法:python内置函数set2.1 方法思路2.2 Python代码2.3 复杂度分析 3 题目总结 1 中文题目 请根据以下规则判断一个 9 x 9 的数独是否有效。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线…

STM32 GPIO 配置

GPIO 八种工作模式 STM32的GPIO八种模式明解STM32—GPIO理论基础知识篇之八种工作模式stm32cubemx hal学习记录:GPIO输入输出[STM32G4系列] GPIO筆記 - CubeMX GPIO整理與應用 模拟量输入输出 ADC 【STM32】HAL库 STM32CubeMX教程九—ADC[通俗易懂] DAC STM32C…

Xcode 16 使用 pod 命令报错解决方案

原文请点击这个跳转 一、问题现象: 有人会遇到 Xcode 升级到 16 后,新建应用然后使用 pod init 命令会报错如下: Stack Ruby : ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [x86_64-darwin23]RubyGems : 3.5.22Host : macOS 15.0 (24A335…

使用 Flask 和 ONLYOFFICE 实现文档在线编辑功能

提示:CSDN 博主测评ONLYOFFICE 文章目录 引言技术栈环境准备安装 ONLYOFFICE 文档服务器获取 API 密钥安装 Flask 和 Requests 创建 Flask 应用项目结构编写 app.py创建模板 templates/index.html 运行应用功能详解文档上传生成编辑器 URL显示编辑器回调处理 安全性…

机器学习——损失函数、代价函数、KL散度

🌺历史文章列表🌺 机器学习——损失函数、代价函数、KL散度机器学习——特征工程、正则化、强化学习机器学习——常见算法汇总机器学习——感知机、MLP、SVM机器学习——KNN机器学习——贝叶斯机器学习——决策树机器学习——随机森林、Bagging、Boostin…

vxe-table 3.10+ 进阶高级用法(一),根据业务需求自定义实现筛选功能

vxe-table 是vue中非常强大的表格的,公司项目中复杂的渲染都是用 vxe-table 的,对于用的排序。筛选之类的都能支持,而且也能任意扩展,非常强大。 默认筛选功能 筛选的普通用法就是给对应的列指定参数: filters&#…

推荐一款好用的postman替代工具2024

Apifox 是国内团队自主研发的 API 文档、API 调试、API Mock、API 自动化测试一体化协作平台,是非常好的一款 postman 替代工具。 它通过一套系统、一份数据,解决多个系统之间的数据同步问题。只要定义好接口文档,接口调试、数据 Mock、接口…

MTSET可溶于DMSO、DMF、THF等有机溶剂,并在水中有轻微的溶解性,91774-25-3

一、基本信息 中文名称:[2-(三甲基铵)乙基]甲硫基磺酸溴;MTSET巯基反应染料 英文名称:MTSET;[2-(Trimethylammonium)ethyl]methanethiosulfonate Bromide CAS号:91774-25-3 分子式:C6H16BrNO2S2 分子量…