WNTR+LSTM实战

在之前的文章中,我们已经实现了WNTR的模拟,数据的预处理,现在我们正式进入LSTM实战,通过原始时间序列的7个输入和每天特定时间点的输入进行预测。

下图是我们的数据集,colum是节点的名称。本次我们使用第5号节点来预测它的用水压力,查看lstm的时间序列预测和模拟的真实数据间的差别。
在这里插入图片描述

首先我们把之前已经完成数据处理的代码放上,详情请见前文:https://blog.csdn.net/wenxiaoshuai001/article/details/118054779?spm=1001.2014.3001.5501

import torch
import torch.nn as nn
from torch.utils.data import Dataset,DataLoader
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
from sklearn.preprocessing import MinMaxScaler

time_series = pd.read_csv('../wntr-data/pressure data.csv')

node5_15min = time_series.loc[:,'5']
# print(len(node5_15min))
#
#
# plt.plot(node5_15min[:385])
# plt.show()

#把数据转换成浮点数
all_data = node5_15min.values.astype(float)

#选择输入的波形
test_data_size = 16
train_data = all_data[:-test_data_size]
test_data = all_data[-test_data_size:]

scaler = MinMaxScaler(feature_range=(0, 1))
train_data_normalized = scaler.fit_transform(train_data .reshape(-1, 1))

train_data = torch.FloatTensor(train_data).view(-1)

train_window = 7
def create_inout_sequences(input_data, tw):
    inout_seq = []
    L = len(input_data)
    for i in range(672,L-tw):
        train_seq1 = input_data[i:i+tw]
        train_seq2 = input_data[i+tw-96*7:i+tw:96]
        train_seq = torch.cat([train_seq1,train_seq2])
        train_label = input_data[i+tw:i+tw+1]
        inout_seq.append((train_seq ,train_label))
    return inout_seq

train_inout_seq = create_inout_sequences(train_data, train_window)
#print(train_inout_seq[:5])

接下来我们正式进行LSTM的构建,由于计算的原因,我们的网络首先选择比较简单的结构,即单层的LSTM,input_size = 1,hidden_size = 64(超参数估计),num_layer = 1
在这里插入图片描述
在这里插入图片描述
我们的batch就设置为1,seq=14,vec = 1,接着使用gpu加速计算
所以out=(seq ,1,1) h/c = (1,1,1) x =(seq ,1,1)

device = torch.device('cuda')

class LSTM(nn.Module):
    def __init__(self, input_size=1, hidden_layer_size=64, output_size=1):
        super().__init__()
        self.hidden_layer_size = hidden_layer_size

        self.lstm = nn.LSTM(input_size, hidden_layer_size)

        self.linear = nn.Linear(hidden_layer_size, output_size)

        self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
                            torch.zeros(1,1,self.hidden_layer_size))

    def forward(self, input_seq):
        #首先我们输入(14,1,1)的输入和hidden_layer
        lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
        #预测得到的out进入线性层转换成一个标量
        predictions = self.linear(lstm_out.view(len(input_seq), -1))
        #所有的预测结果,取最后的值为真正的预测值
        return predictions[-1]
model = LSTM().to(device)
loss_function = nn.MSELoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.003)

epochs = 150,每次遍历中,拿出train_inout_seq的data与target进入模型中
train_inout_seq的数据结构是[(data1,target1),(data2,target2)…]
所以每次输入是(14,1,1)输出是1,输出与target对比计算损失函数

epochs = 101

for i in range(epochs):
    for seq, labels in train_inout_seq:
        seq,labels =seq.to(device),labels.to(device)
        optimizer.zero_grad()
        a = torch.zeros(1, 1, model.hidden_layer_size).to(device)
        b = torch.zeros(1, 1, model.hidden_layer_size).to(device)
        model.hidden_cell = (a,b)


        y_pred = model(seq)

        single_loss = loss_function(y_pred, labels)
        single_loss.backward()
        optimizer.step()

    if i%25 == 1:
        print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')

最后,我们想要看一看预测值和真实值到底差多少。假设最终预测7个值:
我们需要构造最终预测的输入(14,),除了时间序列最后的7个值以外,还需要取7个分别是train_data[-95],train_data[-95-96:-95-96*6-1:96]



test_inputs1 = train_data[-train_window:]
test_inputs2 = train_data[-95]
test_inputs3 = train_data[-95-96:-95-96*6-1:96]
test_inputs = torch.cat([test_inputs1,test_inputs1,test_inputs1]).to(device)
seq = test_inputs
with torch.no_grad():
    a = torch.zeros(1, 1, model.hidden_layer_size).to(device)
    b = torch.zeros(1, 1, model.hidden_layer_size).to(device)
    model.hidden_cell = (a, b)
    print(model(seq))
    print(model(test_inputs) - test_data[0])

