深度学习---新闻数据文本分类---pytorch

调用流程图:
------------------------------以下是代码------------------------------------------------run.py:
import time
# 导入time模块,用于记录数据加载和训练时间import torch
# 导入PyTorch框架,用于构建和训练深度学习模型import numpy as np
# 导入NumPy库,用于进行数值计算和数组操作from train_eval import train, init_network
# 从train_eval.py文件中导入train函数(训练模型)和init_network函数(初始化网络参数)from importlib import import_module
# 从importlib中导入import_module函数,用于动态导入模块import argparse
# 导入argparse模块,用于解析命令行参数from tensorboardX import SummaryWriter
# 导入tensorboardX的SummaryWriter类,用于可视化训练过程中的指标(如loss、accuracy等)# 创建一个ArgumentParser对象,描述为“Chinese Text Classification”
parser = argparse.ArgumentParser(description='Chinese Text Classification')# 添加--model参数,类型为字符串,必须输入,帮助信息提示选择TextCNN、TextRNN等模型
parser.add_argument('--model', type=str, required=True, help='choose a model: TextCNN, TextRNN, FastText, TextRCNN, TextRNN_Att, DPCNN, Transformer')# 添加--embedding参数,默认值为'pre_trained',类型为字符串,帮助信息提示选择预训练或随机词向量
parser.add_argument('--embedding', default='pre_trained', type=str, help='random or pre_trained')# 添加--word参数,默认False,类型为布尔值,帮助信息提示是否使用词粒度(True)还是字符粒度(False)
parser.add_argument('--word', default=False, type=bool, help='True for word, False for char')# 解析命令行传入的参数,并保存在args变量中
args = parser.parse_args()if __name__ == '__main__':# 程序入口,表示这是主程序执行部分# 设置使用的数据集名称为'THUCNews'dataset = 'THUCNews'  # 数据集# 搜狗新闻: embedding_SougouNews.npz, 腾讯: embedding_Tencent.npz, 随机初始化: random# 初始化词向量路径为搜狗新闻预训练词向量文件embedding = 'embedding_SougouNews.npz'# 如果用户指定使用随机初始化词向量if args.embedding == 'random':# 则将embedding设置为'random',表示不使用预训练词向量embedding = 'random'# 获取用户指定的模型名称并保存到model_name变量中model_name = args.model  # TextCNN, TextRNN等# 如果模型是FastTextif model_name == 'FastText':# 动态导入FastText专用的数据处理工具函数from utils_fasttext import build_dataset, build_iterator, get_time_dif# FastText模型强制使用随机初始化词向量embedding = 'random'# 如果不是FastText模型else:# 导入通用的数据处理工具函数from utils import build_dataset, build_iterator, get_time_dif# 使用import_module动态导入对应的模型模块,例如models.TextCNNx = import_module('models.' + model_name)# 实例化模型配置类Config,传入数据集和词向量信息config = x.Config(dataset, embedding)# 设置numpy的随机种子为1,确保每次运行结果一致np.random.seed(1)# 设置PyTorch CPU模式下的随机种子为1torch.manual_seed(1)# 设置所有CUDA设备的随机种子为1,保证GPU训练结果可复现torch.cuda.manual_seed_all(1)# 设置CuDNN为确定性模式,以确保卷积运算的结果可重复torch.backends.cudnn.deterministic = True# 记录开始加载数据的时间戳start_time = time.time()# 打印数据加载提示信息print("Loading data...")# 构建数据集,包括词汇表vocab和训练、验证、测试数据vocab, train_data, dev_data, test_data = build_dataset(config, args.word)# 创建训练数据迭代器train_iter = build_iterator(train_data, config)# 创建验证数据迭代器dev_iter = build_iterator(dev_data, config)# 创建测试数据迭代器test_iter = build_iterator(test_data, config)# 计算数据加载所用时间time_dif = get_time_dif(start_time)# 打印数据加载耗时print("Time usage:", time_dif)# train# 将词汇表大小赋值给config.n_vocab,供模型使用config.n_vocab = len(vocab)# 实例化模型,并将其移动到指定设备(CPU/GPU)model = x.Model(config).to(config.device)# 创建TensorBoard日志写入器,log目录包含当前时间戳以便区分不同训练日志writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))# 如果不是Transformer模型if model_name != 'Transformer':# 调用init_network函数初始化网络参数init_network(model)# 打印模型参数信息print(model.parameters)# 调用train函数开始训练模型,传入配置、模型和数据迭代器train(config, model, train_iter, dev_iter, test_iter, writer)
train_eval.py
import time
# 导入time模块,用于记录数据加载和训练时间import torch
# 导入PyTorch框架,用于构建和训练深度学习模型import numpy as np
# 导入NumPy库,用于进行数值计算和数组操作from train_eval import train, init_network
# 从train_eval.py文件中导入train函数(训练模型)和init_network函数(初始化网络参数)from importlib import import_module
# 从importlib中导入import_module函数,用于动态导入模块import argparse
# 导入argparse模块,用于解析命令行参数from tensorboardX import SummaryWriter
# 导入tensorboardX的SummaryWriter类,用于可视化训练过程中的指标(如loss、accuracy等)# 创建一个ArgumentParser对象,描述为“Chinese Text Classification”
parser = argparse.ArgumentParser(description='Chinese Text Classification')# 添加--model参数,类型为字符串,必须输入,帮助信息提示选择TextCNN、TextRNN等模型
parser.add_argument('--model', type=str, required=True, help='choose a model: TextCNN, TextRNN, FastText, TextRCNN, TextRNN_Att, DPCNN, Transformer')# 添加--embedding参数,默认值为'pre_trained',类型为字符串,帮助信息提示选择预训练或随机词向量
parser.add_argument('--embedding', default='pre_trained', type=str, help='random or pre_trained')# 添加--word参数,默认False,类型为布尔值,帮助信息提示是否使用词粒度(True)还是字符粒度(False)
parser.add_argument('--word', default=False, type=bool, help='True for word, False for char')# 解析命令行传入的参数,并保存在args变量中
args = parser.parse_args()if __name__ == '__main__':# 程序入口,表示这是主程序执行部分# 设置使用的数据集名称为'THUCNews'dataset = 'THUCNews'  # 数据集# 搜狗新闻: embedding_SougouNews.npz, 腾讯: embedding_Tencent.npz, 随机初始化: random# 初始化词向量路径为搜狗新闻预训练词向量文件embedding = 'embedding_SougouNews.npz'# 如果用户指定使用随机初始化词向量if args.embedding == 'random':# 则将embedding设置为'random',表示不使用预训练词向量embedding = 'random'# 获取用户指定的模型名称并保存到model_name变量中model_name = args.model  # TextCNN, TextRNN等# 如果模型是FastTextif model_name == 'FastText':# 动态导入FastText专用的数据处理工具函数from utils_fasttext import build_dataset, build_iterator, get_time_dif# FastText模型强制使用随机初始化词向量embedding = 'random'# 如果不是FastText模型else:# 导入通用的数据处理工具函数from utils import build_dataset, build_iterator, get_time_dif# 使用import_module动态导入对应的模型模块,例如models.TextCNNx = import_module('models.' + model_name)# 实例化模型配置类Config,传入数据集和词向量信息config = x.Config(dataset, embedding)# 设置numpy的随机种子为1,确保每次运行结果一致np.random.seed(1)# 设置PyTorch CPU模式下的随机种子为1torch.manual_seed(1)# 设置所有CUDA设备的随机种子为1,保证GPU训练结果可复现torch.cuda.manual_seed_all(1)# 设置CuDNN为确定性模式,以确保卷积运算的结果可重复torch.backends.cudnn.deterministic = True# 记录开始加载数据的时间戳start_time = time.time()# 打印数据加载提示信息print("Loading data...")# 构建数据集,包括词汇表vocab和训练、验证、测试数据vocab, train_data, dev_data, test_data = build_dataset(config, args.word)# 创建训练数据迭代器train_iter = build_iterator(train_data, config)# 创建验证数据迭代器dev_iter = build_iterator(dev_data, config)# 创建测试数据迭代器test_iter = build_iterator(test_data, config)# 计算数据加载所用时间time_dif = get_time_dif(start_time)# 打印数据加载耗时print("Time usage:", time_dif)# train# 将词汇表大小赋值给config.n_vocab,供模型使用config.n_vocab = len(vocab)# 实例化模型,并将其移动到指定设备(CPU/GPU)model = x.Model(config).to(config.device)# 创建TensorBoard日志写入器,log目录包含当前时间戳以便区分不同训练日志writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))# 如果不是Transformer模型if model_name != 'Transformer':# 调用init_network函数初始化网络参数init_network(model)# 打印模型参数信息print(model.parameters)# 调用train函数开始训练模型,传入配置、模型和数据迭代器train(config, model, train_iter, dev_iter, test_iter, writer)
utils.py:
# coding: UTF-8
# 指定文件编码为UTF-8,支持中文字符import os
# 导入os模块,用于进行操作系统路径和文件操作import torch
# 导入PyTorch框架,用于构建和训练深度学习模型import numpy as np
# 导入NumPy库,用于数值计算和数组操作import pickle as pkl
# 导入pickle模块,用于序列化和反序列化Python对象(如保存和加载词汇表)from tqdm import tqdm
# 从tqdm导入tqdm类,用于在循环中显示进度条import time
# 导入time模块,用于记录时间from datetime import timedelta
# 从datetime导入timedelta类,用于表示时间差MAX_VOCAB_SIZE = 10000
# 设置最大词表大小为10000个词UNK, PAD = '<UNK>', '<PAD>'
# 定义特殊符号:未知词用<UNK>表示,填充符用<PAD>表示def build_vocab(file_path, tokenizer, max_size, min_freq):# 构建词汇表函数,参数包括数据路径、分词器、最大词表大小和最小出现频率vocab_dic = {}# 初始化一个空字典来存储词汇及其频次with open(file_path, 'r', encoding='UTF-8') as f:# 打开文本文件进行读取# 遍历每一行,并显示进度条for line in tqdm(f):# 去除首尾空白字符lin = line.strip()if not lin:continue# 如果是空行,则跳过# 使用制表符分割,取第一个部分作为文本内容content = lin.split('\t')[0]# 使用指定的tokenizer对内容进行分词for word in tokenizer(content):# 统计每个词的出现次数vocab_dic[word] = vocab_dic.get(word, 0) + 1# 筛选出现频率大于等于min_freq的词,并按频率排序后取前max_size个词vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True)[:max_size]# 将筛选后的词列表转换为词到索引的映射字典vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)}# 添加特殊符号到词典中,UNK排在最后,PAD在其后vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})# 返回构建好的词汇表字典return vocab_dic# 构建数据集函数,参数为配置对象config和是否使用词粒度标志use_word
def build_dataset(config, ues_word):# 如果使用词粒度if ues_word:# 使用空格分词,即词级别处理tokenizer = lambda x: x.split(' ')else:# 否则使用字符级别分词,将字符串转为字符列表tokenizer = lambda x: [y for y in x]# 如果已经存在词汇表文件if os.path.exists(config.vocab_path):# 直接加载已有的词汇表vocab = pkl.load(open(config.vocab_path, 'rb'))# 如果不存在词汇表文件else:# 调用build_vocab函数构建新的词汇表vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)# 将新构建的词汇表保存到磁盘文件中pkl.dump(vocab, open(config.vocab_path, 'wb'))# 打印词汇表大小print(f"Vocab size: {len(vocab)}")# 加载单个数据集(训练/验证/测试)的内部函数def load_dataset(path, pad_size=32):# 初始化数据容器contents = []# 打开数据文件with open(path, 'r', encoding='UTF-8') as f:# 逐行读取并显示进度条for line in tqdm(f):# 去除前后空白字符lin = line.strip()# 空行跳过if not lin:continue# 使用制表符分割,获取文本内容和标签content, label = lin.split('\t')# 初始化当前句子的token列表words_line = []# 使用tokenizer对内容进行分词或分字token = tokenizer(content)# 获取原始序列长度seq_len = len(token)# 如果设置了固定长度if pad_size:# 如果当前句子长度小于pad_sizeif len(token) < pad_size:# 用<PAD>补齐至pad_size长度token.extend([vocab.get(PAD)] * (pad_size - len(token)))else:token = token[:pad_size]# 否则截断至pad_size长度seq_len = pad_size# word to idfor word in token:# 将词转换为对应的索引# 如果词不在词典中,使用UNK替代words_line.append(vocab.get(word, vocab.get(UNK)))# 将处理后的数据加入contents列表contents.append((words_line, int(label), seq_len))# 返回处理好的数据集return contents  # [([...], 0), ([...], 1), ...]# 分别加载训练集、验证集和测试集train = load_dataset(config.train_path, config.pad_size)dev = load_dataset(config.dev_path, config.pad_size)test = load_dataset(config.test_path, config.pad_size)# 返回词汇表和三个数据集return vocab, train, dev, test# 自定义数据迭代器类
class DatasetIterater(object):# 初始化方法def __init__(self, batches, batch_size, device):# 设置批量大小self.batch_size = batch_size# 数据批次列表self.batches = batches# 计算完整batch的数量self.n_batches = len(batches) // batch_sizeself.residue = False  # 是否有剩余样本if len(batches) % self.n_batches != 0:self.residue = True# 如果不能整除,标记存在残余数据# 当前遍历的起始索引self.index = 0# 数据所在设备(CPU/GPU)self.device = device# 将数据转换为张量的方法def _to_tensor(self, datas):# 输入序列转为LongTensor并移动到指定设备x = torch.LongTensor([_[0] for _ in datas]).to(self.device)# 标签转为LongTensor并移动到指定设备y = torch.LongTensor([_[1] for _ in datas]).to(self.device)# 序列长度信息转为LongTensor并移动到指定设备seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)# 返回输入、长度和标签return (x, seq_len), y# 实现迭代器的__next__方法def __next__(self):# 如果有残余数据且到达最后一个不完整的batchif self.residue and self.index == self.n_batches:# 取出残余数据batches = self.batches[self.index * self.batch_size: len(self.batches)]# 更新索引self.index += 1# 转换为张量batches = self._to_tensor(batches)# 返回当前batchreturn batches# 如果索引超过总batch数elif self.index > self.n_batches:self.index = 0# 重置索引raise StopIteration# 抛出停止迭代异常else:# 正常取一个batch# 取出当前batch的数据batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]# 更新索引self.index += 1# 转换为张量batches = self._to_tensor(batches)# 返回当前batchreturn batchesdef __iter__(self):# 实现__iter__方法,返回自身即可开始迭代return selfdef __len__(self):# 获取总batch数量if self.residue:# 如果有残余数据,加1return self.n_batches + 1else:# 否则直接返回完整batch数return self.n_batches# 构建数据迭代器函数
def build_iterator(dataset, config):# 创建DatasetIterater实例iter = DatasetIterater(dataset, config.batch_size, config.device)# 返回迭代器对象return iterdef get_time_dif(start_time):"""获取已使用时间"""end_time = time.time()time_dif = end_time - start_time# 返回格式化的时间差对象return timedelta(seconds=int(round(time_dif)))if __name__ == "__main__":'''提取预训练词向量'''# 下面的目录、文件名按需更改。# 定义训练数据集的目录train_dir = "./THUCNews/data/train.txt"# 定义词汇表的目录vocab_dir = "./THUCNews/data/vocab.pkl"# 定义预训练向量的目录pretrain_dir = "./THUCNews/data/sgns.sogou.char"# 定义词向量的维度emb_dim = 300# 定义保存修剪后嵌入层的目录filename_trimmed_dir = "./THUCNews/data/embedding_SougouNews"# 检查词汇表是否已存在if os.path.exists(vocab_dir):# 如果存在,加载词汇表word_to_id = pkl.load(open(vocab_dir, 'rb'))else:# 如果不存在,定义一个分词函数,以字为单位构建词表tokenizer = lambda x: [y for y in x]# 使用训练数据构建词汇表word_to_id = build_vocab(train_dir, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)# 保存词汇表pkl.dump(word_to_id, open(vocab_dir, 'wb'))# 初始化随机嵌入层矩阵,维度为词汇表大小乘以词向量维度embeddings = np.random.rand(len(word_to_id), emb_dim)# 打开预训练的词向量文件f = open(pretrain_dir, "r", encoding='UTF-8')# 遍历预训练的词向量文件,更新嵌入层矩阵for i, line in enumerate(f.readlines()):lin = line.strip().split(" ")# 如果当前词在词汇表中,则更新其对应的词向量if lin[0] in word_to_id:idx = word_to_id[lin[0]]emb = [float(x) for x in lin[1:301]]embeddings[idx] = np.asarray(emb, dtype='float32')# 关闭文件f.close()# 保存修剪后的嵌入层矩阵np.savez_compressed(filename_trimmed_dir, embeddings=embeddings)# 主程序入口,用于生成预训练词向量文件
utils_fasttext.py:
# coding: UTF-8
# 指定文件编码为UTF-8,支持中文字符import os
# 导入os模块,用于进行操作系统路径和文件操作import torch
# 导入PyTorch框架,用于构建和训练深度学习模型import numpy as np
# 导入NumPy库,用于数值计算和数组操作import pickle as pkl
# 导入pickle模块,用于序列化和反序列化Python对象(如保存和加载词汇表)from tqdm import tqdm
# 从tqdm导入tqdm类,用于在循环中显示进度条import time
# 导入time模块,用于记录时间from datetime import timedelta
# 从datetime导入timedelta类,用于表示时间差MAX_VOCAB_SIZE = 10000
# 设置最大词表大小为10000个词UNK, PAD = '<UNK>', '<PAD>'
# 定义特殊符号:未知词用<UNK>表示,填充符用<PAD>表示def build_vocab(file_path, tokenizer, max_size, min_freq):# 构建词汇表函数,参数包括数据路径、分词器、最大词表大小和最小出现频率vocab_dic = {}# 初始化一个空字典来存储词汇及其频次with open(file_path, 'r', encoding='UTF-8') as f:# 打开文本文件进行读取# 遍历每一行,并显示进度条for line in tqdm(f):# 去除首尾空白字符lin = line.strip()if not lin:continue# 如果是空行,则跳过# 使用制表符分割,取第一个部分作为文本内容content = lin.split('\t')[0]# 使用指定的tokenizer对内容进行分词for word in tokenizer(content):# 统计每个词的出现次数vocab_dic[word] = vocab_dic.get(word, 0) + 1# 筛选出现频率大于等于min_freq的词,并按频率排序后取前max_size个词vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True)[:max_size]# 将筛选后的词列表转换为词到索引的映射字典vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)}# 添加特殊符号到词典中,UNK排在最后,PAD在其后vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})# 返回构建好的词汇表字典return vocab_dic# 构建数据集函数,参数为配置对象config和是否使用词粒度标志use_word
def build_dataset(config, ues_word):# 如果使用词粒度if ues_word:# 使用空格分词,即词级别处理tokenizer = lambda x: x.split(' ')else:# 否则使用字符级别分词,将字符串转为字符列表tokenizer = lambda x: [y for y in x]# 如果已经存在词汇表文件if os.path.exists(config.vocab_path):# 直接加载已有的词汇表vocab = pkl.load(open(config.vocab_path, 'rb'))# 如果不存在词汇表文件else:# 调用build_vocab函数构建新的词汇表vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)# 将新构建的词汇表保存到磁盘文件中pkl.dump(vocab, open(config.vocab_path, 'wb'))# 打印词汇表大小print(f"Vocab size: {len(vocab)}")# 加载单个数据集(训练/验证/测试)的内部函数def load_dataset(path, pad_size=32):# 初始化数据容器contents = []# 打开数据文件with open(path, 'r', encoding='UTF-8') as f:# 逐行读取并显示进度条for line in tqdm(f):# 去除前后空白字符lin = line.strip()# 空行跳过if not lin:continue# 使用制表符分割,获取文本内容和标签content, label = lin.split('\t')# 初始化当前句子的token列表words_line = []# 使用tokenizer对内容进行分词或分字token = tokenizer(content)# 获取原始序列长度seq_len = len(token)# 如果设置了固定长度if pad_size:# 如果当前句子长度小于pad_sizeif len(token) < pad_size:# 用<PAD>补齐至pad_size长度token.extend([vocab.get(PAD)] * (pad_size - len(token)))else:token = token[:pad_size]# 否则截断至pad_size长度seq_len = pad_size# word to idfor word in token:# 将词转换为对应的索引# 如果词不在词典中,使用UNK替代words_line.append(vocab.get(word, vocab.get(UNK)))# 将处理后的数据加入contents列表contents.append((words_line, int(label), seq_len))# 返回处理好的数据集return contents  # [([...], 0), ([...], 1), ...]# 分别加载训练集、验证集和测试集train = load_dataset(config.train_path, config.pad_size)dev = load_dataset(config.dev_path, config.pad_size)test = load_dataset(config.test_path, config.pad_size)# 返回词汇表和三个数据集return vocab, train, dev, test# 自定义数据迭代器类
class DatasetIterater(object):# 初始化方法def __init__(self, batches, batch_size, device):# 设置批量大小self.batch_size = batch_size# 数据批次列表self.batches = batches# 计算完整batch的数量self.n_batches = len(batches) // batch_sizeself.residue = False  # 是否有剩余样本if len(batches) % self.n_batches != 0:self.residue = True# 如果不能整除,标记存在残余数据# 当前遍历的起始索引self.index = 0# 数据所在设备(CPU/GPU)self.device = device# 将数据转换为张量的方法def _to_tensor(self, datas):# 输入序列转为LongTensor并移动到指定设备x = torch.LongTensor([_[0] for _ in datas]).to(self.device)# 标签转为LongTensor并移动到指定设备y = torch.LongTensor([_[1] for _ in datas]).to(self.device)# 序列长度信息转为LongTensor并移动到指定设备seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)# 返回输入、长度和标签return (x, seq_len), y# 实现迭代器的__next__方法def __next__(self):# 如果有残余数据且到达最后一个不完整的batchif self.residue and self.index == self.n_batches:# 取出残余数据batches = self.batches[self.index * self.batch_size: len(self.batches)]# 更新索引self.index += 1# 转换为张量batches = self._to_tensor(batches)# 返回当前batchreturn batches# 如果索引超过总batch数elif self.index > self.n_batches:self.index = 0# 重置索引raise StopIteration# 抛出停止迭代异常else:# 正常取一个batch# 取出当前batch的数据batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]# 更新索引self.index += 1# 转换为张量batches = self._to_tensor(batches)# 返回当前batchreturn batchesdef __iter__(self):# 实现__iter__方法,返回自身即可开始迭代return selfdef __len__(self):# 获取总batch数量if self.residue:# 如果有残余数据,加1return self.n_batches + 1else:# 否则直接返回完整batch数return self.n_batches# 构建数据迭代器函数
def build_iterator(dataset, config):# 创建DatasetIterater实例iter = DatasetIterater(dataset, config.batch_size, config.device)# 返回迭代器对象return iterdef get_time_dif(start_time):"""获取已使用时间"""end_time = time.time()time_dif = end_time - start_time# 返回格式化的时间差对象return timedelta(seconds=int(round(time_dif)))if __name__ == "__main__":'''提取预训练词向量'''# 下面的目录、文件名按需更改。# 定义训练数据集的目录train_dir = "./THUCNews/data/train.txt"# 定义词汇表的目录vocab_dir = "./THUCNews/data/vocab.pkl"# 定义预训练向量的目录pretrain_dir = "./THUCNews/data/sgns.sogou.char"# 定义词向量的维度emb_dim = 300# 定义保存修剪后嵌入层的目录filename_trimmed_dir = "./THUCNews/data/embedding_SougouNews"# 检查词汇表是否已存在if os.path.exists(vocab_dir):# 如果存在,加载词汇表word_to_id = pkl.load(open(vocab_dir, 'rb'))else:# 如果不存在,定义一个分词函数,以字为单位构建词表tokenizer = lambda x: [y for y in x]# 使用训练数据构建词汇表word_to_id = build_vocab(train_dir, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)# 保存词汇表pkl.dump(word_to_id, open(vocab_dir, 'wb'))# 初始化随机嵌入层矩阵,维度为词汇表大小乘以词向量维度embeddings = np.random.rand(len(word_to_id), emb_dim)# 打开预训练的词向量文件f = open(pretrain_dir, "r", encoding='UTF-8')# 遍历预训练的词向量文件,更新嵌入层矩阵for i, line in enumerate(f.readlines()):lin = line.strip().split(" ")# 如果当前词在词汇表中,则更新其对应的词向量if lin[0] in word_to_id:idx = word_to_id[lin[0]]emb = [float(x) for x in lin[1:301]]embeddings[idx] = np.asarray(emb, dtype='float32')# 关闭文件f.close()# 保存修剪后的嵌入层矩阵np.savez_compressed(filename_trimmed_dir, embeddings=embeddings)# 主程序入口,用于生成预训练词向量文件
/models/TextCNN.py:
# coding: UTF-8
# 指定文件编码为UTF-8,支持中文字符
# 导入PyTorch框架,用于构建和训练深度学习模型
import torch# 从PyTorch中导入神经网络模块,用于定义神经网络层
import torch.nn as nn# 导入PyTorch的功能性函数模块,如激活函数、卷积等
import torch.nn.functional as F# 导入NumPy库,用于进行数值计算和数组操作
import numpy as np"""配置参数"""
class Config(object):# 初始化配置类,传入数据集名称和词向量类型(预训练或随机)def __init__(self, dataset, embedding):# 设置模型名称为TextCNNself.model_name = 'TextCNN'# 训练集路径,格式为{dataset}/data/train.txtself.train_path = dataset + '/data/train.txt'# 验证集路径,格式为{dataset}/data/dev.txtself.dev_path = dataset + '/data/dev.txt'# 测试集路径,格式为{dataset}/data/test.txtself.test_path = dataset + '/data/test.txt'# 从class.txt中读取类别列表,并去除每行两端空白字符self.class_list = [x.strip() for x in open(dataset + '/data/class.txt').readlines()]# 词汇表保存路径,格式为{dataset}/data/vocab.pklself.vocab_path = dataset + '/data/vocab.pkl'# 模型保存路径,格式为{dataset}/saved_dict/TextCNN.ckptself.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt'# 日志保存路径,格式为{dataset}/log/TextCNNself.log_path = dataset + '/log/' + self.model_name# 如果embedding不是random,则加载预训练词向量;否则设为Noneself.embedding_pretrained = torch.tensor(np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32')) \if embedding != 'random' else None# 设置设备:如果CUDA可用则使用GPU,否则使用CPUself.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# dropout比率,在训练过程中随机失活部分神经元以防止过拟合self.dropout = 0.5# 若验证集loss在1000个batch内未下降,则提前终止训练self.require_improvement = 1000# 类别数量,由class.txt中读取得到self.num_classes = len(self.class_list)# 词表大小,在后续运行时动态赋值self.n_vocab = 0# 训练轮数,总共训练20个epochself.num_epochs = 20# mini-batch大小,每次训练使用的样本数为128self.batch_size = 128# 句子统一长度,短句填充,长句截断self.pad_size = 32# 学习率,控制参数更新步长self.learning_rate = 1e-3# 如果有预训练词向量,字向量维度为预训练维度;否则默认为300维self.embed = self.embedding_pretrained.size(1) \if self.embedding_pretrained is not None else 300# 卷积核尺寸,分别使用2、3、4长度的卷积核提取特征self.filter_sizes = (2, 3, 4)# 卷积核数量,即输出通道数,每个尺寸的卷积核都有256个self.num_filters = 256'''Convolutional Neural Networks for Sentence Classification'''
# 文本分类的卷积神经网络原始论文引用标题# 定义TextCNN模型类,继承自nn.Module
class Model(nn.Module):# 构造函数,初始化模型结构def __init__(self, config):# 调用父类构造函数super(Model, self).__init__()# 如果提供了预训练词向量if config.embedding_pretrained is not None:# 使用预训练词向量,并允许微调(freeze=False)self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)else:# 否则# 创建一个随机初始化的词嵌入层,设置padding_idx为最后一个索引self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)# 创建多个一维卷积层,每个卷积核高度分别为2、3、4,宽度为词向量维度self.convs = nn.ModuleList([nn.Conv2d(1, config.num_filters, (k, config.embed)) for k in config.filter_sizes])# 添加Dropout层,防止过拟合self.dropout = nn.Dropout(config.dropout)# 全连接层,输入大小为所有卷积核输出拼接后的总长度,输出为类别数self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes)# 定义卷积+池化函数,用于处理每个卷积层的输出def conv_and_pool(self, x, conv):# 应用ReLU激活函数并通过卷积层,然后去掉第四个维度(单列)x = F.relu(conv(x)).squeeze(3)# 在时间维度上做最大池化,再去除第二个维度x = F.max_pool1d(x, x.size(2)).squeeze(2)# 返回池化后的结果return x# 前向传播函数,定义数据如何通过网络流动def forward(self, x):# 调试信息:打印输入张量形状print(x[0].shape)# 将输入的token索引转换为词向量表示out = self.embedding(x[0])# 在第2维增加一个通道维度,使其适配Conv2d输入要求out = out.unsqueeze(1)# 对不同尺寸的卷积核分别进行卷积和池化操作,并将结果拼接在一起out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1)# 应用Dropout,减少过拟合风险out = self.dropout(out)# 最终通过全连接层得到分类输出out = self.fc(out)# 返回模型输出结果return out

