长时间序列预测算法---Informer_informer时间序列预测
目录
- 一、传统的 Transformer 模型
- 二、Informer原理
-
- 2.1 Attention计算
- 2.2 “积极”的Q筛选
-
- 2.2.1 KL散度
- 2.2.2 “懒惰”的q处理
- 2.3 Encoder结构
- 2.4 Decoder结构
-
- 2.4.1 Transformer的Decoder操作
- 2.4.2 Informer的Decoder操作
- 2.5 Informer模型的改进
- 三、模型应用
在机器学习和深度学习的世界当中,存在众多经典且有效的(时间)序列模型。这些模型通常通过三种方式来建立样本与样本之间的关联:
ARIMA家族算法群:过去影响未来,因此未来的值由过去的值加权求和而成,以此构建样本与样本之间的关联。
循环网络家族:遍历时间点/样本点,将过去的时间上的信息传递存储在中间变量中,传递给下一个时间点,以此构建样本和样本之间的关联。
卷积网络家族:使用卷积核扫描时间点/样本点,将上下文信息通过卷积计算整合到一起,以此构建样本和样本之间的关联。
时间序列相关参考文章:
时间序列预测算法—ARIMA
基于VARMAX模型的多变量时序数据预测
基于机器学习时序库pmdarima实现时序预测
时间序列预测算法—Prophet
时间序列预测算法—LSTM
长时间序列预测算法—Informer
时间序列分类任务—tsfresh
有季节效应的非平稳序列分析
python时间序列处理
时间序列异常值检测方法
时间序列异常值处理方法
Informer 模型是近年来在时间序列预测领域中比较新颖的一种模型,它基于 Transformer 架构,专门为长时间序列预测任务进行了优化。LSTM模型应用长序列时间预测问题性能不佳的原因:LSTM是串行网络,难以并行化,序列越长反向传播的速度越慢,从而预测速度越慢。
Informer论文
Github原代码库
一、传统的 Transformer 模型
老牌统计学模型:ARIMA和Prophet;传统深度学习模型:LSTM。相关文章可以参考以上给出的链接。
Transformer 是一种深度学习模型,最初应用于自然语言处理(NLP)任务,尤其是在机器翻译、文本生成等任务中表现出色。它的核心思想是通过自注意力机制(Self-Attention) 来捕捉序列中不同位置之间的关系。然而,Transformer 在处理长时间序列数据时会遇到一些困难。因为 Transformer 的计算复杂度是随着序列长度的平方增长的,这在处理非常长的时间序列时会变得非常慢,甚至无法处理。
传统Transformer 模型详解
二、Informer原理
2.1 Attention计算
Transformer计算QKV时,从QK点积的热力图看出,越亮部分表示QK相关性越高。热力图中大部分为黑色,实验发现对于每个Q只有一小部分的K和它有较强的关系。就下图来看,8000个样本,相关性较高的可能只有2000个不到。大部分时候QK的关系都接近于0。
下图纵坐标为Q,横坐标为K。每一行即为一个Q与所有K相关性的结果。红色部分就是一个“积极”的Q,从图中看出它和哪个K相关性较高。绿色部分是一个“懒惰”的Q,它和所有的K关系都很“一般”。
在实际计算中,这些“懒惰”的Q不仅无法提供有效的价值,而且在Q里大部分都是这些“懒惰”的家伙。只选取“积极”的Q来计算注意力机制,而舍弃掉“懒惰”的Q的想法随之诞生。这就是Informer论文的核心:ProbSparse Attention(概率稀疏注意力机制)。
2.2 “积极”的Q筛选
ProbSparse Self-attention 采取了和均匀分布相比较的思路。均匀分布就像上图中的虚线部分,是一条直线。对于每个Q计算它和均匀分布的差异,差异越大就越“活跃”。
2.2.1 KL散度
注意力的概率分布: p( k j ∣ q i )= k ( q i , k j ) ∑ l k ( q i , k l ) p(k_{j}|q_{i})=\\frac{k(q_{i},k_{j})}{\\sum_{l}k(q_{i},k_{l})} p(kj∣qi)=∑lk(qi,kl)k(qi,kj)
均匀分布: q( k j ∣ q i )= 1 L k q(k_{j}|q_{i})=\\frac{1}{L_{k}} q(kj∣qi)=Lk1
这里 k( q i , k l ) k(q_{i},k_{l}) k(qi,kl)选用的计算方式是 e q i k l T d e^{\\frac{q_{i}k_{l}^T}{\\sqrt{d}}} edqiklT, L k L_k Lk 就是query查询向量的长度。度量两种分布的距离—KL散度(描述两个概率分布P和Q差异的一种方法,是非对称的)
离散的KL散度定义: D(P∣∣Q)= ∑ i ∈ x P(i)∗[log( P ( i )Q ( i ) )] D(P||Q)=\\sum_{i\\in{x}}P(i)*[log(\\frac{P(i)}{Q(i)})] D(P∣∣Q)=∑i∈xP(i)∗[log(Q(i)P(i))]
连续的KL散度定义: D(P∣∣Q)= ∫ x P(x)∗[log( P ( i )Q ( i ) )]dx D(P||Q)=\\int_{x}P(x)*[log(\\frac{P(i)}{Q(i)})]dx D(P∣∣Q)=∫xP(x)∗[log(Q(i)P(i))]dx
将上面的两种分布带入KL散度的计算公式,舍弃常数项,最终定义第i个query的稀疏性度量如下:
M ( q i , K ) = l n ∑ j = 1 L k e x p q i k j Td − 1 L k∗ ∑ j = 1 L k q i k j T d M(q_{i},K)={ln\\sum_{j=1}^{L_{k}}exp\\frac{q_{i}k_{j}^T}{\\sqrt{d}}}-\\frac{1}{L_{k}}*\\sum_{j=1}^{L_{k}}\\frac{q_{i}k_{j}^T}{\\sqrt{d}} M(qi,K)=lnj=1∑LkexpdqikjT−Lk1∗j=1∑LkdqikjT
公式中第一项是 q i q_{i} qi和所有k内积的Log-Sum-Exp(LSE),第二项是算术平均数,散度越大,概率分布越多样化,越可能存在关注重点。
上述公式会有两个问题:点积对的计算复杂度是 O ( L Q ∗ L K ) O(L_{Q}*L_{K}) O(LQ∗LK);LSE计算存在数值不稳定的风险,因为 e x e^x ex形式下,可能会数据溢出报错。
为了解决这两个问题,作者采用了以下的方式:
● 随机采样:随机选择其中的top u ( U= L Q ln L K U = L_Q ln L_K U=LQlnLK ) 个点积对计算 M ˉ ( q i ,K) \\bar M(q_i,K) Mˉ(qi,K) 。这样使复杂度降低到 O(LlnL) O(LlnL) O(LlnL)。(代码的默认参数中U=25)
● 用 max( q i k j T d ) max(\\frac{q_{i}k_{j}^T}{\\sqrt{d}}) max(dqikjT)替换 ln ∑ j = 1L k exp q i k j T d ln\\sum_{j=1}^{L_{k}}exp\\frac{q_{i}k_{j}^T}{\\sqrt{d}} ln∑j=1LkexpdqikjT 。直接选择最大值与均匀分布算差异可以进一步加速计算过程。
由此第i个query的“稀疏性度量”表达式改写为:
M ˉ ( q i , K ) = m a x ( q i k j Td ) − 1 L k∗ ∑ j = 1 L k q i k j T d \\bar M(q_{i},K)={max(\\frac{q_{i}k_{j}^T}{\\sqrt{d}}})-\\frac{1}{L_{k}}*\\sum_{j=1}^{L_{k}}\\frac{q_{i}k_{j}^T}{\\sqrt{d}} Mˉ(qi,K)=max(dqikjT)−Lk1∗j=1∑LkdqikjT
这样可以得到每个q的 M ˉ \\bar M Mˉ得分,得分越大这个q越“积极”。然后,在全部的q里选择 M ˉ \\bar M Mˉ得分较大的前U个,定义为“积极”的q。来进行QKV矩阵乘法的计算。(U取值根据实际情况来定,原论文中序列长度为96,作者定义U=25,即选择得分较大的25个Q)
思考:
● 为了求解这个度量得分 M ˉ \\bar M Mˉ,还是要计算全部的QK点积,这样难道不是更“复杂”了吗?并没有减少计算量或者加快计算速度。
● 而且只计算“积极”的Q,“懒惰”的q就完全抛弃吗?矩阵的形状不就发生了变化吗?这会影响后续的计算吗?
答:度量得分 M ˉ \\bar M Mˉ 的计算,只是想用这个得分去筛选“积极”的q,用所有的k参与计算,计算量确实太大。实际上并没有计算全部的QK点积,而是进行了一个抽样。 将每个“积极”的Q和所有k(原论文中是96个k)计算,但在论文源码的实践中,在计算前会随机选取一部分k(原论文中是25个k)来计算,也可以作为它的分布。
2.2.2 “懒惰”的q处理
ProbSparse Self-attention根据上述的内容,允许每个k仅关注U个“积极”的q来获得ProbSparse自注意力:
A ( Q , K , V ) = S o f t m a x ( Q ˉ K T d) V A(Q,K,V)=Softmax(\\frac{\\bar{Q} K^T}{\\sqrt{d}})V A(Q,K,V)=Softmax(dQˉKT)V
这里的 Q ˉ \\bar{Q} Qˉ就是top u个queries选拔后的。对于剩余的“懒惰”的q,作者采取的办法是,用V向量的平均来代替剩余的 Lazy queries 对应的时间点的向量。
通过判定得到的 Lazy queries 的概率分布本来就接近均匀向量,也就是说这个时间点对96个时间点的注意力是均衡的,每个都差不多,所以他们atteniton计算后的向量也应当接近于全部V向量的平均。通过这样的“填充”我们最后的矩阵Z依旧是96*64的维度,但因为是在计算完“积极”Q和K点积后再“填充,计算的时间和空间复杂度都大大降低了。
在理解公式的基础上再梳理一下源码的实现步骤:
(1)输入序列长为96,在K中进行随机采样,随机选取25个K来进行后续计算。
(2)选择“积极”的Q进行计算。 (正常情况下如上推导,将每个“积极”的Q和96个k计算,但在论文源码的实践中,不需要计算那么多,用我们上一步随机选取的25个k来计算,也可以作为它的分布)
(3)每个Q有25个得分,选择25个得分里最大的作为这个q的最终得分 M ˉ ( q i ,K) \\bar M(q_{i},K) Mˉ(qi,K),在96个Q中选择最终得分 M ˉ \\bar M Mˉ最大的25个q。
(4)计算这25个q的QK内积,其余位置直接用V的均值来代替,得到最终的矩阵Z。
2.3 Encoder结构
论文中提出了一种新的EncoderStack结构,由多个Encoder和蒸馏层组合而成。左边绿色的部分,是Encoder的输入。由上面深绿色的scalar和下面浅绿色的stamp组成。
- 深绿色的scalar就相当于我们之前Transformer里的input-embedding 是我们原始输入的向量。
- 浅绿色的stamp包含之前Transformer里的 Positional Ecoding(位置编码)来表示输入序列的相对位置。在时序预测任务中,这个stamp其实由LocalTimeStamp(也就是位置编码)和GobalTimeStamp(与时序相关的编码)共同构成。
Encoder的作用是Self-attention Distilling,由于ProbSparse自相关机制有很多都是用V的mean填充的,所以天然就存在冗余的attention sorce ,因此在相邻的Attention Block之间应用卷积与池化来对特征进行下采样,所以作者在设计Encoder时,采用蒸馏的操作不断抽取重点特征,从而得到值得重点关注的特征图。从图中看到每个Encoder有3个Attention Block;每个Attention Block内有n个头权重矩阵。
Informer的架构图并没有像Transformer一样在Encoder的左边标注“ N x N_x Nx ”来表示N个Encoder的堆叠,而是一大一小两个梯形。
作者为了提高encoder鲁棒性,还提出了一个strick。上面的Encoder是主stack,输入整个embedding后经过了三个Attention Block,最终得到Feature Map。还可以再复制一份具有一半输入的embedding(直接取96个时间点的后48个),让它经过两个Attention Block,最终会得到和上面维度相同的Feature Map,然后把两个Feature Map拼接。作者认为这种方式对短周期的数据可能更有效一些。
2.4 Decoder结构
2.4.1 Transformer的Decoder操作
由1.1的transformer架构图可以得出:Decoder输出后经过Linear+Softmax,Linear将输出扩展到与vocabulary size一样的维度,再经过softmax,就可以选择最高概率的词作为预测结果。
梳理一下训练好模型执行预测的过程:
Decoder:Encoder对embedding操作后的KV+开始符号=预测结果i
Decoder:Encoder对embedding操作后的KV+“i”=预测结果am
Decoder:Encoder对embedding操作后的KV+“i am”=预测结果a
Decoder:Encoder对embedding操作后的KV+“i am a”=预测结果student
Decoder:Encoder对embedding操作后的KV+“i am a student”=预测结果 结尾符号
不难看出Decoder每一步的输出都需要前一步的结果作为输入才可以,这就是step-by-step动态解码的过程。
2.4.2 Informer的Decoder操作
Informer的Decoder由2层相同的多头Attention堆叠而成。Decoder的输入如下: X d e ={ X t o k e n , X 0 } X_{de}=\\{X_{token},X_0\\} Xde={Xtoken,X0}
输入序列是由两部分拼接而来的, X t o k e n ∈ R L t o k e n ∗ d m o d e l X_{token} \\in R^{L_{token}*d_{model}} Xtoken∈RLtoken∗dmodel是开始的token, X 0 ∈ R L y ∗ d m o d e l X_{0} \\in R^{L_{y}*d_{model}} X0∈RLy∗dmodel是用0填充预测序列。假设如果我们想要预测7天的温度,decoder就需要输入前面1-7天的温度,后面用0填充8-14天需要预测的温度的位置,这就是一种Mask的机制。在源码中Decoder输入长度为72,其中前48是真实值,后24是预测值。
第一步是加上mask后做自身的ProbAttention
第二步是自身计算完Attention后与encoder计算Attention
Decoder输入时,将所有需要预测的部分都用0来填充作为掩码。然后,增加掩码Mask后的embedding经过了ProbSparse-Attention,需要注意的一个细节是这里筛选“积极”的q之后,对于“懒惰”的q的填充方式,不同于encoder部分用V的均值(mean)填充,而是用 Cumsum,也就是每一个queries之前所有时间点V向量的累加,来防止模型关注未来的信息。得到来自Encoder的KV和Decoder第一步attention的Q之后,进行的是传统Transformer里的“Multi-head Attention”计算。在结构图中也可以看到这部分是一个“矩形”。
Generative Style Decoder,简而言之,在Decoder部分的改进就是不同于Transformer原始架构的“一个个”预测,而是“一块块”预测。通过上图我们可以直观看出,一个forward就可以得到所有的24个预测结果。
2.5 Informer模型的改进
Informer解决Transformer 难以直接应用于长时间序列预测的三个重要问题;针对Transformer的三点不足,Informer分别在Attention的计算方式,Encoder的蒸馏堆叠和Decoder的生成式预测做出了改进,使得它更适用于长序列的时间序列预测问题。
三、模型应用
Github原代码库
main_informer.py主程序。帮助定义informer所需的所有参数、并执行实际的训练和预测流程。main_informer.py里的全部参数如下:
data:包含一切和数据有关,存放数据集和数据集加载相关代码,核心代码为data_loader.py,既包括处理数据的代码,也包括导入数据的代码。
exp:实验相关,数据加载,模型训练、测试、预测的过程代码,包括了定义损失函数、定义网络结构、进行训练等神经网络的基本流程。
models:Informer模型相关内容,包含词向量编码(embed.py)、注意力机制(attn.py)、encoder编码器(encoder.py)、decoder(decoder.py)解码器和模型定义(model.py)几部分。
utils:与项目相关的辅助代码,这里包含掩码相关(masking.py)、算法衡量指标(metrics.py)、时间特征(timefreatures.py)和其它工具(tools.py)几部分。