NLP实战:使用Word2vec实现文本分类 您所在的位置:网站首页 clip近义词 NLP实战:使用Word2vec实现文本分类

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

2023-06-22 03:06| 来源: 网络整理| 查看: 265

目录

一、数据预处理

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)])



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有