作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/121802852


目录

第1章 预备知识

1.1 业务概述

1.2 CNN网络

1.3 CNN网络与LSTM网络的区别

1.4 LSTM网络的代码

第2章 代码准备 (Jupter)

2.1 代码与数据集下载

2.2 导入库

2.3 系统配置

第3章 构建数据集

3.1 构建单词表API

3.2 定义构建数据集API

3.3 构建三大数据集

3.4 构建迭代器

第4章 构建模型:CNN网络

4.1 定义模型类

4.2 实例化模型并显示模型结构

第5章 模型训练、评估

5.1 模型评估方法

5.2 模型训练方法

5.3 边训练、边评估模型

第6章 在测试集上对模型进行评估

6.1 测试方法的定义

6.2 开始测试




第1章 预备知识

1.1 业务概述

[Pytorch系列-59]:循环神经网络 - 中文新闻文本分类详解-1-业务目标分析与总体架构_文火冰糖(王文兵)的博客-CSDN博客https://blog.csdn.net/HiWangWenBing/article/details/121756744

1.2 CNN网络

(1)概述

本文使用CNN网络来实现具有时序记忆功能的文本分类应用。

我们会发现,通过合理的模型构建,

  • CNN网络具备与LSTM相似的准确率基本相当。
  • CNN网络具备与LSTM相当的复杂度。

(2) 如何为文本分类构建CNN网络

文本分类的CNN网络与图像分类的CNN网络,基本单元都是卷积核,然后,在具体实现时,与图像分类的CNN却不是完全相同的,需要一些特殊的处理。

这些特殊的处理包括:

  • 输入数据:把文本向量集与图像像素进行映射
  • CNN网络:按照文本向量数据的特点设计卷积核的形状

(3)输入数据

图片数据的数据格式为:通道数 * 长 * 宽 = 3 * 244 * 244

文本数据的格式为:通道数 * 长 * 宽 =  1 * 32 * 300

其中:

32: 表示单词的个数

300:表示词向量的长度

经过上述方法构建的输入数据,单词就不是独立的,单词与单词之间也就有了相邻关系和时序关系。一个新闻标题就等效为一张图片。

这是这种“图片”,不是正方形的图片,且只有一个通道,相当于灰色图片。

(4)如何通过卷积获取图片特征

Conv2d (in_channels, out_channels, kernel_size, stride=1,padding=0, dilation=1, groups=1,bias=True, padding_mode=‘zeros’)

  • in_channels:输入的通道数目 【必选】
  • out_channels: 输出的通道数目 【必选】
  • kernel_size:卷积核的大小,类型为int 或者元组,当卷积是方形的时候,只需要一个整数边长即可,卷积不是方形,要输入一个元组表示 高和宽。【必选】
  • stride: 卷积每次滑动的步长为多少,默认是 1 【可选】
  • padding: 设置在所有边界增加 值为 0 的边距的大小(也就是在feature map 外围增加几圈 0 ),例如当 padding =1 的时候,如果原来大小为 3 × 3 ,那么之后的大小为 5 × 5 。即在外围加了一圈 0 。【可选】

