赞
踩
weibo_senti_100k为数据集:ChineseNlpCorpus/datasets/weibo_senti_100k/intro.ipynb at master · SophonPlus/ChineseNlpCorpus · GitHub
hit_stopwords.txt:
hit_stopwords.txt · master · mirrors / goto456 / stopwords · GitCode
# ---------------------------数据准备------------------------------------------# # ---------------------data_processing.py------------------------------------#
import jieba # ---------------------------------------------------------------------# # data_path:微博情感分析数据集的文件路径。 # data_stop_path:停用词文件的路径。 # data_list:从数据集文件中读取的数据列表,每个元素代表一条微博数据。 # stops_word:停用词列表,包含在该列表中的词语会被过滤掉。 # voc_dict:词汇表字典,包含词语及其对应的频次信息。 # min_seq:词语最小出现频次阈值,只有高于这个阈值的词语才会被保留在新的词汇表中。 # top_n:需要保留的高频词语数量。 # UNK:未登录词(Unknown)的标记字符串,用于表示不在词汇表中的词语。 # PAD:填充序列的标记字符串,用于标记长度不足的序列。 # ---------------------------------------------------------------------# data_path = "weibo_senti_100k.csv" data_stop_path = "hit_stopwords.txt" data_list = open(data_path,encoding='utf-8').readlines()[1:] stops_word = open(data_stop_path,encoding='utf-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 = 1000 UNK="<UNK>" PAD = "<PAD>" # ------------------------------------------------------------------# # data_list:数据列表,包含要处理的文本数据。 # label:当前项的标签,即第一个元素。 # content:当前项的内容,即第三个元素去除前后空格后的字符串。 # seg_list:使用结巴分词库将 content 进行分词后的结果,以生成一个分词列表。 # seg_res:用于存储去除停用词后的分词结果列表。 # stops_word:停用词列表,用于过滤掉常见的无意义词语。 # voc_dict:词汇表字典,用于统计每个词语在数据集中出现的频次。 # ------------------------------------------------------------------# for item in data_list[:1000]: label = item[0] content = item[2:].strip() seg_list = jieba.cut(content, cut_all=False) seg_res = [] for seg_item in seg_list: print(seg_item) if seg_item in stops_word: continue seg_res.append(seg_item) if seg_item in voc_dict.keys(): voc_dict[seg_item] = voc_dict[seg_item] + 1 else: voc_dict[seg_item] = 1 print(content) print(seg_res) # ----------------------------------------------------------------------------# # voc_dict:词汇表字典,包含词语及其对应的频次信息。 # min_seq:最小出现频次阈值,只有高于这个阈值的词语才会被保留在新的词汇表中。 # top_n:需要保留的高频词语数量。 # voc_list:通过筛选出频次高于 min_seq 的词语生成的词汇列表。 # lambda x:x[1]:用于指定排序方式的匿名函数,按照词频进行降序排列。 # voc_dict:经过筛选和排序后的新词汇表字典。将高频词语作为键,以它们在排序后的列表中的索引作为值。 # UNK 和 PAD:特殊标记的词语,通常用于处理未登录词(UNK)和填充序列(PAD)。 # ff:打开用于写入词汇表的文件。 # item:循环遍历词汇表字典中的每一项。 # ff.writelines:将词汇表字典中的键值对以 <词语>,<索引> 的格式写入文件中。 # ff.close():关闭文件。 # ----------------------------------------------------------------------------# voc_list = sorted([_ for _ in voc_dict.items() if _[1] > min_seq], key=lambda x:x[1], reverse=True)[:top_n] voc_dict = {word_count[0]: idx for idx,word_count in enumerate(voc_list)} voc_dict.update({UNK:len(voc_dict),PAD:len(voc_dict) + 1}) print(voc_dict) ff = open("dict","w") for item in voc_dict.keys(): ff.writelines("{},{}\n".format(item,voc_dict[item])) ff.close()
代码的主要流程如下: 读取微博情感分析数据集文件,并将数据存储在 data_list 列表中。 读取停用词文件,并将停用词存储在 stops_word 列表中。 将特殊的空格和换行符添加到停用词列表中。 初始化词汇表字典 voc_dict,用于存储词语及其频次信息。 遍历每个微博数据项: 提取标签(情感分类)和内容,并对内容进行分词。 将分词结果保存在 seg_res 列表中,并统计每个词语的频次。 将词语及其频次更新到词汇表字典 voc_dict 中。 根据词频信息筛选出频次高于 min_seq 的词语,并按照词频降序排列,保留前 top_n 个词语。 根据筛选后的词语列表生成新的词汇表字典 voc_dict,键为词语,值为对应的索引。 添加未登录词(UNK)和填充序列标记(PAD)到词汇表字典 voc_dict 中,分别赋予它们索引值。 打印生成的新词汇表字典 voc_dict。 打开文件 "dict",将词汇表字典中的每个键值对写入文件中,每行格式为 <词语>,<索引>。 关闭文件。 这段代码的作用是构建一个词汇表字典,该词汇表包含微博情感分析数据集中出现频次较高的词语,并将该词汇表保存到文件中供后续使用。
运行结果:
# ---------------------------加载数据集---------------------------------------# # ---------------------------datasets.py------------------------------------# from torch.utils.data import Dataset,DataLoader import jieba import numpy as np from configs import Config # -----------------------------------------------# # voc_dict_path:词汇表文件的路径 # -----------------------------------------------# def read_dict(voc_dict_path): voc_dict = {} dict_list = open(voc_dict_path,encoding='gbk').readlines() for item in dict_list: item = item.split(",") voc_dict[item[0]] = int(item[1].strip()) return voc_dict # -----------------------------------------------# # data_path:数据集文件的路径。 # data_stop_path:停用词文件的路径 # data:用于存储处理后的数据的列表。 # max_len_seq:用于记录最长句子的长度 # -----------------------------------------------# def load_data(data_path,data_stop_path): data_list = open(data_path,encoding='utf-8').readlines()[1:] stops_word = open(data_stop_path,encoding='utf-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 np.random.shuffle(data_list) for item in data_list[:1000]: label = item[0] content = item[2:].strip() seg_list = jieba.cut(content, cut_all=False) seg_res = [] for seg_item in seg_list: if seg_item in stops_word: continue seg_res.append(seg_item) if seg_item in voc_dict.keys(): voc_dict[seg_item] = voc_dict[seg_item] + 1 else: voc_dict[seg_item] = 1 if len(seg_res) > max_len_seq: max_len_seq = len(seg_res) data.append([label, seg_res]) return data, max_len_seq # -------------------------------------------------------------------------# # self.data_path:用于保存数据文件路径的实例变量。 # self.data_stop_path:用于保存停用词文件路径的实例变量。 # self.voc_dict:用于保存词汇表字典的实例变量,通过调用 read_dict() 方法从 voc_dict_path 文件中读取。 # self.data:用于保存处理后的数据的实例变量,通过调用 load_data() 方法从 data_path 和 data_stop_path 加载。 # self.max_len_seq:用于保存最长句子的长度的实例变量。 # np.random.shuffle():随机打乱 self.data 列表中的数据顺序,以增加数据的随机性。 # __len__(self):返回数据集中样本的数量。 # __getitem__(self, item):根据索引 item 获取数据集中的一个样本。 # -------------------------------------------------------------------------# class 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_seq = \ load_data(self.data_path,self.data_stop_path) np.random.shuffle(self.data) def __len__(self): return len(self.data) # ----------------------------------------------------------# # self:代表类的实例自身。 # item:样本的索引,通过该索引可以获取数据集中的一个样本。 # data:根据索引 item 从 self.data 列表中获取到的数据项。 # label:将 data[0] 转换为整数类型后的标签。 # word_list:data[1],即样本中的单词列表。 # input_idx:用于保存将单词转换为对应索引后的结果的列表。 # ----------------------------------------------------------# def __getitem__(self, item): data = self.data[item] label = int(data[0]) word_list = data[1] input_idx = [] for word in word_list: if word in self.voc_dict.keys(): input_idx.append(self.voc_dict[word]) else: input_idx.append(self.voc_dict["<UNK>"]) if len(input_idx) < self.max_len_seq: input_idx += [self.voc_dict["<PAD>"] for _ in range(self.max_len_seq - len(input_idx))] data = np.array(input_idx) return label, data # ----------------------------------------------------------# # config.is_shuffle:是否对数据进行随机打乱。 # ----------------------------------------------------------# # def data_loader(data_path,data_stop_path,dict_path): # dataset = text_ClS(dict_path,data_path,data_stop_path) # return DataLoader(dataset, batch_size=10, shuffle=True) def data_loader(dataset, config): return DataLoader(dataset, batch_size=config.batch_size, shuffle=config.is_shuffle) if __name__ == '__main__': data_path = "weibo_senti_100k.csv" data_stop_path = "hit_stopwords.txt" dict_path = "dict" train_dataloader = data_loader(data_path,data_stop_path,dict_path) for i, batch in enumerate(train_dataloader): print(batch)
这段代码的主要流程如下: 导入必要的库和模块。 定义函数read_dict(voc_dict_path),用于从词汇表文件中读取词汇表字典。 定义函数load_data(data_path, data_stop_path),用于加载数据集文件和停用词文件,并进行数据处理。 定义类text_ClS(Dataset),继承自torch.utils.data.Dataset,用于创建自定义的数据集。 初始化方法__init__(self, voc_dict_path, data_path, data_stop_path),用于初始化实例变量,并调用函数read_dict()和load_data()加载数据集和词汇表。 方法__len__(self),用于返回数据集中样本的数量。 方法__getitem__(self, item),根据索引item获取数据集中的一个样本。 定义函数data_loader(dataset, config),用于创建数据加载器。 在主程序中,设置数据集和配置信息。然后通过调用data_loader()函数创建数据加载器,并使用for循环迭代打印每个batch的数据。 总体来说,这段代码实现了对文本数据集的加载、预处理和批量加载,并提供了方便的接口用于训练和测试模型。
运行结果:
# ---------------------------搭建模型结构---------------------------------------# # ---------------------------models.py---------------------------------------# import torch import torch.nn as nn import torch.nn.functional as F import numpy as np # --------------------------------------------------------------------------------# # self.embedding: 嵌入层,用于将词汇索引映射为词向量。参数解释: # config.n_vocab: 词汇表大小,用于指定嵌入层的输入维度。 # config.embed_size: 词向量的维度。 # padding_idx=config.n_vocab -1: 用于指定填充索引的值,当输入序列中有填充时,对应位置的词向量为0。 # self.lstm: LSTM层,用于对序列进行建模和特征提取。参数解释: # config.embed_size: 输入序列的维度,即词向量的维度。 # config.hidden_size: LSTM隐藏状态的维度,控制网络的容量和记忆能力。 # config.num_layers: LSTM层的层数。 # bidirectional=True: 是否为双向LSTM,如果为True,则会返回前向和后向两个方向的隐藏状态。 # batch_first=True: 输入数据的维度顺序,默认为(batch_size, seq_length, input_size)。 # dropout=config.dropout: Dropout层的丢弃概率,用于防止过拟合。 # self.maxpooling: 池化层,用于对序列进行池化操作,提取序列的关键信息。参数解释: # config.pad_size: 输入序列的填充长度,用于指定池化窗口大小。 # self.fc: 全连接层,用于将池化后的特征映射为分类结果。参数解释: # config.hidden_size * 2 + config.embed_size: 输入特征维度,池化层输出的特征与词向量拼接后的维度。 # config.num_classes: 输出的类别数量。 # self.softmax: Softmax层,用于对模型输出的结果进行归一化,生成概率分布。 # --------------------------------------------------------------------------------# class Model(nn.Module): def __init__(self,config): super(Model,self).__init__() self.embeding = nn.Embedding(config.n_vocab,config.embed_size, padding_idx=config.n_vocab -1) self.lstm = nn.LSTM(config.embed_size, config.hidden_size, config.num_layers, bidirectional=True, batch_first=True, dropout=config.dropout) self.maxpooling = nn.MaxPool1d(config.pad_size) self.fc = nn.Linear(config.hidden_size * 2 + config.embed_size , config.num_classes) self.softmax = nn.Softmax(dim=1) def forward(self,x): embed = self.embeding(x) #输出为[batchsize, seqlen, embed_size] 标准RNN网络的输入 out, _ = self.lstm(embed) out = torch.cat((embed,out),2) out = F.relu(out) out = out.permute(0,2,1)#交换维度 out = self.maxpooling(out).reshape(out.size()[0],-1)#转化为2维tensor print(out.size()) out = self.fc(out) out = self.softmax(out) return out if __name__ == '__main__': from configs import Config cfg = Config() cfg.pad_size = 640 model_textcls = Model(config=cfg) 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)
这段代码的主要流程如下: 导入必要的库和模块。 定义类Model(nn.Module),继承自torch.nn.Module,用于构建文本分类模型。 初始化方法__init__(self, config),用于初始化模型的各个组件,包括Embedding层、LSTM层、MaxPooling层、全连接层等。 方法forward(self, x),定义了模型的前向传播过程。首先通过Embedding层将输入x转化为词嵌入表示。然后将词嵌入表示输入到LSTM层中进行序列建模。接着将词嵌入表示与LSTM的输出拼接在一起,并通过ReLU激活函数进行非线性变换。将拼接后的张量进行维度的变换和池化操作,最终将其转换为二维张量。然后将二维张量输入到全连接层中,并使用Softmax函数进行分类。 在主程序中,导入配置信息Config。创建模型对象model_textcls,并给定一个输入张量input_tensor。调用模型的forward()方法对输入张量进行前向传播得到输出张量out_tensor,然后打印其大小和内容。 总体来说,这段代码定义了一个文本分类模型,包括嵌入层、LSTM层、池化层和全连接层,并实现了模型的前向传播过程。在主程序中,可以通过给定输入张量来获取模型的输出张量。
运行结果:
# ---------------------------搭建模型结构---------------------------------------# # ---------------------------configs.py---------------------------------------# import torch # -------------------------------------------------------------------------------# # self.n_vocab:词汇表的长度,即词汇表中不同词汇的数量。 # self.embed_size:嵌入层的维度,用于将输入的离散词汇转换为连续的词嵌入表示。 # self.hidden_size:LSTM隐藏状态的维度,用于捕获输入序列的上下文信息。 # self.num_layers:LSTM层数,表示LSTM中LSTM单元的数量。 # self.dropout:在LSTM中应用的丢弃率,用于减少过拟合。 # self.num_classes:输出的类别数量,用于分类任务的类别预测。在这里是二分类问题,所以该值为2。 # self.pad_size:填充后的序列长度,保证所有输入序列具有相同的长度。 # self.batch_size:每个训练批次中的样本数量。 # self.is_shuffle:是否在每个训练批次之前对样本进行洗牌(随机排序)。 # self.learn_rate:学习率,用于控制模型参数更新的步长。 # self.num_epochs:训练的迭代次数,即遍历整个训练数据集的次数。 # self.devices:设备选择,通过判断是否有GPU可用来确定使用CPU还是GPU进行训练。 # -------------------------------------------------------------------------------# class Config(): def __init__(self): self.n_vocab = 1002 #字典长度 self.embed_size = 128 self.hidden_size = 128 self.num_layers = 3 self.dropout = 0.8 self.num_classes = 2 #二分类问题 self.pad_size = 32 self.batch_size = 256 self.is_shuffle = True self.learn_rate = 0.001 self.num_epochs = 100 self.devices = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# ---------------------------训练模型--------------------------------------# # -------------------------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 = Config() data_path = "weibo_senti_100k.csv" data_stop_path = "hit_stopwords.txt" dict_path = "dict" dataset = text_ClS(dict_path, data_path, data_stop_path) train_dataloader = data_loader(dataset, cfg) cfg.pad_size = dataset.max_len_seq model_text_cls = Model(cfg) model_text_cls.to(cfg.devices) loss_func = nn.CrossEntropyLoss() optimizer = optim.Adam(model_text_cls.parameters(),lr=cfg.learn_rate) for epoch in range(cfg.num_epochs): for i, batch in enumerate(train_dataloader): label, data = batch data = torch.tensor(data).to(cfg.devices) label = torch.tensor(label,dtype=torch.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() if epoch % 100 == 0:#每100次迭代存储一次模型 torch.save(model_text_cls.state_dict(),"models_100.pth")
这段代码的主要流程如下: 导入必要的库和模块。 导入自定义的模型(Model)、数据集类(text_ClS)、数据加载器(data_loader)和配置信息(Config)。 根据配置信息创建一个数据集对象dataset,并指定数据集的相关路径。 使用数据集对象创建训练数据加载器train_dataloader,用于批量加载训练数据。 根据配置信息创建文本分类模型对象model_text_cls,并将其移动到指定的设备上。 定义损失函数loss_func,采用交叉熵损失函数。 定义优化器optimizer,采用Adam优化算法,并将模型的参数传递给优化器。 进行训练的循环,按照指定的迭代次数(cfg.num_epochs)进行循环。 在每个epoch中,遍历训练数据加载器中的每个batch。 从batch中获取标签(label)和数据(data)。 将数据转换为张量类型,并移动到指定的设备上;将标签转换为torch.int64类型,并移动到指定的设备上。 清空优化器的梯度。 使用模型对数据进行前向传播得到预测结果pred。 计算预测结果和标签之间的损失值loss_val。 输出当前epoch、iteration和损失值。 对损失值进行反向传播,并更新模型的参数。 如果当前epoch是10的倍数,则保存模型的权重至文件中。 总体来说,这段代码实现了基于给定数据集进行文本分类任务的训练过程。通过加载数据集、创建模型、定义损失函数和优化器,循环遍历训练数据并进行前向传播、计算损失、反向传播和参数更新。在每个epoch结束时,将模型的权重保存到文件中。
运行结果:
# ---------------------------测试模型----------------------------------# # ---------------------------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 = Config() data_path = "weibo_senti_100k.csv" data_stop_path = "hit_stopwords.txt" dict_path = "dict" dataset = text_ClS(dict_path, data_path, data_stop_path) train_dataloader = data_loader(dataset, cfg) cfg.pad_size = dataset.max_len_seq model_text_cls = Model(cfg) model_text_cls.to(cfg.devices) model_text_cls.load_state_dict(torch.load("models_100.pth")) for i, batch in enumerate(train_dataloader): label, data = batch data = torch.tensor(data).to(cfg.devices) label = torch.tensor(label,dtype=torch.int64).to(cfg.devices) pred_softmax = model_text_cls.forward(data) print(pred_softmax) print(label) pred = torch.argmax(pred_softmax, dim=1) print(pred) #统计准确率 out = torch.eq(pred,label) print(out.sum() * 1.0 / pred.size()[0])
这段代码的主要流程如下: 导入必要的库和模块。 导入自定义的模型(Model)、数据集类(text_ClS)、数据加载器(data_loader)和配置信息(Config)。 根据配置信息创建一个数据集对象dataset,并指定数据集的相关路径。 使用数据集对象创建训练数据加载器train_dataloader,用于批量加载训练数据。 根据配置信息创建文本分类模型对象model_text_cls,并将其移动到指定的设备上。 使用torch.load()方法加载之前保存的模型权重文件"models/10.pth"。 进行验证的循环,遍历训练数据加载器中的每个batch。 从batch中获取标签(label)和数据(data)。 将数据转换为张量类型,并移动到指定的设备上;将标签转换为torch.int64类型,并移动到指定的设备上。 使用模型对数据进行前向传播得到预测结果pred_softmax。 输出预测结果、标签和通过argmax函数计算的预测类别。 统计准确率,通过torch.eq()函数判断预测类别和标签是否相等,并计算正确预测的数量,再除以总样本数来得到准确率。 总体来说,这段代码加载之前保存的模型权重文件,并使用模型对验证数据进行预测,输出预测结果、标签和准确率。这段代码可以用于在训练过程中进行模型的验证和性能评估。
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。