当前位置: 首页 > news >正文

深度学习每周学习总结N4:中文文本分类-Pytorch实现(基本分类(熟悉流程)、textCNN分类(通用模型)、Bert分类(模型进阶))

  • 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
  • 🍖 原作者:K同学啊 | 接辅导、项目定制

目录

    • 0. 总结:
    • 1. 基础模型
      • a. 数据加载
      • b. 数据预处理
      • c. 模型搭建与初始化
      • d. 训练函数
      • e. 评估函数
      • f.拆分数据集运行模型
      • g. 结果可视化
      • h. 测试指定数据
    • 2. TextCNN(通用模型-待拓展)
    • 3. Bert(高级模型-待拓展)

0. 总结:

之前有学习过文本预处理的环节,对文本处理的主要方式有以下三种:

1:词袋模型(one-hot编码)

2:TF-IDF

3:Word2Vec(词向量(Word Embedding) 以及Word2vec(Word Embedding 的方法之一))

详细介绍及中英文分词详见pytorch文本分类(一):文本预处理

上上期主要介绍Embedding,及EmbeddingBag 使用示例(对词索引向量转化为词嵌入向量) ,上期主要介绍:应用三种模型的英文分类

本期将主要介绍中文基本分类(熟悉流程)、拓展:textCNN分类(通用模型)、拓展:Bert分类(模型进阶)

1. 基础模型

a. 数据加载

import torch
import torch.nn as nn
import torchvision
from torchvision import transforms,datasetsimport numpy as np
import pandas as pdimport os,PIL,pathlib,warnings
import matplotlib.pyplot as plt
import warningswarnings.filterwarnings("ignore") # 忽略警告信息
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False   # 用来正常显示负号
plt.rcParams['figure.dpi'] = 100  # 分辨率
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')
# 加载自定义中文数据集
train_data = pd.read_csv('./data/N4-train.csv',sep = '\t',header = None)
train_data.head()
01
0还有双鸭山到淮阴的汽车票吗13号的Travel-Query
1从这里怎么回家Travel-Query
2随便播放一首专辑阁楼里的佛里的歌Music-Play
3给看一下墓王之王嘛FilmTele-Play
4我想看挑战两把s686打突变团竞的游戏视频Video-Play
train_data[0]
0                  还有双鸭山到淮阴的汽车票吗13号的
1                            从这里怎么回家
2                   随便播放一首专辑阁楼里的佛里的歌
3                          给看一下墓王之王嘛
4              我想看挑战两把s686打突变团竞的游戏视频...             
12095          一千六百五十三加三千一百六十五点六五等于几
12096                      稍小点客厅空调风速
12097    黎耀祥陈豪邓萃雯畲诗曼陈法拉敖嘉年杨怡马浚伟等到场出席
12098                  百事盖世群星星光演唱会有谁
12099                 下周一视频会议的闹钟帮我开开
Name: 0, Length: 12100, dtype: object
# 构建数据迭代器
def custom_data_iter(texts,labels):for x,y in zip(texts,labels):yield x,ytrain_iter = custom_data_iter(train_data[0].values[:],train_data[1].values[:])

b. 数据预处理

# 构建词典
from torchtext.data.utils import get_tokenizer
from torchtext.vocab import build_vocab_from_iterator
import jieba# 中文分词方法
tokenizer = jieba.lcut # jieba.cut返回的是一个生成器,而jieba.lcut返回的是一个列表def yield_tokens(data_iter):for text,_ in data_iter:yield tokenizer(text)vocab = build_vocab_from_iterator(yield_tokens(train_iter),specials=["<unk>"])
vocab.set_default_index(vocab["<unk>"])
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\Cheng\AppData\Local\Temp\jieba.cache
Loading model cost 0.549 seconds.
Prefix dict has been built successfully.
tokenizer('我想看和平精英上战神必备技巧的游戏视频')
['我', '想', '看', '和平', '精英', '上', '战神', '必备', '技巧', '的', '游戏', '视频']
vocab(['我','想','看','和平','精英','上','战神','必备','技巧','的','游戏','视频'])
[2, 10, 13, 973, 1079, 146, 7724, 7574, 7793, 1, 186, 28]
text_pipeline = lambda x:vocab(tokenizer(x))
label_pipeline = lambda x:label_name.index(x)
label_name = list(set(train_data[1].values[:]))
print(label_name)
['HomeAppliance-Control', 'Audio-Play', 'Other', 'Weather-Query', 'Music-Play', 'Travel-Query', 'TVProgram-Play', 'Alarm-Update', 'Video-Play', 'Calendar-Query', 'FilmTele-Play', 'Radio-Listen']