我们预测了一个值,因为第二个输入:特定时间的7天周滑动窗口的构建,考虑多因素还是比较麻烦,以下是模拟结果

"C:\Users\wen EX\condaex\anaconda3\python.exe" "C:/Users/wen EX/Desktop/WNTR-LSTM/wntr-code/code4 mult-input.py"
epoch:   1 loss: 5.23556423
epoch:  26 loss: 0.09641330
epoch:  51 loss: 0.00392726
epoch:  76 loss: 0.00107751
tensor([34.4022], device='cuda:0')
tensor([-0.2772], device='cuda:0')

误差在6%,感觉可以接受.

现在我们遇到的问题是如何连续地实现第二个输入的滑动窗口,保证能取到预测值得前七天特定时刻作为输入。
其次是确定超参数的问题,几层lstm网络,几层线性层?还有或许可以取消归一化,直接在网络中实现LN层的加入。
进一步,是否可以预测较长时间的序列,如根据14个特征预测接下来的3个15min的结果等待解决。

总体代码如下所示:

import torch
import torch.nn as nn
from torch.utils.data import Dataset,DataLoader
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
from sklearn.preprocessing import MinMaxScaler

time_series = pd.read_csv('../wntr-data/pressure data.csv')

node5_15min = time_series.loc[:,'5']
# print(len(node5_15min))
#
#
# plt.plot(node5_15min[:385])
# plt.show()

#把数据转换成浮点数
all_data = node5_15min.values.astype(float)
all_data = all_data[:1250]

#选择输入的波形
test_data_size = 16
train_data = all_data[:-test_data_size]
test_data = all_data[-test_data_size:]

scaler = MinMaxScaler(feature_range=(0, 1))
train_data_normalized = scaler.fit_transform(train_data .reshape(-1, 1))

train_data = torch.FloatTensor(train_data).view(-1)

train_window = 7
def create_inout_sequences(input_data, tw):
    inout_seq = []
    L = len(input_data)
    for i in range(672,L-tw):
        train_seq1 = input_data[i:i+tw]
        train_seq2 = input_data[i+tw-96*7:i+tw:96]
        train_seq = torch.cat([train_seq1,train_seq2])
        train_label = input_data[i+tw:i+tw+1]
        inout_seq.append((train_seq ,train_label))
    return inout_seq

train_inout_seq = create_inout_sequences(train_data, train_window)
# print(train_inout_seq[:5])

device = torch.device('cuda')

class LSTM(nn.Module):
    def __init__(self, input_size=1, hidden_layer_size=64, output_size=1):
        super().__init__()
        self.hidden_layer_size = hidden_layer_size

        self.lstm = nn.LSTM(input_size, hidden_layer_size)

        self.linear = nn.Linear(hidden_layer_size, output_size)

        self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
                            torch.zeros(1,1,self.hidden_layer_size))

    def forward(self, input_seq):
        lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
        predictions = self.linear(lstm_out.view(len(input_seq), -1))
        return predictions[-1]
model = LSTM().to(device)
loss_function = nn.MSELoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.002)

epochs = 101

for i in range(epochs):
    for seq, labels in train_inout_seq:
        seq,labels =seq.to(device),labels.to(device)
        optimizer.zero_grad()
        a = torch.zeros(1, 1, model.hidden_layer_size).to(device)
        b = torch.zeros(1, 1, model.hidden_layer_size).to(device)
        model.hidden_cell = (a,b)


        y_pred = model(seq)

        single_loss = loss_function(y_pred, labels)
        single_loss.backward()
        optimizer.step()

    if i%25 == 1:
        print(f'epoch: {i:3} loss: {single_loss.item():10.8f}')


fut_pred = 7

test_inputs1 = train_data[-train_window:]
test_inputs2 = train_data[-95]
test_inputs3 = train_data[-95-96:-95-96*6-1:96]
test_inputs = torch.cat([test_inputs1,test_inputs1,test_inputs1]).to(device)
seq = test_inputs
with torch.no_grad():
    a = torch.zeros(1, 1, model.hidden_layer_size).to(device)
    b = torch.zeros(1, 1, model.hidden_layer_size).to(device)
    model.hidden_cell = (a, b)
    print(model(seq))
    print(model(test_inputs) - test_data[0])
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值