/models/TextRNN.py:

# coding: UTF-8
# 指定文件编码为UTF-8,支持中文字符
# 导入PyTorch框架,用于构建和训练深度学习模型
import torch# 从PyTorch中导入神经网络模块,用于定义神经网络层
import torch.nn as nn# 导入PyTorch的功能性函数模块,如激活函数、卷积等
import torch.nn.functional as F# 导入NumPy库,用于进行数值计算和数组操作
import numpy as np"""配置参数"""
class Config(object):# 初始化配置类,传入数据集名称和词向量类型(预训练或随机)def __init__(self, dataset, embedding):# 设置模型名称为TextRNNself.model_name = 'TextRNN'# 训练集路径,格式为{dataset}/data/train.txtself.train_path = dataset + '/data/train.txt'# 验证集路径,格式为{dataset}/data/dev.txtself.dev_path = dataset + '/data/dev.txt'# 测试集路径,格式为{dataset}/data/test.txtself.test_path = dataset + '/data/test.txt'# 从class.txt中读取类别列表,并去除每行两端空白字符self.class_list = [x.strip() for x in open(dataset + '/data/class.txt').readlines()]# 词汇表保存路径,格式为{dataset}/data/vocab.pklself.vocab_path = dataset + '/data/vocab.pkl'# 模型保存路径,格式为{dataset}/saved_dict/TextRNN.ckptself.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt'# 日志保存路径,格式为{dataset}/log/TextRNNself.log_path = dataset + '/log/' + self.model_name# 如果embedding不是random,则加载预训练词向量;否则设为Noneself.embedding_pretrained = torch.tensor(np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32')) \if embedding != 'random' else None# 设置设备:如果CUDA可用则使用GPU,否则使用CPUself.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# dropout比率,在训练过程中随机失活部分神经元以防止过拟合self.dropout = 0.5# 若验证集loss在1000个batch内未下降,则提前终止训练self.require_improvement = 1000# 类别数量,由class.txt中读取得到self.num_classes = len(self.class_list)# 词表大小,在后续运行时动态赋值self.n_vocab = 0# 训练轮数,总共训练10个epochself.num_epochs = 10# mini-batch大小,每次训练使用的样本数为128self.batch_size = 128# 句子统一长度,短句填充,长句截断self.pad_size = 32# 学习率,控制参数更新步长self.learning_rate = 1e-3# 如果有预训练词向量,字向量维度为预训练维度;否则默认为300维self.embed = self.embedding_pretrained.size(1) \if self.embedding_pretrained is not None else 300# LSTM隐藏层大小,表示每个时刻LSTM输出的特征维度self.hidden_size = 128# LSTM层数,堆叠两层LSTM网络self.num_layers = 2'''Recurrent Neural Network for Text Classification with Multi-Task Learning'''
# 引用论文标题:基于多任务学习的文本分类循环神经网络# 定义TextRNN模型类,继承自nn.Module
class Model(nn.Module):# 构造函数,初始化模型结构def __init__(self, config):# 调用父类构造函数super(Model, self).__init__()# 如果提供了预训练词向量if config.embedding_pretrained is not None:# 使用预训练词向量,并允许微调(freeze=False)self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)else:# 否则# 创建一个随机初始化的词嵌入层,设置padding_idx为最后一个索引self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)# 创建双向LSTM层,输入维度为词向量维度,输出维度为hidden_size,num_layers层,batch_first=True表示输入形状为(batch, seq, feature)self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers,bidirectional=True, batch_first=True, dropout=config.dropout)# 全连接层,将LSTM输出的最后一时刻的拼接结果映射到类别空间self.fc = nn.Linear(config.hidden_size * 2, config.num_classes)# 前向传播函数,定义数据如何通过网络流动def forward(self, x):# 解包输入数据,x是token索引,_ 是其他信息(如seq_len),但此处忽略x, _ = x# 将输入的token索引转换为词向量表示,形状为[batch_size, seq_len, embed]out = self.embedding(x)# 输入到LSTM中,out是所有时间步的输出,形状为[batch_size, seq_len, hidden_size*2](因为是双向)out, _ = self.lstm(out)# 取LSTM最后一步的输出作为句子表示,输入全连接层得到分类结果out = self.fc(out[:, -1, :])# 返回模型输出结果return out

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

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

