最近学RNN的时候对于其中各种输入输出都有点懵,然后参考了刘二大人关于pytorch实践以及下面这篇文章Pytorch深度学习实践(b站刘二大人)P13讲 (RNN循环神经网络高级篇)_努力学习的朱朱的博客-CSDN博客代码把维度问题整理了一下

一、pytorch中embedding在做什么?

我们先看下面这一段代码:

import torch
embedding = torch.nn.Embedding(10, 3)
print(embedding.weight)  # 根据索引取embedding中的词向量
input = torch.LongTensor([[0,2,4,5],[4,3,2,0]])
output = embedding(input)
print(output)
print(output.shape)

这段代码输出如下:

Parameter containing:
tensor([[ 0.1540, -0.8776, -0.9737],[-2.0864, -1.1387, -1.9999],[ 0.3297,  1.2760,  0.4246],[-0.4424,  1.0758, -1.3849],[ 0.6420, -2.5247, -1.1060],[ 1.0529,  1.3949, -1.0098],[ 1.1634, -1.1316, -0.1378],[ 1.3910,  0.9718,  0.1931],[-1.9672, -0.5770,  1.0776],[-0.4043, -0.9368,  3.2478]], requires_grad=True)
tensor([[[ 0.1540, -0.8776, -0.9737],[ 0.3297,  1.2760,  0.4246],[ 0.6420, -2.5247, -1.1060],[ 1.0529,  1.3949, -1.0098]],[[ 0.6420, -2.5247, -1.1060],[-0.4424,  1.0758, -1.3849],[ 0.3297,  1.2760,  0.4246],[ 0.1540, -0.8776, -0.9737]]], grad_fn=<EmbeddingBackward0>)
torch.Size([2, 4, 3])

我们可以看到embedding就是跟我我们设置的参数(词典大小vocab_size,词嵌入向量大小embedding_dim)随机生成一个对应维度的向量矩阵,而nn.embedding就相当于根据对应input的index在这个矩阵中取向量,比如input中[0,2,4,5]就对应了向量矩阵中的第0行,第2行,第4行以及第5行。在这个过程中,输入维度是【batch_size, seq_len】(批量大小,句子长度),输出维度是【batch_size, seq_len, embedding_size】。注意,在实际运用过程中输入【batch_size, seq_len】要进行转置再输入,这里写的是没有经过转置的对应维度,仅为了理解embedding的作用。

二、batch_size与seq_len

在TensorFlow中有专门的seq_len来对应于句子长度,但是pytorch中参数如下:

class torch.nn.LSTM(*args, **kwargs) :input_size:x的特征维度
hidden_size:隐藏层的特征维度
num_layers:lstm隐层的层数,默认为1
bias:False则bihbih=0和bhhbhh=0. 默认为True
batch_first:True则输入输出的数据格式为 (batch, seq, feature)
dropout:除最后一层,每一层的输出都进行dropout,默认为: 0
bidirectional:True则为双向lstm默认为False

显然是没有seq_len,那么在pytorch中我们是怎么解决这个问题的呢?这就需要我们自己在数据输入LSTM前将数据进行padding为同一纬度的向量,对于pytorch中LSTM来说,只要保证每一个batch中的seq_len相同即可。一般来说我们有两种方法:

1.自己构造DataLoader:将每个batch_size中的句子都填充为该batch中最长句子的长度(该方法后面讲)

2.用pytorch中的torch.utils.data.Data.TensorDataset和torch.utils.data.DataLoader,使用这个就需要在最开始就把句子都padding为同一长度,用下面方法:

def truncate_pad(line, num_steps, padding_token):"""截断或填充文本序列"""if len(line) > num_steps:return line[:num_steps]  # 截断return line + [padding_token] * (num_steps - len(line))  # 填充num_steps = 100  #设置padding维度
train_features = torch.tensor([truncate_pad(vocab[line], num_steps, vocab['<pad>']) for line in tokens])train_dataset = Data.TensorDataset(X_train, torch.tensor(y_train))  #构造为Datasettrainloader = DataLoader(train_dataset, batch_size=BATCH_SIZE,shuffle=True)  #构造为DataLoader

三、RNN模型的维度

下面就用刘二大人pytorch教学(《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibili)中的例子来看看数据在LSTM中流转过程各个维度是怎样的

