pytorch从头开始实现一个RNN(循环神经网络)
Posted AI量化实验室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pytorch从头开始实现一个RNN(循环神经网络)相关的知识,希望对你有一定的参考价值。
tensorflow有google的背书,强大的社区,加上开源的时机,alphago的名气等等吧,确实占了先机,但对于深度学习的初学者,真的是噩梦。是一个非得把简单的东西,搞得无比复杂的系统。
比如,tf看似为了灵活,它的示例里,所有的variable都需要你自己去初始化。比如,你可以初始化为0或全1,或者用正态分布随机,还可以设定均值,方差,当然还可以用均匀分布来初始化。但,我想说的是,实践证明,这些设定,与网络训练结果的影响基本没有!!!
只在人群中看了pytorch一眼,就深深着迷了。
其实,就写一个神经网络的训练任务,同样数据准备花的时间,远比搭网络要多得多。但其实这和我们学习与理解深度学习,没有太大的联系。
本文就想写写,直面网络,抛开各种参数设定,数据准备,学习本质。
对于一个网络,肯定有一个input,我们要确定好它的维度就好了。
1,RNN的input,如果就一步计算而言,是二维的,也就是1*vocab_size。如果char-rnn,也就是字母级别的,如果只看小写英文字母,这个vocab_size就是26。也就是说,每一个字母都表示为[1,26]的tensor(这就是传说中的one-hot,比如a = [1,0,0,....0],b=[0,1,0,....0])。
2,rnn的输入,需要有一个input_size=vocab_size,一个hidden_size,这个是rnn的神经元数,数量随意,越大越慢,但信息表达能力越强,然后还有一个output_size,就是rnn输出的维度。最终input经过rnn,由1*vocab_size,就成1*output_size
3.考虑批量实现,也就是一次输入N个char,也就是我们常说的sequence。在名字分类的任务,一个名字串,比如alice,就是一个seq。如果是句子情感分析,一个句子就是一个seq。如果是文章情感分析,一篇文章就是一个seq。
RNN的批量输出要处理成[seq_len, N, vocab_size]。这个新手很容易晕。一般我们处理原始数据,得到[N,seqlen]的数据。比如N个名字,N条句子或N篇文章等。这时候要转置成[seq_len,N],然后再embedding成[seq_len,N,vocab_size]。
这是因为,在RNN或LSTM的计算单元,是按for i in range(seq_len):来计算每一个输出,一个个往写进,后一批使用前一批的hidden_status。
import torch
import torch.nn as nn
from torch.autograd import Variable
class RNN(nn.Module):
#这里自己实现一个RNN.
#input_size就是char_vacab_size=26,hidden_size随意,就是隐层神经元数,output_size要分成categories类
def __init__(self, input_size, hidden_size, output_size):
super(RNN, self).__init__()
self.hidden_size = hidden_size
self.i2h = nn.Linear(input_size + hidden_size, hidden_size)
self.i2o = nn.Linear(input_size + hidden_size, output_size)
self.softmax = nn.LogSoftmax()
def forward(self, input, hidden):
combined = torch.cat((input, hidden), 1)#input:[N,26]+[N,hidden_size]=N,26+hidden_size -> N*hidden_size
hidden = self.i2h(combined) #N*hidden_size,这里计算了一个hidden,hidden会带来下一个combined里
output = self.i2o(combined) # N*output_size,就是一个普通全连接层
output = self.softmax(output)#softmax
return output, hidden
def initHidden(self):
return Variable(torch.zeros(1, self.hidden_size))#hidden=[1,hidden_size]
n_hidden = 128
target_size = 10#分类问题,分成几类
rnn = RNN(26, n_hidden, target_size)
hidden = rnn.initHidden()
#如果输入input,是一个char,按one-hot编码的,假设char空间是26(小写英文字母)
input = Variable(torch.zeros((1,26)))#[torch.FloatTensor of size 1x26],成员都是0
print(input)
output, next_hidden = rnn(input, hidden)#得到[1*10,1*128]
print(output.data.size(),next_hidden.data.size())
如上只是写了单步的运算,但确定了这个就好办了。比如依照需要,我们要实现对“英文名字字符串”的分类。每个名字构成一个seq。
每一个seq结束就应该初始化一次hidden。然后对名字里的每个char进行循环。计算loss,并反向求导。然后在导数方向上对参数进行调整。如果是batch,那每个batch结束yi
扫描下方二维码,关注:AI量化实验室(ailabx),了解AI量化最前沿技术、资讯。r
以上是关于pytorch从头开始实现一个RNN(循环神经网络)的主要内容,如果未能解决你的问题,请参考以下文章