N8 - 使用Word2Vec进行文本分类

news2024/11/26 20:27:28
  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊

目录

  • N2 构建词典
    • 1. 导入数据
    • 2. 设置分词器
    • 3. 去除标点和停用词
    • 4. 文本迭代器
    • 5. 构建词典
    • 6. 文本数字化
  • N3 NLP中的数据集构建
    • 1. Dataset
    • 2. DataLoader
  • N8 使用Word2Vec进行文本分类
    • 环境设置
    • 数据准备
    • 模型设计
    • 模型训练
    • 模型效果展示
  • 总结与心得体会


由于K同学调整了目录,本来这应该是N6,现在是N8了,中间增加了两节内容,在这里一并打卡了。

N2 构建词典

其实在前面的章节打卡中,也涉及到了构建词典,但是没有一个完整的顺序,这节把构建词典的过程详细的梳理了一下。

1. 导入数据

使用自定义的数据,我直接从网络小说里面截取一段出来。然后按句拆开放到一个列表里。

# 数据
data = [
    "我这才想起今天的米彩在上海参加了一天的商务会谈,后又不顾疲惫来酒吧救场,心中除了感谢更过意不去。",
    "CC推了推我说道:“昭阳,你不送送米儿吗?”",
    "我赶忙点头说道:“嗯,我送她出去。”说着便从米彩手中接过手提包帮她提着。",
    "米彩说了声“谢谢”后在我之前向酒吧外走去,我跟上了她说道:“你老和我说谢谢,弄得我们之间多生分吶!”",
    "“有吗?”"
    "米彩心不在焉的回答,让我无从去接她的话,只是在沉默中跟着她的脚步向外面走着。",
    "忽然我们的脚步止于酒吧外面的屋檐下,此刻天空竟然飘起了漫天的雪花,这个冬天终于下雪了。",
    "我下意识的感叹,道:“下雪了!”",
    "“嗯!”米彩应了一声,却比我更会珍惜这样的画面,从手提包里拿出卡片相机将眼前银装素裹的世界定格在了镜头里,然后离开屋檐,走进了漫天的雪花中。"
]
# 把人名弄成自定义字典
user_dictionary = [
    "CC", "昭阳","米儿", "米彩"
]

2. 设置分词器

import jieba
tokenizer = jieba.lcut
jieba.load_userdict(user_dictionary)

3. 去除标点和停用词

编写一个过滤函数去除标点符号

import re
def remove_punctuation(text):
	return re.sub(r'[^\w\s]', '', text)

维护一个停用词列表,编写停用词过滤函数

stopwords = ['的', '这', '是']
def remove_stopwords(words):
	return [word for word in words if word not in stopwords]

4. 文本迭代器

编写一个迭代器,将文本转化成返回单词

def yield_tokens(data_iter):
	for text in data_iter:
		# 去除标点符号
		text = remove_punctuation(text)
		# 分词
		words = tokenizer(text)
		# 去除停用词
		words = remove_stopwords(words)
		yield words

5. 构建词典

from torchtext.vocab import build_vocab_from_iterator
# 遍历所有的分词结果,构建词典
vocab = build_vocab_from_iterator(yield_tokens(data), specials=['<unk>'])

# 将未知的词汇设置为<unk>
vocab.set_default_index(vocab['<unk>'])

build_vocab_from_iterator用来从一个可迭代对象中统计token的频次,并返回一个词典
它的原型如下

def build_vocab_from_iterator(iterator: Iterable,
							  min_freq: int = 1,
							  specials: Optional[List[str]] = None,
							  special_first: bool = True,
							  max_tokens: Optional[int] = None
							  )

参数解释如下:

  • iterator: 用于创建词典的可迭代对象
  • min_freq: 最小频数,文本中的词汇只有频数大于min_freq的才会保留下来,出现在词典中
  • specials: 特殊标志,值是一个字符串的列表。用于在词典中添加一些特殊的token,例如我们使用<unk>来代表字典中不存在的token。
  • special_first: 表示是否将special token放在词典顺序的最前面(也就是Index小),默认是True
  • max_tokens: 限制词典词汇的最大数量

备注:除了special_token之外的token是按词频来降序排列的,如果两个词的频次一样,则按出现顺序。
set_default_index可以设置默认使用的token,比如添加一个<unk>设置为默认。

6. 文本数字化

