pytorch入门:pytorch实现 LSTM ,GRU,RNN

循环神经网络变种

标准循环神经网络虽然有记忆,但很健忘,再深层结构中循环神经网络实际上再时间序列的各个时刻重复应用相同的操作来构建深的计算图,而且模型的参数共享。比如 W 需要再时间步中反复用于相乘,如果W 可以特征值分解:

在这里插入图片描述
当特征值 λ 不在 1 附件,如果大于1 产生梯度爆炸,小于 1 就会产生梯度消失。梯度消失会使我们难以知道参数朝哪个方向移动能改进代价函数,而梯度爆炸会让学习过程变得不稳定。

再任何深度网络中都会存在这样的问题,就是RNN 更加明显,再RNN 中,相邻的时间步是链接再一起的,所有权重偏导数要么都小于1 ,要么都大于1 ,这样与前馈神经网络相比,RNN 的梯度消失和爆炸的问题更加明显。简单的RNN 随层数增加网络就会无法训练,无法实现长时间的记忆,这就导致RNN 存在短时记忆的问题。解决方法:

  1. 选择更好的激活函数,比如 ReLU,右导数恒为1 ,可以避免梯度消失
  2. 加入BN 层,有点可以加速收敛,控制过拟合
  3. 修改网络结构,比如LSTM 结构就可以有效的解决问题。

LSTM

长短时记忆网络(LSTM),还有基于LSTM 的集中变种算法,GRU算法等。可以解决信息的长期依赖,避免梯度消失和爆炸。与RNN 相比结构上设计了 循环体结构,用两个门来控制单元状态的内容,一个是遗忘门(Forget Gate) ,决定了上一时刻的单元状态有多少要保留到当前时刻,另一个输入门,决定当前时刻网络的输入 xt 有多少保存到单元状态中。用输出门 控制单元状态 ct 有多少输出到当前输出值 ht。

在这里插入图片描述

GRU

LSTM 结构比较复杂,计数复杂度较高。又推出其他变种 GRU ,对LSTM 进行了很多简化,计数效率更高,占用内存更少。但效果差异不大。

  • 将输入门,遗忘门,输出门 简化成了, 更新门,重置门
  • 将单元状态和输出合并为一个状态 ht.

在这里插入图片描述

Bi-RNN

在这里插入图片描述

双向循环神经网络,增加了RNN 可利用的信息,同时使用时序数据输入历史和未来数据,时序相反的两个循环神经网络链接同一个输出,输出层可以同时获取 t 历史和未来的信息。

百度语音识别就是通过 Bi-RNN 综合上下文语境,提升模型准确率。基本思想就是每一个训练序列向前向后分别是两个RNN ,而且这两个都链接一个 输出层。这个结构给输出每一个点完整的过去和未来的上下文信息。上图就是一个沿时间展开的双向循环神经网络,6个独特的权值参数共享。输入到向前和向后隐含层 (w1,w3)、隐含层到隐含层自己(w2,w5)、向前和向后隐含层到输出层 (w4,w6)。值得注意的是,向前和向后隐含层之间没有信息流,这保证了 展开图是非循环的。

循环神经网络pytorch实现

pytroch 提供了响应的API, 单元版的 nn.RNNCell, nn.LSTMCell, nn.GRUCell. 封装版的 nn.RNN, nn.LSTM, nn.GRU 。两者的区别就是输入,前者是时间步或序列的一个元素,后者是一个时间步序列。。。

RNN 实现

torch.nn.RNN( args, * kwargs)
# at=tanh(w^ih*x^t+b^ih+w^hh*a^t-1 +b^hh)   状态输出at 的计算公式

参数:
- input_size ,输入x 的特征数量
- hidden_size: 隐藏层的特征数量
- num_layers RNN 的层数
- nonlinearity : 激活函数默认 tanh ,可以选择relu
- bias :默认True,是否使用偏置权重 bi, bh 。
- batch_first,如果为True,输入Tensor的 shape应该是(batch, seq, feature),输出也是一样。默认输入
			(seq, batch, feature) 序列长度,批次大小,特征维度。
- dropout,0-1 默认0,除了最后一层,其他层的输出都会加上一个 dropout层
- bidirectional,True 就变成一个双向rnn ,默认 False

输入:
- 特征 x (seq_len, batch, input_size)
- 隐含状态 h0 形状 (num_layers*num_directions,batch,hidden_size),
	其中num_layers为层数, 
	num_directions方向数,如果取2则表示双向(bidirectional,),取1则表示单向。

输出:
- output^t (seq_len,batch,num_directions*hidden_size)
- hn (num_layers*num_directions,batch,hidden_size)

属性:
~RNN.weight_ih_l[k] – 第k层可学习的输入层-隐藏层的权重 of shape (hidden_size, input_size) for k = 0. Otherwise, the shape is (hidden_size, num_directions * hidden_size)

