使用Pytorch构建LSTM网络实现对时间序列的预测

使用Python构建LSTM网络实现对时间序列的预测

1. LSTM网络神经元结构


LSTM网络 神经元结构示意图

  在任一时刻 t,LSTM网络神经元接收该时刻输入信息 xt,输出此时刻的隐藏状态 ht,而 ht 不仅取决于 xt,还受到 t1 时刻细胞状态 (cell state) ct1 和隐藏状态 (hidden state) ht1 的影响;图中水平贯穿神经元内部的上下两条传送带则分别表示细胞状态及隐藏状态各自从上一时刻传递至下一时刻。

  观察神经元内部结构,黄色方框从左至右可分别看作:

  • 遗忘门 (forget gate):ft=σ(Wf·[xt,ht1]+bf),表示对信息的记忆程度

  • 输入门 (input gate):it=σ(Wi·[xt,ht1]+bi),表示对信息的输入强度

  • 状态门 (cell gate):gt=tanh(Wg·[xt,ht1]+bg),表示对输入信息的处理

  • 输出门 (output gate):ot=σ(Wo·[xt,ht1]+bo),表示对信息的输出强度

其中, [xt,ht1] 表示两向量的并列 (concatenate) 向量,ht1 表示神经元 t1 时刻的隐藏状态,σ 为 sigmoid 函数。

  在此基础上可更新神经元 t 时刻的细胞状态 ct 与隐藏状态 ht 如下:

  • ct=ftct1+itgt,即细胞状态 = 经过遗忘后的旧细胞状态 + 神经元处理后的新信息;

  • ht=ottanh(ct),即隐藏状态 = 输出强度 × tanh处理后的细胞状态;

其中 表示哈达玛积 (Hadamard product),即向量对应元素相乘。

2. 多层LSTM网络

  除去神经元内部结构的特殊性,LSTM 神经网络也分为输入层、隐(藏)层与输出层,输入层、输出层分别对应神经网络模型的输入向量 Xt=(X1t,X2t,,XDt)输出向量 Yt~,神经元个数一般与输入、输出向量的维数一致;同层神经元之间无连接,各隐层神经元接收前一层神经元的输出信号,并输出下一层神经元的接收信号。



多层LSTM网络结构示意图

  • 单层 LSTM 网络:
    隐层神经元的输入信号 xt 即为 Xt
  • 多层 LSTM 网络:
    第 1 层隐层神经元的输入信号 xt(1)=Xt
    l(l2) 神经元的输入信号 xt(l)=δt(l1)·ht(l1),其中 δt(l1) 服从取 0 概率为 dropout 的伯努利分布,dropout 自行指定。

  对于输入向量 Xt目标输出向量 Yt,LSTM 神经网络模型总概如下:
训练目标para=argminparasYt~Yt2
训练参数paras={ Wf,bf; Wi,bi; Wg,bg; Wo,bo }

训练方法:反向传播(本文训练方法),模拟退火法等

[========]

3. 构建 LSTM 网络

声明数据:

  • 已知数据 X={X1,,Xm},其中 Xt=(X1t,X2t,,XDt), t=1,2,,m
  • 预测目标向量 Ym=(ym,ym+1,,ym+L1)=(Xsm,Xsm+1,,Xsm+L1)
    也就是说, 输入数据维度为 D,时间点个数为 m,预测步长为 L1.

声明 LSTM 网络:

  • 输入数据维度 input_size=D, 隐层神经元个数 (隐层状态 ht 特征数) hidden_size=n, 隐层数为 num_layers=l
import torch
import nn from torch
myLSTM = nn.LSTM(input_size, hidden_size, num_layers)

    LSTM 网络其他参数:

  • bias : If False , then the layer does not use bias weights bih and bhh. Default: True
  • batch_first : If True , then the input and output tensors are provided as (batch_size,m,D) instead of (m,batch_size,D). Note that this does not apply to hidden or cell states. Default: False.
  • dropout : If non-zero , introduces a Dropout layer on the outputs of each LSTM layer except the last layer, with dropout probability equal to dropout. Default: 0
  • bidirectional : If True , becomes a bidirectional LSTM (denote bid=2). Default: False (denote bid=1).
  • proj_size : If > 0 , will use LSTM with projections (投影) of corresponding size (denote Hout=projsize). Default: 0 (denote Hout=n). 换句话说,proj_size 表现了细胞状态与隐藏状态的维数是否一致.

