为什么使用rnn模型时,需要用到滑动窗口预测所有数据:

        由于RNN模型,是之前的输入会对后来的输入样本的预测结果有影响。所以训练模型时候,在网络构建中定义的输入尺寸,在这里定义了输入的样本数是 TIME_STEP 个,所以预测时,也要用相同的尺寸,预测出相应尺寸的结果。

        如果这段话你听的不太明白你需要在深入理解一下RNN循环神经网络的原理。

参考:史上最详细循环神经网络讲解(RNN/LSTM/GRU) - 知乎

        RNN 循环神经网络 回归 - 简书


这里是我构建的rnn网络的结构:

class RNN(nn.Module):
    def __init__(self):
        super(RNN, self).__init__()

        self.rnn = nn.RNN(
            input_size=INPUT_SIZE,
            hidden_size=128,
            num_layers=1,
            batch_first=True,
        )
        self.fc1 = nn.Linear(128, 64)
        self.fc2 = nn.Linear(64, 1)

    # https://zhuanlan.zhihu.com/p/60792047
    def forward(self, x, h_state):
        r_out, h_state = self.rnn(x, h_state)
        # outs = []
        # for time_step in range(r_out.size(1)):
        #     outs.append(self.out(r_out[:, time_step, :]))
        # return torch.stack(outs, dim=1), h_state

        # instead, for simplicity, you can replace above codes by follows
        r_out = r_out.reshape(-1, 128)
        outs = self.fc1(r_out)
        outs = F.relu(outs)
        # outs = outs.reshape(-1, 64)
        outs = self.fc2(outs)

        outs = outs.view(-1, TIME_STEP, 1)
        return outs, h_state

训练模型的过程:

# 训练模型    # 创建rnn网络模型
rnn = RNN()
# 模型加入装置
rnn.to(device)
# 优化器
optimizer = torch.optim.Adam(rnn.parameters(), lr=Lr)
# 损失函数
loss_func = nn.MSELoss()
# 初始化隐藏状态
h_state = None

losses = []
for epoch in range(300):
    batch_loss = []
    batch_count = batch_size*TIME_STEP
    for start in range(0, len(X_data), batch_count):
        if start + batch_count < len(X_data):
            end = start + batch_count
            # print(rf'{start}--->{end}')
            # 提取数据变成张量,提取shape(batch, time_step, input_size/output_size)
            xx = torch.tensor(X_data[start:end], dtype=torch.float, requires_grad=True).view(
                [batch_size, TIME_STEP, INPUT_SIZE])
            yy = torch.tensor(y_data[start:end], dtype=torch.float, requires_grad=True).view(
                [batch_size, TIME_STEP, 1])
            # print(yy.view([10, 10, 22]))  # tensor_01.view([2, 3, -1, 2])
            # print(yy.shape)
            # print(yy)
            prediction, h_state = rnn(xx, h_state)  # rnn output
            # !! next step is important !!
            h_state = h_state.data  # repack the hidden state, break the connection from last iteration

            loss = loss_func(prediction, yy)
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            try:
                batch_loss.append(loss.data.numpy())
            except:
                batch_loss.append(loss.data.numpy())

    if epoch % 10 == 0:
        losses.append(np.mean(batch_loss))
        print(epoch, losses[-1])

在测试集,用滑动窗口预测全部数据的操作:

# 转化tensor格式
x = torch.tensor(X_data, dtype=torch.float).to(device)
# 滑动窗口预测(十个结果全取的结果)
# 初始化隐藏状态
h_state = None
prediction_ = torch.FloatTensor()
for start in range(0, len(X_data), TIME_STEP):
    if start + TIME_STEP < len(X_data):
        end = start + TIME_STEP
        x_ = x[start:end].view([1, TIME_STEP, 22])
        prediction, h_state = rnn(x_, h_state)
        h_state = h_state.data  # rnn output
        prediction_ = torch.cat((prediction_, prediction), 0)
# 预测结果tensor拉平
prediction_ = prediction_.view(-1, 1)
# 添加最后没法与预测的边角料,目的使预测结果长度与真实结果长度一致
last_len = len(X_data) % 10
last_ = torch.rand(last_len, 1).to(device)
prediction_ = torch.cat((prediction_, last_), 0)
# 转化为数组形式
predict = prediction_.data.numpy()

结果展示:

        预测了一个风电场7天出力,结果显示还可以,但是比不上xgb,建议在特征量没有很大量的时候,还是慎重使用深度学习去预测。

 

 

更多推荐