NLP实战:使用Word2vec实现文本分类

news2024/11/15 21:33:29

目录

一、数据预处理

1、加载数据

2. 构建词典

3.生成数据批次和迭代器

二、模型构建

1.搭建模型

2.初始化模型

3.定义训练与评估函数

三、训练模型

1. 拆分数据集并运行模型

2. 测试指定数据


🍨 本文为[🔗365天深度学习训练营]内部限免文章(版权归 *K同学啊* 所有)
🍖 作者:[K同学啊]

一、数据预处理
1. 任务说明
本次将加入Word2vec使用PyTorch实现中文文本分类,Word2Vec 则是其中的一种词嵌入方法,是一种用于生成词向量的浅层神经网络模型,由Tomas Mikolov及其团队于2013年提出。Word2Vec通过学习大量文本数据,将每个单词表示为一个连续的向量,这些向量可以捕捉单词之间的语义和句法关系。更详细的内容可见训练营内的NLP基础知识,数据示例如下:

📌 本周任务:
●结合Word2Vec文本内容(第1列)预测文本标签(第2列)
●尝试根据第2周的内容独立实现,尽可能的不看本文的代码
●进一步了解并学习Word2Vec

一、数据预处理

1、加载数据

import torch
import torch.nn as nn
import torchvision
from torchvision import transforms, datasets
import os,PIL,pathlib,warnings

warnings.filterwarnings("ignore")             #忽略警告信息

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

cuda

import pandas as pd

# 加载自定义中文数据
train_data = pd.read_csv('./train.csv', sep='\t', header=None)
print(train_data)

# 构造数据集迭代器
def coustom_data_iter(texts, labels):
    for x, y in zip(texts, labels):
        yield x, y
        
x = train_data[0].values[:]
#多类标签的one-hot展开
y = train_data[1].values[:]

2. 构建词典

调用gensim库

from gensim.models.word2vec import Word2Vec
import numpy as np

# 训练 Word2Vec 浅层神经网络模型
w2v = Word2Vec(vector_size=100, #是指特征向量的维度,默认为100。
               min_count=3)     #可以对字典做截断. 词频少于min_count次数的单词会被丢弃掉, 默认值为5。

w2v.build_vocab(x)
w2v.train(x,                         
          total_examples=w2v.corpus_count, 
          epochs=20)

Word2Vec可以直接训练模型,一步到位。这里分了三步

  • 第一步构建一个空模型
  • 第二步使用 build_vocab 方法根据输入的文本数据 x 构建词典。build_vocab 方法会统计输入文本中每个词汇出现的次数,并按照词频从高到低的顺序将词汇加入词典中。
  • 第三步使用 train 方法对模型进行训练,total_examples 参数指定了训练时使用的文本数量,这里使用的是 w2v.corpus_count 属性,表示输入文本的数量
# 将文本转化为向量
def average_vec(text):
    vec = np.zeros(100).reshape((1, 100))
    for word in text:
        try:
            vec += w2v.wv[word].reshape((1, 100))
        except KeyError:
            continue
    return vec

# 将词向量保存为 Ndarray
x_vec = np.concatenate([average_vec(z) for z in x])

# 保存 Word2Vec 模型及词向量
w2v.save('w2v_model.pkl')

这段代码定义了一个函数 average_vec(text),它接受一个包含多个词的列表 text 作为输入,并返回这些词对应词向量的平均值。该函数

  • 首先初始化一个形状为 (1, 100) 的全零 numpy 数组来表示平均向量
  • 然后遍历 text 中的每个词,并尝试从 Word2Vec 模型 w2v 中使用 wv 属性获取其对应的词向量。如果在模型中找到了该词,函数将其向量加到 vec 中。如果未找到该词,函数会继续迭代下一个词
  • 最后,函数返回平均向量 vec

然后使用列表推导式将 average_vec() 函数应用于列表 x 中的每个元素。得到的平均向量列表使用 np.concatenate() 连接成一个 numpy 数组 x_vec,该数组表示 x 中所有元素的平均向量。x_vec 的形状为 (n, 100),其中 n 是 x 中元素的数量。

train_iter = coustom_data_iter(x_vec, y)
print(len(x),len(x_vec))

12100 12100

label_name = list(set(train_data[1].values[:]))
print(label_name)

