一、循环神经网络
它并非刚性地记忆所有固定长度的序列,而是通过隐藏状态来存储之前时间步的信息。
我们想象现在有一组序列数据 data 0,1,2,3。 在当预测 result0 的时候,我们基于的是 data0, 同样在预测其他数据的时候, 我们也都只单单基于单个的数据。 每次使用的神经网络都是同一个 NN(neural network)。不过这些数据是有关联顺序的 , 就像在厨房做菜, 酱料 A 要比酱料 B 早放, 不然就串味了。所以普通的神经网络结构并不能让 NN 了解这些数据之间的关联。
那我们如何让数据间的关联也被 NN 加以分析呢? 想想我们人类是怎么分析各种事物的关联吧, 最基本的方式,就是记住之前发生的事情. 那我们让神经网络也具备这种记住之前发生的事的能力. 再分析 Data0 的时候, 我们把分析结果存入记忆. 然后当分析 data1的时候, NN会产生新的记忆, 但是新记忆和老记忆是没有联系的. 我们就简单的把老记忆调用过来, 一起分析. 如果继续分析更多的有序数据 , RNN就会把之前的记忆都累积起来, 一起分析.
我们再重复一遍刚才的流程, 不过这次是以加入一些数学方面的东西. 每次 RNN 运算完之后都会产生一个对于当前状态的描述 , state. 我们用简写 S(t) 代替, 然后这个 RNN开始分析 x(t+1) , 他会根据 x(t+1)产生s(t+1), 不过此时 y(t+1) 是由 s(t) 和 s(t+1) 共同创造的. 所以我们通常看到的 RNN 也可以表达成这种样子.
二、代码案例:
1.相关包
import torch
from torch import nn
import numpy as np
import matplotlib.pyplot as plt
2.网络结构
time_step和input_size的关系:每一个time_step,也就是每一次时间节点,都会读取input_size大小的数据。例如本次案例中,steps = np.linspace(start, end, 10, dtype=np.float32),每一步随机给出10个数据点,而input_size=1,也就是每一次时间节点读取1个数据,而共有10个数据点,因此time_step=10.
# Hyper Parameters
TIME_STEP = 10 # rnn time step
INPUT_SIZE = 1 # rnn input size
LR = 0.02 # learning rate
class RNN(nn.Module):
def __init__(self):
super(RNN,self).__init__()
self.rnn=nn.RNN(
input_size=1, #输入特征值
hidden_size=32,#隐藏层
num_layers=1,#有几层RNN layers
batch_first=True## input & output 会是以 batch size 为第一维度的特征集 e.g. (batch, time_step, input_size)
)
self.out=nn.Linear(32,1)
def forward(self,x,h_state):
# x (batch, time_step, input_size)
# h_state (n_layers, batch, hidden_size)
# r_out (batch, time_step, output_size)
r_out,h_state=self.rnn(x,h_state) #会输出目标值,还有状态值
outs=[]#保存所有时间点的预测值
for time_step in range(TIME_STEP):
outs.append(self.out(r_out[:,time_step,:]))
return torch.stack(outs,dim=1),h_state #因为outs是一个列表,转化成torch要进行压缩
# r_out, h_state = self.rnn(x, h_state)
# r_out = r_out.view(-1, 32)
# outs = self.out(r_out)
# return outs.view(-1, 32, TIME_STEP), h_state
3.训练及其可视化
rnn=RNN()
optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) # optimize all rnn parameters
loss_func = nn.MSELoss()
h_state = None # 要使用初始 hidden state, 可以设成 None
plt.ion()
for step in range(100):
start, end = step * np.pi, (step+1)*np.pi # time steps
# sin 预测 cos
steps = np.linspace(start, end, 10, dtype=np.float32)
x_np = np.sin(steps) # float32 for converting torch FloatTensor
y_np = np.cos(steps)
x = torch.from_numpy(x_np[np.newaxis, :, np.newaxis]) # shape (batch, time_step, input_size)
y = torch.from_numpy(y_np[np.newaxis, :, np.newaxis])
prediction, h_state = rnn(x, h_state) # rnn 对于每个 step 的 prediction, 还有最后一个 step 的 h_state
# !! 下一步十分重要 !!
h_state = h_state.data # 要把 h_state 重新包装一下才能放入下一个 iteration, 不然会报错
loss = loss_func(prediction, y) # cross entropy loss
optimizer.zero_grad() # clear gradients for this training step
loss.backward() # backpropagation, compute gradients
optimizer.step() # apply gradients
plt.plot(steps,prediction.data.numpy().flatten(),'b-')#因为最后prediction的shape为(1,10,1),需要压缩
plt.plot(steps,y_np,'r-')
plt.draw()
plt.pause(0.1)
plt.ioff()
plt.show()
可视化输出结果: