当前位置:   article > 正文

Keras 之 LSTM 有状态模型(stateful LSTM)和无状态模型(stateless LSTM)_electricityloaddiagrams20112014

electricityloaddiagrams20112014

 目录

1. 区别

2. 例子

3. 疑问解答

4. 实战

    1. 实例1:官方的example——lstm_stateful.py

    2.  实例2:用Keras实现有状态LSTM——电量消费预测

    3.  实例3:用Keras实现有状态LSTM序列预测 

普通多层神经网络

stateless LSTM

单层Stateful LSTM

双层stacked Stateful LSTM


有状态的RNN,能在训练中维护跨批次的状态信息,即为当前批次的训练数据计算的状态值,可以用作下一批次训练数据的初始隐藏状态。因为Keras RNN默认是无状态的,这需要显示设置。stateful代表除了每个样本内的时间步内传递,而且每个样本之间会有信息(c,h)传递,而stateless指的只是样本内的信息传递。

参考目录:


1. 区别

  • stateful LSTM

       能让模型学习到你输入的samples之间的时序特征,适合一些长序列的预测,哪个sample在前,哪个sample在后对模型是有影响的。

       优点:更小的网络,或更少的训练时间。

       缺点:需要使用反应数据周期性的批大小来训练网络,并在每个训练批后重置状态。

  • stateless LSTM:

        输入samples后,默认就会shuffle,可以说是每个sample独立,之间无前后关系,适合输入一些没有关系的样本。


2. 例子

  1. stateful LSTM:我想根据一篇1000句的文章预测第1001句,每一句是一个sample。我会选用stateful,因为这文章里的1000句是有前后关联的,是有时序的特征的,我不想丢弃这个特征。利用这个时序性能让第一句的特征传递到我们预测的第1001句。(batch_size = 10时)
  2. stateless LSTM:我想训练LSTM自动写诗句,我想训练1000首诗,每一首是一个sample,我会选用stateless LSTM,因为这1000首诗是独立的,不存在关联,哪怕打乱它们的顺序,对于模型训练来说也没区别。

当使用有状态 RNN 时,假定:

  1. 所有的批次都有相同数量的样本
  2. 如果 x1 和 x2 是连续批次的样本,则x2[i]是 x1[i] 的后续序列,对于每个i。

要在 RNN 中使用状态,需要:

  1. 通过将 batch_size 参数传递给模型的第一层来显式指定你正在使用的批大小。例如,对于 10 个时间步长的 32 样本的 batch,每个时间步长具有 16 个特征,batch_size = 32。
  2. 在 RNN 层中设置 stateful = True。
  3. 在调用 fit() 时指定 shuffle = False。

重置累积状态:

  1. 使用 model.reset_states()来重置模型中所有层的状态
  2. 使用layer.reset_states()来重置指定有状态 RNN 层的状态

     

3. 疑问解答

  1. 将一个很长的序列(例如时间序列)分成小序列来构建我的输入矩阵。那LSTM网络会发现我这些小序列之间的关联依赖吗?
           不会,除非你使用 stateful LSTM 。大多数问题使用stateless LSTM即可解决,所以如果你想使用stateful LSTM,请确保自己是真的需要它。在stateless时,长期记忆网络并不意味着你的LSTM将记住之前batch的内容。
  2. 在Keras中stateless LSTM中的stateless指的是?
            注意,此文所说的stateful是指的在Keras中特有的,是batch之间的记忆cell状态传递。而非说的是LSTM论文模型中表示那些记忆门,遗忘门,c,h等等在同一sequence中不同timesteps时间步之间的状态传递。
            假定我们的输入X是一个三维矩阵,shape = (nb_samples, timesteps, input_dim),每一个row代表一个sample,每个sample都是一个sequence小序列。X[i]表示输入矩阵中第isample。步长啥的我们先不用管。
            当我们在默认状态stateless下,Keras会在训练每个sequence小序列(=sample)开始时,将LSTM网络中的记忆状态参数reset初始化(指的是c,h而并非权重w),即调用model.reset_states()

  3. 为啥stateless LSTM每次训练都要初始化记忆参数?
            因为Keras在训练时会默认地shuffle samples,所以导致sequence之间的依赖性消失,samplesample之间就没有时序关系,顺序被打乱,这时记忆参数在batch、小序列之间进行传递就没意义了,所以Keras要把记忆参数初始化。
  4. 那stateful LSTM到底怎么传递记忆参数?
           首先要明确一点,LSTM作为有记忆的网络,它的有记忆指的是在一个sequence中,记忆在不同的timesteps中传播。举个例子,就是你有一篇文章X,分解,然后把每个句子作为一个sample训练对象(sequence),X[i]就代表一句话,而一句话里的每个word各自代表一个timestep时间步,LSTM的有记忆即指的是在一句话里,X[i][0]第一个单词(时间步)的信息可以被记忆,传递到第5个单词(时间步)X[i][5]中。
           而我们突然觉得,这还远远不够,因为句子和句子之间没有任何的记忆啊,假设文章一共1000句话,我们想预测出第1001句是什么,不想丢弃前1000句里的一些时序性特征(stateless时这1000句训练时会被打乱,时序性特征丢失)。那么,stateful LSTM就可以做到。
           在stateful = True 时,我们要在fit中手动使得shuffle = False。随后,在X[i](表示输入矩阵中第isample)这个小序列训练完之后,Keras会将将训练完的记忆参数传递给X[i+bs](表示第i+bs个sample),作为其初始的记忆参数。bs = batch_size。这样一来,我们的记忆参数就能顺利地在samplesample之间传递,X[i+n*bs]也能知道X[i]的信息