['Radio-Listen', 'FilmTele-Play', 'Weather-Query', 'Music-Play', 'Audio-Play', 'Other', 'Travel-Query', 'Alarm-Update', 'HomeAppliance-Control', 'Calendar-Query', 'Video-Play', 'TVProgram-Play']

3.生成数据批次和迭代器

text_pipeline  = lambda x: average_vec(x)
label_pipeline = lambda x: label_name.index(x)
print(text_pipeline("你在干嘛"))

print(label_pipeline("Travel-Query"))

8

from torch.utils.data import DataLoader

def collate_batch(batch):
    label_list, text_list= [], []
    
    for (_text, _label) in batch:
        # 标签列表
        label_list.append(label_pipeline(_label))
        
        # 文本列表
        processed_text = torch.tensor(text_pipeline(_text), dtype=torch.float32)
        text_list.append(processed_text)

    label_list = torch.tensor(label_list, dtype=torch.int64)
    text_list  = torch.cat(text_list)
    
    return text_list.to(device),label_list.to(device)

# 数据加载器,调用示例
dataloader = DataLoader(train_iter,
                        batch_size=8,
                        shuffle   =False,
                        collate_fn=collate_batch)

二、模型构建

1.搭建模型

from torch import nn

class TextClassificationModel(nn.Module):

    def __init__(self, num_class):
        super(TextClassificationModel, self).__init__()
        self.fc = nn.Linear(100, num_class)

    def forward(self, text):
        return self.fc(text)

2.初始化模型

num_class  = len(label_name)
vocab_size = 100000
em_size    = 12
model      = TextClassificationModel(num_class).to(device)

3.定义训练与评估函数

import time

def train(dataloader):
    model.train()  # 切换为训练模式
    total_acc, train_loss, total_count = 0, 0, 0
    log_interval = 50
    start_time   = time.time()

    for idx, (text,label) in enumerate(dataloader):
        predicted_label = model(text)
        
        optimizer.zero_grad()                    # grad属性归零
        loss = criterion(predicted_label, label) # 计算网络输出和真实值之间的差距,label为真实值
        loss.backward()                          # 反向传播
        torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1) # 梯度裁剪
        optimizer.step()  # 每一步自动更新
        
        # 记录acc与loss
        total_acc   += (predicted_label.argmax(1) == label).sum().item()
        train_loss  += loss.item()
        total_count += label.size(0)
        
        if idx % log_interval == 0 and idx > 0:
            elapsed = time.time() - start_time
            print('| epoch {:1d} | {:4d}/{:4d} batches '
                  '| train_acc {:4.3f} train_loss {:4.5f}'.format(epoch, idx,len(dataloader),
                                              total_acc/total_count, train_loss/total_count))
            total_acc, train_loss, total_count = 0, 0, 0
            start_time = time.time()

def evaluate(dataloader):
    model.eval()  # 切换为测试模式
    total_acc, train_loss, total_count = 0, 0, 0

    with torch.no_grad():
        for idx, (text,label) in enumerate(dataloader):
            predicted_label = model(text)
            
            loss = criterion(predicted_label, label)  # 计算loss值
            # 记录测试数据
            total_acc   += (predicted_label.argmax(1) == label).sum().item()
            train_loss  += loss.item()
            total_count += label.size(0)
            
    return total_acc/total_count, train_loss/total_count

torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1)是一个PyTorch函数,用于在训练神经网络时限制梯度的大小。这种操作被称为梯度裁剪(gradient clipping),可以防止梯度爆炸问题,从而提高神经网络的稳定性和性能。

在这个函数中:

  • model.parameters()表示模型的所有参数。对于一个神经网络,参数通常包括权重和偏置项。
  • 0.1是一个指定的阈值,表示梯度的最大范数(L2范数)。如果计算出的梯度范数超过这个阈值,梯度会被缩放,使其范数等于阈值。

梯度裁剪的主要目的是防止梯度爆炸。梯度爆炸通常发生在训练深度神经网络时,尤其是在处理长序列数据的循环神经网络(RNN)中。当梯度爆炸时,参数更新可能会变得非常大,导致模型无法收敛或出现数值不稳定。通过限制梯度的大小,梯度裁剪有助于解决这些问题,使模型训练变得更加稳定。

三、训练模型

1. 拆分数据集并运行模型

from torch.utils.data.dataset  import random_split
from torchtext.data.functional import to_map_style_dataset
# 超参数
EPOCHS     = 10 # epoch
LR         = 5  # 学习率
BATCH_SIZE = 64 # batch size for training

criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=LR)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.1)
total_accu = None

# 构建数据集
train_iter    = coustom_data_iter(train_data[0].values[:], train_data[1].values[:])
train_dataset = to_map_style_dataset(train_iter)

split_train_, split_valid_ = random_split(train_dataset,
                                          [int(len(train_dataset)*0.8),int(len(train_dataset)*0.2)])

train_dataloader = DataLoader(split_train_, batch_size=BATCH_SIZE,
                              shuffle=True, collate_fn=collate_batch)

valid_dataloader = DataLoader(split_valid_, batch_size=BATCH_SIZE,
                              shuffle=True, collate_fn=collate_batch)

for epoch in range(1, EPOCHS + 1):
    epoch_start_time = time.time()
    train(train_dataloader)
    val_acc, val_loss = evaluate(valid_dataloader)
    
    # 获取当前的学习率
    lr = optimizer.state_dict()['param_groups'][0]['lr']
    
    if total_accu is not None and total_accu > val_acc:
        scheduler.step()
    else:
        total_accu = val_acc
    print('-' * 69)
    print('| epoch {:1d} | time: {:4.2f}s | '
          'valid_acc {:4.3f} valid_loss {:4.3f} | lr {:4.6f}'.format(epoch,
                                           time.time() - epoch_start_time,
                                           val_acc,val_loss,lr))

    print('-' * 69)

test_acc, test_loss = evaluate(valid_dataloader)
print('模型准确率为:{:5.4f}'.format(test_acc))

 模型准确率为:0.8814

2. 测试指定数据

def predict(text, text_pipeline):
    with torch.no_grad():
        text = torch.tensor(text_pipeline(text), dtype=torch.float32)
        print(text.shape)
        output = model(text)
        return output.argmax(1).item()

# ex_text_str = "随便播放一首专辑阁楼里的佛里的歌"
ex_text_str = "还有双鸭山到淮阴的汽车票吗13号的"

model = model.to("cpu")

print("该文本的类别是:%s" %label_name[predict(ex_text_str, text_pipeline)])

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式篇---单例模式

文章目录 概念结构与实现优缺点 概念 单例模式是结构最简单的设计模式,通过单例模式可以保证在整个系统中的一个类只有一个实例,从而节约系统资源。举个例子,比如windows电脑下的任务管理器只能打开一个,这个就是单例模式&#x…

【C语言进阶】程序员必备技能之文件操作

目录 🥅什么是文件: 🏑程序文件:🏑数据文件: 🏑文件名: 🥅文件的打开和关闭:🏑文件指针: 🏑fopen和fclose: &a…

genlogic GLG -CE 4.3 For Java/C#/C++ Crack

GLG CE工具包是一个极其灵活和强大的图形框架,用于构建显示实时数据的可视化界面,例如过程控制和监控的操作员显示、SCADA / HMI模拟和图表、 交通、遥测和网络监控显示,以及其他任务关键应用程序。 航电仪表板演示 该工具包包括 用于创建动…

面向对象三大特征

面向对象三大特征 众所周知,面向对象有三大特征 封装继承多态 封装继承多态,就好像武侠小说里的“金、木、水、火、土”一样,相生相克 封装 封装就像是武侠里的金钟罩铁布衫,把对象的数据和方法封装起来,对外只暴露…

C语言strstr函数的使用和模拟实现

strstr 函数原型: char *strstr( const char *string, const char *strCharSet );const char *string 要搜索的字符串const char *strCharSet 子串char *strstr 返回第一个出现字串的起始地址,方便函数链式访问 函数作用: 在 string 字符串…

逻辑越权之验证码|token|接口(36)

token是类似于会话一串数字代表数据包的唯一性,数据包的编号,防止一些csrf,或者一些存放数据包的攻击;一般数据包里面有token,就会检验数据包的唯一性,就会造成提交数据包,被token拦截掉。 验证…

第八章 图像压缩

文章目录 第八章 图像压缩8.1基础知识8.1.1 编码冗余8.1.4图像信息的度量8.1.5保真准则8.1.6图像压缩模型8.17图像格式、容器和压缩标准 8.2一些基本的压缩方法8.2.1霍夫曼编码8.2.2Golomb编码8.2.3算术编码8.2.4LZW编码8.2.5行程编码8.2.6基于符号的编码8.2.7比特平面编码8.2.…