print(text_pipeline('我想看和平精英上战神必备技巧的游戏视频'))
print(label_pipeline('Video-Play'))
[2, 10, 13, 973, 1079, 146, 7724, 7574, 7793, 1, 186, 28]
8
# 生成数据批次和迭代器
from torch.utils.data import DataLoaderdef collate_batch(batch):label_list,text_list,offsets = [],[],[0]for (_text,_label) in batch:# 标签列表label_list.append(label_pipeline(_label))# 文本列表processed_text = torch.tensor(text_pipeline(_text),dtype = torch.int64)text_list.append(processed_text)# 偏移量(即语句的总词汇量)offsets.append(processed_text.size(0))label_list = torch.tensor(label_list,dtype = torch.int64)text_list = torch.cat(text_list)offsets = torch.tensor(offsets[:-1]).cumsum(dim=0) # 返回维度dim中输入元素的累计和return text_list.to(device),label_list.to(device),offsets.to(device)# 数据加载器,调用示例
dataloader = DataLoader(train_iter,batch_size = 8,shuffle = False,collate_fn = collate_batch)

c. 模型搭建与初始化

from torch import nnclass TextClassificationModel(nn.Module):def __init__(self,vocab_size,embed_dim,num_class):super(TextClassificationModel,self).__init__()self.embedding = nn.EmbeddingBag(vocab_size,  # 词典大小embed_dim,   # 嵌入维度sparse=False)self.fc = nn.Linear(embed_dim,num_class)self.init_weights()def init_weights(self):initrange = 0.5self.embedding.weight.data.uniform_(-initrange,initrange) # 初始化权重self.fc.weight.data.uniform_(-initrange,initrange)self.fc.bias.data.zero_()def forward(self,text,offsets):embedded = self.embedding(text,offsets)return self.fc(embedded)
# 初始化模型
num_class = len(label_name)
vocab_size = len(vocab)
em_size = 64
model = TextClassificationModel(vocab_size,em_size,num_class).to(device)

d. 训练函数

import timedef train(dataloader):size = len(dataloader.dataset) # 训练集的大小num_batches = len(dataloader)  # 批次数目, (size/batch_size,向上取整)train_acc,train_loss = 0,0 # 初始化训练损失和正确率for idx,(text,label,offsets) in enumerate(dataloader):# 计算预测误差predicted_label = model(text,offsets)   # 网络输出loss = criterion(predicted_label,label) # 计算网络输出和真实值之间的差距,label为真实值,计算二者差值即为损失# 反向传播optimizer.zero_grad() # grad属性归零loss.backward() # 反向传播torch.nn.utils.clip_grad_norm_(model.parameters(),0.1)optimizer.step() # 每一步自动更新# 记录acc与losstrain_acc += (predicted_label.argmax(1) == label).sum().item()train_loss  += loss.item()train_acc /= sizetrain_loss /= num_batchesreturn train_acc,train_loss

e. 评估函数

import timedef evaluate(dataloader):test_acc,test_loss,total_count = 0,0,0with torch.no_grad():for idx,(text,label,offsets) in enumerate(dataloader):# 计算预测误差predicted_label = model(text,offsets)loss = criterion(predicted_label,label)# 记录测试数据test_acc += (predicted_label.argmax(1) == label).sum().item()test_loss += loss.item()total_count += label.size(0)return test_acc/total_count,test_loss/total_count

f.拆分数据集运行模型

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 trainingcriterion = 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 = custom_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)
import copytrain_acc = []
train_loss = []
test_acc = []
test_loss = []best_acc = None # 设置一个最佳准确率,作为最佳模型的判别指标for epoch in range(1, EPOCHS + 1):epoch_start_time = time.time()model.train() # 切换为训练模式epoch_train_acc,epoch_train_loss = train(train_dataloader)model.eval() # 切换为测试模式epoch_test_acc,epoch_test_loss = evaluate(valid_dataloader)if best_acc is not None and best_acc > epoch_test_acc:scheduler.step()else:best_acc = epoch_test_accbest_model = copy.deepcopy(model)train_acc.append(epoch_train_acc)train_loss.append(epoch_train_loss)test_acc.append(epoch_test_acc)test_loss.append(epoch_test_loss)# 获取当前的学习率lr = optimizer.state_dict()['param_groups'][0]['lr']template = ('Epoch:{:2d},Train_acc:{:.1f}%,Train_loss:{:.3f},Test_acc:{:.1f}%,Test_loss:{:.3f},Lr:{:.2E}')print(template.format(epoch,epoch_train_acc*100,epoch_train_loss,epoch_test_acc*100,epoch_test_loss,lr))print('Done!')
Epoch: 1,Train_acc:63.8%,Train_loss:1.339,Test_acc:79.5%,Test_loss:0.012,Lr:5.00E+00
Epoch: 2,Train_acc:83.2%,Train_loss:0.592,Test_acc:84.8%,Test_loss:0.008,Lr:5.00E+00
Epoch: 3,Train_acc:88.2%,Train_loss:0.413,Test_acc:86.8%,Test_loss:0.007,Lr:5.00E+00
Epoch: 4,Train_acc:91.1%,Train_loss:0.313,Test_acc:87.6%,Test_loss:0.006,Lr:5.00E+00
Epoch: 5,Train_acc:93.3%,Train_loss:0.241,Test_acc:89.8%,Test_loss:0.006,Lr:5.00E+00
Epoch: 6,Train_acc:95.0%,Train_loss:0.189,Test_acc:89.8%,Test_loss:0.006,Lr:5.00E-01
Epoch: 7,Train_acc:96.7%,Train_loss:0.144,Test_acc:89.6%,Test_loss:0.006,Lr:5.00E-02
Epoch: 8,Train_acc:96.8%,Train_loss:0.139,Test_acc:89.6%,Test_loss:0.006,Lr:5.00E-03
Epoch: 9,Train_acc:96.8%,Train_loss:0.139,Test_acc:89.6%,Test_loss:0.006,Lr:5.00E-04
Epoch:10,Train_acc:96.8%,Train_loss:0.139,Test_acc:89.6%,Test_loss:0.005,Lr:5.00E-05
Done!

g. 结果可视化

epochs_range = range(EPOCHS)plt.figure(figsize=(12,3))
plt.subplot(1,2,1)plt.plot(epochs_range,train_acc,label='Training Accuracy')
plt.plot(epochs_range,test_acc,label='Test Accuracy')
plt.legend(loc = 'lower right')
plt.title('Training and Validation Accuracy')plt.subplot(1,2,2)
plt.plot(epochs_range,train_loss,label='Train Loss')
plt.plot(epochs_range,test_loss,label='Test Loss')
plt.legend(loc = 'lower right')
plt.title('Training and Validation Loss')
plt.show()


在这里插入图片描述

h. 测试指定数据

注意以下俩种测试方法,必须保证模型和数据在同样的设备上(GPU或CPU)

def predict(text, text_pipeline):with torch.no_grad():text = torch.tensor(text_pipeline(text))output = model(text, torch.tensor([0]))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)])
该文本的类别是:Travel-Query

def predict(text, text_pipeline, model, device):model.eval()  # 切换为评估模式with torch.no_grad():# 将文本和偏移量张量都移动到相同的设备text = torch.tensor(text_pipeline(text)).to(device)offsets = torch.tensor([0]).to(device)output = model(text, offsets)return output.argmax(1).item()ex_text_str = "还有双鸭山到淮阴的汽车票吗13号的"# 确保模型在设备上
model = model.to(device)print("该文本的类别是:%s" % label_name[predict(ex_text_str, text_pipeline, model, device)])
该文本的类别是:Travel-Query

2. TextCNN(通用模型-待拓展)


3. Bert(高级模型-待拓展)


相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • tcp协议下的socket函数
  • DICOM CT\MR片子免费在线查看工具;python pydicom包加载查看;mayavi 3d查看
  • vxe-弹窗初始化激活选中Vxe-Table表格中第一行input输入框
  • debian 更新源
  • Spring Boot集成SFTP快速入门Demo
  • 独立站外链如何影响搜索引擎排名?
  • AI算法17-贝叶斯岭回归算法Bayesian Ridge Regression | BRR
  • C/C++ json库
  • 如何在电脑上演示手机上APP,远程排查移动端app问题
  • C#数字医学影像系统(RIS/PACS)源码,Oracle数据库,C/S架构,运行稳定
  • 入坑树莓派(2)——树莓派4B与手机蓝牙通信
  • vue使用了代理跨域,部署上线,使用Nginx配置出现问题,访问不到后端接口
  • 农业旅游与乡村旅游:融合绿色田野与诗意远方的经济新篇章
  • Zookeeper是什么,为什么要用,怎么用?
  • 探索数据的内在结构:使用Scikit-Learn确定聚类数
  • 【刷算法】从上往下打印二叉树
  • Angular 4.x 动态创建组件
  • Fundebug计费标准解释:事件数是如何定义的?
  • Mysql数据库的条件查询语句
  • Python进阶细节
  • Python连接Oracle
  • Tornado学习笔记(1)
  • Vue小说阅读器(仿追书神器)
  • yii2权限控制rbac之rule详细讲解
  • 从零搭建Koa2 Server
  • 二维平面内的碰撞检测【一】
  • 分布式事物理论与实践
  • - 概述 - 《设计模式(极简c++版)》
  • 简单易用的leetcode开发测试工具(npm)
  • 将 Measurements 和 Units 应用到物理学
  • 两列自适应布局方案整理
  • 写给高年级小学生看的《Bash 指南》
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • #pragma multi_compile #pragma shader_feature
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .net Signalr 使用笔记
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • @component注解的分类
  • @SpringBootConfiguration重复加载报错
  • [000-01-011].第2节:持久层方案的对比
  • [2016.7 day.5] T2
  • [Android]使用Git将项目提交到GitHub
  • [Android]通过PhoneLookup读取所有电话号码
  • [Angularjs]asp.net mvc+angularjs+web api单页应用
  • [AutoSar]状态管理(五)Dcm与BswM、EcuM的复位实现
  • [C++]Leetcode17电话号码的字母组合
  • [C++]命名空间等——喵喵要吃C嘎嘎
  • [codevs1288] 埃及分数
  • [Excel] vlookup函数
  • [GKCTF 2021]excel 骚操作1
  • [jQuery]使用jQuery.Validate进行客户端验证(中级篇-上)——不使用微软验证控件的理由...