(5)如何通过卷积获取文本特征

  (convs): ModuleList((0): Conv2d(1, 256, kernel_size=(2, 300), stride=(1, 1))(1): Conv2d(1, 256, kernel_size=(3, 300), stride=(1, 1))(2): Conv2d(1, 256, kernel_size=(4, 300), stride=(1, 1))

卷积核的尺寸:

  • 宽度:与单词向量相同的size=300,stride的步长为1,因此,一次卷积核的移动,移动一个单词的词向量的长度。
  • 长度=2, 3, 4:这里有三种并行的卷积核,长度分别为2, 3, 4。2表示,一次卷积,覆盖相邻的2个单词。3表示,一次卷积,覆盖相邻的3个单词。4表示,一次卷积,覆盖相邻的4个单词。每种卷积核的个数是out_channels。

Cond2d输入输出:

  • in_channels=1:输入文本的通道数是1,而不是图片通道数3,因此文本数据相当于灰色图片。
  • out_channels=256:反应的相同卷积尺寸的卷积核的个数。

(6)池化层

池化层核的尺寸与卷积核的输出特征是相同尺寸

因此,池化核的输出是1*1

一共有 256 * 3 = 768个池化核的输出

(7)dropout

(dropout): Dropout(p=0.5, inplace=False)

(8)全连接层

(fc): Linear(in_features=768, out_features=10, bias=True)
  • in_features:256 * 3 = 768,来自池化层的输出。
  • out_features:10分类

1.3 CNN网络与LSTM网络的区别

本文的代码与LSTM网络的代码基本相同,除了如下的区别:

(1)系统配置:class Config(object):

# 模型参数
        self.filter_sizes = (2, 3, 4)                                   # 三层卷积核,卷积核尺寸
        self.num_filters = 256                                          # 卷积核数量(channels数)

(2)神经网络模型结构:class Model(nn.Module)

(3)神经网络的名称:model_name = "TextCNN"

(4)训练的输出结果:训练结果

1.4 LSTM网络的代码

[Pytorch系列-60]:循环神经网络 - 中文新闻文本分类详解-2-LSTM网络训练与评估代码详解_文火冰糖(王文兵)的博客-CSDN博客作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客本文网址:目录第1章 预备知识1.1 业务概述1.2 LSTM网络第2章 代码准备 (Jupter)2.1 代码与数据集下载2.2 导入库2.3系统配置第3章 构建数据集3.1 构建单词表API3.2 定义构建数据集API3.3 构建三大数据集3.4 构建迭代器第4章 构建模型:LSTM4.1 定义模型类4.2 实例化模型并显示模型结构4.3 初.https://blog.csdn.net/HiWangWenBing/article/details/121800521

第2章 代码准备 (Jupter)

2.1 代码与数据集下载

https://download.csdn.net/download/HiWangWenBing/60358291https://download.csdn.net/download/HiWangWenBing/60358291

2.2 导入库

import time
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from tensorboardX import SummaryWriter
from sklearn import metrics
import os
import torch
import numpy as np
import pickle as pkl
from tqdm import tqdm
import time
from datetime import timedelta

2.3 系统配置

(1)系统配置数据结构

class Config(object):"""配置参数"""def __init__(self, dataset, embedding):self.model_name = 'TextRNN'#数据集路径self.train_path = dataset + '/data/train.txt'                                # 训练集self.dev_path = dataset + '/data/dev.txt'                                    # 验证集self.test_path = dataset + '/data/test.txt'                                  # 测试集#类别文件self.class_list = [x.strip() for x in open(dataset + '/data/class.txt').readlines()]                                # 类别名单#单词表:是单词与其索引的对应表self.vocab_path = dataset + '/data/vocab.pkl'                                # 词表# 词向量表: 是索引与向量编码的对应表self.embedding_pretrained = torch.tensor(np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\if embedding != 'random' else None                                       # 预训练词向量self.embed = self.embedding_pretrained.size(1)\if self.embedding_pretrained is not None else 300           # 字向量维度, 若使用了预训练词向量,则维度统一# 训练数据保存self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt'        # 模型训练结果self.log_path = dataset + '/log/' + self.model_name# GPU or CPUself.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')   # 设备# 模型参数self.filter_sizes = (2, 3, 4)                                   # 三层卷积核,卷积核尺寸self.num_filters = 256                                          # 卷积核数量(channels数)# 训练时的参数self.dropout = 0.5                                              # 随机失活self.require_improvement = 1000                                 # 若超过1000batch效果还没提升,则提前结束训练self.num_classes = len(self.class_list)                         # 类别数self.n_vocab = 0                                                # 词表大小,在运行时赋值self.num_epochs = 20                                            # epoch数self.batch_size = 64                                           # mini-batch大小self.pad_size = 32                                              # 每句话处理成的长度(短填长切)self.learning_rate = 1e-3                                       # 学习率

(2)实例化配置对象

# 数据集目录
dataset = 'THUCNews'  # 搜狗新闻:embedding_SougouNews.npz, 腾讯:embedding_Tencent.npz, 随机初始化:random
embedding = 'embedding_SougouNews.npz'#通过空格分隔的英文单词还是中文的字符
word = False#初始化配置实例
config = Config(dataset, embedding)#显示配置信息
print(config.device)
print(config.embed)
print(config.embedding_pretrained)

第3章 构建数据集

3.1 构建单词表API

MAX_VOCAB_SIZE = 10000#新闻标题的填充,固定输入长度为32
UNK, PAD = '<UNK>', '<PAD>'# 单词表不是词向量表,而是单词与其索引对应关系的字典表。
# 从指定单词表中读取词向量表:
# file_path:单词表的路径
# tokenizer:分词器,与英文不同,中文的单词是仅仅相邻的,中间没有空格,因此需要分词器进行分词。
# max_size:单词的最大数量
# min_freq:单词表排序时的参考词频
def build_vocab(file_path, tokenizer, max_size, min_freq):# 单词表是一个字典vocab_dic = {}with open(file_path, 'r', encoding='UTF-8') as f:# 通过tqdm从单词表中读取一行单词,tqdm能够显示进度条for line in tqdm(f):# 移除字符串头尾指定的字符(默认为空格或换行符)或字符序列lin = line.strip()if not lin:#空行continue#按照空格或table键,把字符转换成短语列表content = lin.split('\t')[0]# 从列表中提取一个个独立的中文单词(即中文字)for word in tokenizer(content):# 构建单词字典表vocab_dic[word] = vocab_dic.get(word, 0) + 1#对单词表进行排序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填充单词表的尾部#  ,'<UNK>': 4760, '<PAD>': 4761}vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})return vocab_dic

3.2 定义构建数据集API

def build_dataset(config, ues_word):print("构建单词表")# 指定分词器print("ues_word=",ues_word)if ues_word:tokenizer = lambda x: x.split(' ')  # 以空格隔开,word-levelelse:tokenizer = lambda x: [y for y in x]  # char-level =》适合中文# load单词表if os.path.exists(config.vocab_path):# 如果有现成的单词表,则使用已有的单词表(单词与索引的字典)print("使用已有的单词表:", config.vocab_path)vocab = pkl.load(open(config.vocab_path, 'rb'))else:# 如果没有现成的单词表,则基于训练集,构建一个新的词表print("基于训练集,新构建单词表:", config.train_path)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)}")print("构建数据集")# 定义load和转换数据集的函数# 固定长度为32。def load_dataset(path, pad_size=32):contents = []print("数据集:", path)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')words_line = []token = tokenizer(content)seq_len = len(token)# 根据填充单词,确定有效字符长度:seq_lenif pad_size:if len(token) < pad_size:token.extend([vocab.get(PAD)] * (pad_size - len(token)))else:token = token[:pad_size]seq_len = pad_size#构建一个个样本数据for word in token:# 从单词表中获取每个单词对应的索引index,并添加到文字样本对应的列表中# words_line:存放当个样本数据(单词的index列表)words_line.append(vocab.get(word, vocab.get(UNK)))#contents:存放所有样本数据(单词的index列表)contents.append((words_line, int(label), seq_len))return contents  # [([...], 0), ([...], 1), ...]# load训练数据集train = load_dataset(config.train_path, config.pad_size)# load 验证数据集dev = load_dataset(config.dev_path, config.pad_size)# load 测试数据集test = load_dataset(config.test_path, config.pad_size)return vocab, train, dev, test

3.3 构建三大数据集

(1)构建数据集

def get_time_dif(start_time):"""获取已使用时间"""end_time = time.time()time_dif = end_time - start_timereturn timedelta(seconds=int(round(time_dif)))start_time = time.time()#构建三大数据集
print("Loading data...")
vocab, train_data, dev_data, test_data = build_dataset(config, word)# 更新词向量的长度
config.n_vocab = len(vocab)time_dif = get_time_dif(start_time)
print("Time usage:", time_dif)

(2)显示单词表

print(vocab)
{' ': 0, '0': 1, '1': 2, '2': 3, ':': 4, '大': 5, '国': 6, '图': 7, '(': 8, ')': 9, '3': 10, '人': 11, '年': 12, '5': 13, '中': 14, '新': 15, '9': 16, '生': 17, '金': 18, '高': 19, '《': 20, '》': 21, '4': 22, '上': 23, '8': 24, '不': 25, '考': 26, '一': 27, '6': 28, '日': 29, '元': 30, '开': 31, '美': 32, '价': 33, '发': 34, '学': 35, '公': 36, '成': 37, '月': 38, '将': 39, '万': 40, '7': 41, '基': 42, '市': 43, '出': 44, '子': 45, '行': 46, '机': 47, '业': 48, '被': 49, '家': 50, '股': 51, '的': 52, '在': 53, '网': 54, '女': 55, '期': 56, '平': 57, '房': 58, '名': 59, '三': 60, '-': 61, '会': 62, '地': 63, '场': 64, '全': 65, '小': 66, '现': 67, '有': 68, '分': 69, '后': 70, '称': 71, '组': 72, '为': 73, '下': 74, '盘': 75, '最': 76, '“': 7

........

737, '恫': 4738, '诣': 4739, '叁': 4740, '氮': 4741, '曳': 4742, '膑': 4743, '峦': 4744, '攫': 4745, '鹄': 4746, '啄': 4747, '憩': 4748, '鞑': 4749, '垠': 4750, '鹕': 4751, '鄞': 4752, '呸': 4753, 'V': 4754, '玷': 4755, '瘁': 4756, '蚱': 4757, '§': 4758, '霎': 4759, '<UNK>': 4760, '<PAD>': 4761}

(3)显示训练数据集

# 训练集索引是单词的索引
# 样本:
# 第一组数: 输入:32个单词序列的索引,文本新闻标题样本,转换成其索引,固定长度为32个单词,不足填充=》4760:PAD
# 第二个数:分类的类别
# 第三个数:有效字符的长度(不包括填充字符)# 训练集输入数据的长度(包括填充字符)
print(len(train_data[0][0]))#中华女子学院:本科层次仅1专业招男生  3
print(train_data[0])#两天价网站背后重重迷雾:做个网站究竟要多少钱  4
print(train_data[1])
32
([14, 125, 55, 45, 35, 307, 4, 81, 161, 941, 258, 494, 2, 175, 48, 145, 97, 17, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760], 3, 18)
([135, 80, 33, 54, 505, 1032, 70, 95, 95, 681, 2288, 4, 486, 179, 54, 505, 626, 1156, 180, 115, 421, 561, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760], 4, 22)

(3)显示验证数据集

print(dev_data[0])
print(dev_data[1])
([173, 714, 3, 186, 1844, 889, 0, 2641, 80, 2061, 416, 478, 382, 5, 308, 15, 1264, 1344, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760], 8, 18)
([28, 1, 12, 567, 1371, 31, 365, 899, 846, 1300, 1095, 256, 1311, 8, 72, 7, 9, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760], 5, 17)

(4)显示测试数据集

print(test_data[0])
print(test_data[1])
([1393, 686, 1350, 656, 110, 232, 1138, 0, 1, 24, 12, 26, 216, 1533, 56, 123, 434, 270, 742, 65, 112, 236, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760], 3, 22)
([14, 6, 11, 156, 36, 211, 5, 35, 3, 1, 2, 3, 12, 830, 324, 216, 626, 17, 334, 291, 461, 659, 334, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760, 4760], 3, 23)

3.4 构建迭代器

(1)定义类或函数

# 迭代器类
class DatasetIterater(object):def __init__(self, batches, batch_size, device):self.batch_size = batch_sizeself.batches = batchesself.n_batches = len(batches) // batch_sizeself.residue = False  # 记录batch数量是否为整数if len(batches) % self.n_batches != 0:self.residue = Trueself.index = 0self.device = devicedef _to_tensor(self, datas):x = torch.LongTensor([_[0] for _ in datas]).to(self.device)y = torch.LongTensor([_[1] for _ in datas]).to(self.device)# pad前的长度(超过pad_size的设为pad_size)seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)return (x, seq_len), y# 迭代函数def __next__(self):if self.residue and self.index == self.n_batches:batches = self.batches[self.index * self.batch_size: len(self.batches)]self.index += 1batches = self._to_tensor(batches)return batcheselif self.index > self.n_batches:self.index = 0raise StopIterationelse:batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]self.index += 1batches = self._to_tensor(batches)return batchesdef __iter__(self):return selfdef __len__(self):if self.residue:return self.n_batches + 1else:return self.n_batches# 构建迭代器的API
def build_iterator(dataset, config):iter = DatasetIterater(dataset, config.batch_size, config.device)return iter

(2)实例化

# 训练集loader
train_iter = build_iterator(train_data, config)# 验证集loader
dev_iter = build_iterator(dev_data, config)# 测试集loader
test_iter = build_iterator(test_data, config)print(train_iter)
<__main__.DatasetIterater object at 0x0000022804DAFD30>

第4章 构建模型:CNN网络

4.1 定义模型类

class Model(nn.Module):def __init__(self, config):super(Model, self).__init__()# 词向量网络if config.embedding_pretrained is not None:# 使用不需要重新训练的、预训练好的词向量,加快训练速度、提升性能self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)else:# 使用新定义的可训练的词词向量self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)# 卷积神经网络CNN# num_filters:卷积核的通道数# config.filter_sizes:卷积核尺寸:(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)# 全连接分类网络# 输入 = num_filters * len(config.filter_sizes) = 768 = 256 * 3# config.num_classes:输出分类数,10类self.fc = nn.Linear(config.num_filters * len(config.filter_sizes), config.num_classes)# 定义池化层def conv_and_pool(self, x, conv):x = F.relu(conv(x)).squeeze(3)x = F.max_pool1d(x, x.size(2)).squeeze(2)return xdef forward(self, x):#print (x[0].shape)out = self.embedding(x[0])out = out.unsqueeze(1)out = torch.cat([self.conv_and_pool(out, conv) for conv in self.convs], 1)out = self.dropout(out)out = self.fc(out)return out

4.2 实例化模型并显示模型结构

# 构建模型
#设定随机种子,确保每次随机初始化的结果是一样的
np.random.seed(1)
torch.manual_seed(1)
torch.cuda.manual_seed_all(1)
torch.backends.cudnn.deterministic = True  # 保证每次结果一样model_name = "TextRNN"# 创建模型实例
model = Model(config).to(config.device)#显示网络参数
for name, w in model.named_parameters():print(name)print(model.parameters)
embedding.weightconvs.0.weight
convs.0.bias
convs.1.weight
convs.1.bias
convs.2.weight
convs.2.bias
fc.weight
fc.bias<bound method Module.parameters of Model((embedding): Embedding(4762, 300)(convs): ModuleList((0): Conv2d(1, 256, kernel_size=(2, 300), stride=(1, 1))(1): Conv2d(1, 256, kernel_size=(3, 300), stride=(1, 1))(2): Conv2d(1, 256, kernel_size=(4, 300), stride=(1, 1)))(dropout): Dropout(p=0.5, inplace=False)(fc): Linear(in_features=768, out_features=10, bias=True)
)>
# 权重初始化:不同的初始化方法,导致精确性和收敛时间不同
# 默认xavier
# xavier:“Xavier”初始化方法是一种很有效的神经网络初始化方法
# kaiming:何凯明初始化
# normal_: 正态分布初始化
def init_network(model, method='xavier', exclude='embedding', seed=123):for name, w in model.named_parameters():if exclude not in name:if 'weight' in name:if method == 'xavier':nn.init.xavier_normal_(w)elif method == 'kaiming':nn.init.kaiming_normal_(w)else:nn.init.normal_(w)elif 'bias' in name:nn.init.constant_(w, 0)else:pass#初始化网络
init_network(model)

第5章 模型训练、评估

5.1 模型评估方法

# 模型评估方法
def evaluate(config, model, data_iter, test=False):# 设置在评估模式model.eval()loss_total = 0predict_all = np.array([], dtype=int)labels_all = np.array([], dtype=int)# 不进行梯度更新with torch.no_grad():# 数据集迭代for texts, labels in data_iter:# 模型预测输出outputs = model(texts)# 计算当前的lossloss = F.cross_entropy(outputs, labels)loss_total += loss# 计算当前的精度labels = labels.data.cpu().numpy()predic = torch.max(outputs.data, 1)[1].cpu().numpy()# 记录当前的label的数目labels_all = np.append(labels_all, labels)# 记录当前正确预测的数目predict_all = np.append(predict_all, predic)# 计算整个数据集上的平均精度acc = metrics.accuracy_score(labels_all, predict_all)if test:report = metrics.classification_report(labels_all, predict_all, target_names=config.class_list, digits=4)confusion = metrics.confusion_matrix(labels_all, predict_all)return acc, loss_total / len(data_iter), report, confusion# 返回整个数据集上的平均精度与平均lossreturn acc, loss_total / len(data_iter)

5.2 模型训练方法

# 训练方法
writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))def train(config, model, train_iter, dev_iter, writer):start_time = time.time()# 设定在模式下model.train()#设定优化器optimizer = torch.optim.Adam(model.parameters(), lr=config.learning_rate)# 学习率指数衰减,每次epoch:学习率 = gamma * 学习率# scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)total_batch = 0  # 记录进行到多少batch,一个训练集包含多个batch#记录当前最好的loss值dev_best_loss = float('inf')last_improve = 0  # 记录上次验证集loss下降的batch数flag = False  # 记录是否很久没有效果提升# 启动一个SummaryWriter对象,用于 记录训练过程writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))#开始训练for epoch in range(config.num_epochs):print('Epoch [{}/{}]'.format(epoch + 1, config.num_epochs))#自动调整学习率#scheduler.step() # 学习率衰减# 迭代数据集for i, (trains, labels) in enumerate(train_iter):#print (trains[0].shape)#获取模型输出outputs = model(trains)#复位模型梯度model.zero_grad()# 计算模型lossloss = F.cross_entropy(outputs, labels)# 根据loss计算梯度loss.backward()# 反向迭代,更新W参数optimizer.step()# 对迭代进行测试与评估# 每100次迭代输出,在训练集和验证集上的评估一次效果if total_batch % 100 == 0:# 获取训练集上的精度true = labels.data.cpu()predic = torch.max(outputs.data, 1)[1].cpu()train_acc = metrics.accuracy_score(true, predic)# 获取验证集上的精度dev_acc, dev_loss = evaluate(config, model, dev_iter, test=False)if dev_loss < dev_best_loss:dev_best_loss = dev_loss# 保存当前精度更高时候的模型torch.save(model.state_dict(), config.save_path)improve = '*'# 记录模型更新时的batch数last_improve = total_batchelse:improve = ''# 打印log信息time_dif = get_time_dif(start_time)msg = 'Iter: {0:>6},  Train Loss: {1:>5.2},  Train Acc: {2:>6.2%},  Val Loss: {3:>5.2},  Val Acc: {4:>6.2%},  Time: {5} {6}'print(msg.format(total_batch, loss.item(), train_acc, dev_loss, dev_acc, time_dif, improve))writer.add_scalar("loss/train", loss.item(), total_batch)writer.add_scalar("loss/dev", dev_loss, total_batch)writer.add_scalar("acc/train", train_acc, total_batch)writer.add_scalar("acc/dev", dev_acc, total_batch)#重新进入训练模式model.train()# batch数++total_batch += 1# 如果连续迭代后,精度没有得到进一步的提升,当次数得到一定的设定值后,自动停止迭代。# total_batch:连续进行了多少次batch# last_improve:记录模型更新时的batch数# config.require_improvementif total_batch - last_improve > config.require_improvement:# 验证集loss超过1000batch 没下降,结束训练print("No optimization for a long time, auto-stopping...")print("total_batch=", total_batch)print("last_improve=", last_improve)print("require_improvement=", config.require_improvement)flag = Truebreakif flag:breakwriter.close()