JVM调优常用的工具JPS、JMAP、JSTAT、JSTACK和JCMD的使用详解

查看PID信息 首先启动一个服务 使用jps 和 jps -l 的区别,使用jps -l 能够显示出服务的名称 熟悉JVM调优中常用的工具JMAP、JSTAT和JSTACK JMAP、JSTAT和JSTACK是Java开发中常用的工具,用于分析和调试Java应用程序。它们的使用场景如下: JMA…

S7 1200 CM1241组态modbus rtu

S7 1200 V4.5版本 CM1241 V2.0版本 1 一开始遇到问题 CM1241 绿色灯一直闪烁, PLC 显示LED红色错误 网上查找可能固件不匹配 我一开始选的V2.2 最后选到V2.0才行 如果CM1241 绿灯变为常亮, 这样才是正确组态 如果不是常亮,那么是没有输出的 2 程序 弄了M1.0来启动配置m…

K-means算法

文章目录 1. K-means算法简介2. K-means算法原理2.1 算法具体步骤2.2 k取值方法2.2.1 手肘法2.2.2 轮廓系数法 2.3 K-means2.4 算法终止条件 3. K-means算法特点4. K-means算法应用场景5. K-means算法的Python应用5.1 K-means算法的Python实现5.2 sklearn.cluster.Kmeans函数的…

【Linux】timerfd——定时器

文章目录 前言认识 timerfdAPI timerfdAPI clock 官方示例简单使用epoll实现 前言 在 Linux 系统编程中,使用 timerfd 实现定时器功能是一种更加可靠、高效、灵活的方式。本文是对 timerfd 的简单使用,不涉及太过深入知识,熟练掌握几个常用 …

该死的科斯定理和三条保命原则

* * * 原创:刘教链 * * * 号外:今天在“刘教链”公众号次条发表了《内参:美联储下半年加息时间表和路径》,一号两文无法直接链接,请大家点击公众号卡片进入文章列表打开阅读。星球会员可以直接打开知识星球或discord …

企业级微服务架构实战项目--xx优选3-mq+nacos+es实现上下架

一 nacosmqes实现上下架 1.1 架构图 1.2 工程结构 1.3 核心代码流程 1.3.1 请求product模块 2.修改数据库,推送rabbitmq中 1.3.2 rabbitmq的工具类 1.3.3 search模块中rabbit客户端订阅信息 1.监听器监听信息 2.调用相应的上下架方法 2.1 调用product模块&…

c#网编实验五--WCF和TCP消息通信实验

分别编写服务端和客户端程序,利用基于WCF的TCP技术,实现在线聊天功能,完成在线用户列表管理,消息发送、接收的功能。 在同一个解决方案中,分别编写服务端程序和客户端程序,利用TCP实现简单的群聊功能。 具…

【领域驱动设计专题】一文带领你透视DDD领域驱动模型的本质和设计原理分析指南(构建领域知识)

一文带领你透视DDD领域驱动模型的本质和设计原理分析指南 前提介绍传统的软件设计方案瀑布设计方法敏捷方法学敏捷方法学的问题和局限性 构建领域知识认识和了解领域内容实体模型介绍分析飞行计划路线(route)路线(route) 领域专家进行交流,相互交换知识挖掘出关键的…

一台服务器最大能支持多少条 TCP 连接

一、一台服务器最大能打开的文件数 1、限制参数 我们知道在Linux中一切皆文件,那么一台服务器最大能打开多少个文件呢?Linux上能打开的最大文件数量受三个参数影响,分别是: fs.file-max (系统级别参数)&a…

npm发布自己的包

按照上面流程操作

基于Echarts构建停车场数据可视化大屏

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

XSS—存储型xss

xss >跨站脚本攻击>前端代码注入>用户输入的数据会被当做前端代码执行。 原理:使用者提交的XSS代码被存储到服务器上的数据库里或页面或某个上传文件里,导致用户访问页面展示的内容时直接触发xss代码。 输入内容后直接在下方回显,回…

【Python 随练】今天是哪一天?

题目: 输入某年某月某日,判断这一天是这一年的第几天? 简介: 在本篇博客中,我们将使用Python代码解决一个日期相关的问题:如何确定某一天是给定年份的第几天。我们将提供问题的解析,并给出一…