相关文章

7.15 腾讯云智面经整理

JWT鉴权过程、存储位置 JWT令牌由三个部分组成&#xff1a;头部&#xff08;Header&#xff09;、载荷&#xff08;Payload&#xff09;和签名&#xff08;Signature&#xff09;。其中&#xff0c;头部和载荷均为JSON格式&#xff0c;使用Base64编码进行序列化&#xff0c;而签…

无人设备遥控器之双向通讯技术篇

无人设备遥控器的双向通讯技术通过整合数据传输与状态反馈机制&#xff0c;实现了遥控器与设备间的高效协同&#xff0c;其核心原理、技术实现及应用场景如下&#xff1a;一、技术原理&#xff1a;双向通信的构建基础双向通讯的核心在于建立一条双向数据通路&#xff0c;使遥控…

百度移动开发面经合集

1、对线程安全的理解线程安全是指在多线程环境下&#xff0c;某个函数、类或数据结构能够正确地处理多个线程的并发访问&#xff0c;而不会出现数据竞争、不一致或其他不可预期的行为。线程安全的实现通常需要考虑以下几点&#xff1a;原子性&#xff1a;操作是不可分割的&…

Wiz笔记二次开发

目前wiz笔记的docker版本停留在1.0.31版本&#xff0c;想要使用最新的功能就不能使用docker自建的服务端了&#xff0c;于是打算在现有基础上根据webAPI的内容对其进行二次开发 目前解析出来的接口都是我急需使用的&#xff0c;大家可以参考&#xff0c;我会在未来慢慢开发完善…