5.3 边训练、边评估模型

在训练集上训练,在验证集上评估

# 一边训练,一边评估
train(config, model, train_iter, dev_iter, writer)
Epoch [1/20]
Iter:      0,  Train Loss:   2.3,  Train Acc:  4.69%,  Val Loss:   2.6,  Val Acc: 13.59%,  Time: 0:00:00 *
Iter:    100,  Train Loss:   1.1,  Train Acc: 64.06%,  Val Loss:  0.79,  Val Acc: 75.50%,  Time: 0:00:02 *
Iter:    200,  Train Loss:  0.66,  Train Acc: 81.25%,  Val Loss:  0.65,  Val Acc: 79.40%,  Time: 0:00:04 *
Iter:    300,  Train Loss:  0.65,  Train Acc: 84.38%,  Val Loss:  0.56,  Val Acc: 82.18%,  Time: 0:00:06 *
Iter:    400,  Train Loss:  0.52,  Train Acc: 78.12%,  Val Loss:  0.51,  Val Acc: 84.03%,  Time: 0:00:08 *
Iter:    500,  Train Loss:  0.49,  Train Acc: 79.69%,  Val Loss:  0.48,  Val Acc: 85.09%,  Time: 0:00:10 *
.............................................................................
Iter:   7200,  Train Loss:  0.31,  Train Acc: 92.19%,  Val Loss:  0.33,  Val Acc: 90.02%,  Time: 0:02:17
Iter:   7300,  Train Loss:  0.25,  Train Acc: 93.75%,  Val Loss:  0.34,  Val Acc: 89.66%,  Time: 0:02:19
Iter:   7400,  Train Loss:  0.18,  Train Acc: 92.19%,  Val Loss:  0.33,  Val Acc: 89.92%,  Time: 0:02:21
Iter:   7500,  Train Loss:   0.3,  Train Acc: 89.06%,  Val Loss:  0.33,  Val Acc: 90.24%,  Time: 0:02:23
Iter:   7600,  Train Loss:  0.31,  Train Acc: 93.75%,  Val Loss:  0.33,  Val Acc: 89.81%,  Time: 0:02:25
No optimization for a long time, auto-stopping...
total_batch= 7601
last_improve= 6600
require_improvement= 1000

