《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibili

Advance RNN

1、RNN分类问题

判断数据集中的每个名字所属的国家,共有18个国家类别

2、网络结构

①基础RNN

seq2seq,可以解决自动翻译问题

②简化RNN

利用最终的隐藏层状态 h_H 通过一个线性层来

③本例具体结构

3、输入数据

文本数据

数据中的每个名字,实际上是一个序列,每个字母是序列中的一个输入,处理远比想象中费力

每个名字长短不一,即序列之间本身的长度是不固定的。

4、代码部分啦

①Main Cycle

def time_since(since):
s = time.time() - since
m = math.floor(s / 60)
s -= m*60
return '%dm %ds' % (m, s) if __name__ == '__main__':
'''
N_CHARS:字符数量,英文字母转变为One-Hot向量
HIDDEN_SIZE:GRU输出的隐层的维度
N_COUNTRY:分类的类别总数
N_LAYER:GRU层数
'''
classifier = RNNClassifier(N_CHARS, HIDDEN_SIZE, N_COUNTRY, N_LAYER)
#迁移至GPU
if USE_GPU:
device = torch.device("cuda:0")
classifier.to(device) criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(classifier.parameters(), lr=0.001) # 记录训练的时长
start = time.time()
print("Training for %d epochs ... " % N_EPOCHS)
#记录训练准确率
acc_list = []
for epoch in range(1, N_EPOCHS+1):
#训练模型
trainModel()
#检测模型
acc = testModel()
acc_list.append(acc) #绘制图像
epoch = np.arange(1, len(acc_list)+1, 1)
acc_list = np.array(acc_list)
plt.plot(epoch, acc_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.grid()
plt.show()

  

②Preparing Data

先将【Name】单词拆分成 字符,再用ASCII作为字典

每一个ASCII码值实际上代表着一个长为128的独热向量,以77为例,即在77处为1,其余全部为0

为保证计算,需要将所有输入的名字填充至等长,即进行padding填充,使之能够成为矩阵(张量)

输出的国家类别形成分类索引

##Preparing Data
class NameDataset(Dataset):
def __init__(self, is_train_set=True): #读数据
filename = 'names_train.csv.gz' if is_train_set else 'names_test.csv.gz'
with gzip.open(filename, 'rt') as f:
reader = csv.reader(f)
rows = list(reader) #数据元组(name,country),将其中的name和country提取出来,并记录数量
self.names = [row[0] for row in rows]
self. len = len(self.names)
self.countries = [row[1] for row in rows] #将country转换成索引
#列表->集合->排序->列表->字典
# set将列表变成集合(去重)--排序--列表
self.country_list = list(sorted(set(self.countries)))
#列表->字典
self.country_dict = self.getCountryDict()
#获取长度
self.country_num = len(self.country_list) #name是字符串
#country是字典,获取键值对,country(key)-index(value)
def __getitem__(self, index):
return self.names[index], self.country_dict[self.countries[index]] def __len__(self):
return self.len def getCountryDict(self):
country_dict = dict()
for idx,country_name in enumerate(self.country_list, 0):
country_dict[country_name]=idx
return country_dict #根据索引返回国家名
def idx2country(self, index):
return self.country_list[index] #返回国家数目
def getCountriesNum(self):
return self.country_num # 参数设置
HIDDEN_SIZE = 100
BATCH_SIZE = 256
N_LAYER = 2 #GRU2层
N_EPOCHS = 100
N_CHARS = 128 #字典长度(ASCII码)
USE_GPU = False # 实例
trainset = NameDataset(is_train_set = True)
# 加载器
trainloader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True) testset = NameDataset(is_train_set=False)
testloader = DataLoader(testset, batch_size=BATCH_SIZE, shuffle=False) #最终的输出维度(国家类别数量)
N_COUNTRY = trainset.getCountriesNum()

  

③Model Design

