自学内容网 自学内容网

Pytorch如何使用RNN而不是RNNCell进行单步(迭代,递归)更新

文章目录

背景

以前初学的时候是使用的RNNCell,是用来迭代的,接收的是两个参数,一个是当前位置输入,一个是之前隐状态,然后就更新得到新的状态。

简要概括为:

输入:当前位置输入[bs,hdim] 之前隐状态[bs,hdim]
输出:现在隐状态[bs,hdim]
bs为批大小,hdim为向量维度。

后来直接使用RNN了,可以输入多个位置的输入,直接得到最后一个位置的隐状态。可以看到,它不需要RNNCell那样手动每一个位置迭代了,屏蔽了内部细节,直接得到最后一个位置的隐状态。

简要概括为:

输入:所有位置输入[bs,seqlen,hdim] 初始隐状态[x,bs,hdim]#这个x和层数以及是否双向有关,不用管,我们默认为1
输出:所有位置隐状态[bs,seqlen,hdim2]以及最后一个位置隐状态[x,bs,hdim]#这个hdim2默认是hdim,除非x不为1。
bs为批大小,seqlen为序列长度,hdim为向量维度。

可以看到,RNN更加方便了,直接得到所有信息,不需要我们手动去循环递归,现在问题是某些场景下需要去递归怎么办呢?一种方法当然是用回RNNCell,但是之前训练模型的时候用的是RNN,不方便换回去重新训练RNNCell,现在想在RNN基础上加一个递归的功能。这个功能可以用来干嘛?当然就是用来测试test或者推断inference喽,例如训练好RNN之后我们要自回归地生成一个句子,AI自动写诗写文章等,这个时候单词是一个一个生成,递归生成的,需要用到这个功能。

解决方案

import torch
import torch.nn as nn

这里以GRU为例,其实都是差不多的。

rnn=nn.GRU(2,2,batch_first=True)

构造两个位置的输入

x=torch.tensor([1.,2,3,4]).view(1,2,2)#[bs=1,seqlen=2,hdim=2]

可以直接将上述多个位置的输入放到RNN中,

rnn(x)#输出的是所有位置的隐向量以及最后一个位置的隐向量。所以没有毛病。

(tensor([[[-0.5278, 0.0937],
[-0.9068, 0.7536]]], grad_fn=<TransposeBackward1>),
tensor([[[-0.9068, 0.7536]]], grad_fn=<StackBackward>))

得到的结果的含义,前面已经说了,我们现在的任务是,能不能利用RNN递归地得到上述结果呢?

seqlen=x.shape[1]
hiddens=[torch.tensor([0.,0]).view(1,1,-1)]#[1,bs,hdim],其中这个1指代的是方向,可以不管。
for i in range(seqlen):#逐个位置进行传播。
    all_hidden,hidden=rnn(x[:,[i]],hiddens[-1])#当前输入以及上一个时刻之后的隐状态。
    #输出是所有位置的隐状态以及最后一个时刻的隐状态,我们这里逐位置传播,所以其实只有一个位置,两者相等。
    hiddens.append(hidden)
print(hiddens[1:])

注:初始化的隐状态是0。

结果如下,可以看到,和之前的结果一模一样。

[tensor([[[-0.5278, 0.0937]]], grad_fn=), tensor([[[-0.9068, 0.7536]]], grad_fn=)]


原文地址:https://blog.csdn.net/qq_43391414/article/details/135702668

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!