CW-RNN收益率时间序列回归

内容来自:A Clockwork RNN
Jan Koutník, Klaus Greff, Faustino Gomez, Jürgen Schmidhuber

360截图20170629152646685.jpg

CW-RNN是一个带时钟频率的RNN变种,似乎是对回归有不错的效果,不过这个有争论。对一个时间序列,无论是回归还是分类都是将数据经过循环按照时间序列输入,RNN使用隐藏矩阵进行记忆,然后判定输出。针对原始RNN对长序列记忆效果极差,作者在这里设计了一种将隐藏状态矩阵(记忆机制)分割成g个小模块并使用类时钟频率掩码的方式,将RNN的记忆分割成几个部分,然后经过特定设计,使CW-RNN记忆矩阵中每个部分处理不同的时刻的数据,加强记忆效果。

在论文中作者列举的数据显示这种设计在特定的应用中具有更优的效果。例如,对一个长度为L的时间序列进行预测,在使用CW-RNN的时候可以通过设置时钟频率人工设定记忆序列。如,L长度为36,那我们可以设置CW为[1,2,4,8,16,12,18,36],这相当于在长度为36的序列设置了多个记忆点,每个记忆点基于此记忆点之前的输入值进行抽象记忆。这个设计与RNN经典变种LSTM有巨大的差异。LSTM通过gate结构实现自动的记忆选择汲取,这里的CW设计需要有一种类似于先验值的CW设定,这并不是一种十分优雅的设计。但这种设计增加的人工设定序列节点选取的操作空间,应该可以在一定程度上对标收益率的时间序列进行特别设计,从而取得不错的回归效果。

该设计进行时间序列回归拟合,在取局部图的时候可以观察到,LSTM的回归效果相对平滑,而CW-RNN并没有这种缺陷。

360截图20170629152817533.jpg
import numpy as np
import pandas as pd
# import statsmodels.api as sm
import tensorflow as tf
# import matplotlib.pylab as plt
import seaborn as sns
# %matplotlib inline
sns.set_style('whitegrid')


