1

利用深度学习实现序列模型

利用深度学习实现序列模型

序列问题的含义是接收一个序列作为输入,然后期望预测这个序列的后续。例如继续预测2,4,6,8,10...。这在时间序列中是相当常见的,可以用来预测股市的波动、患者的体温曲线或者赛车所需的加速度。
从原理上说,卷积神经网络可以有效处理空间信息,那么循环神经网络则能更好处理序列信息。

对超出已知观测范围进行预测称为外推法(extrapolation),而在现有观测值之间进行估计称为内插法(interpolation)。显然,外推法较内插法更为困难。预测未来明显是令人更兴奋的事。
例如股票预测问题,假设股票价格与之前某时刻的价格相关,因此有如下预测方法:
\(x_{t} \sim P(x_{t}|x_{t-1},\cdots ,x_{1})\), 其中\(x_{t}\)t时刻的价格。

利用深度学习神经网络实现序列模型

  • 生成数据
    使用正弦函数和一些可加性噪声来生成序列数据
%matplotlib inline
import torch
from torch import nn
from d2l import torch as d2l

T = 1000 # 总共产⽣1000个点
time = torch.arange(1, T + 1, dtype=torch.float32)
x = torch.sin(0.01 * time) + torch.normal(0, 0.2, (T,))
d2l.plot(time, [x], 'time', 'x', xlim=[1, 1000], figsize=(6, 3))

使用前600个数据进行训练

tau = 4
features = torch.zeros((T - tau, tau))
for i in range(tau):
  features[:, i] = x[i: T - tau + i]
labels = x[tau:].reshape((-1, 1))
batch_size, n_train = 16, 600
# 只有前n_train个样本⽤于训练
train_iter = d2l.load_array((features[:n_train], labels[:n_train]),
batch_size, is_train=True)
  • 神经网络模型
# 初始化⽹络权重的函数
def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.xavier_uniform_(m.weight)
# ⼀个简单的多层感知机
def get_net():
    net = nn.Sequential(nn.Linear(4, 10),
        nn.ReLU(),
        nn.Linear(10, 1))
    net.apply(init_weights)
    return net
# 平⽅损失。注意:MSELoss计算平⽅误差时不带系数1/2
loss = nn.MSELoss(reduction='none')
  • 模型训练
def train(net, train_iter, loss, epochs, lr):
    trainer = torch.optim.Adam(net.parameters(), lr)
    for epoch in range(epochs):
        for X, y in train_iter:
            trainer.zero_grad()
            l = loss(net(X), y)
            l.sum().backward()
            trainer.step()
        print(f'epoch {epoch + 1}, '
               f'loss: {d2l.evaluate_loss(net, train_iter, loss):f}')

net = get_net()
train(net, train_iter, loss, 5, 0.01)

  • 预测:下一个时间步的预测能力
onestep_preds = net(features)
d2l.plot([time, time[tau:]],
    [x.detach().numpy(), onestep_preds.detach().numpy()], 'time',
    'x', legend=['data', '1-step preds'], xlim=[1, 1000],
    figsize=(6, 3))


以上是单步预测,效果不错,即使预测的时间超过了600+4(n_train + tau),其结果看起来仍然可信,然而如果数据观察序列的时间步只到604,我们需要一步一步地向前迈进:

通常,对于直到\(x_{t}\)的观测序列,其在时间步t+k处的预测输出\(\hat{x} _{t+k}\)称为k步预测(k-step-ahead-prediction)。
由于我们的观察已经到了\(x_{604}\) ,它的k步预测是\(\hat{x} _{604+k}\) 。换句话说,我们必须使⽤我们⾃⼰的预测(⽽不是原
始数据)来进⾏多步预测。让我们看看效果如何。

multistep_preds = torch.zeros(T)
multistep_preds[: n_train + tau] = x[: n_train + tau]
for i in range(n_train + tau, T):
    multistep_preds[i] = net(
          multistep_preds[i - tau:i].reshape((1, -1)))
d2l.plot([time, time[tau:], time[n_train + tau:]],
    [x.detach().numpy(), onestep_preds.detach().numpy(),
    multistep_preds[n_train + tau:].detach().numpy()], 'time',
    'x', legend=['data', '1-step preds', 'multistep preds'],
    xlim=[1, 1000], figsize=(6, 3))


如上⾯的例⼦所⽰,绿线的预测显然并不理想。经过⼏个预测步骤之后,预测的结果很快就会衰减到⼀个常
数。为什么这个算法效果这么差呢?事实是由于错误的累积:假设在步骤1之后,我们积累了⼀些错误\(\epsilon_{1} =\overline{\epsilon _{0}}\)

于是,步骤2的输⼊被扰动了\(epsilon_{1}\) ,结果积累的误差是依照次序的\(\epsilon_{2} =\overline{\epsilon} + c\epsilon_{1}\) ,其中c为某个常数,后⾯的预测
误差依此类推。因此误差可能会相当快地偏离真实的观测结果。例如,未来24⼩时的天⽓预报往往相当准确,
但超过这⼀点,精度就会迅速下降。我们将在本章及后续章节中讨论如何改进这⼀点。
基于k = 1,4,16,64,通过对整个序列预测的计算,让我们更仔细地看⼀下k步预测的困难。

max_steps = 64
features = torch.zeros((T - tau - max_steps + 1, tau + max_steps))
# 列i(i<tau)是来⾃x的观测,其时间步从(i)到(i+T-tau-max_steps+1)
for i in range(tau):
    features[:, i] = x[i: i + T - tau - max_steps + 1]
# 列i(i>=tau)是来⾃(i-tau+1)步的预测,其时间步从(i)到(i+T-tau-max_steps+1)
for i in range(tau, tau + max_steps):
    features[:, i] = net(features[:, i - tau:i]).reshape(-1)

steps = (1, 4, 16, 64)
d2l.plot([time[tau + i - 1: T - max_steps + i] for i in steps],
[features[:, tau + i - 1].detach().numpy() for i in steps], 'time', 'x',
legend=[f'{i}-step preds' for i in steps], xlim=[5, 1000],
figsize=(6, 3))


以上例⼦清楚地说明了当我们试图预测更远的未来时,预测的质量是如何变化的。虽然“4步预测”看起来仍
然不错,但超过这个跨度的任何预测⼏乎都是⽆⽤的。

posted @ 2023-04-28 15:23  Bonne_chance  阅读(108)  评论(0)    收藏  举报
1