时间序列数据的表示学习是深度学习大环境下时序研究的重要方向,有很多有意思,开脑洞的研究工作。最近,来自加拿大 Borealis AI (加拿大皇家银行成立的人工智能理论和应用研究部门)的几位研究者提出了Time2Vec模型,将动态时间序列数据转化为静态的特征向量。
本期文章为大家简要介绍这一工作。
概述
Time2Vec模型很有意思,它针对的场景是比较广泛的,比如说在风控场景中,数据包括静态数据(如用户的性别,身高,籍贯等),和动态数据(如用户的历史消费金额)。该论文的研究者们认为过去通用的方法是人工去设计不同的时间窗、滞后算子之类的手工特征,这种方式太麻烦而且需要较多的领域知识,因此想做出一种时序特征的自动表示方法将动态的数据转化为静态的表示向量。Time2Ve应运而生。
在设计time2vec时,研究者确定了三个重要的特性:
- 表示的结果应该能够捕获周期模式和非周期模式
- 表示的结果应对时间的变动保持稳定不变
- 表示的结果应足够简单,可以与许多模型相结合
01
周期性
在许多场景中,一些事件周期性地发生。 例如,商店的销售额可能在周末或假日更高。 天气状况通常遵循不同季节的周期性模式。 钢琴曲中的一些音符通常周期性地重复。 其他一些事件可能是非周期性的,但只有在一个时间点之后和或随着时间的推移而变得更有可能发生。 例如,一些疾病更有可能发生在老年。 这种周期性和非周期性模式将时间与其他需要更好的处理和更好地表示时间的特征区分开来。 特别是,使用能够捕获周期模式和非周期模式的表示非常重要。
02
稳定性
举个例子说明这个稳定不变的特性,例如我们有一个序列数据一共100个样本,代表了100秒的样本,此时我们得到了一个时序的表示结果,那么,如果序列此时的时间刻度变成了小时或者天,比如100天,则我们的表示结果只要经过某个周期参数的调整就可以和原始的表示产生相似的结果。
03
简单性
公式如下:
其中ķ是time2vec维度,τ是原始时间序列特征,F是周期性激活函数,ω和φ是一组可学习的参数,也就是time2vec的表示层中的权重系数的概念。在实验中,为了使得算法能够捕获数据中的周期性行为,F选定为一个正弦函数。与此同时线性项(对应i=0对应的公式)表示时间的非周期进程,用于捕获时间输入中的非周期性模式。
实现
以下是一个Kears的实现:
代码语言:javascript复制class T2V(Layer):
def __init__(self, output_dim=None, **kwargs):
self.output_dim = output_dim
super(T2V, self).__init__(**kwargs)
def build(self, input_shape):
self.W = self.add_weight(name='W',
shape=(1, self.output_dim),
initializer='uniform',
trainable=True)
self.P = self.add_weight(name='P',
shape=(1, self.output_dim),
initializer='uniform',
trainable=True)
self.w = self.add_weight(name='w',
shape=(1, 1),
initializer='uniform',
trainable=True)
self.p = self.add_weight(name='p',
shape=(1, 1),
initializer='uniform',
trainable=True)
super(T2V, self).build(input_shape)
def call(self, x):
original = self.w * x self.p
sin_trans = K.sin(K.dot(x, self.W) self.P)
return K.concatenate([sin_trans, original], -1)
可以将这里的T2V的layer当作一个基于时间序列的表示层,对照公式可以看到,实现确实相当简单了。其中 original = self.w * x self.p 用于拟合序列数据的非周期模式,而 sin_trans = K.sin(K.dot(x, self.W) self.P) 用于拟合序列数据的周期模式,这里的K.sin使用K.cos来代替也是可以的。最终的输出是将非周期部分和周期部分直接进行连接得到的。
这个用户自定义层的输出维度是用户指定的维度(1≤i≤k),即从网络学到的正弦波(周期特性),加上输入的线性表示(i = 0)。有了这个组件,我们只需要将它与其他层堆叠在一起,然后在案例研究中尝试使用它的强大功能。
到这里问题已经解决了一半了,还有一半就是,这个layer怎么用?样本和标签是啥?损失函数有啥特殊的吗?
代码语言:javascript复制def T2V_NN(param, dim):
inp = Input(shape=(dim,1))
x = T2V(param['t2v_dim'], dim)(inp)
x = LSTM(param['unit'], activation=param['act'])(x)
x = Dense(1)(x)
m = Model(inp, x)
m.compile(loss='mse', optimizer=Adam(lr=param['lr']))
return m
def NN(param, dim):
inp = Input(shape=(dim,1))
x = LSTM(param['unit'], activation=param['act'])(inp)
x = Dense(1)(x)
m = Model(inp, x)
m.compile(loss='mse', optimizer=Adam(lr=param['lr']))
return m
这里研究者们做了一个测试,可以看到,这里T2V embeding layer直接作为表示层放置在LSTM前面,可以看到这个形式和文本分类是非常相似的,文本分类中对词进行表示然后依次输入LSTM中,而这里通过T2V embedding对连续性的序列数据进行embedding然后送入LSTM中。
总结
time2vec构建了文本分类和时间序列预测的桥梁,通过time2vec的思路,时间序列回归和时间序列分类(尤其是时间序列分类,非常相似)的处理方法和文本分类的思路非常相似。