4. 实战

    1. 实例1官方的example——lstm_stateful.py

https://github.com/keras-team/keras/blob/master/examples/lstm_stateful.py

    2.  实例2:用Keras实现有状态LSTM——电量消费预测

代码如下:

数据集:UCI机器学习库下载 ElectricityLoadDiagrams20112014

  1. from __future__ import division, print_function
  2. from keras.layers.core import Dense
  3. from keras.layers.recurrent import LSTM
  4. from keras.models import Sequential
  5. from sklearn.preprocessing import MinMaxScaler
  6. import numpy as np
  7. import math
  8. import os
  9. DATA_DIR = "../data"
  10. data = np.load(os.path.join(DATA_DIR, "LD_250.npy"))
  11. STATELESS = False
  12. NUM_TIMESTEPS = 20
  13. HIDDEN_SIZE = 10
  14. BATCH_SIZE = 96 # 24 hours (15 min intervals)
  15. NUM_EPOCHS = 5
  16. # 归一化:range (0, 1)
  17. data = data.reshape(-1, 1)
  18. scaler = MinMaxScaler(feature_range=(0, 1), copy=False)
  19. data = scaler.fit_transform(data)
  20. # 把输入张量调整为LSTM需要的三维向量,即(样例,时间步,特征)
  21. X = np.zeros((data.shape[0], NUM_TIMESTEPS))
  22. Y = np.zeros((data.shape[0], 1))
  23. for i in range(len(data) - NUM_TIMESTEPS - 1):
  24. X[i] = data[i:i + NUM_TIMESTEPS].T
  25. Y[i] = data[i + NUM_TIMESTEPS + 1]
  26. # 将X变形为三维 (samples, timesteps, features)
  27. X = np.expand_dims(X, axis=2)
  28. # 在第axis=2维加上一维数据,即(data.shape[0],,NUM_TIMESTEPS,1),最后一维代表1个特征
  29. # 划分数据集
  30. sp = int(0.7 * len(data))
  31. Xtrain, Xtest, Ytrain, Ytest = X[0:sp], X[sp:], Y[0:sp], Y[sp:]
  32. print(Xtrain.shape, Xtest.shape, Ytrain.shape, Ytest.shape)
  33. # 无状态
  34. if STATELESS:
  35. # stateless
  36. model = Sequential()
  37. model.add(LSTM(HIDDEN_SIZE, input_shape=(NUM_TIMESTEPS, 1),
  38. return_sequences=False))
  39. model.add(Dense(1))
  40. # 有状态
  41. else:
  42. # stateful
  43. model = Sequential()
  44. model.add(LSTM(HIDDEN_SIZE, stateful=True,
  45. batch_input_shape=(BATCH_SIZE, NUM_TIMESTEPS, 1),
  46. return_sequences=False))
  47. model.add(Dense(1))
  48. model.compile(loss="mean_squared_error", optimizer="adam",
  49. metrics=["mean_squared_error"])
  50. # 无状态
  51. if STATELESS:
  52. # stateless
  53. model.fit(Xtrain, Ytrain, epochs=NUM_EPOCHS, batch_size=BATCH_SIZE,
  54. validation_data=(Xtest, Ytest),
  55. shuffle=False)
  56. # 有状态
  57. else:
  58. # 将训练和测试数据设为BATCH_SIZE的倍数
  59. train_size = (Xtrain.shape[0] // BATCH_SIZE) * BATCH_SIZE
  60. test_size = (Xtest.shape[0] // BATCH_SIZE) * BATCH_SIZE
  61. Xtrain, Ytrain = Xtrain[0:train_size], Ytrain[0:train_size]
  62. Xtest, Ytest = Xtest[0:test_size], Ytest[0:test_size]
  63. print(Xtrain.shape, Xtest.shape, Ytrain.shape, Ytest.shape)
  64. for i in range(NUM_EPOCHS):
  65. print("Epoch {:d}/{:d}".format(i+1, NUM_EPOCHS))
  66. model.fit(Xtrain, Ytrain, batch_size=BATCH_SIZE, epochs=1,
  67. validation_data=(Xtest, Ytest),
  68. shuffle=False)
  69. model.reset_states()
  70. score, _ = model.evaluate(Xtest, Ytest, batch_size=BATCH_SIZE)
  71. rmse = math.sqrt(score)
  72. print("\nMSE: {:.3f}, RMSE: {:.3f}".format(score, rmse))
  73. pre = model.predict(Xtest, batch_size=BATCH_SIZE)
  74. plt.figure(figsize=(12,5))
  75. # plt.subplot(211)
  76. plt.plot(pre[:1000],'r',label='predctions')
  77. # plt.subplot(212)
  78. plt.plot(Ytest[:1000],label='origin')
  79. plt.legend()
  80. plt.show()

结果: 

 3.  实例3:用Keras实现有状态LSTM序列预测

本实战代码地址:GitHub
       https://github.com/youyuge34/Cosine_Stateful_Lstm/blob/master/Stateful_Lstm_Keras.ipynb

  • 普通多层神经网络

  1. import numpy as np
  2. from __future__ import print_function
  3. from standard_plots import *
  4. from keras.models import Sequential
  5. from keras.layers import Dense, LSTM, Dropout
  6. import matplotlib.pyplot as plt
  7. # 创建数据集
  8. dataset = np.cos(np.arange(1000)*(20*np.pi/1000))
  9. plt_plot(y = dataset, title = 'cos')
  10. # 转换数据为LSTM输入格式: dataset matrix
  11. def create_dataset(dataset, look_back=1):
  12. dataX, dataY = [], []
  13. for i in range(len(dataset)-look_back):
  14. dataX.append(dataset[i:(i+look_back)])
  15. dataY.append(dataset[i + look_back])
  16. return np.array(dataX), np.array(dataY)
  17. look_back =40
  18. dataset = np.cos(np.arange(1000)*(20*np.pi/1000))
  19. # 归一化,y值域为(0,1)
  20. dataset = (dataset+1) / 2.
  21. # split into train and test sets
  22. train_size = int(len(dataset) * 0.8)
  23. test_size = len(dataset) - train_size
  24. train, test = dataset[:train_size], dataset[train_size:]
  25. trainX, trainY = create_dataset(train, look_back)
  26. print(trainX.shape)
  27. print(trainY.shape)
  28. trainX = np.squeeze(trainX)
  29. testX = np.squeeze(testX)
  30. model4 = Sequential()
  31. model4.add(Dense(units=32,input_dim=look_back,activation="relu"))
  32. model4.add(Dropout(0.3))
  33. for i in range(2):
  34. model4.add(Dense(units=32,activation="relu"))
  35. model4.add(Dropout(0.3))
  36. model4.add(Dense(1))
  37. model4.compile(loss='mse', optimizer='adagrad')
  38. model4.fit(trainX, trainY, epochs=400, batch_size=32, verbose=0)
  39. x = np.hstack((trainX[-1][1:],(trainY[-1])))
  40. preds = []
  41. pred_num = 500
  42. for i in np.arange(pred_num):
  43. pred = model4.predict(x.reshape((1,-1)),batch_size = batch_size)
  44. preds.append(pred.squeeze())
  45. x = np.append(x[1:],pred)
  46. # print(preds[:20])
  47. # print(np.array(preds).shape)
  48. plt.figure(figsize=(12,5))
  49. plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
  50. cos_y = (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
  51. plt.plot(np.arange(pred_num),cos_y,label='origin')
  52. plt.legend()
  53. plt.show()
预测结果:

 

  • stateless LSTM

  1. # 20长度的滑动窗口进行预测
  2. look_back = 20
  3. #归一化,y值域为(0,1)
  4. dataset = (dataset+1) / 2.
  5. # split into train and test sets
  6. train_size = int(len(dataset) * 0.8)
  7. test_size = len(dataset) - train_size
  8. train, test = dataset[:train_size], dataset[train_size:]
  9. trainX, trainY = create_dataset(train, look_back)
  10. testX, testY = create_dataset(test, look_back)
  11. trainX = np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
  12. testX = np.reshape(testX, (testX.shape[0], testX.shape[1], 1))
  13. '''
  14. trainX.shape = (780, 20, 1)
  15. testX.shape = (180, 20, 1)
  16. trainY.shape = (780,)
  17. testY.shape = (180,)
  18. '''
  19. batch_size = 1
  20. # 建立模型
  21. # 无状态LSTM
  22. model = Sequential()
  23. model.add(LSTM(32, input_shape=(20, 1)))
  24. model.add(Dropout(0.2))
  25. model.add(Dense(1))
  26. model.compile(loss = 'mse', optimizer = 'adam')
  27. model.fit(trainX,trainY,batch_size = batch_size,epochs=30, verbose=2)
  28. # 预测
  29. x = np.vstack((trainX[-1][1:],(trainY[-1]))) # 获取trainX的最后一个窗口数据,来预测未来数据
  30. preds = []
  31. pred_num = 500
  32. for i in np.arange(pred_num):
  33. pred = model.predict(x.reshape((1,-1,1)),batch_size = batch_size)
  34. preds.append(pred.squeeze())
  35. x = np.vstack((x[1:],pred))
  36. # print(preds[:20])
  37. # print(np.array(preds).shape)
  38. plt.figure(figsize=(12,5))
  39. plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
  40. cos_y = (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
  41. plt.plot(np.arange(pred_num),cos_y,label='origin')
  42. plt.legend()
  43. plt.show()

输出结果:

  • 单层Stateful LSTM

  1. # 有状态 LSTM network
  2. batch_size = 1
  3. model2 = Sequential()
  4. model2.add(LSTM(32, batch_input_shape=(batch_size, look_back, 1), stateful=True))
  5. model2.add(Dropout(0.2))
  6. model2.add(Dense(1))
  7. model2.compile(loss='mse', optimizer='adam')
  8. for i in range(30):
  9. model2.fit(trainX, trainY, epochs=1, batch_size=batch_size, shuffle=False)
  10. model2.reset_states()
  11. x = np.vstack((trainX[-1][1:],(trainY[-1])))
  12. preds = []
  13. pred_num = 500
  14. for i in np.arange(pred_num):
  15. pred = model2.predict(x.reshape((1,-1,1)),batch_size = batch_size)
  16. preds.append(pred.squeeze())
  17. x = np.vstack((x[1:],pred))
  18. # print(preds[:20])
  19. # print(np.array(preds).shape)
  20. plt.figure(figsize=(12,5))
  21. plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
  22. cos_y = (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
  23. plt.plot(np.arange(pred_num),cos_y,label='origin')
  24. plt.legend()
  25. plt.show()

输出结果:

  • 双层stacked Stateful LSTM

  1. look_back =40
  2. dataset = np.cos(np.arange(1000)*(20*np.pi/1000))
  3. #归一化,y值域为(0,1)
  4. dataset = (dataset+1) / 2.
  5. # split into train and test sets
  6. train_size = int(len(dataset) * 0.8)
  7. test_size = len(dataset) - train_size
  8. train, test = dataset[:train_size], dataset[train_size:]
  9. trainX, trainY = create_dataset(train, look_back)
  10. testX, testY = create_dataset(test, look_back)
  11. trainX = np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
  12. testX = np.reshape(testX, (testX.shape[0], testX.shape[1], 1))
  13. # 建立模型:有状态
  14. batch_size = 1
  15. model3 = Sequential()
  16. model3.add(LSTM(32, batch_input_shape=(batch_size, look_back, 1), stateful=True, return_sequences=True))
  17. model3.add(Dropout(0.3))
  18. model3.add(LSTM(32, batch_input_shape=(batch_size, look_back, 1), stateful=True))
  19. model3.add(Dropout(0.3))
  20. model3.add(Dense(1))
  21. model3.compile(loss='mean_squared_error', optimizer='adam')
  22. for i in range(100):
  23. model3.fit(trainX, trainY, epochs=1, batch_size=batch_size, verbose=0, shuffle=False)
  24. model3.reset_states()
  25. # 预测
  26. x = np.vstack((trainX[-1][1:],(trainY[-1])))
  27. preds = []
  28. pred_num = 500
  29. for i in np.arange(pred_num):
  30. pred = model3.predict(x.reshape((1,-1,1)),batch_size = batch_size)
  31. preds.append(pred.squeeze())
  32. x = np.vstack((x[1:],pred))
  33. # print(preds[:20])
  34. # print(np.array(preds).shape)
  35. plt.figure(figsize=(12,5))
  36. plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
  37. cos_y = (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
  38. plt.plot(np.arange(pred_num),cos_y,label='origin')
  39. plt.legend()
  40. plt.show()

输出结果:

因此,有状态模型生成的结果略优于无状态模型。

警告: 永远不要在不熟悉stateful LSTM的情况下使用它

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/848267
推荐阅读
相关标签
  

闽ICP备14008679号