# 打印词典中的内容
print('词典大小:', len(vocab))
print('词典内部映射:', vocab.get_stoi())

text = "外面是冬天"
words = remove_stopwords(jieba.lcut(text))
print()
print('jieba分词后的文本:', jieba.lcut(text))
print('去除停用词后的文本:', words)
print('数字化后的文本:', [vocab[word] for word in words])

词典结果

N3 NLP中的数据集构建

torch.utils.data 是pytorch中用于数据加载和预处理的模块,其中包含DatasetDataLoader两个类,通常结合使用来加载和处理数据。

1. Dataset

torch.utils.data.Dataset是一个抽象类,用于表示数据集。

自定义Dataset需要继承这个基类,并实现两个方法__len____getitem__

其中__len__返回的是数据集的大小,__getitem__用于根据索引返回一个数据样本。

自定义一个数据集的示例

from torch.utils.data import Dataset

class MyDataset(Dataset):
    def __init__(self, texts, labels):
        self.texts = texts
        self.labels = labels

    def __len__(self):
        return len(self.labels)

    def __getitem__(self, idx):
        texts = self.texts[idx]
        labels = self.labels[idx]
        return texts, labels

2. DataLoader

torch.utils.data.DataLoader是pytorch中一个重要的类,用于高效的加载数据集。它可以将数据批次化、打乱数据的顺序、多线程加载数据等。

import torch
from torch.utils.data import DataLoader
# 假数据
text_data = [
	torch.tensor([1, 2, 3, 4], dtype=torch.long),
	torch.tensor([4, 3, 2], dtype=torch.long),
	torch.tensor([1, 2], dtype=torch.long)
]
text_labels = torch.tensor([1, 0, 1], dtype=torch.float)

# 创建dataset
my_dataset = MyDataset(text_data, text_labels)
# 通过dataset创建dataloader
dataloader = DataLoader(my_dataset, batch_size=2, shuffle=True, collate_fn=lambda x: x)

# 打印一下dataloader里面的数据
for batch in dataloader:
	print(batch)

重复执行几次,可以看到batch中的数据是随机的,没有固定的顺序
数据集展示1
数据集展示2

N8 使用Word2Vec进行文本分类

Word2Vec是一种用于生成词向量的浅层神经网络模型,由Tomas Mikolov及其团队于2013年提出。Word2Vec通过学习大量的文本数据,将每个单词表示为一个连续的向量,这些向量可以捕捉单词之间的主义和句法关系。上一节的打卡中,我们使用gensim在一篇小说内容上训练了一个Word2Vec模型。

这节我们训练一个word2vec模型,并用它来做文本分类任务。

环境设置

创建全局的torch device

import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

数据准备

使用pandas读取csv

import pandas as pd

# 读取当前目录下的train.csv,里面的数据按\t分隔,并且没有表头
data = pd.read_csv('train.csv', sep='\t', header=None)
data.head()

预览数据
拆分数据中的文本和标签

data_x = data[0].values[:]
data_y = data[1].values[:]

创建并训练word2vec模型

from gensim.models.word2vec import Word2Vec

# 创建一个输出向量为100维的word2vec模型,并且忽略词频小于3的单词
w2v = Word2Vec(vector_size=100, min_count=3)
# 使用数据集构建词典
w2v.build_vocab(data_x)
# 训练word2vec模型,文本数量使用上一步统计的输入文本数量(total_examples=w2v.corpus_count),训练20轮(epochs=20)
w2v.train(data_x, total_examples=w2v.corpus_count, epochs=20)

word2vex训练输出
现在word2vec模型已经训练好了,我们直接把csv中的所有数据跑一下,让文本数据集变成向量数据集

import numpy as np
import os
# 把一段文本转换成向量,将其中的所有单词向量相加
def text_vector(text):
	vec = np.zeros((1, 100))
	for word in text:
		try:
			# 因为词频小于3的单词忽略了,所有会有找不到key的异常抛出这里直接try了忽略掉
			vec += w2v.wv[word].reshape((1, 100))
		except KeyError:
			continue
	return vec

# 把x转换为向量的x
vec_x = torch.concatenate([text_vector(text) for text in data_x])

# 保存word2vec模型
if not os.path.exists('model'):
	os.makedirs('model', exist_ok=True)
w2v.save('model/w2v_model.pkl')

编写一个迭代函数,把x和y组合到一起

def yield_zip_iter(data_x, data_y):
	for x, y in zip(data_x, data_y):
		yield x, y

