《深度学习》【项目】自然语言处理——情感分析 <下>

目录

一、了解项目

1、任务

2、文件内容

二、续接上篇内容

1、打包数据,转化Tensor类型

2、定义模型,前向传播函数

3、定义训练、测试函数

4、最终文件格式

5、定义主函数

运行结果:


一、了解项目

1、任务

        对微博评论信息的情感分析,建立模型,自动识别评论信息的情绪状态。

2、文件内容

二、续接上篇内容

《深度学习》【项目】自然语言处理——情感分析 <上>-CSDN博客文章浏览阅读537次,点赞23次,收藏16次。对微博评论信息的情感分析,建立模型,自动识别评论信息的情绪状态。https://ahao1004.blog.csdn.net/article/details/142926591?fromshare=blogdetail&sharetype=blogdetail&sharerId=142926591&sharerefer=PC&sharesource=qq_64603703&sharefrom=from_link

        上篇博客,我们已经实现了评论固定长度输出、词表的生成、数据集的切分等操作,接下来需要对数据进行打包、放入模型进行训练等操作

1、打包数据,转化Tensor类型

        将下列代码写入上述创建的load_dataset.py文件内,写成下列格式

class DatasetIterater(object):   # 定义一个类,用于迭代地处理数据集,将其分割成指定大小的批次(batch),并能够在GPU或其他设备上运行
    # 将数据batches   切分为batch_size的包。
    def __init__(self,batches,batch_size,device):  # 输入参数为:样本数据、单个批次中的样本条数、设备GPU
        self.batch_size = batch_size
        self.batches = batches
        self.n_batches = len(batches) // batch_size   # 计算批次数
        self.residue = False   # 记录划分后的数据是否存在剩余的数据,初始化为False
        if len(batches) % self.n_batches != 0:  # 表示有余数
            self.residue = True
        self.index = 0   # 追踪当前批次的索引
        self.device = device


    def _to_tensor(self,datas):   # 自己定义的一个函数私有方法,将一批数据转换为PyTorch张量,并发送到指定设备(GPU),datas为一个列表
        x = torch.LongTensor([_[0] for _ in datas]).to(self.device)  # _[0]为评论内容
        y = torch.LongTensor([_[1] for _ in datas]).to(self.device)  # _[1]评论情感

        #  pad前的长度(超过pad_size的设为pad_size)
        seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)  # _[2]为评论长度
        return (x,seq_len),y   # 返回评论的内容、评论长度、标签

    # getitem__: 是通过索引的方式获取数据对象中的内容。-_next_是使用 for i in trgin_iter:
    def __next__(self):  # 用于定义迭代器对象的下一个元素。当一个对象实现了__next__方法时,它可以被用于创建迭代器对象。
        # 处理打包后的剩余数据的批次数据
        if self.residue and self.index == self.n_batches:   # 存在剩余数据 并且 当前批次索引等于批次数,此时即最后一部分打包不齐而剩余的数据
            batches = self.batches[self.index*self.batch_size:len(self.batches)]  # self.index*self.batch_size为批次索引*批次内样本个数,即当前批次中的样本所在总样本内的位置 到 总样本数据长度,此条表示取出打包剩余的样本
            self.index += 1  # 批次数加一
            batches = self._to_tensor(batches)  # 调用上述的私有函数,将样本数据传入,将其转换数据类型tensor
            return batches   # 返回Tensor数据类型的样本数据

        elif self.index > self.n_batches:  # 如果迭代使批次索引超过批次总数,终止循环
            self.index = 0  # 重置批次索引为1
            raise StopIteration    # 为了防止迭代永远进行,我们可以使用StopIteration(停止迭代)语句
        else:    # 当没有读取到最后一个batch批次时:
            baches = self.batches[self.index*self.batch_size:(self.index+1)*self.batch_size]   # 提取当前批次的数据样本
            self.index += 1   # 批次索引+1
            baches = self._to_tensor(baches)   # 将样本数据转化为张量格式
            return baches   # 返回张量类型的样本数据

    def __iter__(self):  # 这个方法使得类的实例能够成为迭代器,返回实例本身。
        return self

    def __len__(self):  # 返回迭代器的长度,即完整批次的数量
        if self.residue:
            return self.n_batches + 1  # 如果存在剩余数据,长度会增加1。
        else:
            return self.n_batches

2、定义模型,前向传播函数

        将下列代码写入新创建的文件TextRNN.py


import torch.nn as nn

class Model(nn.Module):   # 定义一个类,继承神经网络的基类,参数管理、模型保存加载...
    def __init__(self,embedding_pretrained,n_vocab,embed,num_classes):   # 传入参数表示为:预训练的词向量(当前项目导入腾讯训练好的词向量)、词汇表的长度、词向量维度、分类标签的数量
        super(Model,self).__init__()
        if embedding_pretrained is not None:  # 如果有预训练模型
            # 创建一个词嵌入层,用与接收预训练的嵌入层权重作为输入,指定填充词在词汇表中的索引为n_vocab-1,freeze:指定是否冻结embedinq层的权重,False表示可以更新预训练模型的权重参数
            self.embedding = nn.Embedding.from_pretrained(embedding_pretrained,padding_idx=n_vocab-1,freeze=False)

        else:  # 如果没有预训练模型,则初始化一个随机嵌入层,维度为n_vocab*embed   项目内是4762*200
            self.embedding = nn.Embedding(n_vocab,embed,padding_idx=n_vocab-1)

        # 建立LSTM网络层,输入维度为embed,有128个隐藏单元共三层,bidirectional=True表示双向LSTM,所以输出为128*2,batch_first=True表示输入张量第一个维度是批次数,dropout = 0.3表示LSTM层使用的dropout比例
        self.lstm = nn.LSTM(embed,128,3,bidirectional=True,batch_first=True,dropout=0.3)
        # 128为每一层中每个隐状态中的U、W、V的神经元个数,
        # 3为隐藏层的层数,batch_first=True表示输入和输出张量将以(batch,seq,feature)而不是(seq,betch,featur)。
        # bidirectiongl = True: 指定LSTM是双向的。网络会同时从前向后和从后向前处理输入序列,两个方向的
        # dropout = 0.3: 这指定了在LSTM层中使用的dropout比例。Dropout是一种正则化技术,用于防止网络在训练过程中过拟?
        self.fc = nn.Linear(128*2,num_classes)  # 设置全连接层,在每个时间步的最后一个状态的输出映射到类别数上

    def forward(self,x):   # 定义前向传播函数,输入的参数x为batch_size批次数以及sequence_length单词样本数
        x,_ = x    # 返回新的x值为批次数
        out = self.embedding(x)   # 将批次数传入词嵌入层,将整数索引转换为连续的、密集的词向量
        out,_ = self.lstm(out)   # 将词向量传入LSTM网络层
        out = self.fc(out[:,-1,:])   # 只选择LSTM输出序列的最后一个时间步的隐藏状态传递给self.fc
        return out

3、定义训练、测试函数

        创建一个文件train_eval_test.py,将下列代码写入其中

import torch
import torch.nn.functional as F
import numpy as np
from sklearn import metrics
import time


def evaluate(class_list,model,data_iter,test=False):   # 传入参数:种类名称列表、训练好的模型、验证集数据,test表示是否进行测试模式
    model.eval()   # 模型开始测试
    loss_total = 0  # 初始化总损失值为0
    predict_all = np.array([],dtype=int)   # 定义一个数组用于存放预测结果的标签
    labels_all = np.array([],dtype=int)    # 存放所有样本的真实标签
    with torch.no_grad():  # 一个上下文管理器,关闭梯度计算
        for texts,labels in data_iter:   # 遍历出来 每128条评价的包 的独热编码及长度 和标签
            outputs = model(texts)   # 输出模型进行测试,返回每个包中每条评论的测试结果
            loss = F.cross_entropy(outputs,labels)   # 计算交叉熵损失值
            loss_total += loss   # 损失值叠加
            labels = labels.data.cpu().numpy()   # 将真实标签转化为numpy数组
            predic = torch.max(outputs.data,1)[1].cpu().numpy()   # 计算预测值的标签并转化为numpy数组
            labels_all = np.append(labels_all,labels)    # 将真实标签增加到labels_all数组
            predict_all = np.append(predict_all,predic)

    acc = metrics.accuracy_score(labels_all,predict_all)   # 计算模型在所有样本上的准确率
    # 返回结果
    if test:   #
        report = metrics.classification_report(labels_all,predict_all,target_names=class_list,digits=4)   # 如果不是测试模式,那么打印分类报告,target_names用于识别每个类别的名称class_list,digits表示打印报告中浮点数的位数
        return acc,loss_total/len(data_iter),report   # 返回准确率、平均损失值、分类报告
    return acc,loss_total/len(data_iter)    # 返回准确率、平均损失值