import torch
import random
import  time
import csv
import gzip
from  torch.utils.data import DataLoader
import datetime
import matplotlib.pyplot as plt
import numpy as np# Parameters
HIDDEN_SIZE = 100
BATCH_SIZE = 32
N_LAYER = 2
N_EPOCHS = 20
N_CHARS = 128
USE_GPU = Falseclass NameDataset():         #处理数据集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)random.shuffle(rows)rows = rows[:256]self.names = [row[0] for row in rows]   #取出人名self.len = len(self.names)              #人名数量self.countries = [row[1] for row in rows]#取出国家名self.country_list = list(sorted(set(self.countries)))#国家名集合,18个国家名的集合#countrys是所有国家名,set(countrys)把所有国家明元素设为集合(去除重复项),sorted()函数是将集合排序#测试了一下,实际list(sorted(set(self.countrys)))==sorted(set(self.countrys))self.country_dict = self.getCountryDict()#转变成词典self.country_num = len(self.country_list)#得到国家集合的长度18def __getitem__(self, index):return self.names[index], self.country_dict[self.countries[index]]def __len__(self):return self.lendef getCountryDict(self):country_dict = dict()                                       #创建空字典for idx, country_name in enumerate(self.country_list,0):    #取出序号和对应国家名country_dict[country_name] = idx                        #把对应的国家名和序号存入字典return country_dictdef idx2country(self,index):            #返回索引对应国家名return self.country_list(index)def getCountrysNum(self):               #返回国家数量return self.country_numtrainset = 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)for item in trainloader:print(item)N_COUNTRY = trainset.getCountrysNum() 

为了方便展示,我只选择了其中256来演示,我们可以看一下样本转为dataloader后的样子:

每一个batch由32个名字和对应国家组成,接下俩我们需要将其转变为向量

def name2list(name):"""返回ASCII码表示的姓名列表与列表长度"""arr = [ord(c) for c in name]return arr, len(arr)def make_tensors(names, countries):sequences_and_lengths = [name2list(name) for name in names]表name_sequences = [sl[0] for sl in sequences_and_lengths]seq_lengths = torch.LongTensor([sl[1] for sl in sequences_and_lengths])countries = countries.long()seq_tensor = torch.zeros(len(name_sequences), seq_lengths.max()).long()for idx, (seq, seq_len) in enumerate(zip(name_sequences, seq_lengths), 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 seq_tensor, seq_lengths, countries

这段代码做的其实就是把每个batch转化为每个名字长度一致的向量,每一个batch向量维度为:batch*seq_len

我们可以看一下处理后的数据:

for i, (names, countries) in enumerate(trainloader, 1):print('names',names, 'Coounties',countries)inputs, seq_lengths, target = make_tensors(names, countries)print('inputs, seq_lengths, target',inputs, seq_lengths, target)print('inputs.shape',inputs.shape)
names ('Balawin', 'Likhovtsev', 'Cullen', 'Abadi', 'Uzky', 'Moshnyaga', 'Abrosimov', 'Fencl', 'Antar', 'Pastore', 'Matjeka', 'Larsen', 'Mikhalkov', 'Chavez', 'Agoshkov', 'Hasek', 'Fedotko', 'Koury', 'Winter', 'Hautem', 'Dioli', 'Chershintsev', 'Herbert', 'Anami', 'Makferson', 'Christakos', 'Molnovetsky', 'Tsagareli', 'Hublaryan', 'Matskovsky', 'Radford', 'Antyushin') Coounties tensor([13, 13,  4,  0, 13, 13, 13,  2,  0,  9,  2,  4, 13, 14, 13,  6, 13,  0,4,  3,  9, 13,  4, 10, 13,  7, 13, 13, 13, 13,  4, 13])
inputs, seq_lengths, target tensor([[ 67, 104, 101, 114, 115, 104, 105, 110, 116, 115, 101, 118],[ 77, 111, 108, 110, 111, 118, 101, 116, 115, 107, 121,   0],[ 76, 105, 107, 104, 111, 118, 116, 115, 101, 118,   0,   0],[ 67, 104, 114, 105, 115, 116,  97, 107, 111, 115,   0,   0],[ 77,  97, 116, 115, 107, 111, 118, 115, 107, 121,   0,   0],[ 77, 111, 115, 104, 110, 121,  97, 103,  97,   0,   0,   0],[ 65,  98, 114, 111, 115, 105, 109, 111, 118,   0,   0,   0],[ 77, 105, 107, 104,  97, 108, 107, 111, 118,   0,   0,   0],[ 77,  97, 107, 102, 101, 114, 115, 111, 110,   0,   0,   0],[ 84, 115,  97, 103,  97, 114, 101, 108, 105,   0,   0,   0],[ 72, 117,  98, 108,  97, 114, 121,  97, 110,   0,   0,   0],[ 65, 110, 116, 121, 117, 115, 104, 105, 110,   0,   0,   0],[ 65, 103, 111, 115, 104, 107, 111, 118,   0,   0,   0,   0],[ 66,  97, 108,  97, 119, 105, 110,   0,   0,   0,   0,   0],[ 80,  97, 115, 116, 111, 114, 101,   0,   0,   0,   0,   0],[ 77,  97, 116, 106, 101, 107,  97,   0,   0,   0,   0,   0],[ 70, 101, 100, 111, 116, 107, 111,   0,   0,   0,   0,   0],[ 72, 101, 114,  98, 101, 114, 116,   0,   0,   0,   0,   0],[ 82,  97, 100, 102, 111, 114, 100,   0,   0,   0,   0,   0],[ 67, 117, 108, 108, 101, 110,   0,   0,   0,   0,   0,   0],[ 76,  97, 114, 115, 101, 110,   0,   0,   0,   0,   0,   0],[ 67, 104,  97, 118, 101, 122,   0,   0,   0,   0,   0,   0],[ 87, 105, 110, 116, 101, 114,   0,   0,   0,   0,   0,   0],[ 72,  97, 117, 116, 101, 109,   0,   0,   0,   0,   0,   0],[ 65,  98,  97, 100, 105,   0,   0,   0,   0,   0,   0,   0],[ 70, 101, 110,  99, 108,   0,   0,   0,   0,   0,   0,   0],[ 65, 110, 116,  97, 114,   0,   0,   0,   0,   0,   0,   0],[ 72,  97, 115, 101, 107,   0,   0,   0,   0,   0,   0,   0],[ 75, 111, 117, 114, 121,   0,   0,   0,   0,   0,   0,   0],[ 68, 105, 111, 108, 105,   0,   0,   0,   0,   0,   0,   0],[ 65, 110,  97, 109, 105,   0,   0,   0,   0,   0,   0,   0],[ 85, 122, 107, 121,   0,   0,   0,   0,   0,   0,   0,   0]]) tensor([12, 11, 10, 10, 10,  9,  9,  9,  9,  9,  9,  9,  8,  7,  7,  7,  7,  7,7,  6,  6,  6,  6,  6,  5,  5,  5,  5,  5,  5,  5,  4]) tensor([13, 13, 13,  7, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,  9,  2, 13,  4,4,  4,  4, 14,  4,  3,  0,  2,  0,  6,  0,  9, 10, 13])
inputs.shape torch.Size([32, 12])

这里展示的就是一个batch的数据情况,接下来就开始构造我们的RNN模型,这里用的是GRU

class RNNClassifier(torch.nn.Module):def __init__(self, vocab_size, embedding_size, output_size, n_layers=1, bidirectional=True):super(RNNClassifier, self).__init__()self.hidden_size = embedding_size self.n_layers = n_layersself.n_directions = 2 if bidirectional else 1self.embedding = torch.nn.Embedding(vocab_size, embedding_size)#input.shape=(seqlen,batch) output.shape=(seqlen,batch,hiddensize)self.gru = torch.nn.GRU(embedding_size, self.hidden_size , n_layers, bidirectional=bidirectional)                               self.fc = torch.nn.Linear(self.hidden_size * self.n_directions, output_size)def forward(self, input, seq_lengths):input = input.t()               print('input.shape',input.shape)batch_size = input.size(1)hidden =self._init_hidden(batch_size)print('hidden shape',hidden.shape)embedding = self.embedding(input)print('embedding shape',embedding.shape)seq_lengths = seq_lengths.cpu()output, hidden = self.gru(embedding, hidden)print("output, hidden",output.shape, hidden.shape)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_outputdef _init_hidden(self,batch_size):hidden = torch.zeros(self.n_layers * self.n_directions, batch_size, self.hidden_size)return  create_tensor(hidden)

然后开始训练模型

def trainModel():total_loss = 0for i, (names, countries) in enumerate(trainloader, 1):optimizer.zero_grad()inputs, seq_lengths, target = make_tensors(names, countries)output = classifier(inputs, seq_lengths)    #把输入和序列放入分类器loss = criterion(output, target)            #计算损失loss.backward()optimizer.step()total_loss += loss.item()#打印输出结果if i == len(trainset) // BATCH_SIZE :print(f'loss={total_loss / (i * len(inputs))}')return total_lossprint("Train for %d epochs..." % N_EPOCHS)
classifier = RNNClassifier(N_CHARS, HIDDEN_SIZE, N_COUNTRY, N_LAYER)
if USE_GPU:device = torch.device('cuda:0')classifier.to(device)criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(classifier.parameters(), lr = 0.001)   for epoch in range(1, N_EPOCHS+1):#训练print('%d / %d:' % (epoch, N_EPOCHS))trainModel()

我们可以看一下维度的情况(只截取了部分结果):,

Train for 20 epochs...
1 / 20:
input.shape torch.Size([10, 32])
hidden shape torch.Size([4, 32, 100])
embedding shape torch.Size([10, 32, 100])
output, hidden torch.Size([10, 32, 200]) torch.Size([4, 32, 100])
input.shape torch.Size([14, 32])
hidden shape torch.Size([4, 32, 100])
embedding shape torch.Size([14, 32, 100])
output, hidden torch.Size([14, 32, 200]) torch.Size([4, 32, 100])
input.shape torch.Size([13, 32])
hidden shape torch.Size([4, 32, 100])
embedding shape torch.Size([13, 32, 100])
output, hidden torch.Size([13, 32, 200]) torch.Size([4, 32, 100])

input就是我们经过向量化的一个batch向量,因为在这里进行了转置,由之前的(batch_size, seq_len)变为了(seq_len,batch_size),其中seq_len就对应于一个batch中最长的单词(句子)长度

hidden就是GRU中隐藏层输出(最开始我们先初始化h0),它对应的维度是(n_layers * n_directions, batch_size, hidden_size)

embedding代表的是input经过nn.Embedding层计算后得到的结果,他的维度是:(seq_len,batch_size, embedding_size)

经过GRU模型后有两个输出结果,output:(seq_len, batch, n_directions*hidden_size),hn:(n_layers*n_directions, batch, hiddem_size)

这里的output和hn分别对应的是中间所有输出以及最后隐藏层输出:

 也可以直接看官方说明:

这篇文章主要讲了一下RNN模型的维度问题,希望对大家有帮助!

RNN(pytorch)的维度问题——用GRU实现文本分类(参考刘二大人)相关推荐

  1. 【从线性回归到 卷积神经网络CNN 循环神经网络RNN Pytorch 学习笔记 目录整合 源码解读 B站刘二大人 绪论(0/10)】

    深度学习 Pytorch 学习笔记 目录整合 数学推导与源码详解 B站刘二大人 目录传送门: 线性模型 Linear-Model 数学原理分析以及源码详解 深度学习 Pytorch笔记 B站刘二大人( ...

  2. 《PyTorch深度学习实践》完结合集--B站刘二大人学习总结

    本篇主要是各类模型的基本介绍及应用,不涉及深层技术. 学习视频指路→B站指路 代码实践指路→代码指路 课件获取:通过百度网盘分享的文件:PyTorch深- 链接:https://pan.baidu.c ...

  3. 【Pytorch深度学习实践】B站up刘二大人课程笔记——目录与索引(已完结)

    从有代码的课程开始讨论 [Pytorch深度学习实践]B站up刘二大人之LinearModel -代码理解与实现(1/9) [Pytorch深度学习实践]B站up刘二大人之 Gradient Desc ...

  4. 【卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10)】

    卷积神经网络CNN 实战案例 GoogleNet 实现手写数字识别 源码详解 深度学习 Pytorch笔记 B站刘二大人 (9.5/10) 在上一章已经完成了卷积神经网络的结构分析,并通过各个模块理解 ...

  5. 【 数据集加载 DatasetDataLoader 模块实现与源码详解 深度学习 Pytorch笔记 B站刘二大人 (7/10)】

    数据集加载 Dataset&DataLoader 模块实现与源码详解 深度学习 Pytorch笔记 B站刘二大人 (7/10) 模块介绍 在本节中没有关于数学原理的相关介绍,使用的数据集和类型 ...

  6. 【Pytorch深度学习实践】B站up刘二大人之 Gradient Descend-代码理解与实现(2/9)

    开篇几句题外话: 以往的代码,都是随便看看就过去了,没有这样较真过,以至于看了很久的深度学习和Python,都没有能够形成编程能力: 这次算是废寝忘食的深入进去了,踏实地把每一个代码都理解透,包括其中 ...

  7. 自然语言处理入门实战——基于循环神经网络RNN、LSTM、GRU的文本分类(超级详细,学不会找我!!!)

    1  一.实验过程 1.1  实验目的 通过这个课程项目大,期望达到以下目的: 1.了解如何对 自然语言处理 的数据集进行预处理操作. 2.初识自然语言数据集处理操作的步骤流程. 3.进一步学习RNN ...

  8. pytorch创建模型并训练(初探文本分类问题)

        本博客对pytorch在深度学习上的使用进行了介绍,本博客并不会对怎么训练一个好的模型进行介绍(其实我也不会),我觉得训练一个好的模型首先得选对一个模型(关键的问题在于模型如何设计),然后再经 ...

  9. 【多输入模型 Multiple-Dimension 数学原理分析以及源码详解 深度学习 Pytorch笔记 B站刘二大人 (6/10)】

    多输入模型 Multiple-Dimension 数学原理分析以及源码源码详解 深度学习 Pytorch笔记 B站刘二大人(6/10) 数学推导 在之前实现的模型普遍都是单输入单输出模型,显然,在现实 ...

  10. 【刘二大人 - PyTorch深度学习实践】学习随手记(一)

    目录 1. Overview 1.Human Intelligence 2.Machine Learning 3.How to develop learning system? 4.Tradition ...

最新文章

  1. JavaScript模式读书笔记 第5章 对象创建模式
  2. linue 查询端口号 netstat
  3. 0421实验二 作业调度模拟程序
  4. desc excel 公式_Excel小技巧之Power Pivot Generate函数、高级DAX函数与常用筛选器函数...
  5. 「日常训练」Skills(Codeforce Round #339 Div.2 D)
  6. Linux 命令简单介绍第一课笔记
  7. Linux运维工程师面试-部分题库
  8. 使用 RESTful 的方式开发 Web应用
  9. 手机能打开的表白代码_不是程序员都能学会的5个表白代码,一学就会,附源码...
  10. 【油猴脚本】GM_xmlhttpRequest跨域请求初探
  11. git send-email 使用126邮件发送patch
  12. 2021-2027全球与中国电动汽车线束和连接器市场现状及未来发展趋势
  13. HPLC鬼峰、基线漂移、拖尾、分叉峰、保留时间漂移、柱压过高等系列问题解析
  14. ERNIE1.0 与 ERNIE2.0 论文解读
  15. 大数据之当传统产业遭遇互联网
  16. 潜入维基解密机房:探访维基总部
  17. 最通俗易懂的解释hbase热点问题rowkey设计原则region分区及解决方案
  18. Fluent 时间步长【转载】
  19. GitHub协作开发项目
  20. mysql to_base64自动换行_BASE64 官方方法,我自己用的,注意记住换行问题。

热门文章

  1. Problem 2 慢跑问题
  2. 应届生如何快速提高职业竞争力
  3. blink usb无线网卡驱动 linux,blink随身wifi驱动
  4. chrome浏览器更新后重新安装配置chromedriver
  5. 周期性的方波 matlab,matlab产生方波脉冲和周期性方波信号 - 副本
  6. java normalize_Java Path normalize()用法及代码示例
  7. linux下编写脚本从ftp服务器定时下载文件
  8. Centos安装Wordpress
  9. win 64 安装 sql server 2000、出现挂起 解决
  10. Exception | 优雅的输出Exception异常信息