AI-Compass RLHF人类反馈强化学习技术栈:集成TRL、OpenRLHF、veRL等框架,涵盖PPO、DPO算法实现大模型人类价值对齐

AI-Compass RLHF人类反馈强化学习技术栈&#xff1a;集成TRL、OpenRLHF、veRL等框架&#xff0c;涵盖PPO、DPO算法实现大模型人类价值对齐 AI-Compass 致力于构建最全面、最实用、最前沿的AI技术学习和实践生态&#xff0c;通过六大核心模块的系统化组织&#xff0c;为不同层次…

阿里云 Kubernetes 的 kubectl 配置

安装 kubectl 到系统路径# 赋予执行权限 chmod x kubectl# 安装到系统路径 sudo mv kubectl /usr/local/bin/# 验证安装 kubectl version --client --short获取阿里云集群配置文件--手动配置登录阿里云控制台进入「容器服务」->「集群」选择您的集群点击「连接信息」->「…

C++-linux系统编程 8.进程(二)exec函数族详解

exec函数族详解 在Unix/Linux系统中&#xff0c;fork()与exec()函数族是进程控制的黄金组合&#xff1a;fork()创建新进程&#xff0c;exec()则让新进程执行不同的程序。这种组合是实现shell命令执行、服务器进程动态加载任务等核心功能的基础。本文将详细解析exec函数族的原理…