~RNN.weight_hh_l[k] – the learnable hidden-hidden weights of the k-th layer, of shape (hidden_size, hidden_size)

~RNN.bias_ih_l[k] – the learnable input-hidden bias of the k-th layer, of shape (hidden_size)

~RNN.bias_hh_l[k] – the learnable hidden-hidden bias of the k-th layer, of shape (hidden_size)

# 简单测试一下
rnn = nn.RNN(input_size=10, hidden_size=20,num_layers= 2)
# 推测:输入维度为10,隐含状态维度20,单向两层网络,输入节点和隐藏层节点之间是全连接
# 所有 w^ih 应该是 20*10,w^hh是20×20,b^ih和b^hh都 是hidden_size。
print("第一层:wih形状{},whh形状{},bih形状{}"
      .format(rnn.weight_ih_l0.shape,rnn.weight_hh_l0.shape,rnn.bias_hh_l0.shape))

print("第二层:wih形状{},whh形状{},bih形状{}"
      .format(rnn.weight_ih_l1.shape,rnn.weight_hh_l1.shape,rnn.bias_hh_l1.shape))
第一层:wih形状torch.Size([20, 10]),whh形状torch.Size([20, 20]),bih形状torch.Size([20])
第二层:wih形状torch.Size([20, 20]),whh形状torch.Size([20, 20]),bih形状torch.Size([20])

# 网络搭建好了,方便啊。。然后就可以传入(xt,h0),根据网络配置和网络要求生成输入数据。
# 输入特征长度为100,批量大小32,特征维度10 的张量,隐藏层形状为 (2,32,20)
input=torch.randn(100,32,10) 
h_0=torch.randn(2,32,20)

# 得到输出和更新后的隐含层状态值。推测输出的shape 应该为 (100,32,20)
output,h_n = rnn(input,h_0)
print(output.shape,h_n.shape)
torch.Size([100, 32, 20]) torch.Size([2, 32, 20])

# 使用pytorch实现该网络
class RNN(nn.Module):
    def __init__(self,input_size,hidden_size,output_size):
        super().__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(dim=1)
    def forward(self,input,hidden):
        combined = torch.cat((input,hidden),1)
        hidden = self.i2h(combined)
        ouput = self.i2o(combined)
        output = self.softmax(output)
        return output,hidden
    def initHidden(self):
        return torch.zeros(1,self.hidden_size)

在这里插入图片描述

LSTM 实现

LSTM 再RNN 的基础上增加了长时间记忆功能,具体通过增加一个状态C 利用三个门来实现对信息的更精准控制。比起RNN 多了三个线性变换,多出的三个线性变换的权重组合再一起就是RNN 的4倍,偏移量也是RNN 的4倍。所以LSTM 的参数个数是 RNN 的四倍。

除了参数LSTM 还多出了一个隐含状态 c0, 与h0 形状相同,都是(num_layers * num_directions, batch,hidden_size) , 两个合在一起构成了LSTM 的隐含状态。所以,LSTM 的输入隐含状态为 (h0,c0) ,输出隐含状态为(hn, cn),其他输入和输出就与RNN 相同了。

lstm = nn.LSTM(input_size=10,hidden_size=20,num_layers=2)
# 推测:输入维度为10,隐含状态维度20,单向两层网络,输入节点和隐藏层节点之间是全连接
# 所有 w^ih 应该是 20*10,w^hh是20×20,b^ih和b^hh都 是hidden_size。
print("第一层:wih形状{},whh形状{},bih形状{}"
      .format(lstm.weight_ih_l0.shape,lstm.weight_hh_l0.shape,lstm.bias_hh_l0.shape))

print("第二层:wih形状{},whh形状{},bih形状{}"
      .format(lstm.weight_ih_l1.shape,lstm.weight_hh_l1.shape,lstm.bias_hh_l1.shape))
# 结果正好是RNN 的四倍。
第一层:wih形状torch.Size([80, 10]),whh形状torch.Size([80, 20]),bih形状torch.Size([80])
第二层:wih形状torch.Size([80, 20]),whh形状torch.Size([80, 20]),bih形状torch.Size([80])

input=torch.randn(100,32,10) 
h_0=torch.randn(2,32,20)
h0 = (h_0,h_0)          # 这就是合并嘛。。。
output,h_n = lstm(input,h0)
print(output.size(),h_n[0].size(),h_n[1].size())

torch.Size([100, 32, 20]) torch.Size([2, 32, 20]) torch.Size([2, 32, 20])

