1.前言
笔者最近在阅读TIMESNET这篇论文,但在阅读代码的过程中发现了一些问题,其在reshape的细节上可能与原论文的叙述出现了一些偏差,不知道是不是笔者本人的误解,故记录,与供感兴趣的同学进一步探讨。
2.简介
本文是ICLR2023的一篇论文,主要是提出了一种新的时间建模思路,即将一维的时间序列通过快速傅里叶变换求得多个周期(根据频域峰值确定周期),然后将原始的一维时间序列reshape成二维的周期序列,如:一个10帧的时间序列,求得周期为2,则将其reshape成一个[2,5]的时间序列,这样就可以使用二维的卷积核捕捉周期内的信息,以及周期间的信息。而传统的一维卷积核,只能聚合相邻帧之间的信息,无法实现对周期性信息的建模。文章在多种时间序列任务上均取得了不错的效果,且笔者觉得思路非常有趣,具体的细节值得各位亲自阅读,这里不再赘述。
3.代码的一处细节疑问
根据论文作者给出的开源代码,笔者进一步进行了研究,发现在/model/TimesNet.py内有这样一处:
# reshape
out = out.reshape(B, length // period, period, N).permute(0, 3, 1, 2).contiguous()
# 2D conv: from 1d Variation to 2d Variation
out = self.conv(out)
其中,out 是输入的时间序列,B 为 batch,length 为时间序列长度,period 为文中方法计算的周期,length // period 则为一个周期的长度,N为通道数。不难发现,reshape 后形为[B, N, length // period,period],为了方便理解,我们省去B,并做一个简单的模拟,看一看结果。
首先,我们模拟一个[3,10]的信号,表示3通道,10帧的一个时间序列:
图1. 模拟信号
假设我们算出周期为2,则应reshape为 [3,5,2]:
图2. reshape之后的信号
图1表明了,第一个通道上这个时间序列的顺序是0.7138, 0.5638, 0.0741, 0.3191, 0.2234, 0.9412, 0.7298, 0.6380, 0.7597,0.3348,那根据原论文的意思,笔者理解为应该reshape为[3,2,5]:
图3. 笔者认为的reshape方法
因为,如果想建立周期内的信息和周期间的信息,比如说我用一个2*2的卷积核,是不是应该扫过第1、2和第6、7帧,因为对于上述例子,第1帧和第6帧分别是两个周期的开始,论文是希望建立这两者的连接,但是如果按照作者给出的代码,得到图2的reshape结果,是否在卷积核扫过的时候,包括在内的是第1、2、3、4帧,这样的卷积方式,似乎跟一维的TCN没有什么区别。
不知道是笔者理解错误还是代码出现了一些瑕疵,期待各位探讨指正。