时间序列预测最强模型DLinear代码详解

        时间序列预测算法现在也是百花齐放了,从统计学模型移动平均、指数平滑以及ARIMA等,到RNN-based的LSTM、GRU、LSTNet,再到如今爆火的Transformer-based的Informer、Autoformer等等。模型的复杂程度可以说是直线上升。之前一直知道DLinear,不过因为掉到transformer的坑里了,一直也没有了解。最近看了DLinear的原文,有点要给Time Series Forecasting洗牌的感觉,非常有意思。代码也非常非常简单,不过看到网上没有很详细的解析,所以尝试写一篇。


原文链接:https://arxiv.org/pdf/2205.13504v3

Github源码链接:https://github.com/cure-lab/LTSF-Linear


        首先需要了解的是,我们的数据在时间序列网络里,通常是3个维度[B,T,N]BBatch Size即批次大小,TSequence Length即一个批次里时间序列数据的长度,N指Channels即通道数,也就是指特征的数量。

        搞明白输入数据的结构后,就可以开始看看DLinear是怎么进行操作的。首先我们拿一个[128,288,9]的输入作为示例。

输入的第一行就会使用decompsition函数获得季节分量趋势分量,下面来看一下decompsition(series_decomp):

class moving_avg(nn.Module):

    def __init__(self, kernel_size, stride):
        super(moving_avg, self).__init__()
        self.kernel_size = kernel_size
        self.avg = nn.AvgPool1d(kernel_size=kernel_size, stride=stride, padding=0)

    def forward(self, x):
        front = x[:, 0:1, :].repeat(1, (self.kernel_size - 1) // 2, 1)
        end = x[:, -1:, :].repeat(1, (self.kernel_size - 1) // 2, 1)
        x = torch.cat([front, x, end], dim=1)
        x = self.avg(x.permute(0, 2, 1))
        x = x.permute(0, 2, 1)
        return x


class series_decomp(nn.Module):

    def __init__(self, kernel_size):
        super(series_decomp, self).__init__()
        self.moving_avg = moving_avg(kernel_size, stride=1)

    def forward(self, x):
        moving_mean = self.moving_avg(x)
        res = x - moving_mean
        return res, moving_mean

        series_decomp所做的事情非常简单,通过调用self.moving_avg获取移动平均值,然后用原始值减去移动平均值获得他们的残差,残差res就别看作为季节分量,移动平均值就被看作为趋势分量。

        下面来逐行看一下moving_avg的代码:

输入x的shape目前是[128,288,9]x[:, 0:1, :]是取T维度第一个值,x[:, -1:, :]是取T维度最后一个值,此时这两个指的shape为[128,1,9],然后通过repeat在第二个维度上复制kernel_size-1份,这么做的目的是因为数据在经过平均池化(AvgPool)后长度会缩短,因此需要在池化前将第一个数据和最后一个数据分别在首位多复制几份,保证池化后的到的序列和原始序列长度保持一致。

由于我的kernel_size设置为5,因此数据会被复制两份。得到的front和end的shape就为[128,2,9]

通过cat将front[128,2,9]x[128,96,9]end[128,2,9]进行拼接,得到新的x[128,292,9]

这样再经过平均池化层后,得到的输出就和原始x的shape一致了x[128,288,9]

        返回主代码处,我们将得到的季节分量和趋势分量分别输入两个线性层:

        线性层的定义也很简单,将输入长度映射至预测长度:

        即使用N个历史值,预测M个未来值,对应了原文的图:

        最后将这两个线性层的输出直接相加,得到最终输出:

        到这DLinear就结束了。深刻体会到原文为什么会用embarrass-ingly simple one-layer linear models去描述DLinear,现在比这个结构更简单的网络应该没几个,然而就是这个网络在直接输出多步预测的任务上表现超越了一众Transformer。

最后展示一下一天96点数据,3天历史值预测未来10天值的结果:

DLinear:

自己的算法(同为MLP_Based):

        可以看到效果差不了太多,但是Dlinear的结果更加光滑,不过由于Dlinear只有了两个线性层,复杂程度要远远低于我的算法,确实很牛。只能说现在的时序算法设计真的要做减法,而不是一味的无脑复杂化。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值