## Model Design
class RNNClassifier(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size, n_layers =1 , bidirectional = True):
super(RNNClassifier, self).__init__()
self.hidden_size = hidden_size
self.n_layers = n_layers
self.n_directions = 2 if bidirectional else 1 #Embedding层输入 (SeqLen,BatchSize)
#Embedding层输出 (SeqLen,BatchSize,HiddenSize)
#将原先样本总数为SeqLen,批量数为BatchSize的数据,转换为HiddenSize维的向量
self.embedding = torch.nn.Embedding(input_size, hidden_size)
#bidirection用于表示神经网络是单向还是双向
self.gru = torch.nn.GRU(hidden_size, hidden_size, n_layers, bidirectional = bidirectional)
#线性层需要*direction
self.fc = torch.nn.Linear(hidden_size * self.n_directions, output_size) def _init_hidden(self):
hidden = torch.zeros(self.n_layers * self.n_directions, batch_size, self.hidden_size) return create_tensors(hidden) def forward(self, input, seq_length):
#对input进行转置:Batch x Seq -> Batch x Seq
input = input.t()
batch_size = input.size(1) #(n_Layer * nDirections, BatchSize, HiddenSize)
hidden = self._init_hidden(batch_size)
#(SeqLen, BatchSize, HiddenSize)
embedding = self.embedding(input) #对数据计算过程提速
#需要得到嵌入层的结果(输入数据)及每条输入数据的长度
gru_input = pack_padded_sequence(embedding, seq_length) output, hidden = self.gru(gru_input, hidden) #如果是双向神经网络会有h_N^f以及h_N^b两个hidden
if self.n_directions == 2:
hidden_cat = torch.cat([hidden[-1], hidden[-2]], dim=1)
else:
hidden_cat = hidden[-1] fc_output = self.fc(hidden_cat) return fc_output

  

Bi-direction RNN/LSTM/GRU

全面考虑上下文信息

对于RNN系列的网络而言,其输出包括output以及hidden两部分。

output:序列对应输出,也就是 h_1....h_N

hidden:hidden指的是隐含层最终输出结果,在双向网络中即为 h_f_N 和 h_b_N

数据转置

pack_padded_sequence

其原理在于,由于先前对于长短不一的数据需要填充0,而填充的0本质上不必参与运算,因此可以进行优化。

Embedding变换后的结果如图所示,其中深色部分为实际值为0即padding的部分。这部分可以不用参与运算。

***填充0的Embedding大小应该一样,下图有误***

Batch中的序列先按照序列长短进行降序排序

然后记录真正有意义的数字以及该序列的真正长度,最终返回一个PackedSequence对象

Name 转换成 Tensor

需要 Batch_size、Seq_size 和 每个name长度组成的list

转换过程:

字符串 → 字符 → ASCII码值 → Padding → 转置 → 排序

#ord()取ASCII码值
def name2list(name):
arr = [ord(c) for c in name]
return arr, len(arr) def create_tensor(tensor):
if USE_GPU:
device = torch.device("cuda:0")
tensor = tensor.to(device)
return tensor def make_tensors(names, countries):
sequences_and_length = [name2list(name) for name in names]
#取出所有的列表中每个姓名的ASCII码序列
name_sequences = [s1[0] for s1 in sequences_and_length]
#将列表车行度转换为LongTensor
seq_length = torch.LongTensor([s1[1] for s1 in sequences_and_length])
#将整型变为长整型
countries = countries.long() #做padding
#新建一个全0张量大小为最大长度-当前长度
seq_tensor = torch.zeros(len(name_sequences), seq_lengths.max()).long()
#取出每个序列及其长度idx固定0
for idx, (seq, seq_len) in enumerate(zip(name_sequences, seq_length), 0):
#将序列转化为LongTensor填充至第idx维的0到当前长度的位置
seq_tensor[idx, :seq_len] = torch.LongTensor(seq) #返回排序后的序列及索引
seq_length, perm_idx = seq_length.sort(dim = 0, descending = True)
seq_tensor = seq_tensor[perm_idx]
countries = countries[perm_idx] return create_tensor(seq_tensor),
create_tensor(seq_length),
create_tensor(countries)

  

④Training & Test

def trainModel():
total_loss = 0
for i, (names, countries) in enumerate(trainloader, 1):
inputs, seq_lengths, target = make_tensors(names, countries)
output = classifier(inputs, seq_lengths)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step() total_loss += loss.item() if i % 10 == 0:
print(f'[{time_since(start)}] Epoch {epoch} ', end='')
print(f'[{i * len(inputs)}/{len(train_set)}]', end='')
print(f'loss={total_loss / (i * len(inputs))}') return total_loss def testModel():
correct = 0
total = len(testset)
print("evaluating trained model……")
# 测试不需要求梯度
with torch.no_grad():
for i, (names, countries) in enumerate(testloader, 1):
inputs, seq_lengths, target = make_tensors(names, countries)
output = classifier(inputs, seq_lengths)
pred = output.max(dim=1, keepdim=True)[1]
correct += pred.eq(target.view_as(pred)).sum().item() percent = '%.2f' % (100*correct/total)
print(f'Test set: Accuracy {correct}/{total} {percent}%')
return correct/total

  