PTL亮灯拣选系统提升仓库运营效率的方案

随着电商、零售、制造等行业的快速发展&#xff0c;仓库的作业效率成为企业竞争力的关键因素之一。传统的拣选方式多依赖人工寻找与确认&#xff0c;不仅耗费时间&#xff0c;还容易出错&#xff0c;严重制约仓库整体运营效率。为了应对日益增长的订单需求与提高拣选准确率&…

LVS三种模式实战

IPVS基本上是一种高效的Layer-4交换机&#xff0c;它提供负载平衡的功能。当一个TCP连接的初始SYN报文到达时&#xff0c;IPVS就选择一台服务器&#xff0c;将报文转发给它。此后通过查看报文的IP和TCP报文头地址&#xff0c;保证此连接的后继报文被转发到相同的服务器。这样&a…

HCIA第二次综合实验:OSPF

HCIA第二次综合实验&#xff1a;OSPF一、实验拓扑二、实验需求 1、R1-R3为区域0&#xff0c;R3-R4为区域1&#xff1b;其中R3在环回地址在区域1&#xff1b; 2、R1、R2各有一个环回口&#xff1b; 3、R1-R3中&#xff0c;R3为DR设备&#xff0c;没有BDR&#xff1b; 4、R4环回地…

深入解析环境变量:从基础概念到系统级应用