取出所有的分类名,用于将分类标签转成索引

label_names = list(set(data_y))
label_names

分类名
标签文本转索引的函数

label_pipeline = lambda y: label_names.index(y)
label_pipeline('Travel-Query')

标签文本转索引
编写批次数据的整理函数,用于把一个批次原本的形状如[(x1,y1), (x2,y2)]的数据转换为[x1,x2]和[y1, y2]

def collate_batch(batch):
	data_list, label_list = [], []
	for x, y in batch:
		data_list.append(torch.tensor(x, dtype=torch.float32))
		label_list.append(label_pipeline(y))
	#转为tensor
	data_list = torch.stack(data_list)
	label_list = torch.tensor(label_list, dtype=torch.int64)
	return data_list.to(device), label_list.to(device)

生成数据集

from torchtext.utils import to_map_style_dataset
from torch.utils.data import random_split

# 创建数据迭代器
data_iter = yield_zip_iter(vec_x , data_y)
# 把迭代器转成dataset
train_dataset = to_map_style_dataset(data_iter)

# 拆分dataset为训练和验证
train_size = int(len(train_dataset) * 0.8)
train_split = random_split(train_dataset, [train_size, len(train_dataset) - train_size])

模型设计

创建torch模型,只有一层简单的全连接就可以,只有一层全连接准确度不达标,增加一层bottleneck提升准确率

import torch.nn as nn

class TextClassificationModel(nn.Module):
    def __init__(self, num_classes):
        super().__init__()
        self.fc = nn.Sequential(nn.Linear(100, 64),nn.ReLU(), nn.Linear(64, num_classes)) 

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

model = TextClassificationModel(len(label_names)).to(device)

模型训练

编写模型训练函数

# 编写训练函数
import time

def train(dataloader):
    model.train()
    train_acc, train_loss, total_count = 0, 0, 0
    log_interval = 50
    start_time = time.time()

    for idx, (vector, label) in enumerate(dataloader):
        # 前向传播
        predicted_label = model(vector)

        # 反向传播
        optimizer.zero_grad()
        loss = criterion(predicted_label, label)
        loss.backward()
        nn.utils.clip_grad_norm_(model.parameters(), 0.1) # 梯度裁剪
        optimizer.step()

        # 记录数据
        train_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), train_acc/total_count, train_loss/total_count))
            train_acc, train_acc, total_count = 0, 0, 0
            start_time = time.time()

def evaluate(dataloader):
    model.eval()
    total_acc, total_loss, total_count = 0, 0, 0
    with torch.no_grad():
        for idx, (vector, label) in enumerate(dataloader):
            predicted_label = model(vector)

            loss = criterion(predicted_label, label)
            # 记录数据
            total_acc += (predicted_label.argmax(1) == label).sum().item()
            total_loss += loss.item()
            total_count += label.size(0)

    return total_acc / total_count, total_loss / total_count

开始训练

from torch.utils.data import DataLoader
# 超参数
epochs = 10
lr = 5
batch_size = 64

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

train_dataloader = DataLoader(split_train, batch_size=batch_size, shuffle=True, collate_fn=collate_batch)
valid_dataloader = DataLoader(split_valid, batch_size, shuffle=True, collate_fn=collate_batch)

acc_history, loss_history = [], []

# 训练
for epoch in range(1, epochs+1):
	epoch_start_time = time.time()
    train(train_dataloader)
    val_acc, val_loss = evaluate(valid_dataloader)
    acc_history.append(val_acc)
    loss_history.append(val_loss)
    
    lr = optimizer.state_dict()['param_groups'][0]['lr']
    if total_acc is not None and total_acc > val_acc:
        scheduler.step()
    else:
        total_acc = 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))

准确率

模型效果展示

编写一个用来预测的函数,输入文本,输出标签

def predict(text):
    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_names[predict(ex_text_str)])

模型预测
可以发现结果是正确的

画一下训练过程的数据曲线

import matplotlib.pyplot as plt
ranges = list(range(1, epochs+1))

plt.title('Validation Accuracy')
plt.plot(ranges, acc_history, label='Accuracy')

验证的准确度

plt.title('Validation Loss')
plt.plot(ranges, loss_history, label='Loss')

验证的损失

总结与心得体会