⑤完整代码

import torch
import matplotlib.pyplot as plt
import numpy as np
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
import gzip
import csv
import time
from torch.nn.utils.rnn import pack_padded_sequence
import math
#可不加
import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" ##Preparing Data
class NameDataset(Dataset):
def __init__(self, is_train_set=True): #读数据
filename = 'names_train.csv.gz' if is_train_set else 'names_test.csv.gz'
with gzip.open(filename, 'rt') as f:
reader = csv.reader(f)
rows = list(reader) #数据元组(name,country),将其中的name和country提取出来,并记录数量
self.names = [row[0] for row in rows]
self. len = len(self.names)
self.countries = [row[1] for row in rows] #将country转换成索引
#列表->集合->排序->列表->字典
# set将列表变成集合(去重)--排序--列表
self.country_list = list(sorted(set(self.countries)))
#列表->字典
self.country_dict = self.getCountryDict()
#获取长度
self.country_num = len(self.country_list) #name是字符串
#country是字典,获取键值对,country(key)-index(value)
def __getitem__(self, index):
return self.names[index], self.country_dict[self.countries[index]] def __len__(self):
return self.len def getCountryDict(self):
country_dict = dict()
for idx,country_name in enumerate(self.country_list, 0):
country_dict[country_name]=idx
return country_dict #根据索引返回国家名
def idx2country(self, index):
return self.country_list[index] #返回国家数目
def getCountriesNum(self):
return self.country_num # 参数设置
HIDDEN_SIZE = 100
BATCH_SIZE = 256
N_LAYER = 2 #GRU2层
N_EPOCHS = 100
N_CHARS = 128 #字典长度(ASCII码)
USE_GPU = False # 实例
trainset = NameDataset(is_train_set = True)
# 加载器
trainloader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True) testset = NameDataset(is_train_set=False)
testloader = DataLoader(testset, batch_size=BATCH_SIZE, shuffle=False) #最终的输出维度(国家类别数量)
N_COUNTRY = trainset.getCountriesNum() ## Model Design
class RNNClassifier(torch.nn.Module):
def __init__(self, input_size, hidden_size, output_size, n_layers =1 , bidirectional = True):
super(RNNClassifier, self).__init__()
self.hidden_size = hidden_size
self.n_layers = n_layers
self.n_directions = 2 if bidirectional else 1 #Embedding层输入 (SeqLen,BatchSize)
#Embedding层输出 (SeqLen,BatchSize,HiddenSize)
#将原先样本总数为SeqLen,批量数为BatchSize的数据,转换为HiddenSize维的向量
self.embedding = torch.nn.Embedding(input_size, hidden_size)
#bidirection用于表示神经网络是单向还是双向
self.gru = torch.nn.GRU(hidden_size, hidden_size, n_layers, bidirectional = bidirectional)
#线性层需要*direction
self.fc = torch.nn.Linear(hidden_size * self.n_directions, output_size) def _init_hidden(self, batch_size):
hidden = torch.zeros(self.n_layers * self.n_directions, batch_size, self.hidden_size) return hidden def forward(self, input, seq_length):
#对input进行转置:Batch x Seq -> Batch x Seq
input = input.t()
batch_size = input.size(1) #(n_Layer * nDirections, BatchSize, HiddenSize)
hidden = self._init_hidden(batch_size)
#(SeqLen, BatchSize, HiddenSize)
embedding = self.embedding(input) #对数据计算过程提速
#需要得到嵌入层的结果(输入数据)及每条输入数据的长度
gru_input = pack_padded_sequence(embedding, seq_length) output, hidden = self.gru(gru_input, hidden) #如果是双向神经网络会有h_N^f以及h_N^b两个hidden
if self.n_directions == 2:
hidden_cat = torch.cat([hidden[-1], hidden[-2]], dim=1)
else:
hidden_cat = hidden[-1] fc_output = self.fc(hidden_cat) return fc_output #ord()取ASCII码值
def name2list(name):
arr = [ord(c) for c in name]
return arr, len(arr) def create_tensor(tensor):
if USE_GPU:
device = torch.device("cuda:0")
tensor = tensor.to(device)
return tensor ## Name 转换成 Tensor
def make_tensors(names, countries):
sequences_and_length = [name2list(name) for name in names]
#取出所有的列表中每个姓名的ASCII码序列
name_sequences = [s1[0] for s1 in sequences_and_length]
#将列表车行度转换为LongTensor
seq_lengths = torch.LongTensor([s1[1] for s1 in sequences_and_length])
#将整型变为长整型
countries = countries.long() #做padding
#新建一个全0张量大小为最大长度-当前长度
seq_tensor = torch.zeros(len(name_sequences), seq_lengths.max()).long()
#取出每个序列及其长度idx固定0
for idx, (seq, seq_len) in enumerate(zip(name_sequences, seq_lengths), 0):
#将序列转化为LongTensor填充至第idx维的0到当前长度的位置
seq_tensor[idx, :seq_len] = torch.LongTensor(seq) #返回排序后的序列及索引
seq_lengths, perm_idx = seq_lengths.sort(dim = 0, descending = True)
seq_tensor = seq_tensor[perm_idx]
countries = countries[perm_idx] return create_tensor(seq_tensor), create_tensor(seq_lengths), create_tensor(countries) def trainModel():
total_loss = 0
for i, (names, countries) in enumerate(trainloader, 1):
inputs, seq_lengths, target = make_tensors(names, countries)
output = classifier(inputs, seq_lengths)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step() total_loss += loss.item() if i % 10 == 0:
print(f'[{time_since(start)}] Epoch {epoch} ', end='')
print(f'[{i * len(inputs)}/{len(trainset)}]', end='')
print(f'loss={total_loss / (i * len(inputs))}') return total_loss def testModel():
correct = 0
total = len(testset)
print("evaluating trained model……")
# 测试不需要求梯度
with torch.no_grad():
for i, (names, countries) in enumerate(testloader, 1):
inputs, seq_lengths, target = make_tensors(names, countries)
output = classifier(inputs, seq_lengths)
pred = output.max(dim=1, keepdim=True)[1]
correct += pred.eq(target.view_as(pred)).sum().item() percent = '%.2f' % (100*correct/total)
print(f'Test set: Accuracy {correct}/{total} {percent}%')
return correct/total def time_since(since):
s = time.time() - since
m = math.floor(s / 60)
s -= m*60
return '%dm %ds' % (m, s) if __name__ == '__main__':
'''
N_CHARS:字符数量,英文字母转变为One-Hot向量
HIDDEN_SIZE:GRU输出的隐层的维度
N_COUNTRY:分类的类别总数
N_LAYER:GRU层数
'''
classifier = RNNClassifier(N_CHARS, HIDDEN_SIZE, N_COUNTRY, N_LAYER)
#迁移至GPU
if USE_GPU:
device = torch.device("cuda:0")
classifier.to(device) criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(classifier.parameters(), lr=0.001) # 记录训练的时长
start = time.time()
print("Training for %d epochs ... " % N_EPOCHS)
#记录训练准确率
acc_list = []
for epoch in range(1, N_EPOCHS+1):
#训练模型
trainModel()
#检测模型
acc = testModel()
acc_list.append(acc) #绘制图像
epoch = np.arange(1, len(acc_list)+1, 1)
acc_list = np.array(acc_list)
plt.plot(epoch, acc_list)
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.grid()
plt.show()