目录 一、基本概念及其核心作用 1、基本概念 2、核心作用 二、常见环境变量 三、查看环境变量方法 四、测试PATH 1、对比执行&#xff1a;./project和直接执行project的区别 2、思考&#xff1a;为何某些命令可直接执行而无需路径&#xff0c;但我们的二进制程序却需要…

Spring Boot:DTO 字段 cPlanId 无法反序列化的奇葩问题

本文记录一次在 Spring Boot 项目中&#xff0c;DTO 字段明明有值&#xff0c;反序列化后却是 null 的问题。最终发现并不是常见的 JSON 工具库 Bug&#xff0c;而是隐藏在 setter 命名大小写规则中的坑。&#x1f4bb; 背景介绍技术栈如下&#xff1a;Spring Boot&#xff1a;…

文本生成视频的主要开源模型

AI文本到视频生成技术发展迅速&#xff0c;这些模型的“快速”通常指相对于传统视频制作的效率&#xff08;生成时间从几秒到几分钟&#xff0c;取决于硬件&#xff09;&#xff0c;但实际速度取决于您的计算资源&#xff08;如GPU&#xff09;。这些模型大多依赖于深度学习框架…

vscode里面怎么配置ssh步骤

01.ubuntu里面下载几个插件还需要下载插件net-tools02.vscode里面下载插件会生成下面类似电视机的插件(room6)