第6章 在测试集上对模型进行评估

6.1 测试方法的定义

# 在测试集上对模型进行评估
def test(config, model, test_iter):# test# 获取保存的最佳精度的模型model.load_state_dict(torch.load(config.save_path))# 进入评估模式model.eval()start_time = time.time()# 测试测试集进行评估test_acc, test_loss, test_report, test_confusion = evaluate(config, model, test_iter, test=True)# 打印测试集的评估结果# 测试集的loss和精度msg = 'Test Loss: {0:>5.2},  Test Acc: {1:>6.2%}'print(msg.format(test_loss, test_acc))# 打印准确率、召回率、F1-Score的分数print("Precision, Recall and F1-Score...")print(test_report)# 打印混淆矩阵print("Confusion Matrix...")print(test_confusion)time_dif = get_time_dif(start_time)print("Time usage:", time_dif)

备注:

至于模型的评分指标:Loss、accuracy、Precision, Recall and F1-Score,请参看相关文章。

6.2 开始测试

# 对训练好的模型进行测试
test(config, model, test_iter)
Test Loss:   0.3,  Test Acc: 90.50%
Precision, Recall and F1-Score...precision    recall  f1-score   supportfinance     0.9180    0.8840    0.9007      1000realty     0.9331    0.9200    0.9265      1000stocks     0.8651    0.8530    0.8590      1000education     0.9556    0.9480    0.9518      1000science     0.8402    0.8830    0.8610      1000society     0.8695    0.9260    0.8969      1000politics     0.9025    0.8610    0.8813      1000sports     0.9222    0.9600    0.9407      1000game     0.9290    0.9030    0.9158      1000
entertainment     0.9212    0.9120    0.9166      1000accuracy                         0.9050     10000macro avg     0.9056    0.9050    0.9050     10000weighted avg     0.9056    0.9050    0.9050     10000Confusion Matrix...
[[884  13  51   4  17   9   7  10   1   4][ 13 920  14   1   9  20   7   4   3   9][ 46  19 853   2  35   3  31   5   4   2][  2   2   4 948   7  17   7   5   0   8][  2   3  22   4 883  16  16   6  34  14][  4  16   1  15   8 926  15   3   2  10][  9   5  32   8  20  46 861  12   1   6][  1   2   1   1   3   9   4 960   4  15][  0   0   7   3  55   6   2  14 903  10][  2   6   1   6  14  13   4  22  20 912]]
Time usage: 0:00:00

作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/121802852

[Pytorch系列-61]:循环神经网络 - 中文新闻文本分类详解-3-CNN网络训练与评估代码详解相关推荐

  1. [Pytorch系列-60]:循环神经网络 - 中文新闻文本分类详解-2-LSTM网络训练与评估代码详解

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  2. 人工智能--基于循环神经网络的新闻话题分类

    学习目标: 理解循环神经网络RNN的基本原理. 掌握利用循环神经网络进行文本分类的方法. 学习内容: 利用循环神经网络进行新闻话题分类的代码,设置Embedding的trainable=True,并调 ...

  3. 基于 LSTM-Attention 的中文新闻文本分类

    1.摘 要 经典的 LSTM 分类模型,一种是利用 LSTM 最后时刻的输出作为高一级的表示,而另一种是将所有时刻的LSTM 输出求平均作为高一级的表示.这两种表示都存在一定的缺陷,第一种缺失了前面的 ...

  4. NLP实战-中文新闻文本分类

    目录 1.思路 2.基于paddle的ERINE模型进行迁移学习训练 3.分步实现 3.1 获取数据 (1)数据解压 (2)将文本转成变量,这里为了好计算,我只选了新闻标题做文本分类 3.2 中文分词 ...

  5. 基于GPT2实现中文新闻文本分类任务

    前言 大家好,我是阿光. 本专栏整理了<PyTorch深度学习项目实战100例>,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集. 正在更新 ...

  6. 基于神经网络语言模型的中文新闻文本聚类算法

    一.新闻文本集  其中  通过TF-IDF排序 中的词(由大到小),选择其中的 t 个词作为关键字,,是对应关键字的TF-IDF值. 二.神经网络语言模型 输入:该词的上下文中相邻的几个词向量(词袋模 ...

  7. 卷积神经网络实现THUCNews新闻文本分类(Pytorch实现)

    代码结构 整体代码结构如下图所示: 点击run.py文件,直接运行.可以手动调节参数以及更换模型 1数据集 本文采用的数据集属于清华NLP组提供的THUCNews新闻文本分类数据集的一个子集(原始的数 ...

  8. Paddle2.0实现中文新闻文本标题分类

    Paddle2.0实现中文新闻文本标题分类 中文新闻文本标题分类Paddle2.0版本基线(非官方) 调优小建议 数据集地址 任务描述 数据说明 提交答案 代码思路说明 数据集解压 数据处理 数据读取 ...

  9. 深度学习实战3-文本卷积神经网络(TextCNN)新闻文本分类

    文章目录 一.前期工作 1. 设置GPU 2. 导入预处理词库类 二.导入预处理词库类 三.参数设定 四.创建模型 五.训练模型函数 六.测试模型函数 七.训练模型与预测 今天给大家带来一个简单的中文 ...

最新文章

  1. 2019最后一期—宏基因组分析技术研讨会
  2. ActionBar右边菜单按钮的添加
  3. 网站建设技术方案_企业网站建设解决方案
  4. 文件 在线压缩 技术
  5. 已知线性表最多可能有20个元素,存储每个元素需要8字节,存储每个指针需要4字节。当元素个数为( )时使用单链表比使用数组存储此线性表更加节约空间。
  6. 学生信息的电子化管理考试题
  7. 为什么以前的电视一打雷就容易烧坏,现在的电视就不那么怕雷?
  8. LINUX中注销其他已登陆帐户
  9. DeepStream插件Gstreamer(一):插件汇总
  10. [转]Android学习系列(1)--为App签名(为apk签名)
  11. 在B/S系统中引入定时器的功能
  12. 最新linux 编程视频教程下载
  13. echarts散列图示例
  14. CSS颜色和背景详解- 背景颜色 - 背景图片 - (color background-color background-image...)
  15. conda 解决An HTTP error occurred when trying to retrieve this URL.
  16. 武林外传服务器时间修改,浅谈武林外传关于2021年4月29日大合区
  17. 三大变换与自控(二)傅里叶级数的复数形式推导
  18. Java程序设置的目的_java程序设计教学大纲的课程性质与目的.doc
  19. 【最优化算法】基于【MATLAB】的最速下降仿真
  20. 骁龙780G和麒麟990哪个好

热门文章

  1. “机器学习实战”刻意练习1/8周
  2. ISO 32000-2 国际标准7.7
  3. win7设置电脑锁屏时间
  4. Mysql查看表的数据量
  5. BPSK码元速率与带宽的关系
  6. hadoop是什么?特点?
  7. idea 编译时,报“编码GBK的不可映射字符”
  8. selenium打开chrome浏览器无痕模式
  9. JS中正则表达式常用语法总结
  10. 如何获得coredump