声明 LSTM 网络的输入与输出:

  • 网络输入与输出均为张量 (tensor)
  • 网络输入:input,(h0, c0);网络输出: output, (hm, cm)
  • 指导手册上提出了 unbatched inputs 和 outputs 的情况,但在实际操作中,会提示 inputs 必须是 3 维的 (这里可能是笔者的操作有问题,欢迎大家来交流!)
output, (hn, cn) = myLSTM(input, (h0, c0))
input h0 c0
unbatched (m,D) (bid×l,Hout) (bid×l,n)
batch_first=True (batch_size,m,D) (bid×l,batch_size,Hout) (bid×l,batch_size,n)
batch_first=False (m,batch_size,D)
description D 维,m 个时间点 初始时刻的隐藏状态
Default:0
初始时刻的细胞状态
Default:0

output hm cm
unbatched (m,bid×Hout) (bid×l,Hout) (bid×l,n)
batch_first=True (batch_size,m,bid×Hout) (bid×l,batch_size,Hout) (bid×l,batch_size,n)
batch_first=False (m,batch_size,bid×Hout)
description 各个时刻 t
最后一层节点的隐藏状态
最终时刻
全部节点的隐藏状态
最终时刻
全部节点的细胞状态
注:对于双向 LSTM 网络,hm 包含最终时刻的前馈隐藏状态和反馈隐藏状态,而 output 的最后一个元素则是最后一层 节点*最终时刻*的前馈隐藏状态和*初始时刻*的反馈隐藏状态,当 batch_first=False 时可直接分为(m,batch_size,2,Hout).

构建 LSTM 网络结构:

输入数据维度 input_size=D
隐层神经元个数 (隐层状态 ht 特征数) hidden_size=n
隐层数为 num_layers=l
传播方向为 单向
注:所有 weights 和 bias 的初始值服从均匀分布 U(k,k) ,其中 k=1n
   整个过程可以选择在 GPU 上进行来提高运算速度,此时需要将模型所有的输入向量都转到 GPU 上,具体使用 .to(device) 语句

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
class myLSTM(nn.Module):
def __init__(self, input_size, output_size, hidden_size, num_layers):
super(myLSTM, self).__init__()
self.LSTM = nn.LSTM(input_size, hidden_size, num_layers) # LSTM
self.reg = nn.Linear(hidden_size, output_size) # regression, 也就是隐藏层到输出层的线性全连接层
def forward(self, x):
# 在这里,可以指定 (h0, c0),要记得.to(device)
# 如果不指定则默认为 0 向量
x = x.to(device)
output = self.LSTM(x)[0] # output, (hm, cm) = self.LSTM(x)
# output = self.LSTM(x, (h0, c0))[0]
# seq_len是输入数据的时间点个数
seq_len, batch_size, hidden_size = output.shape # for default batch_first=False
# seq_len, hidden_size = output.shape # for unbatched input
output = output[-1,:,:] #只取最终时刻最后一层节点的隐藏状态做回归,也可以通过hm取
output = self.reg(output)
return output

4. 训练 LSTM 网络及预测

# 声明已知数据,可预先进行预处理
train_x # D*(m-L+1),因为之后时刻的 X^t 对应的 y^t 不完全已知,不同的预测任务可能会有所不同
train_y = train_x[s, :]
train_x = train_x.to(device)
train_y = train_y.to(device)
# 加载模型
net = myLSTM(input_size=D, output_size=L, hidden_size=n, num_layers=l).to(device) # 定义模型
loss = nn.MSELoss().to(device) #定义损失函数
optimizer = torch.optim.Adam(net.parameters(), lr=1e-2) #定义优化器
# 开始训练
for i in range(100): # 迭代次数
output = net(train_x) # 向前传播
Loss = loss(out, train_y) # 计算损失
optimizer.zero_grad() # 梯度清零
Loss.backward() # 反向传播
optimizer.step() # 梯度更新
if i % 10 == 0:
print('Epoch: {:4}, Loss: {:.5f}'.format(i, Loss.item()))
# 验证 LSTM 网络
test_x # D*m,为全部时刻的数据
pred_y = net(test_x)[0]
pred_y = pred_y[-1,:].item() # 简单预测最终时刻 X^m 对应的目标变量 y^m

5. 总结

5.1 功能总结

5.1 如何理解 batch?

5.2 pad_sequence 的作用?


  1. bih 指输入层与隐藏层间的 bias 向量,$b_{hh} 指隐藏层之间的 bias 向量, 也就是 第1部分 中出现的 {bf,bi,bg,bo}. ↩︎

  2. If inputs are unbatched, then this argument is ignored and the input tensor is (m,D) ↩︎

posted @   卡塔  阅读(1807)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示