运行结果:准确率最高 83.79%,训练100次,花费18分半钟

  

Pytorch实战学习(九):进阶RNN的更多相关文章

  1. 深度学习之PyTorch实战(1)——基础学习及搭建环境

    最近在学习PyTorch框架,买了一本<深度学习之PyTorch实战计算机视觉>,从学习开始,小编会整理学习笔记,并博客记录,希望自己好好学完这本书,最后能熟练应用此框架. PyTorch ...

  2. 深度学习之PyTorch实战(3)——实战手写数字识别

    上一节,我们已经学会了基于PyTorch深度学习框架高效,快捷的搭建一个神经网络,并对模型进行训练和对参数进行优化的方法,接下来让我们牛刀小试,基于PyTorch框架使用神经网络来解决一个关于手写数字 ...

  3. 对比学习:《深度学习之Pytorch》《PyTorch深度学习实战》+代码

    PyTorch是一个基于Python的深度学习平台,该平台简单易用上手快,从计算机视觉.自然语言处理再到强化学习,PyTorch的功能强大,支持PyTorch的工具包有用于自然语言处理的Allen N ...

  4. 参考《深度学习之PyTorch实战计算机视觉》PDF

    计算机视觉.自然语言处理和语音识别是目前深度学习领域很热门的三大应用方向. 计算机视觉学习,推荐阅读<深度学习之PyTorch实战计算机视觉>.学到人工智能的基础概念及Python 编程技 ...

  5. 『深度应用』NLP机器翻译深度学习实战课程·壹(RNN base)

    深度学习用的有一年多了,最近开始NLP自然处理方面的研发.刚好趁着这个机会写一系列NLP机器翻译深度学习实战课程. 本系列课程将从原理讲解与数据处理深入到如何动手实践与应用部署,将包括以下内容:(更新 ...

  6. 深度学习之PyTorch实战(2)——神经网络模型搭建和参数优化

    上一篇博客先搭建了基础环境,并熟悉了基础知识,本节基于此,再进行深一步的学习. 接下来看看如何基于PyTorch深度学习框架用简单快捷的方式搭建出复杂的神经网络模型,同时让模型参数的优化方法趋于高效. ...

  7. [原创].NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略

    原文:[原创].NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略 .NET 业务框架开发实战之九 Mapping属性原理和验证规则的实现策略 前言:之前的讨论一直关注在怎么从D ...

  8. PyTorch 实战:计算 Wasserstein 距离

    PyTorch 实战:计算 Wasserstein 距离 2019-09-23 18:42:56 This blog is copied from: https://mp.weixin.qq.com/ ...

  9. Python接口测试框架实战与自动化进阶✍✍✍

    Python接口测试框架实战与自动化进阶  整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看 ...

  10. Android学习笔记进阶之在图片上涂鸦(能清屏)

    Android学习笔记进阶之在图片上涂鸦(能清屏) 2013-11-19 10:52 117人阅读 评论(0) 收藏 举报 HandWritingActivity.java package xiaos ...

随机推荐

  1. WPF 使用动画绘制一个点赞大拇指

    效果图 好久没有写wpf了. 最近看到飞书的点赞动画非常有意思,决定试试,虽然不及飞书那样的绚丽,但是练手还是可以的,希望自己的手艺还在! 那么如何写一个这样的动画呢? 首先需要刨析这个动画的构成: ...

  2. JSTL标签库C标签的使用注意事项

    今天在写jsp中在c标签上踩了不少坑,在此记录一下. <c:if>标签单独使用,不与<c:otherwise>配套使用,搭配使用会报错. <c:otherwise> ...

  3. The Missing Semester - 第四讲 学习笔记

    第四讲 数据整理 课程视频地址:https://www.bilibili.com/video/BV1ym4y197iZ 课程讲义地址:https://missing-semester-cn.githu ...

  4. C++练习5 对引用进行初始化

    1 #include <iostream> 2 using namespace std; 3 int main() 4 { 5 const int cInt = 3;//定义常量cInt并 ...

  5. vue3语法糖+ts组件传值

    在开发中有些功能是通用的,而且逻辑大致相同,像这种东西可以封成一个组件,比较常用的就是函数封装,组件封装,组件封装是需要引入到页面使用的,所以通常它会有一些自己的方法,父子组件可以通过一些值来进行关联 ...

  6. echarts使用dataset数据集创建单轴散点图

    dataset创建单轴散点图 由于使用echarts作图时,我很喜欢用dataset作为数据源,但是官方案例中,有没有给出相关示例,于是,在翻阅官方文档相关案例之后,结合官方文档使用dataset的示 ...

  7. [代码审计基础 14]某cms变量覆盖到N处漏洞

    PHP:5.4.5 设置调试:https://blog.csdn.net/m0_46641521/article/details/120107786 PHPCMS变量覆盖到SQL注入 0x01:路由分 ...

  8. JZOJ 1075. 【GDKOI2006】新红黑树

    \(\text{Problem}\) A君和B君在玩一种叫做新红黑树的游戏,即在一棵由红枝和黑枝构成的树上轮流砍树枝,每次砍一枝,A君每次只能砍红枝,B君每次只能砍黑枝,当其中某人已经没有树枝砍的时候 ...

  9. Java语言输出菱形图型

    package fuxi;public class Diamond {    public static void main(String[] args) {        printHollowRh ...

  10. P5318 【深基18.例3】查找文献题解(链式前向星)

    P5318 [深基18.例3]查找文献题解 用head记录这一起点的最后一条边, next记录这一起点的上一条边. 注意要按照参考文献的倒叙排序(要按顺序看,而链式前向星是逆着来的,也就是为什么最简单 ...