通过对新增的两个章节的回顾和本章的任务的训练,让我印象最深刻的就是to_map_style_dataset这个函数的使用。通过它把一个简单的yield函数变成了数据集,具体的dataset不需要自己来实现,这样做的好处是非常快捷。但是这种方式应该仅限于数据量不大的情况下使用,如果数据量太大,它会全部加载到内存中,这时候就应该使用自定义的数据集,通过索引来进行取数据,具体的逻辑更加灵活,不用在没有训练的时候就把数据加载到内存里。
还有就是使用word2vec来实现文本分类任务的过程,开始看到这个下意识的认为需要用pytorch重写一个word2vex模型,最后发现完全可以使用不同的库组合进来达到最终的目的。

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

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

相关文章

当代最杰出的思想家姓名学大师颜廷利:当学历与文凭突破了道德底线。。。

在当今社会&#xff0c;文凭和学历被频繁提及&#xff0c;并似乎成为了衡量个人价值的重要尺度。然而&#xff0c;当这些学术凭证超越了道德的底线时&#xff0c;整个社会便开始笼罩在谎言和欺骗的阴影之下。善良与纯真&#xff0c;如同无助的羔羊&#xff0c;在利益的屠刀下黯…

(亲测有效)SpringBoot项目集成腾讯云COS对象存储(1)

目录 一、腾讯云对象存储使用 1、创建Bucket 2、使用web控制台上传和浏览文件 3、创建API秘钥 二、代码对接腾讯云COS&#xff08;以Java为例&#xff09; 1、初始化客户端 2、填写配置文件 3、通用能力类 文件上传 测试 一、腾讯云对象存储使用 1、创建Bucket &am…

通义千问报错“撞脸”OpenAI?

笔者团队一个月前为能够使系统可以支持AI Agent的应用&#xff0c;集成了通义千问的模型接口&#xff0c;特别是集成了其可以通过推理调用外部工具的能力。并录制了相关视频如何无代码DIY一个AI Agent&#xff0c;体验还是非常不错的。 今日为客户进行该能力演示时&#xff0c;…

CAN-Linux

1.修改Makefile 然后编译 g -o hello_cpp main.cpp /home/peter/my_tool/controlcan/libcontrolcan.so -lpthread 2.查看 3.测试

2024年化工自动化控制仪表证模拟考试题库及化工自动化控制仪表理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年化工自动化控制仪表证模拟考试题库及化工自动化控制仪表理论考试试题是由安全生产模拟考试一点通提供&#xff0c;化工自动化控制仪表证模拟考试题库是根据化工自动化控制仪表最新版教材&#xff0c;化工自动化…

CSS——弹性盒(flex)

一、弹性盒的简介 1、flex&#xff08;弹性盒、伸缩盒&#xff09;&#xff1a;是css中的又一种布局手段&#xff0c;他主要用来代替浮动完成页面的布局。 2、flex可以使元素具有弹性&#xff0c;让元素可以跟随页面的大小的改变而改变。 3、弹性容器&#xff1a;要使用弹性盒&…

离谱测试!小米SU7对撞极氪007,暴露了极氪007一亮点

文 | AUTO芯球 作者 | 谦行 拿小米SU7和极氪007对撞&#xff0c;他娘的真是个人才&#xff01; 两辆车都是60km/h的速度 &#xff0c; 90%的重叠率 &#xff0c;这可比面对面撞更惨烈&#xff01; 结果&#xff0c;两辆车车头都稀烂 好在乘员舱完整&#xff0c;气囊也都弹出&…

基于808协议和1078协议的视频监控系统

卫星定位云服务平台 卫星定位云服务平台是一个车载视频终端监控系统,用于对卫星定位设备进行实时监控、实时定位、轨迹回放、指令下发、拍照记录、报警信息、实时视频、历史视频等功能。808协议和1078协议 内置功能 车队管理&#xff1a;车队信息的增删改查。型号管理&#…

2024年入职/转行网络安全,该如何规划?_网络安全职业规划

前言 前段时间&#xff0c;知名机构麦可思研究院发布了 《2022年中国本科生就业报告》&#xff0c;其中详细列出近五年的本科绿牌专业&#xff0c;其中&#xff0c;信息安全位列第一。 网络安全前景 对于网络安全的发展与就业前景&#xff0c;想必无需我多言&#xff0c;作为…

互联网私有IP地址列表

最近因为业务需要&#xff0c;要判断用户的IP是否私有IP&#xff0c; 以前知道的私有IP&#xff0c;基本上只有如下几个(注意&#xff1a;这不是正确答案)&#xff1a; 10.0.0.0/8&#xff08;10.0.0.0-10.255.255.255&#xff09;172.16.0.0/12&#xff08;172.16.0.0-172.31…

springboot智慧畜牧信息监控系统---附源码39012

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 智慧畜牧信息监控系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据增加流程 2.2.2 数据修改流程 2.2.3 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.…

碳化硅陶瓷膜过滤器的选购建议

碳化硅陶瓷膜过滤器是一种利用碳化硅陶瓷膜技术进行过滤和分离的设备&#xff0c;其性能和用途广泛。以下是关于碳化硅陶瓷膜过滤器的详细介绍&#xff1a; 一、工作原理 碳化硅陶瓷膜过滤器的工作原理主要包括两个过程&#xff1a; 过滤&#xff1a;通过碳化硅陶瓷膜的微孔结构…

Windows下串口编程与单片机串口设备通信(win32-API)

一、前言 串行通信接口&#xff0c;通常简称为“串口”&#xff0c;是一种数据传输方式&#xff0c;其中信息以连续的比特流形式发送&#xff0c;每个比特在不同的时间点被传输。这与并行通信形成对比&#xff0c;在并行通信中&#xff0c;多个比特同时通过多个线路传输。串口…

运维的利器–监控–zabbix–第二步:建设–部署zabbix agent5.0–客户端是linux系统–实操记录xy

文章目录 部署zabbix agent5.0–客户端是linux系统第一步&#xff1a;安装agent第二&#x1f645;‍&#xff1a;更改agent配置文件第三&#x1f645;‍&#xff1a;防火墙配置第四&#x1f645;‍&#xff1a;启动agent进程第五&#x1f645;‍&#xff1a;网页端添加主机失败…

互联网大厂薪资分布:90%的人月薪拿到2w-5w!你拖后腿了吗?

互联网大厂的高薪&#xff0c;早已是众人皆知&#xff0c;但究竟高到何种程度&#xff1f;普通人的薪资水平在大厂中处于什么位置&#xff1f;我们是否也拥有跻身高薪行列的可能&#xff1f; 带着这些疑问&#xff0c;我们不妨来深入探究一下互联网大厂的薪资分布情况。 如果…

在阿里云ecs上构建一个WordPress博客网站

1、购买ECS 使用抢占式实例&#xff0c;RDS 使用按量付费 2、在安全组的出入方向添加80端口 3、购买一个公网IP绑定该ecs 4、云数据库rds选择按量付费 5、创建一个名为test_user的普通账号 6、创建数据库 7、设置RDS实例白名单 8、远程登录ecs实例 9、安装apache服务及其扩展包…

【PyCharm激活】2024年最新下载安装激活汉化Pycharm教程!(附激活码)

PyCharm激活码&#xff08;下方领取&#xff09;&#xff1a; 一、下载PyCharm 访问官网&#xff1a; 打开浏览器&#xff0c;访问PyCharm官网。 选择版本&#xff1a; PyCharm提供两个版本&#xff1a;专业版&#xff08;Professional&#xff09;和社区版&#xff08;Commun…

企业级 Zabbix 监控

一、zabbix 监控 1、zabbix 监控架构 zabbix的监控架构在实际监控架构中&#xff0c;zabbix根据网络环境、监控规模等 分了如下两种架构&#xff1a; server-client 、server-proxy-client 1、server-client架构也是zabbix的最简单的架构&#xff0c;监控机和被监控机之间不经…

ElasticSearch文档数据关联关系处理

文章目录 ES如何处理关联关系对象类型案例一 适用场景案例二 不适用场景 嵌套对象nested object父子关联关系嵌套文档 VS 父子关系 ES如何处理关联关系 关系型数据库中的范式化&#xff1a; 减少了数据冗余&#xff0c;节省了磁盘空间减少了不必要的更新操作&#xff0c;因为…

SQL注入(head、报错、盲注)

目录 【学习目标、重难点知识】 【学习目标】 【重难点知识】 1. 报错注入 1.1 那么什么是报错注入呢&#xff1f; 1.2 报错注入原理 extractvalue函数 updatexml函数 1.3 靶场解析 靶场练习 2. HEAD注入 2.1 相关全局变量 2.2 靶场解析 burp暴力破解 靶场练习 3…