初始PyTorch(七):循环神经网络RNN

循环神经网络RNN,即一个序列当前的输出与前面的输出也有关。具体的表现形式为网络会对前面的信息进行记忆并应用于当前输出的计算中,即隐藏层之间的节点不再无连接而是有连接的,并且隐藏层的输入不仅这次的输入x,还包括上一时刻隐藏层h。

RNN公式:h_{t}=f_{w}(h_{t-1},x_{t})——>h_{t}=tanh(W_{hh}*h_{t-1}+W_{xh}*x_{t}),y_{t}=W_{hy}*h_{t}

一、tensor表示

输入x:[input_num,batch,feacture_num]
特征xt:[batch,feacture_num]
上一层h:[batch,hidden_num]
输出y:[b,f]@[h,f]+[b,h]@[h,h]=[b,h]
假设输入x为[5,3,10],即有5个单词分为3段,有100个特征表示。对于每个单词的特征xt为[3,100],前面传播过来的h0维度为[3,20],可以计算当前的输出y的张量为[3,100]@[20,100]+[3,20]@[20,20]=[3,20]

nn.RNN(f,h,l)
out,ht=forward(x,h0)#ht[l,b,h]返回最后一个h,out[n,b,h]返回中间所有h.

二、RNN结构

单层RNN:

#方法一nn.RNN(f,h,l)
rnn = nn.RNN(num_feature=100, hidden_size=20, num_layers=1)
print(rnn) #RNN(100, 20)
x = torch.randn(10, 3, 100) #x[n,b,f]
out, h = rnn(x, torch.zeros(1, 3, 20)) #rnn(x,h0)
print(out.shape, h.shape)#torch.Size([10, 3, 20]) torch.Size([1, 3, 20])
#方法二nn.RNNCell(f,h)
cell1 = nn.RNNCell(100, 20)
h1 = torch.zeros(3, 20)
for xt in x:          #x[n,b,f]=[10,3,100] xt[b,f]=[3,100]
   h1 = cell1(xt, h1) #h[l,b,h]
print(h1.shape) #torch.Size([3, 20])

多层RNN:

#方法一 nn.RNN()
rnn = nn.RNN(num_feature=100, hidden_size=20, num_layers=4)
print(rnn) #RNN(100, 20, num_layers=4)
x = torch.randn(10, 3, 100)
out, h = rnn(x, torch.zeros(4, 3, 20))
print(out.shape, h.shape)#torch.Size([10, 3, 20]) torch.Size([4, 3, 20])
#方法二 nn.RNNCell()
cell1 = nn.RNNCell(100, 30)
cell2 = nn.RNNCell(30, 20)
h1 = torch.zeros(3, 30)
h2 = torch.zeros(3, 20)
for xt in x:
   h1 = cell1(xt, h1)
   h2 = cell2(h1, h2)
print(h2.shape) #torch.Size([3, 20])

三、实现代码:网络的组成&训练&测试

'''采样'''
start = np.random.randint(3, size=1)[0]
time_steps = np.linspace(start, start + 10, num_time_steps)
data = np.sin(time_steps)
data = data.reshape(num_time_steps, 1)
x = torch.tensor(data[:-1]).float().view(1, num_time_steps - 1, 1) #0~48
y = torch.tensor(data[1:]).float().view(1, num_time_steps - 1, 1) #1~49

'''网络'''
class Net(nn.Module):

    def __init__(self, ):
        super(Net, self).__init__()
    
        self.rnn = nn.RNN(
            input_size=input_size,
            hidden_size=hidden_size,
            num_layers=1,
            batch_first=True,
        ) #[n,h,l]
        self.linear = nn.Linear(hidden_size, output_size)

    def forward(self, x, hidden_prev):
       out, hidden_prev = self.rnn(x, hidden_prev)
       # [b, n , h]=> [n,h]
       out = out.view(-1, hidden_size)
       out = self.linear(out) #[n,h]=>[n,1]
       out = out.unsqueeze(dim=0) # =>[1,seq,1]
       return out, hidden_prev
'''训练'''
model = Net()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr)
hidden_prev = torch.zeros(1, 1, hidden_size)

#采样
for iter in range(6000):
    start = np.random.randint(3, size=1)[0]
    time_steps = np.linspace(start, start + 10, num_time_steps)
    data = np.sin(time_steps)
    data = data.reshape(num_time_steps, 1)
    x = torch.tensor(data[:-1]).float().view(1, num_time_steps - 1, 1)
    y = torch.tensor(data[1:]).float().view(1, num_time_steps - 1, 1)

    output, hidden_prev = model(x, hidden_prev)
    hidden_prev = hidden_prev.detach()
#loss来更新参数Whh,Wih
    loss = criterion(output, y)
    model.zero_grad()
    loss.backward()
    optimizer.step()

    if iter % 100 == 0:
        print("Iteration: {} loss {}".format(iter, loss.item()))
'''测试'''
predictions = []
input = x[:, 0, :]
for _ in range(x.shape[1]):
  input = input.view(1, 1, 1)
  (pred, hidden_prev) = model(input, hidden_prev)
  input = pred
  predictions.append(pred.detach().numpy().ravel()[0])

四、RNN改进算法

RNN处理时间序列的问题的效果很好, 但是容易出现梯度消失=>0或者梯度爆炸=>∞的问题。

对于梯度消失: 由于它们都有特殊的方式存储”记忆”,那么以前梯度比较大的”记忆”不会像简单的RNN一样马上被抹除,因此可以一定程度上克服梯度消失问题。可以使用 LSTM 算法。

对于梯度爆炸:用来克服梯度爆炸的问题就是gradient clipping,也就是当你计算的梯度超过阈值c或者小于阈值-c的时候,便把此时的梯度设置成c或-c。 

#对于梯度爆炸
loss=criterion(output,y)
model.zero_grad()
loss.backward()
for p in model.parameters():
    print(p.grad.norm()) #查看每个梯度的模
    torch.nn.utils.clip_grad_norm(p,10) #把模限制在<10
optimizet.step()

1)长短期记忆网络LSTM (待更新

RNN的Short-term-memory 只能记住比较短的时间序列,保留相近的信息。
Long-Short-term-memory 改进RNN的梯度离散和长度问题。有三个门,遗忘门,输入门,输出门。一个方向。
Bi-LSTM:双向长短期记忆网络。在单向LSTM上变成双向。

1.遗忘门

2.输入门

3.输出门

2)Bi-LSTM (待更新

3)注意力Attention模型 (待更新

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nooobme

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值