def test(model,test_iter,class_list):
    model.load_state_dict(torch.load('TextRNN.ckpt'))
    model.eval()
    start_time = time.time()
    test_acc,test_loss,test_report = evaluate(class_list,model,test_iter,test=True)
    msg = "Test Loss:{0:>5.2},Test Acc:{1:6.2%}"
    print(msg.format(test_loss,test_acc))
    print(test_report)


def train(model,train_iter,dev_iter,test_iter,class_list):  # 传入模型结构、训练集、验证集、测试集、标签类别
    model.train()   # 开始训练
    optimizer = torch.optim.Adam(model.parameters(),lr=1e-3)   # 优化器,用于更新模型权重,学习率为0.001

    total_batch = 0
    dev_best_loss = float('inf')  # 初始化设置最大损失值为正无穷大
    last_improve = 0
    flag = False
    epochs = 2   # 设置训练次数
    for epoch in range(epochs):
        print('Epoch [{}/{}]'.format(epoch+1,epochs))  # 第一轮[1/2],第二轮[2/2]
        for i,(trains,labels) in enumerate(train_iter):  # 遍历训练集的索引和数据,数据存放的是 每128条评价的包 的字在词表中的索引信息、标签信息、评价长度
            # 经过DatasetIterater中的 to_tensor 返回的数据格式为:(x,seq_len),y,即独热编码、长度、标签
            outputs = model(trains)   # 将数据放入模型进行训练,得到预测输出值,这里的forward没有展示,即传入模型进行前向传播,返回预测结果格式为128*4
            loss = F.cross_entropy(outputs,labels)   # 将输出值与标签放入交叉熵损失计算损失值,多分类计算损失值
            model.zero_grad()   # 对模型进行梯度清0,为下一轮训练做准备
            loss.backward()   # 根据损失计算梯度
            optimizer.step()   # 根据梯度更新模型参数
            if total_batch % 100 == 0:   # 每100轮 输出 在训练集和验证集上的效果,每一百个批次的包打印出来一次
                predic = torch.max(outputs.data,1)[1].cpu()  # outputs.data为 每128条评价的包 的预测大小状态128*4,因为都在GPU中,所以为Tensor类型,torch.max返回第二个维度的最大值及索引,1表示第二个维度,[1]表示取索引的值当做预测结果,然后将预测结果传入cpu
                train_acc = metrics.accuracy_score(labels.data.cpu(),predic)   # 将真实值的标签结果与预测结果输入函数计算准确率
                dev_acc,dev_loss = evaluate(class_list,model,dev_iter)    # 将种类名、模型、验证集数据传入evaluate函数,获得验证结果,返回准确率和损失值
                if dev_loss < dev_best_loss:   # 判断当前损失值是否小于历史损失值
                    dev_best_loss = dev_loss  # 如果损失值比前面的小,那么更新之前的损失值,然后保存这个模型的权重信息
                    torch.save(model.state_dict(),'TextRNN.ckpt')  # 保存最优模型
                    last_improve = total_batch   # 保存最优模型的batch值,整数赋值给last_improve
                # 打印模型的轮数右对齐字符宽为6、训练集的损失值长度为5保留2个小数、训练集的准确率、验证集的损失值和准确率,其中的0,1,2,3,4表示序号第一个参数第二个参数...
                msg = 'Iter:{0:>6},Train Loss:{1:>5.2},Train Acc:{2:>6.2%},Val Loss:{3:>5.2},Val Acc:{4:>6.2%}'
                print(msg.format(total_batch,loss.item(), train_acc, dev_loss, dev_acc))

                model.train()  # 因为上述使用了evaluate将模型设置了测试模式,所以此处再次设置为训练模式
            total_batch += 1   # 每运行一次训练了一个包的文件,对数值加1
            if total_batch - last_improve > 10000:
                print("No optimization for a long time,auto-stopping...")
                flag = True

        if flag:
            break

    test(model,test_iter,class_list)  # 调用test函数进行测试

4、最终文件格式

5、定义主函数

        创建一个文件命名为main.py,将下列代码写入文件

import torch
import numpy as np
import load_dataset,TextRNN
from train_eval_test import train

device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"   # 判断当前使用的是GPU还是CPU或者是mac
np.random.seed(1)   # 设置numpy的随机种子为1,使用numpy生成的随机数序列都是相同的
torch.manual_seed(1)  # 设置PyTorch全局随机种子为1
torch.cuda.manual_seed_all(1)   # 为cuda设备设置随机种子,确保使用多个GPU时,PyTorch生成的随机数是可重复的
torch.backends.cudnn.deterministic = True  # 启用了CuDNN的确定性模式,优化PyTorch等框架在GPU上的性能,CuDNN的某些操作(如卷积和池化)可能是非确定性的,即它们可能会在不同的运行之间产生略微不同的结果,即使输入和随机种子都是相同的,设置为True表示可以牺牲一些性能换取结果的一致性