# pytorch 实现,这个过程按照上面哪个LSTM 的流程图来看,还是很直观的。。。
class LSTMCell(nn.Module):
    def __init__(self, input_size, hidden_size, cell_size, output_size):
        super(LSTMCell, self).__init__()
        self.hidden_size = hidden_size
        self.cell_size = cell_size
        self.gate = nn.Linear(input_size + hidden_size, cell_size)
        self.output = nn.Linear(hidden_size, output_size)
        self.sigmoid = nn.Sigmoid()
        self.tanh = nn.Tanh()
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden, cell):
        combined = torch.cat((input, hidden), 1)
        f_gate = self.sigmoid(self.gate(combined))  # 遗忘门
        i_gate = self.sigmoid(self.gate(combined))  # 输入门
        o_gate = self.sigmoid(self.gate(combined))  # 输出门
        z_state = self.tanh(self.gate(combined))    # 输入状态
        cell = torch.add(torch.mul(cell, f_gate), torch.mul(z_state, i_gate))
        hidden = torch.mul(self.tanh(cell), o_gate)
        output = self.output(hidden)
        output = self.softmax(output)
        return output, hidden, cell

    def initHidden(self):
        return torch.zeros(1, self.hidden_size)

    def initCell(self):
        return torch.zeros(1, self.cell_size)

lstmcell = LSTMCell(input_size=10, hidden_size = 20,cell_size = 20, output_size=10)
input = torch.randn(32,10)
h_0 = torch.randn(32,20)

out,hn,cn = lstmcell(input,h_0,h_0)

print(output.size(),hn.size(),cn.size())
>>> torch.Size([100, 32, 20]) torch.Size([32, 20]) torch.Size([32, 20])

GRU 实现

这个与LSTM 基本相同,主要区别是GRU 只有两个门,一个隐含状态,其参数是标准RNN 的三倍。

# 这个实现和 LSTM 很相似
class GRUCell(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(GRUCell, self).__init__()
        self.hidden_size = hidden_size
        self.gate = nn.Linear(input_size + hidden_size, hidden_size)
        self.output = nn.Linear(hidden_size, output_size)
        self.sigmoid = nn.Sigmoid()
        self.tanh = nn.Tanh()
        self.softmax = nn.LogSoftmax(dim=1)

    def forward(self, input, hidden):
        combined = torch.cat((input, hidden), 1)        
        z_gate = self.sigmoid(self.gate(combined))    # 两个门
        r_gate = self.sigmoid(self.gate(combined))
        combined01 = torch.cat((input, torch.mul(hidden,r_gate)), 1)  
        h1_state = self.tanh(self.gate(combined01))   # 一个隐含状态
        
        h_state = torch.add(torch.mul((1-z_gate), hidden), torch.mul(h1_state, z_gate))
        output = self.output(h_state)
        output = self.softmax(output)
        return output, h_state

    def initHidden(self):
        return torch.zeros(1, self.hidden_size)    

grucell = GRUCell(input_size=10,hidden_size=20,output_size=10)

input=torch.randn(32,10)
h_0=torch.randn(32,20)

output,hn=grucell(input,h_0)
print(output.size(),hn.size())
>>> torch.Size([32, 10]) torch.Size([32, 20])
  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用PyTorch实现RNN模型,你可以按照以下步骤进行操作: 1. 准备数据:首先,你需要获取股票数据,并将其转换为PyTorch需要的格式。你可以使用Quandl API获取股票数据,并将其保存为CSV文件。然后,读取CSV文件,并选择股票收盘价列。最后,对数据进行归一化处理,并将其转换为PyTorch的tensor格式。 2. 定义RNN模型:在PyTorch中,你可以使用nn.RNN类来定义RNN模型。你需要指定输入大小、隐藏层大小和是否使用偏置项等参数。另外,你也可以使用nn.RNNCell类来定义RNN模型的单个单元。 3. 训练模型:使用定义好的RNN模型,你可以使用MSE损失函数和Adam优化器来训练模型。你可以定义一个训练函数,该函数会迭代训练集中的每个序列,并在每个epoch结束时保存模型。 4. 保存模型:在训练结束后,你可以使用torch.save函数将训练好的模型保存到文件中。 5. 加载模型并生成交易信号:使用torch.load函数加载保存的模型文件。然后,使用加载的模型生成交易信号。你可以使用torch.no_grad()上下文管理器来禁用梯度计算,以提高推理速度。在循环中,你可以将输入数据传递给加载的模型,并获取输出结果。最后,将生成的交易信号保存为Series对象。 综上所述,你可以按照上述步骤使用PyTorch实现RNN模型。\[2\] #### 引用[.reference_title] - *1* *2* [用pytorch实现RNN模型做股票量化交易](https://blog.csdn.net/qq_24250441/article/details/130885802)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Pytorch实现RNNLSTMGRU等经典循环网络模型,简直不能再简单。](https://blog.csdn.net/weixin_39490300/article/details/123167335)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值