【人工智能99问】激活函数有哪些,如何选择使用哪个激活函数?(5/99)

文章目录激活函数一、激活函数的分类1. 按“是否线性”分类2. 按“是否饱和”分类&#xff08;针对非线性激活函数&#xff09;3. 按“适用层”分类二、常见激活函数及特点&#xff08;一&#xff09;非线性激活函数&#xff08;主要用于隐藏层&#xff09;1. 饱和激活函数&…

代数——第4章——线性算子(算符)(Michael Artin)

第 4 章 线性算子(Linear Operators) That confusions of thought and errors of reasoning still darken the beginnings of Algebra, is the earnest and just complaint of sober and thoughtful men. (思维混乱和推理错误 仍然使代数的开端变得模糊不清&#xff0c; …

Neo4j Python 驱动库完整教程(带输入输出示例)

Neo4j Python 驱动库完整教程&#xff08;带输入输出示例&#xff09; 1. 基础连接示例 输入代码 from neo4j import GraphDatabase# 连接配置 URI "bolt://localhost:7687" USER "neo4j" PASSWORD "password123" # 替换为你的实际密码def t…

Axios 和 Promise 区别对比

Axios 和 Promise 是前端开发中两个不同的概念&#xff0c;尽管 Axios 基于 Promise 实现&#xff0c;但它们的核心定位和功能有显著区别。以下是对比分析&#xff1a; 1. 核心定位与功能Promise 定义&#xff1a;Promise 是 JavaScript 的异步编程方案&#xff0c;用于处理异步…

Git分支管理与工作流详解

前言 分支管理是Git最强大的功能之一&#xff0c;它允许开发者在不影响主代码库的情况下创建独立的工作空间。本文将详细介绍Git分支的操作和常见工作流策略&#xff0c;帮助团队更高效地协作开发。 1. Git分支的基本概念 1.1 什么是分支 在Git中&#xff0c;分支本质上是指…

【flutter】flutter网易云信令 + im + 声网rtm从0实现通话视频文字聊天的踩坑

接了一个国外的项目,项目采用网易云im 网易云信令声网rtm遇到的一些问题这个项目只对接口,给的工期是两周,延了工期,问题还是比较多的 需要全局监听rtm信息,收到监听内容,引起视频通话网易云给的文档太烂,所有的类型推策只能文档一点点推声网的rtm配置网易云的信令,坑太多,比如…