#
# 调用之前写的文件中定义的函数,并输入参数:文件地址,返回词库、训练集、验证集、测试集 元组形式存放
vocab,train_data,dev_data,test_data = load_dataset.load_dataset('simplifyweibo_4_moods.csv')

"""获取数据集"""
train_iter = load_dataset.DatasetIterater(train_data,128,device)
dev_iter = load_dataset.DatasetIterater(dev_data,128,device)
test_iter = load_dataset.DatasetIterater(test_data,128,device)

"""调用腾讯训练好的的词嵌入模型"""
# 读取预先训练好的模型,将其转化为张量格式传入GPU进行运算,模型格式为4760*200
embedding_pretrained = torch.tensor(np.load('embedding_Tencent.npz')['embeddings'].astype('float32'))
# embedding_pretrained =None   # 不使用外部训练的词向量,则使用随机初始化的词嵌入

# 使用if语句,表示如果导入了预先训练好的模型,那么使用模型的第二个维度,即嵌入向量的维度,否则定义词向量维度为200
embed = embedding_pretrained.size(1) if embedding_pretrained is not None else 200
class_list = ['喜悦','愤怒','厌恶','低落']   # 定义情感分析的标签类别
num_classes = len(class_list)   # 返回类别种类个数

# 传入参数定义模型
model = TextRNN.Model(embedding_pretrained,len(vocab),embed,num_classes).to(device)
#
train(model,train_iter,dev_iter,test_iter,class_list)
        运行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基础IO -- 理解文件(2)

目录 三&#xff1a;理解文件 1.先用和认识系统调用的文件操作 a. 标记位传参的理解 b.文件打开后权限 c. 关闭文件 d. 向文件里写入 2.引入文件操作符fd 3.理解fd 4.Linux下一切皆文件 5.解决前面衍生出的一些问题 C语言FILE*的理解 C语言为什么这么做 三&#xff…

视觉检测解决方案

视觉检测解决方案是一种利用计算机视觉技术模拟人类视觉功能&#xff0c;对工业产品进行非接触式的图像采集、处理与分析&#xff0c;以实现自动化检测、识别与测量的过程。以下是朗观视觉小编对视觉检测解决方案的详细阐述&#xff1a; 一、技术原理 视觉检测解决方案主要基于…

21世纪当代国学易经起名大师颜廷利:全球知名哲学家思想家

融合儒道精髓&#xff0c;东方智慧倡和谐与品德&#xff0c;道家无为而治显自然之道。21世纪全球最具影响力的思想家颜廷利哲学深思&#xff0c;西方哲学则重人本、实用与理性&#xff0c;科学思维引领实证探索&#xff0c;共绘智慧新篇章。 当代知名哲学家思想家教育家颜廷利的…

前端html css js 练习巩固沉淀2

做一个这样的特效 相当于步骤一样的样式逻辑 我直接粘贴代码了 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…

【02】Windows特殊权限-Trustedinstaller

知识点&#xff1a; “TrustedInstaller” 是 Windows 操作系统中的一个特殊账户&#xff0c;用于管理和保护重要的系统文件。它是 Windows 模块安装程序 (Windows Modules Installer) 的一部分&#xff0c;负责安装、修改和删除 Windows 更新和可选组件。默认情况下&#xff…

【C++篇】领会C++标准库:STL

文章目录 前言 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…

5、JavaScript(四) ajax+js高级+BOM

25.ajax : 前端向后端异步的取数据而无需刷新页面的技术 1 公司中的整体工作流程 1、项目开发的流程 每个职位该做的工作&#xff1a; 产品经理&#xff1a;提需求的 与客户沟通 画出原型图给程序员使用 UI设计师&#xff1a;美化 替换UI框架&#xff1a;antd element-ui e…

如何克隆Git仓库的子目录:稀疏检出

一、环境 Git 2.34.1 二、前言 一般来说&#xff0c;我们在克隆git仓库的时候&#xff0c;都是一整个仓库都克隆出来的。如果假设现在有一个很大的仓库&#xff0c;仓库里有多个子项目&#xff0c;而我们只想克隆其中一个子项目的时候&#xff0c;应该怎么做呢&#xff1f; …