class ClockworkRNN(object):
    def __init__(self,
                 in_length,
                 in_width,
                 out_width,
                 training_epochs=1e2,
                 batch_size=1024,
                 learning_rate=1e-4,
                 hidden_neurons=360,
                 Rb=60,
                 Ti=2,
                 Ti_sum=6,
                 display=1e2):
        #
        self.in_length = in_length
        self.in_width = in_width
        self.out_width = out_width
        self.batch_size = batch_size
        self.learning_rate = learning_rate
        self.display = display
        #
        self.hidden_neurons = hidden_neurons
        self.Rb = Rb
        self.Ti = Ti
        self.Ti_sum = Ti_sum
        self.clockwork_periods = [self.Ti ** x for x in range(self.Ti_sum)]
        self.training_epochs = training_epochs
        self.inputs = tf.placeholder(dtype=tf.float32, shape=[None, self.in_length, self.in_width], name='inputs')
        self.targets = tf.placeholder(dtype=tf.float32, shape=[None, self.out_width], name='targets')
        #
        self.__inference()

        #  下三角掩码矩阵,处理g-moduels划分形成的上三角权重矩阵

    def __Mask_Matrix(self, W, k):
        length = np.int(W / k)
        tmp = np.ones([W, W])
        for i in range(length)[1:]:
            tmp[i * k:(i + 1) * k, :i * k] = 0
        tmp[(i + 1) * k:, :i * k] = 0
        return np.transpose(tmp)

    def __inference(self):
        self.sess = sess = tf.InteractiveSession()

        # 标准RNN初始权重
        with tf.variable_scope('input_layers'):
            self.WI = tf.get_variable('W', shape=[self.in_width, self.hidden_neurons],
                                      initializer=tf.truncated_normal_initializer(stddev=0.1))
            self.bI = tf.get_variable('b', shape=[self.hidden_neurons],
                                      initializer=tf.truncated_normal_initializer(stddev=0.1))

        traingular_mask = self.__Mask_Matrix(self.hidden_neurons, self.Rb)
        self.traingular_mask = tf.constant(traingular_mask, dtype=tf.float32, name='mask_upper_traingular')
        with tf.variable_scope('hidden_layers'):
            self.WH = tf.get_variable('W', shape=[self.hidden_neurons, self.hidden_neurons],
                                      initializer=tf.truncated_normal_initializer(stddev=0.1))
            self.WH = tf.multiply(self.WH, self.traingular_mask)
            self.bH = tf.get_variable('b', shape=[self.hidden_neurons],
                                      initializer=tf.truncated_normal_initializer(stddev=0.1))

        with tf.variable_scope('output_layers'):
            self.WO = tf.get_variable('W', shape=[self.hidden_neurons, self.out_width],
                                      initializer=tf.truncated_normal_initializer(stddev=0.1))
            self.bO = tf.get_variable('b', shape=[self.out_width],
                                      initializer=tf.truncated_normal_initializer(stddev=0.1))

        # 输入训练数据转换为列表
        X_list = [tf.squeeze(x, axis=[1]) for x
                  in tf.split(value=self.inputs, axis=1, num_or_size_splits=self.in_length, name='inputs_list')]

        with tf.variable_scope('clockwork_rnn') as scope:
            # 定义初始时刻的隐藏状态,设定为全0
            self.state = tf.get_variable('hidden_sate', shape=[self.batch_size, self.hidden_neurons],
                                         initializer=tf.zeros_initializer(), trainable=False)
            for i in range(self.in_length):

                # 获取g_moduels索引
                if i > 0:
                    scope.reuse_variables()
                g_counter = 0
                for j in range(self.Ti_sum):
                    if i % self.clockwork_periods[j] == 0:
                        g_counter += 1
                if g_counter == self.Ti_sum:
                    g_counter = self.hidden_neurons
                else:
                    g_counter *= self.Rb

                # t时刻eq1
                tmp_right = tf.matmul(X_list[i], tf.slice(self.WI, [0, 0], [-1, g_counter]))
                tmp_right = tf.nn.bias_add(tmp_right, tf.slice(self.bI, [0], [g_counter]))
                self.WH = tf.multiply(self.WH, self.traingular_mask)
                tmp_left = tf.matmul(self.state, tf.slice(self.WH, [0, 0], [-1, g_counter]))
                tmp_left = tf.nn.bias_add(tmp_left, tf.slice(self.bH, [0], [g_counter]))
                tmp_hidden = tf.tanh(tf.add(tmp_left, tmp_right))

                # 更新隐藏状态
                self.state = tf.concat(axis=1, values=[tmp_hidden, tf.slice(self.state, [0, g_counter], [-1, -1])])

            self.final_state = self.state
            self.pred = tf.nn.bias_add(tf.matmul(self.final_state, self.WO), self.bO)
            # self.cost_sum = tf.reduce_sum(tf.square(self.targets - self.pred))
            self.cost = tf.reduce_sum(tf.square(self.targets - self.pred))
        self.optimizer = tf.train.AdamOptimizer(self.learning_rate).minimize(self.cost)
        self.sess.run(tf.global_variables_initializer())

    def fit(self, inputs, targets):
        sess = self.sess
        for step in range(np.int(self.training_epochs)):
            for i in range(np.int(len(targets) / self.batch_size)):
                batch_x = inputs[i * self.batch_size:(i + 1) * self.batch_size].reshape(
                    [self.batch_size, self.in_length, self.in_width])
                batch_y = targets[i * self.batch_size:(i + 1) * self.batch_size].reshape(
                    [self.batch_size, self.out_width])
                sess.run(self.optimizer, feed_dict={self.inputs: batch_x, self.targets: batch_y})
            if len(targets) % self.batch_size != 0:
                batch_x = inputs[-self.batch_size:].reshape([self.batch_size, self.in_length, self.in_width])
                batch_y = targets[-self.batch_size:].reshape([self.batch_size, self.out_width])
                sess.run(self.optimizer, feed_dict={self.inputs: batch_x, self.targets: batch_y})
            if step % self.display == 0:
                print(sess.run(self.cost, feed_dict={self.inputs: batch_x, self.targets: batch_y}))

    def prediction(self, inputs):
        sess = self.sess
        tmp = np.zeros(self.out_width)
        for i in range(np.int(len(inputs) / self.batch_size)):
            batch_x = inputs[i * self.batch_size:(i + 1) * self.batch_size].reshape(
                [self.batch_size, self.in_length, self.in_width])
            tmp = np.vstack((tmp, sess.run(self.pred, feed_dict={self.inputs: batch_x})))
        if len(inputs) % self.batch_size != 0:
            batch_x = inputs[-self.batch_size:].reshape([self.batch_size, self.in_length, self.in_width])
            tp = np.vstack((tmp, sess.run(self.pred, feed_dict={self.inputs: batch_x})))
            l = len(targets) % self.batch_size
            tp = tp[-l:]
            tmp = np.vstack((tmp, tp))
        tmp = np.delete(tmp, 0, 0)
        return tmp


tmp = pd.read_csv('SHCOMP.csv')
tmp['trading_moment'] = pd.to_datetime(tmp['DATE'].values)
tmp.set_index('trading_moment', drop=True, inplace=True)
tmp['Returns'] = np.log(tmp.Close.shift(-10) / tmp.Close)
tmp.dropna(inplace=True)
tp = np.array(tmp['Returns'])
# del tmp['Unnamed: 0']

in_length = 36
out_length = 1
inputs = np.zeros(in_length)
targets = np.zeros(1)
for i in range(len(tp))[in_length:-out_length]:
    m = tp[i - in_length:i]
    R = tp[i:i + 1]
    inputs = np.vstack((inputs, m))
    targets = np.vstack((targets, R))
targets = np.delete(targets, 0, 0)
inputs = np.delete(inputs, 0, 0)

T_inputs = inputs[:512]
T_targets = targets[:512]

a = ClockworkRNN(36, 1, 1, training_epochs=2e4, batch_size=512)
a.fit(T_inputs, T_targets)

outputs = a.prediction(T_inputs)
CW_RNN = outputs
show = pd.DataFrame([T_targets.ravel('C'), outputs.ravel('C')]).T
show.plot()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,000评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,825评论 2 374
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,055评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,766评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,639评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,453评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,860评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,492评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,783评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,817评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,624评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,439评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,872评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,075评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,372评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,868评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,075评论 2 338

推荐阅读更多精彩内容