0


基于自注意力机制的LSTM多变量负荷预测

1.引言

  1. 在之前使用长短期记忆网络构建电力负荷预测模型的基础上,将自注意力机制 (Self-Attention)融入到负荷预测模型中。具体内容是是在LSTM层后面接Self-Attention层,在加入Self-Attention后,可以将负荷数据通过加权求和的方式进行处理,对负荷特征添加注意力权重,来突出负荷的影响因数。结果表明,通过自注意力机制,可以更好的挖掘电力负荷数据的特征以及变化规律信息,提高预测模型的性能。
  2. 环境:python3.8tensorflow2.5.

2.原理

2.1.自注意力机制

  1. 自注意力机制网上很多推导,这里就不再赘述,需要的可以看博客,这个博客讲的很好。

2.2 模型结构

主要包含输入层,LSTM层,位置编码层,自注意力机制层,以及输出层。

3. 实战

3.1 数据结构

  1. 采用2016电工杯负荷预测数据,每15分钟采样一次,一天共96个负荷值与5个气象数据(温度湿度降雨量啥的)。我们采用滚动建模预测,就是利用1n天的所有值为输入,第n+1天的96个负荷值为输出;然后2n+1天的所有值为输入,第n+2天的96个负荷值为输出,这样进行滚动序列建模。这个n就是时间步,程序里面设置的是20,所以上面的输入层你看到是Nonex20x101,输出是Nonex96

3.2 建模预测

  1. # coding: utf-8
  2. from sklearn.preprocessing import StandardScaler,MinMaxScaler
  3. from sklearn.metrics import r2_score
  4. import pandas as pd
  5. import numpy as np
  6. import os
  7. import matplotlib.pyplot as plt
  8. plt.rcParams['font.sans-serif']=['SimHei']
  9. plt.rcParams['axes.unicode_minus'] = False
  10. from tensorflow.keras.models import Model
  11. from tensorflow.keras.layers import Input,Dense,LSTM
  12. import tensorflow as tf
  13. from Layers import SelfAttention,AddSinusoidalPositionalEncodings
  14. os.environ["PATH"] += os.pathsep + 'C:/Program Files (x86)/Graphviz2.38/bin/'
  15. from tensorflow.keras.utils import plot_model
  16. # In[]定义一些需要的函数
  17. def build_model(seq,fea,out):
  18. input_ = Input(shape=(seq,fea))
  19. x=LSTM(20, return_sequences=True)(input_)
  20. pos = AddSinusoidalPositionalEncodings()(x)
  21. att = SelfAttention(100,100,return_sequence=False, dropout=.0)(pos)
  22. out = Dense(out, activation=None)(att)
  23. model = Model(inputs=input_, outputs=out)
  24. return model
  25. def split_data(data, n):
  26. in_ = []
  27. out_ = []
  28. N = data.shape[0] - n
  29. for i in range(N):
  30. in_.append(data[i:i + n,:])
  31. out_.append(data[i + n,:96])
  32. in_ = np.array(in_).reshape(len(in_), -1)
  33. out_ = np.array(out_).reshape(len(out_), -1)
  34. return in_, out_
  35. def result(real,pred,name):
  36. # ss_X = MinMaxScaler(feature_range=(-1, 1))
  37. # real = ss_X.fit_transform(real).reshape(-1,)
  38. # pred = ss_X.transform(pred).reshape(-1,)
  39. real=real.reshape(-1,)
  40. pred=pred.reshape(-1,)
  41. # mape
  42. test_mape = np.mean(np.abs((pred - real) / real))
  43. # rmse
  44. test_rmse = np.sqrt(np.mean(np.square(pred - real)))
  45. # mae
  46. test_mae = np.mean(np.abs(pred - real))
  47. # R2
  48. test_r2 = r2_score(real, pred)
  49. print(name,'的mape:%.4f,rmse:%.4f,mae:%.4f,R2:%.4f'%(test_mape ,test_rmse, test_mae, test_r2))
  50. # In[]
  51. df=pd.read_csv('数据集/data196.csv').fillna(0).iloc[:,1:]
  52. data=df.values
  53. time_steps=20
  54. in_,out_=split_data(data,time_steps)
  55. n=range(in_.shape[0])
  56. #m=int(0.8*in_.shape[0])#前80%训练 后20%测试
  57. m=-2#最后两天测试
  58. train_data = in_[n[0:m],]
  59. test_data = in_[n[m:],]
  60. train_label = out_[n[0:m],]
  61. test_label = out_[n[m:],]
  62. # 归一化
  63. ss_X = StandardScaler().fit(train_data)
  64. ss_Y = StandardScaler().fit(train_label)
  65. # ss_X = MinMaxScaler(feature_range=(0, 1)).fit(train_data)
  66. # ss_Y = MinMaxScaler(feature_range=(0, 1)).fit(train_label)
  67. train_data = ss_X.transform(train_data).reshape(train_data.shape[0], time_steps, -1)
  68. train_label = ss_Y.transform(train_label)
  69. test_data = ss_X.transform(test_data).reshape(test_data.shape[0], time_steps, -1)
  70. test_label = ss_Y.transform(test_label)
  71. # In[]
  72. model=build_model(train_data.shape[-2],train_data.shape[-1],train_label.shape[-1])
  73. #查看网络结构
  74. model.summary()
  75. plot_model(model, show_shapes=True, to_file='result/lstmsa_model.jpg')
  76. train_again=True #为 False 的时候就直接加载训练好的模型进行测试
  77. #训练模型
  78. if train_again:
  79. #编译模型
  80. model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001), loss='mse')
  81. #训练模型
  82. history=model.fit(train_data,train_label,batch_size=64,epochs=100,
  83. verbose=1,validation_data=(test_data,test_label))
  84. # In[8]
  85. model.save_weights('result/lstmsa_model.h5')
  86. loss = history.history['loss']
  87. val_loss = history.history['val_loss']
  88. plt.plot( loss, label='Train Loss')
  89. plt.plot( val_loss, label='Test Loss')
  90. plt.title('Train and Val Loss')
  91. plt.legend()
  92. plt.savefig('result/lstmsa_model_loss.jpg')
  93. plt.show()
  94. else:#加载模型
  95. model.load_weights('result/lstmsa_model.h5')
  96. # In[]
  97. test_pred = model.predict(test_data)
  98. # 对测试集的预测结果进行反归一化
  99. test_label1 = ss_Y.inverse_transform(test_label)
  100. test_pred1 = ss_Y.inverse_transform(test_pred)
  101. # In[]计算各种指标
  102. result(test_label1,test_pred1,'LSTM-SA')
  103. np.savez('result/lstmsa1.npz',real=test_label1,pred=test_pred1)
  104. test_label=test_label1.reshape(-1,)
  105. test_pred=test_pred1.reshape(-1,)
  106. # plot test_set result
  107. plt.figure()
  108. plt.plot(test_label, c='r', label='real')
  109. plt.plot(test_pred, c='b', label='pred')
  110. plt.legend()
  111. plt.xlabel('样本点')
  112. plt.ylabel('功率')
  113. plt.title('测试集')
  114. plt.show()

3.2 结果对比

  1. 将其与RNNLSTM进行对比,结果如下

测试集取的是最后两天的,从结果上看,显然提出的方法效果最好

4.代码

  1. 详细代码见评论区。

本文转载自: https://blog.csdn.net/qq_41043389/article/details/128510691
版权归原作者 机器鱼 所有, 如有侵权,请联系我们删除。

“基于自注意力机制的LSTM多变量负荷预测”的评论:

还没有评论