长短期记忆(LSTM)模型是一种能够学习观察序列的循环神经网络。原理如图:
一、就几个问题,LSTM的参数
-
input_size (int) - 输入 元素维度 的大小。
-
hidden_size (int) - 隐藏状态元素维度大小。
-
num_layers (int,可选) - 循环网络的层数。例如,将层数设为2,会将两层GRU网络堆叠在一起,第二层的输入来自第一层的输出。默认为1。
-
direction (str,可选) - 网络迭代方向,可设置为forward或bidirect(或bidirectional)。foward指从序列开始到序列结束的单向GRU网络方向,bidirectional指从序列开始到序列结束,又从序列结束到开始的双向GRU网络方向。默认为forward。
-
time_major (bool,可选) - 指定input的第一个维度是否是time steps。如果time_major为True,则Tensor的形状为[time_steps,batch_size,input_size],否则为[batch_size,time_steps,input_size]。time_steps 指输入序列的长度。默认为False。
-
dropout (float,可选) - dropout概率,指的是出第一层外每层输入时的dropout概率。范围为[0, 1]。默认为0。
-
weight_ih_attr (ParamAttr,可选) - weight_ih的参数。默认为None。
-
weight_hh_attr (ParamAttr,可选) - weight_hh的参数。默认为None。
-
bias_ih_attr (ParamAttr,可选) - bias_ih的参数。默认为None。
-
bias_hh_attr (ParamAttr,可选) - bias_hh的参数。默认为None。
二、很多初学者,对第一个参数和第五个参数,不太理解,下面是我个人的一些看法:
1、输入元素维度,怎么理解呢,例如,在NLP中,文字,‘你’,‘我’,‘她’,你需要数字化表示例如one-hot或者embeding,需要多少个位,就是这个输入元素维度input_size了
2、第五个,batch_size,time_steps,input_size 这里第一个batch_size 就一个批多少,一次训练投入多个。time_steps是时间序列,说白 一些,就是我们需要多少个前后顺序的元素数,来构建的网络,或者是我用多少连续元素来推出我们需要的东西。一般可以根据具体问题来,例如航班预测,一般24小时,刚好周期。如果是语言,一般是一句话的长度。
三、下面使用LSTM来拟合曲线:
函有一个曲线f(x)=5*sin(x)+2*cos(x) ,利用LSTM模型预测一下,分析:
(1)绘制图形
import paddle,os,imp
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(-500,500,1001)
y=5*np.sin(x)+2*np.cos(x)
plt.figure(figsize=(10,4))
plt.plot(x[-100:],y[-100:])
函数样式如下:
(2)以6个为时间系列,6个元素来推第7个元素,搭建数据集
dataset=[]
tw=6
for i in range(len(y)-tw):
data=y[i:i+tw]
label=y[tw+i]
dataset.append([data,label])
(3)转为向量
class MyDataSet(paddle.io.Dataset):
def __init__(self,datasets):
super(MyDataSet,self).__init__()
self.datas=datasets
def __getitem__(self,idx):
data=self.datas[idx]
v=paddle.to_tensor(data[0],dtype='float32')
k=paddle.to_tensor(data[1],dtype='float32')
return v,k
def __len__(self):
return len(self.datas)
###########################################
Data=MyDataSet(dataset)
(4)构造模型:
class MyNet(paddle.nn.Layer):
def __init__(self):
super(MyNet,self).__init__()
self.lstm=paddle.nn.LSTM(input_size=1,hidden_size=20,dropout=0.1,num_layers=2)
self.line=paddle.nn.Linear(20,1)
def forward(self,x,hidden=None):
x=paddle.unsqueeze(x,axis=-1)
x=paddle.unsqueeze(x,axis=0)
if hidden==None:
h=paddle.zeros((2,1,20))
c=paddle.zeros((2,1,20))
hidden=(h,c)
lstm_out,newhidden=self.lstm(x,hidden)
x=self.line(paddle.reshape(lstm_out,(tw,-1)))
return x[-1],newhidden
详细参数表:
(5)超参数
from paddle.regularizer import L2Decay
Net=MyNet()
loss_fn=paddle.nn.MSELoss()
optim = paddle.optimizer.Momentum(learning_rate=0.0005, momentum=0.9,weight_decay=L2Decay(1e-4),parameters=Net.parameters())
(6)训练,隐藏层不用返回
epochs=50
lossvaluelist=[]
for i in range(epochs):
lossvalue_sum=0
for data in Data:
value=data[0]
label=data[1]
#print(data[0].shape)
pred,_=Net(data[0])
lossvalue=loss_fn(pred,label)
lossvalue.backward()
optim.step()
optim.clear_grad()
lossvalue_sum+=lossvalue.numpy()
lossvaluelist.append(lossvalue_sum)
print(i,lossvalue_sum)
plt.plot(range(epochs),lossvaluelist)
... 最后的第49轮后,总值:10.568565
(7)预测
用函数作图和用模型预测数据作图,比较
xx=np.linspace(500,600,101)
yy=5*np.sin(xx)+2*np.cos(xx)
###################################################
mylist=list(yy[0:tw])
hide=None
for i in range(95):
data=paddle.to_tensor(np.array(mylist[i:i+tw]),dtype='float32')
data=paddle.flatten(data)
#print(data.shape)
v,hide=Net(data,hide)
#print(v.shape)
values=v[0]
mylist.append(values)
#######################################
plt.figure(figsize=(13,4))
plt.plot(xx,yy)
plt.plot(xx,mylist)
效果图:
总结,训练过程中,Hiden输出不那么重要,在预测中,可以放入,效果更佳明显。这次训练是batch_size=1,time_steps=6,input_dim=1。上述有不足的地方,欢迎斧正。