上海网站设计网页设计,毕业设计 网站建设,适合女生的十大热门专业,系统管理在哪里找怎么找整体过程就是首先拿到了数据集微博100K#xff0c;对个这个评论数据集进行处理#xff0c;分类标签和评论内容。对评论内容进行分词处理#xff0c;之后进行词频统计对高词频的进行编码#xff0c;低词频的进用《UNK》表示#xff0c;并使用《PAD》把他们扩展到等长列表便…
整体过程就是首先拿到了数据集微博100K对个这个评论数据集进行处理分类标签和评论内容。对评论内容进行分词处理之后进行词频统计对高词频的进行编码低词频的进用《UNK》表示并使用《PAD》把他们扩展到等长列表便于处理。
拿到处理好的数据集将其输入通过嵌入层得到密集表示向量表示之后通过LSTM层激活函数层池化层全连接层最后应用softmax激活函数得到类别概率。 1 数据准备 训练集 微博评论100K
停用词 采用合工大停用词表
对数据进行处理-拿到字典-利用字典对语料信息进行编码
1 读取评论和停用词文件
2 对评论内容进行分词处理并进行停用词过滤操作
3 根据分词结果统计词典
4 对词典进行排序 取top n的词作为最终词典其余词作为同一个字符因为不重要提高运算速度UNKPAD放最后
data_processing.py
# codingutf-8import jieba # jieba中文分词使用# 微博评论数据路径
data_path sources/weibo_senti_100k.csv
# 停用词路径
data_stop_path sources/hit_stopword.txt
# 读取文件中的每一行并将每一行作为一个字符串存储在一个列表中,跳过第一行
data_list open(data_path, encodingutf-8).readlines()[1:]
# 拿到停用词列表
stops_word open(data_stop_path, encodingutf-8).readlines()
# 过滤停用词换行符
stops_word [line.strip() for line in stops_word]
# 手动添加过滤空格和换行
stops_word.append( )
stops_word.append(\n)# 定义统计字典
voc_dict {}
# 字典中的最小词频数
min_seq 1
# 取字典中前top_n个
top_n 1000
# 对于前1000以为的值为UNK
UNK UNK
# NLP建模需要PAD到固定长度
PAD PAD# 对每条评论进行分词处理
for item in data_list:# 标签 1代表积极 0代表消极label item[0]# 评论内容content item[2:].strip() # .strip() 方法去除前后的空格。# 使用jieba进行分词 例梦想 有 多 大 舞台 就 有 多 大 ! 鼓掌seg_list jieba.cut(content, cut_allFalse)# 去除停用词后的最终分词结果seg_res []# 去除停用词并创建词频字典for seg_item in seg_list:# 判断分词词语是否为停用词if (seg_item in stops_word):continueseg_res.append(seg_item)# seg_res : [梦想, 大, 舞台, 大, !, 鼓掌]# 判断该词语是否在字典中if seg_item in voc_dict.keys():voc_dict[seg_item] voc_dict[seg_item] 1 # 在的话词频1else:voc_dict[seg_item] 1 # 不在就加进字典去# voc_dict:{\ufeff: 1, 更博: 1, 爆照: 2, 帅: 3, 越来越: 1, 爱: 4, 生快: 1, 傻: 1, 缺: 1}# 对字典进行排序
voc_list sorted([_ for _ in voc_dict.items() if _[1] min_seq],keylambda x: x[1], # keylambda x:x[1]指定排序的依据是每个项中的第二个元素即值。reverseTrue)[:top_n]for idx, word_count in enumerate(voc_list):print(idx, ,word_count)0 (爱, 6)
1 (都, 2)
2 (大, 2)
# 将处理后的字典重新赋值给voc_dict
voc_dict {word_count[0]: idx for idx, word_count in enumerate(voc_list)} # enumerate得到voc_list的键值和索引值# UNK:len(voc_dict) 表示将 UNK 这个词映射到一个特定的索引值 len(voc_dict)。这意味着如果在后续的处理中遇到 UNK它将被视为一个有效的词汇并被分配一个特定的索引。
# PAD:len(voc_dict)1 类似地将 PAD 映射到一个比 voc_dict 中最后一个词汇的索引大 1 的值。这通常用于填充序列使其达到固定的长度。
voc_dict.update({UNK: len(voc_dict), PAD: len(voc_dict) 1})# 保存字典
ff open(sources/dict, w, encodingutf-8)
for item in voc_dict.keys():ff.writelines({},{}\n.format(item, voc_dict[item]))
ff.close()dataset类的定义 自定义训练模型的数据类
作用 利用字典对词进行编码操作 拿到编码后的数据集
1 实现text_CLS(Dataset):类包括初始化获取长度获得编码后的分词数据集
2 实现初始化 通过load_data对数据集进行分词过滤停用词拿到数据集的数据字典和最大分词长度
3 实现获取长度 获得数据集长度
4 实现获得编码后的分词数据集
编码是自己之保存了词频超过1的词频为1的用UNK表示为了统一长度用PAD的编码填充。
datasets.py
from torch.utils.data import Dataset, DataLoader # 从 torch 库中导入数据集Dataset和数据加载器DataLoader类
import jieba # 导入中文分词库 jieba
import numpy as np # 导入科学计算库 numpy# 在 PyTorch 中Dataset 是一个抽象类用于表示数据集。它提供了一种统一的接口用于读取和处理数据
# 并与 DataLoader 结合使用实现数据的批处理和迭代加载。# 读取字典
def read_dict(voc_dict_path):voc_dict {}# 读取字典中的内容 {泪,0 嘻嘻,1 都,2 爱,3...}dict_list open(voc_dict_path, encodingutf-8).readlines()for item in dict_list:item item.split(,)voc_dict[item[0]] int(item[1].strip())# 拿到字典return voc_dict#加载数据
#获得 [[1, [\ufeff, 更博, 爆照, 帅, 越来越, 爱, 生快, 傻, 缺, 爱, 爱, 爱]], [1, [张晓鹏, jonathan, 土耳其, 事要, 认真对待, 直接, 开除, 丁丁, 看, 世界, 很, 细心, 酒店, 都, 全部, OK]]]
#和 最大的字典项长度
def load_data(data_path, data_stop_path):# 读取文件中的每一行并将每一行作为一个字符串存储在一个列表中,跳过第一行data_list open(data_path, encodingutf-8).readlines()[1:]# 拿到停用词列表stops_word open(data_stop_path, encodingutf-8).readlines()# 过滤停用词换行符stops_word [line.strip() for line in stops_word]# 手动添加过滤空格和换行stops_word.append( )stops_word.append(\n)# 定义统计字典voc_dict {}# 定义存储最终数据data []# 最长句子的长度max_len_seq 0# 对每条评论进行分词处理for item in data_list:# 标签 1代表积极 0代表消极label item[0]# 评论内容content item[2:].strip() # .strip() 方法去除前后的空格。# 使用jieba进行分词 例梦想 有 多 大 舞台 就 有 多 大 ! 鼓掌seg_list jieba.cut(content, cut_allFalse)# 去除停用词后的最终分词结果seg_res []# 去除停用词并创建词频字典for seg_item in seg_list:# 判断分词词语是否为停用词if (seg_item in stops_word):continueseg_res.append(seg_item)# seg_res : [梦想, 大, 舞台, 大, !, 鼓掌]# 判断该词语是否在字典中if seg_item in voc_dict.keys():voc_dict[seg_item] voc_dict[seg_item] 1 # 在的话词频1else:voc_dict[seg_item] 1 # 不在就加进字典去# voc_dict:{\ufeff: 1, 更博: 1, 爆照: 2, 帅: 3, 越来越: 1, 爱: 4, 生快: 1, 傻: 1, 缺: 1}# 记录最长句子的长度 #将句子PAD到固定的长度 以最长的句子为基准if len(seg_res) max_len_seq:max_len_seq len(seg_res)# 添加到数据集data [[1, [\ufeff, 更博, 爆照, 帅, 越来越, 爱, 生快, 傻, 缺, 爱, 爱, 爱]], [1, [张晓鹏, jonathan, 土耳其, 事要, 认真对待, 直接, 开除, 丁丁, 看, 世界, 很, 细心, 酒店, 都, 全部, OK]]]data.append([label, seg_res])# print(data)return data, max_len_seqclass text_CLS(Dataset):def __init__(self, voc_dict_path, data_path, data_stop_path):# 微博评论数据路径self.data_path data_path# 停用词路径self.data_stop_path data_stop_path# 拿到字典self.voc_dict read_dict(voc_dict_path)# 加载训练数据self.data, self.max_len_path load_data(self.data_path, self.data_stop_path)# 随机打乱一个数组。np.random.shuffle(self.data)def __len__(self):return len(self.data)def __getitem__(self, item):data self.data[item] # [1, [\ufeff, 更博, 爆照, 帅, 越来越, 爱, 生快, 傻, 缺, 爱, 爱, 爱]]lable int(data[0]) # 1word_list data[1] # [\ufeff, 更博, 爆照, 帅, 越来越, 爱, 生快, 傻, 缺, 爱, 爱, 爱]input_idx []# 将word转化为对应的idfor word in word_list:if word in self.voc_dict.keys(): # 在字典中取字典的编码input_idx.append(self.voc_dict[word])else: # 不在取UNKinput_idx.append(self.voc_dict[UNK])# 对齐长度 以最大的为基准if len(input_idx) self.max_len_path:input_idx [self.voc_dict[PAD] for _ in range(self.max_len_path - len(input_idx))]# 转为数组data np.array(input_idx)return lable, datadef data_loader(dataset,config):# # 微博评论数据路径# data_path sources/weibo_senti_100k.csv# # 停用词路径# data_stop_path sources/hit_stopword.txt# # 字典路径# dict_path sources/dictreturn DataLoader(dataset, batch_sizeconfig.batch_size, shuffleconfig.is_shuffle)#将数据集拆分为小批次并在训练或推理过程中按批次提供数据。if __name__ __main__:# 微博评论数据路径data_path sources/weibo_senti_100k.csv# 停用词路径data_stop_path sources/hit_stopword.txt# 字典路径dict_path sources/dicttrain_dataloader data_loader(dict_path,data_path,data_stop_path)for i,batch in enumerate(train_dataloader):print(batch)
config.py 用于配置训练模型
import torchclass Config():def __init__(self):# 词汇表的大小表示模型可以处理的不同词汇的数量。self.n_vocab 1002# 词嵌入的维度即将词索引转换为密集向量表示的维度。self.embed_size 128# LSTM隐藏状态的维度决定了模型的记忆容量和表示能力。self.hidden_size 128# LSTM层的数量表示堆叠的LSTM层的层数。self.num_layers 3# 用于控制模型中的dropout概率以减少过拟合。self.dropout 0.8# 模型要预测的类别数量。self.num_classes 2# 输入序列的固定长度用于处理变长序列的情况。self.pad_size 32self.batch_size128self.is_shuffleTrueself.numepochs 100#学习率self.learn_rate0.001# 用于指定模型在哪个设备上运行如果CUDA可用则使用GPU进行加速否则使用CPU。self.devices torch.device(cuda if torch.cuda.is_available() else cpu)model.py
import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as npclass Model(nn.Module):# config网络搭建所需要的参数def __init__(self, config):super(Model, self).__init__()# 词嵌入层 将输入序列转化为向量 嵌入层用于将输入的离散化的文本数据转换为连续的稠密向量表示。 嵌入向量通常是随机初始化的并在训练过程中通过反向传播算法进行优化。# config.n_vocab# 表示词汇表的大小即输入文本中不同单词的数量。# config.embed_size# 表示嵌入向量的维度即每个单词表示为一个向量的长度。# padding_idx config.n_vocab - 1# 表示填充位置的索引通常用于处理序列长度不一致的情况。这里将最后一个单词的索引设置为填充位置。self.embeding nn.Embedding(config.n_vocab,config.embed_size,padding_idxconfig.n_vocab - 1)# 定义STML层 模型可以对输入的序列数据进行建模和处理捕捉序列中的长期依赖关系。# LSTM 层在训练过程中会学习到如何根据输入的序列数据生成隐藏状态并在后续的计算中使用这些隐藏状态。# 输入为词嵌入层的输出即词向量化之后的结果self.lstm nn.LSTM(config.embed_size,config.hidden_size, # 隐藏层节点的数量config.num_layers, # 使用几个LSTMbidirectionalTrue, # 双向STMLbatch_firstTrue, # 表示输入数据的批次维度位于第一个位置dropoutconfig.dropout) # 随机抑制一些节点防止过拟合# 定义卷积网络# 是一个实例变量用于创建一个最大池化层MaxPool1d。最大池化层用于对输入数据进行下采样减少特征图的尺寸。self.maxPool nn.MaxPool1d(config.pad_size) # config.pad_size表示池化操作中的填充大小用于处理输入序列长度不一致的情况。# 定义fc层即线性层 用于创建一个全连接层Linear。全连接层用于将之前的特征映射转换为分类输出。self.fc nn.Linear(config.hidden_size * 2 config.embed_size,# 表示全连接层的输入维度由 LSTM 层的隐藏状态维度乘以 2因为是双向 LSTM加上词嵌入层的输出维度组成。config.num_classes) # 表示分类任务的类别数量即全连接层的输出维度。# Softmax 层用于将全连接层的输出转换为概率分布表示每个类别的预测概率。self.softmax nn.Softmax(dim1)# 模型的前向传播方法它描述了数据在模型中的流动过程def forward(self, x):# 输出结果[batch_size,seqlen,embed_size]embed self.embeding(x) # 将输入通过嵌入层得到密集表示out, _ self.lstm(embed) # 将嵌入的输入通过LSTM层得到输出序列out torch.cat((embed, out), 2) # 沿特征维度连接嵌入的输入和LSTM输出out F.relu(out) # 应用ReLU激活函数out out.permute(0, 2, 1) # 调整张量的维度以进行最大池化操作out self.maxPool(out).reshape(out.size()[0], -1) # 执行最大池化操作获得固定大小的可变长度输入表示out self.fc(out) # 将池化输出通过全连接层out self.softmax(out) # 应用softmax激活函数得到类别概率return outif __name__ __main__:from configs import Configcfg Config()cfg.pad_size 640 # 这个参数用于指定输入序列的固定长度。model_textcls Model(configcfg)# 创建一个输入张量input_tensor包含从0到639的索引序列并将其reshape为形状为[1, 640]的张量。这里使用了列表推导式来生成索引序列。input_tensor torch.tensor([i for i in range(640)]).reshape([1, 640])out_tensor model_textcls.forward(input_tensor)print(out_tensor.size())print(out_tensor)run_train.py
import torch
import torch.nn as nn
from torch import optim # 导入优化器
from models import Model # 导入模型
from datasets import data_loader, text_CLS # 导入数据
from configs import Config # 导入配置# 创建一个配置对象cfg
cfg Config()# 微博评论数据路径
data_path sources/weibo_senti_100k.csv
# 停用词路径
data_stop_path sources/hit_stopword.txt
# 字典路径
dict_path sources/dictdataset text_CLS(dict_path, data_path, data_stop_path)
# 使用data_loader函数创建一个训练数据的数据加载器train_dataloader用于按批次加载数据。
train_dataloader data_loader(dataset, cfg)# 将配置对象cfg的pad_size属性设置为数据集的最大序列长度。
cfg.pad_size dataset.max_len_path# 创建一个模型对象model_text_cls并将其移动到指定的设备GPU或CPU上进行计算。
model_text_cls Model(configcfg)
model_text_cls.to(cfg.devices)# 定义损失函数 采用交叉熵
loss_func nn.CrossEntropyLoss()
# 定义优化器
optimizer optim.Adam(model_text_cls.parameters(), lrcfg.learn_rate)flag 1
# 开始训练使用嵌套的循环进行模型的训练。外层循环迭代训练的轮数numepochs内层循环迭代每个批次的数据。
在每个批次中将数据和标签转换为张量并移动到指定的设备上。然后将模型的梯度清零zero_grad()
通过调用模型的前向传播方法forward()获取预测结果并计算损失值。
接着通过调用损失函数的backward()方法进行反向传播计算梯度并更新模型的参数step()。for epoch in range(cfg.numepochs):for i, batch in enumerate(train_dataloader): # 使用enumerate函数获取批次的索引i和对应的数据batch。label, data batch# 将数据和标签转换为张量并将它们移动到指定的设备上GPU或CPU。data torch.tensor(data).to(cfg.devices)label torch.tensor(label, dtypetorch.int64).to(cfg.devices)optimizer.zero_grad() # 将优化器的梯度缓冲区清零以便进行下一次反向传播。pred model_text_cls.forward(data) # 通过调用模型的前向传播方法将数据输入模型获得预测结果。loss_val loss_func(pred, label) # 使用损失函数计算预测结果与标签之间的损失值。# 打印预测结果# print(pred)# print(label)# print(epoch is {} ,ite is {},val is {}.format(epoch, i, loss_val))loss_val.backward() # 执行反向传播计算梯度。optimizer.step() # 根据计算得到的梯度更新模型的参数。print(f完成{flag}次迭代{epoch})flag 1if epoch % 20 0:print(保存了{}.format(epoch))torch.save(model_text_cls.state_dict(), models/{}.pth.format(epoch))print(训练完成)test.py
import torch
import torch.nn as nn
from torch import optim # 导入优化器
from models import Model # 导入模型
from datasets import data_loader, text_CLS # 导入数据
from configs import Config # 导入配置
#创建一个配置对象cfg
cfg Config()# 微博评论数据路径
data_path sources/weibo_senti_100k.csv
# 停用词路径
data_stop_path sources/hit_stopword.txt
# 字典路径
dict_path sources/dictdataset text_CLS(dict_path, data_path, data_stop_path)
#使用data_loader函数创建一个训练数据的数据加载器train_dataloader用于按批次加载数据。
train_dataloader data_loader(dataset, cfg)#将配置对象cfg的pad_size属性设置为数据集的最大序列长度。
cfg.pad_size dataset.max_len_path# 创建一个模型对象model_text_cls并将其移动到指定的设备GPU或CPU上进行计算。
model_text_cls Model(configcfg)
model_text_cls.to(cfg.devices)model_text_cls.load_state_dict(torch.load(models))# 开始训练使用嵌套的循环进行模型的训练。外层循环迭代训练的轮数numepochs内层循环迭代每个批次的数据。
在每个批次中将数据和标签转换为张量并移动到指定的设备上。然后将模型的梯度清零zero_grad()
通过调用模型的前向传播方法forward()获取预测结果并计算损失值。
接着通过调用损失函数的backward()方法进行反向传播计算梯度并更新模型的参数step()。
for i, batch in enumerate(train_dataloader): #使用enumerate函数获取批次的索引i和对应的数据batch。label, data batch#将数据和标签转换为张量并将它们移动到指定的设备上GPU或CPU。data torch.tensor(data).to(cfg.devices)label torch.tensor(label, dtypetorch.int64).to(cfg.devices)pred_softmax model_text_cls.forward(data) #通过调用模型的前向传播方法将数据输入模型获得预测结果。# 打印预测结果# print(pred_softmax)# print(label)# print(epoch is {} ,ite is {},val is {}.format(epoch, i, loss_val))predtorch.argmax(pred_softmax,dim1)# print(pred)out torch.eq(pred,label)# print(out)print(out.sum()*1.0/pred.size()[0])