【时间之外】IT人求职和创业应知【11】

认知决定你的赚钱能力。以下是今天可能影响你求职和创业的热点新闻&#xff1a; 今日关键字&#xff1a;AI【不用解释吧】 1. 尚福林&#xff1a;人工智能将对金融业的经营运行产生深远影响 新闻概要&#xff1a; 在2024金融街论坛年会上&#xff0c;十三届全国政协经济委员…

Oracle VirtualBox虚拟机导入VMware ESXi的方法

VDI文件导入VMware ESXi 软件版本 Oracle VirtualBox 版本7.0 VMware EXSi 5.5 VDI(Virtual Disk Image)是Oracle VirtualBox支持的虚拟磁盘格式。本次操作的VDI文件20GB左右&#xff0c;包含一个使用unbuntn的非结构化系统。而VMware EXSi 6.5支持的格式是OVF或VMDK。 操作步…

数据结构广度优先搜索遍历(有向图和无向图均可)(C语言代码+邻接矩阵方式+连通图和非连通图均可)

#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #define MAXVEX 100//最大顶点数 typedef struct {int vexs[MAXVEX];//存储顶点的数组int matrix[MAXVEX][MAXVEX];//存储邻接矩阵的二维数组int vexnum, edgenum;//顶点数边数 }MGraph;…

医院信息化与智能化系统(3)

医院信息化与智能化系统(3) 这里只描述对应过程&#xff0c;和可能遇到的问题及解决办法以及对应的参考链接&#xff0c;并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图&#xff0c;可以试试PlantUML&#xff0c;告诉GPT你的文件结构&#xff0c;让他给你对应的…

Leetcode 最小路径和

这段代码解决的是LeetCode第64题“最小路径和”&#xff0c;其核心思想是动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;。以下是算法的具体解释&#xff1a; 1. 问题描述&#xff1a; 我们给定一个包含非负整数的 m x n 网格&#xff08;grid&…

智慧园区能带来哪些便利?

所谓智慧园区&#xff0c;是指通过信息化手段&#xff0c;实现园区内各项业务的数字化和智能化管理。园区管理者可以利用智能化平台实时监控各项运营情况&#xff0c;如能源使用、安全监控和物流运输等&#xff0c;及时调整管理策略&#xff0c;提高运营效率。智慧园区利用大数…

基于SSM+微信小程序的打印室预约管理系统(打印2)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM微信小程序的打印室预约管理系统实现了管理员和用户两个角色。 1、管理员功能有个人中心&#xff0c;用户管理&#xff0c;附近打印店管理&#xff0c;文件打印管理&#xff0c;当…

【配色网站分享】

个人比较喜欢收藏一些好看的插画、UI设计图和配色&#xff0c;于是有了此篇&#xff0c;推荐一些配色网站&#xff0c;希望能对自己和大家有些帮助。 1.uiGradients 一个主打渐变风网站&#xff0c;还可以直接复制颜色。 左上角的“show all gradients”可以查看一些预设的渐…

redis的发布订阅模式

1.发布订阅模式的结构 结合上图和消息中间件&#xff0c;可以将channel和消息中间件中的topic主题对应起来 2. Redis发布订阅功能 &#xff08;1&#xff09;发送消息 Redis采用PUBLISH命令发送消息&#xff0c;其返回值为接收到该消息的订阅者的数量。 &#xff08;2&#xf…

C++进阶——set和map

目录 前言 一、set 1.set的基本介绍 2.set的使用 2.1构造与迭代器 2.2插入 2.3删除 2.4查找 2.5获取需要的区间 2.6一些使用示例 3.set和multiset的区别 4.set相关oj题目 二、map 1.map的基本介绍 2.map的使用 2.1构造与迭代器 2.2增删查以及获取区间 2.3数据…

java基础:while循环-猜数字游戏(附源码)

知识点&#xff1a;while循环 参考该文&#xff1a;JAVA中while循环的使用 实践&#xff1a;猜数字游戏 通过while 判断是否正确&#xff0c; 猜中结束&#xff0c; 若猜不中&#xff0c;猜3次结束 package com.game;import java.util.Scanner;public class Game {public…

DNS安全概述

一、DNS的解析过程 1.递归解析 递归解析是一种由DNS客户端&#xff08;通常是用户的应用程序&#xff0c;如一个浏览器&#xff09;向本地DNS解析器发出解析请求&#xff0c;然后本地DNS解析器负责查询最终结果并将结果返回给客户端&#xff0c;而中间的所有查询请求都由本地D…