使用 LSTM 实现长期预测

pytorch LSTM:https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html

最近看 google 的论文 autopilot,讲的是怎么通过一个app的历史的资源使用数据,来预测这个app到底需要多少资源,才能满足其服务的正常运行

论文讲了2种方法,就是:

  1. 一种是传统的,对历史数据加权
  2. 一种是基于增强学习的,这个有点复杂,没太看懂

不过我有个疑问,像资源使用这种时序的数据,用 lstm 这种循环神经网络不是最简单吗?为什么要用增强学习这么复杂的东西(状态空间复杂,状态的迁移也复杂,并且需要更大的计算量)

所以我打算试试用 lstm 来实现长期的资源预测

我的数据样本:

20220510000000,38.388889
20220510003000,33.722222
20220510010000,31.538889
...
20220510053000,31.183333
20220510060000,32.983333
20220510063000,36.694444

第一列是明文的时间,第二列是app的cpu使用

1. 思路

使用 lstm 有几个关键的地方:

  1. 定义好网络的输入输出,简单来说就是你希望神经网络帮你学习什么样的特征映射。
  2. 怎么实现长期预测

由于典型的 rnn 神经网络,是输入一串历史数据,输出下一个时刻的预测值。这是经典用法,可能也有一些方法,可以直接输出多个历史预测值的,不过我没研究过,这里不讨论

我的方法也比较简单,就是用预测出来的值作为神经网络的数据,继续滚动预测下一个值,通过这种方法,实现“长期”的预测

2. 网络(输入、输出)建模

首先要定义清楚网络的输入,输出是什么

由于经典的 rnn 只有一个输出,就是我们下一步要预测的值,所以这个没什么好讨论的

但是输入是可以多个的,你可以用当前最近的2个数据来预测下一个数据,也可以用当前10个数据预测下一个数据,也可以是N个。但是据我的实测观察来看,使用2个数据预测下一个数据效果好像更好一些

2个数据预测1个

0

10个数据预测1个

0

其他的一些问题

1)pytorch.LSTM 其实也没讲清楚input的输入定义到底是什么

这里第一次使用lstm的人可能就会比较容易混淆,比如我看有些人,输入数据其实是一维的,只有历史值一个特征,但是通过numpy的各种reshape操作,转变成n个特征

也有一些人的输入是真正多维的,比如把时间也输入进去了。这样神经网络可以学习到时间维度的特征

2)时间数据怎么输入?

时间数据要格式化,比如不要像我上面的原始数据那样直接输入到神经网络,不然学习不到什么特征。要归一化,归一化成0-24小时这样。

3)pytorch.LSTM 的输入是一个3维的tensor,怎么理解?

比如我的输入是 shape = (266,1,10)

根据官方文档的定义:

L = 266,是 sequence length,可以理解为有多少个批次的数据

N = 1,是batch size,可以理解为每批次有多少条记录

Hin = 10,input size,可以理解为没条记录有多少个特征值

如下:

266 1 10
tensor([[[0.9601, 0.9315, 0.9274,  ..., 1.0427, 1.1029, 1.2270]],
        [[0.9315, 0.9274, 0.8978,  ..., 1.1029, 1.2270, 1.2424]],
        [[0.9274, 0.8978, 0.9294,  ..., 1.2270, 1.2424, 1.3554]],
        ...,
        [[1.7358, 1.7107, 1.6911,  ..., 1.6732, 1.6415, 1.6108]],
        [[1.7107, 1.6911, 1.7251,  ..., 1.6415, 1.6108, 1.6038]],
        [[1.6911, 1.7251, 1.7141,  ..., 1.6108, 1.6038, 1.6444]]])

Hin就是训练的最小单位,表示一条记录,每条记录里面有N个特征,在这里一条记录就是 [0.9601, 0.9315, 0.9274, …, 1.0427, 1.1029, 1.2270],N是batch size的意思,我们这里 batch size 是1,也就是每批次训练是1条记录,所以是 [[0.9601, 0.9315, 0.9274, …, 1.0427, 1.1029, 1.2270]],如果N=2,那就是[[0.9601, 0.9315, 0.9274, …, 1.0427, 1.1029, 1.2270], [0.9601, 0.9315, 0.9274, …, 1.0427, 1.1029, 1.2270]] 这样,最后一个是L,序列长度,就是有多少批次

3. 长期预测方法

通过滚动的方式进行长期预测的时候,一定要把 LSTM 的隐藏层状态 h 输入到 rnn 里面去,否则长期预测出来的数据会很差,比如

方法1:不使用 LSTM 的隐藏层状态

pred = dataset.copy()
for i in range(train_size, len(dataset) - feature_size):
    x = [dataset[j:j+feature_size] for j in range(max(0, i-1), i)]
    x = torch.from_numpy(np.array(x).reshape(-1, 1, feature_size))
    y = net(x)
    y = y.view(-1).data.numpy()
    pred[i+1] = y[-1]

效果是这样的

0

方法2:使用 LSTM 的隐藏层状态

pred = dataset.copy()
hc = None
for i in range(train_size, len(dataset) - feature_size):
    x = [dataset[j:j+feature_size] for j in range(max(0, i-1), i)]
    x = torch.from_numpy(np.array(x).reshape(-1, 1, feature_size))
    y, hc = net.forward2(x, hc)    // 核心是这里,保存每次预测的 lstm 中间隐藏层状态
    y = y.view(-1).data.numpy()
    pred[i+1] = y[-1]

效果是这样的

0

4. 长期预测能力的表现

由于网络上大多数例子,讲的都是最简单的场景,就是根据前N个数据,预测下一个时刻的数据。但是实际生产环境中,真实的数据要远比这个复杂。

上面的例子里面,我们实现的长期预测,也是比较简单的,数据的表现都非常单一

下面我们来看看,对一些更复杂场景下的数据,lstm 的长期预测能力表现如何

4.1. 周期性的波动

比如,一个典型的场景是,快手app,在工作日和周六日,用户的流量肯定是不一样的。工作日大家刷手机的时间段,周六日放假了,特别是疫情期间,大家刷手机的频率肯定比平时更高

这种场景下,lstm 的预测表现如何呢?

0

4.2. 长期缓慢上涨或者下降趋势

有一些数据,比如某支股票的价格,每个小周期看起来可能很像,但又有细微差别,可能处于长期下降,或者上升趋势

这种上升趋势或者下降趋势,lstm 能不能预测到?

xx

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注