深度学习入门6-RNN、LSTM、GRU和注意力机制的代码实现

文章目录

  • 前言
  • 一、导入库
  • 二、各框架实现
    • 1.RNN
    • 2.LSTM
    • 3.GRU
    • 4.注意力机制
  • 总结


前言

今天要实现的代码是RNN、LSTM、GRU和注意力机制的框架部分。
深度学习入门6-RNN、LSTM、GRU和注意力机制的代码实现_第1张图片
RNN、LSTM和GRU的框架图如上所示。

一、导入库

import torch
import torch.nn as nn
import torch.nn.functional as F

二、各框架实现

1.RNN

rnn=nn.RNN(64,4,3) #input_size,hidden_size(隐藏层神经元数),num_layers(隐藏层层数)

input=torch.randn(150,3,64) #sequence_length,batch_size,input_size
h0=torch.randn(3,3,4) #num_layers*num_directions,batch_size,hidden_size

output,hn=rnn(input,h0)
print(output.shape) #sequence_length,batch_size,hidden_size -> (150,3,4)
print(hn.shape) #the same as h0 -> (3,3,4)

2.LSTM

lstm=nn.LSTM(64,4,3) #input_size,hidden_size,num_layers

input=torch.randn(150,3,64) #sequence_length,batch_size,input_size
h0=torch.randn(3,3,4) #num_layers*num_directions,batch_size,hidden_size
c0=torch.randn(3,3,4) #num_layers*num_directions,batch_size,hidden_size

output,(hn,cn)=lstm(input,(h0,c0))
print(output.shape) #sequence_length,batch_size,hidden_size -> (150,3,4)
print(hn.shape) #the same as h0 -> (3,3,4)
print(cn.shape) #the same as c0 -> (3,3,4)

3.GRU

gru=nn.GRU(64,4,3) #input_size,hidden_size,num_layers

input=torch.randn(150,3,64) #sequence_length,batch_size,input_size
h0=torch.randn(3,3,4) #num_layers*num_directions,batch_size,hidden_size

output,hn=gru(input,h0)
print(output.shape) #sequence_length,batch_size,hidden_size -> (150,3,4)
print(hn.shape) #the same as h0 -> (3,3,4)

4.注意力机制

#bmm运算
mat1=torch.randn(10,3,4) #(b,m,n)
mat2=torch.randn(10,4,5) #(b,n,p)
res=torch.bmm(mat1,mat2)
print(res.size()) #(b,m,p) -> (10,3,5)

#torch.bmm运算针对的是两个第一个维度相同的三维张量如(b,m,n)(b,n,p),运算过程第一个维度不变,后两个维度进行矩阵乘法,则运算结果为(b,m,p)

class Attn(nn.Module):
    def __init__(self,query_size,key_size,value_size1,value_size2,output_size):
        #query_size代表的是Q的最后一个维度,key_size代表K的最后一个维度
        #V的尺寸表示(1,value_size1,value_size2)
        #output_size代表输出的最后一个维度的大小
        super(Attn,self).__init__()
        self.query_size=query_size
        self.key_size=key_size
        self.value_size1=value_size1
        self.value_size2=value_size2
        self.output_size=output_size

        #初始化注意力机制实现中第一步的线性层
        self.attn=nn.Linear(self.query_size+self.key_size,self.value_size1)

        #初始化注意力机制实现中第三步的线性层
        self.attn_combine=nn.Linear(self.query_size+self.value_size2,self.output_size)

    def forward(self,Q,K,V):
        #注意我们假定Q,K,V都是三维张量
        #第一步,将Q,K进行纵轴的拼接,然后做一次线性变换,最后使用softmax进行处理得到注意力向量
        attn_weights=F.softmax(self.attn(torch.cat((Q[0],K[0]),1)),dim=1)
            
        #将注意力矩阵和V进行一次bmm运算
        attn_applied=torch.bmm(attn_weights.unsqueeze(0),V)

        #再次去Q[0]进行降维,再次和上面的运算结果进行一次拼接
        output=torch.cat((Q[0],attn_applied[0]),1)

        #第三步就是将上面的输出进行一次线性变换,然后再扩展维度成3维张量
        output=self.attn_combine(output).unsqueeze(0)
        return output,attn_weights

query_size=32
key_size=32
value_size1=32
value_size2=64
output_size=64

attn=Attn(query_size,key_size,value_size1,value_size2,output_size)
Q=torch.randn(1,1,32)
K=torch.randn(1,1,32)
V=torch.randn(1,32,64)
output=attn(Q,K,V)
print(output[0])
print(output[0].size()) #对应output的形状 -> (1,1,64)
print(output[1])
print(output[1].size()) #对应attn_weights的形状 -> (1,32)

总结

对于RNN、LSTM和GRU来说,弄清楚什么是input_size,什么是sequence_length很重要。
一种新的torch的运算方式bmm,对两个第一个维度相等的三维矩阵的后两维进行矩阵乘法运算。
对于注意力机制,弄清楚Q、K、V各自的size和维度的意义很重要。
当Q=K=V的时候为自注意力。
需要用案例进行进一步的理解。

你可能感兴趣的:(rnn,lstm,gru)