pytorch LSTM:https://pytorch.org/docs/stable/generated/torch.nn.LSTM.html
最近看 google 的论文 autopilot,讲的是怎么通过一个app的历史的资源使用数据,来预测这个app到底需要多少资源,才能满足其服务的正常运行
论文讲了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 有几个关键的地方:
- 定义好网络的输入输出,简单来说就是你希望神经网络帮你学习什么样的特征映射。
- 怎么实现长期预测
由于典型的 rnn 神经网络,是输入一串历史数据,输出下一个时刻的预测值。这是经典用法,可能也有一些方法,可以直接输出多个历史预测值的,不过我没研究过,这里不讨论
我的方法也比较简单,就是用预测出来的值作为神经网络的数据,继续滚动预测下一个值,通过这种方法,实现“长期”的预测
2. 网络(输入、输出)建模
首先要定义清楚网络的输入,输出是什么
由于经典的 rnn 只有一个输出,就是我们下一步要预测的值,所以这个没什么好讨论的
但是输入是可以多个的,你可以用当前最近的2个数据来预测下一个数据,也可以用当前10个数据预测下一个数据,也可以是N个。但是据我的实测观察来看,使用2个数据预测下一个数据效果好像更好一些
2个数据预测1个
10个数据预测1个
其他的一些问题
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]
效果是这样的
方法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]
效果是这样的
4. 长期预测能力的表现
由于网络上大多数例子,讲的都是最简单的场景,就是根据前N个数据,预测下一个时刻的数据。但是实际生产环境中,真实的数据要远比这个复杂。
上面的例子里面,我们实现的长期预测,也是比较简单的,数据的表现都非常单一
下面我们来看看,对一些更复杂场景下的数据,lstm 的长期预测能力表现如何
4.1. 周期性的波动
比如,一个典型的场景是,快手app,在工作日和周六日,用户的流量肯定是不一样的。工作日大家刷手机的时间段,周六日放假了,特别是疫情期间,大家刷手机的频率肯定比平时更高
这种场景下,lstm 的预测表现如何呢?
4.2. 长期缓慢上涨或者下降趋势
有一些数据,比如某支股票的价格,每个小周期看起来可能很像,但又有细微差别,可能处于长期下降,或者上升趋势
这种上升趋势或者下降趋势,lstm 能不能预测到?
xx