NeuralGPU卷積與RNN結合超線性計算時間多因子時間序列預測

看NTM blog的時候發現的NeuralGPU的paper,感覺這個東西要是能夠打破RNN架構或者是更加巧妙的利用卷積將會是一個令人驚嘆的設計,但是幾篇論文裡面都還是在糅合CNN和RNN,個人感覺這個設計應該還是處於早期設計階段。

更新:

NeuralGPU簡單介紹---在我前面的短文裡面介紹了一種常見的使用卷積CNN網路處理多因子股票收益率序列的玩法,在處理多因子數據的時候,將多因子數據合成一副圖片,然後使用CNN處理這個圖片,進行預測。這裡NeuralGPU的玩法大致類似,有一點區別的地方在於,模型將卷積核裡面的通道(每層卷積濾波器的數量)擴展成一個輸入多因子數據的維度,同時將原來的2D圖片的高度當作是時間序列步,這樣在第一副圖片輸入的時候(原始數據嵌入)in_channels進入通道數量從原來的表示3幅紅綠藍三基色的圖片變成了多因子數據。

為了便於理解,可以參照下面的立方體圖片,前表面就是常見的卷積圖片,立方體的厚度也就是通常的卷積濾波器的數量,這裡將前表面的上第一列的數據點當作時刻標度,然後每個數據點對應的厚度也就是一個超長的數據列嵌入多因子序列。這個時候這個立方體就嵌入一張圖片,在yoz軸線上,這個立方體其他地方初始置0就完成初始數據嵌入了。

更新:

在後續的paper裡面任務原始的模型設計對NLP處理效果欠佳,並探索了馬爾科夫擴展和卷積擴展,這裡由於使用many to one的數據處理,稍作調整,在最後一步直接使用tf.matmul處理取代卷積操作。

數據擴展如下圖1,在對模型循環n次之後,使用另外的n次循環每次依次獲得一個時刻輸出,並累積時刻輸出進入迭代公式,顯式達到前一個時刻輸出影響後一時刻的效果(這裡又從新回到了RNN模型思路上了),設置tape緩存,初始置0,然後沒循環一次填充一個t時刻的輸出結果並進入下一次循環中。

對於一個實例來學習演算法,NeuralGPU最大的一個優點是實現超線性計算時間的演算法學習,這個是目前僅有的一個支持超線性計算時間的RNN變種[2]。在對NeuralGPU進行擴展之後取得了相當不錯的效果在NLP上面[1]。

NeuralGPU的使用方法可以假想下面的立方體。

使用tf.nn.conv2d裡面的in_channels表示多因子數據,對應卷積操作為,2D卷積中圖片的高度為RNN中的時間步,寬度為初始置0,多通道的為多因子數據。

如上圖,對應一個2d卷積核操作,第一列(陰影列)為時間步,每個像素點對應一個RNN的時刻k的輸入,也就是圖片的高度輸入時間步,寬度非第一列初始置0. 將多通道(多濾波器)。

輸入數據格式為[batch, in_length, in_width] batch x 時刻 x 多因子數據

調整為[batch, in_length, w, in_width]數據格式,其中w第一列為輸入數據,其餘置0在初始狀態。多因子數據對應2D卷積的通道操作。

立方體 in_length*w 面為論文裡面的mental image,深度(in_width,多因子數據)對應tf.nn.conv2d裡面的channels,這個地方是一個比較容易錯意的地方。總的來說雖然這個模型引入的卷積,並且擁有一個超線性的計算時間,但是經過仔細研究,我認為這依然是一個廣義線性玩法,這樣進行建模對應多因子序列預測會探索多因子之間的相互關係,但是並不會改變多因子因子的階次,所以該模型建立之後,經過學習對應的APT模型依然是i=1的情況。

r_p = alpha + beta_1 x^n_1+...+ beta_i x^n_i

這個模型我在14~16年HS300成份股橫面數據處理方式進行多因子時間序列預測的時候,泛化效果相當不錯,加上兩層dropout之後泛化效果相當好,但是模型構建求解特別麻煩。

參考:

Can Active Memory Replace Attention?

Extensions and Limitations of the Neural GPU

Neural GPUs Learn Algorithms

python代碼:

卷積RNN函數部分

import tensorflow as tfnndef CGRU(state, parameter, prefix):n kh = parameter[0]n kw = parameter[1]n c_in = parameter[2]n c_out = parameter[3]n n with tf.variable_scope(prefix):n # resetn U_1 = tf.get_variable(name=U1_kernel_bank, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n B_1 = tf.get_variable(name=B1_bias_vectors, shape=[c_out], initializer=tf.truncated_normal_initializer()) n reset = tf.sigmoid(tf.add(x=tf.nn.conv2d(input=state, filter=U_1, strides=[1,1,1,1], padding=SAME), y=B_1))n #reset = sigmoid_cutoff(tf.add(x=tf.nn.conv2d(input=state, filter=U_1, strides=[1,1,1,1], padding=SAME), y=B_1))n n n # updaten U_2 = tf.get_variable(name=U2_kernel_bank, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n B_2 = tf.get_variable(name=B2_bias_vectors, shape=[c_out], initializer=tf.truncated_normal_initializer()) n update = tf.sigmoid(tf.add(x=tf.nn.conv2d(input=state, filter=U_2, strides=[1,1,1,1], padding=SAME), y=B_2))n n # CGRU(s)n U_0 = tf.get_variable(name=U0_kernel_bank, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n B_0 = tf.get_variable(name=B0_bias_vectors, shape=[c_out], initializer=tf.truncated_normal_initializer()) n cgru_tmp = tf.add(tf.nn.conv2d(input=tf.multiply(reset,state), filter=U_0, strides=[1,1,1,1], padding=SAME), B_0)n return tf.add(tf.multiply(update, state), tf.multiply(tf.subtract(1.,update),tf.tanh(cgru_tmp)))n ndef Multi_CGRUs(state, parameter, layers_num, prefix):n for i in range(layers_num):n state = CGRU(state, parameter, prefix+"multi_%d"%i)n return statenndef CGRU_d(state, tape, prameter, prefix):n kh = parameter[0]n kw = parameter[1]n c_in = parameter[2]n c_out = parameter[3]n n with tf.variable_scope(prefix):n # resetn U_1 = tf.get_variable(name=U1_kernel_bank, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n W_1 = tf.get_variable(name=W1, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n B_1 = tf.get_variable(name=B1_bias_vectors, shape=[c_out], initializer=tf.truncated_normal_initializer()) n r1 = tf.nn.conv2d(input=state, filter=U_1, strides=[1,1,1,1], padding=SAME)n r2 = tf.nn.conv2d(input=tape, filter=W_1, strides=[1,1,1,1], padding=SAME)n reset = tf.sigmoid(tf.add(tf.add(r1,r2),B_1))n n # updaten U_2 = tf.get_variable(name=U2_kernel_bank, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n W_2 = tf.get_variable(name=W2, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n B_2 = tf.get_variable(name=B2_bias_vectors, shape=[c_out], initializer=tf.truncated_normal_initializer())n u1 = tf.nn.conv2d(input=state, filter=U_2, strides=[1,1,1,1], padding=SAME)n u2 = tf.nn.conv2d(input=tape, filter=W_2, strides=[1,1,1,1], padding=SAME)n update = tf.sigmoid(tf.add(tf.add(u1,u2),B_2))n n # CGRU(s)n U_0 = tf.get_variable(name=U0_kernel_bank, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n W_0 = tf.get_variable(name=W0, shape=[kh, kw, c_in, c_out], initializer=tf.truncated_normal_initializer())n B_0 = tf.get_variable(name=B0_bias_vectors, shape=[c_out], initializer=tf.truncated_normal_initializer()) n c1 = tf.nn.conv2d(input=tf.multiply(reset,state), filter=U_0, strides=[1,1,1,1], padding=SAME)n c2 = tf.nn.conv2d(input=tape, filter=W_0, strides=[1,1,1,1], padding=SAME)n c3 = tf.tanh(tf.add(tf.add(c1,c2),B_0))n return tf.add(tf.multiply(update, state), tf.multiply(tf.subtract(1.,update),c3)) nndef Multi_CGRUDs(state, tape, parameter, layers_num, prefix):n for i in range(layers_num):n state = CGRU_d(state, tape, parameter, prefix+"multi_%d"%i)n return staten

原始Nerual_GPU的 拓撲結構構建,使用tf.whlie_loop的swap節省顯存,這一部分主要是一個元細胞結構,也就是可以學習n多進位位「四則運算」的那個初始模型。

with tf.variable_scope(previous) as scope_previous:n tmp = Multi_CGRUs(X, parameter, layers, prefix=previous_part_for_n_steps_)n n def cond(tp, tmp):n return tf.less(tp, in_length)nn def body(tp, tmp):n scope_previous.reuse_variables()n tmp = Multi_CGRUs(tmp, parameter, layers, prefix=previous_part_for_n_steps_)n tp = tp +1n return tp, tmpnn ftp, prev = tf.while_loop(cond, body, [1, tmp]) nPrevious_Part = prev nlen(tf.trainable_variables())n

NerualGPU 擴展輸出部分,這是擴展對輸出結果進行n步掃描或者卷積處理NLP的擴展模型,本文所說的多因子時間序列是使用如下的拓撲結構構建的。這一部分我暫時沒有找到好的方法,可以使用笨法子,顯式配置多GPU顯存跑到512濾波器。

for tp in range(in_length):n with tf.variable_scope(previous) as scope_previous:n if tp == 0:n tmp = Multi_CGRUs(X, parameter, layers, prefix=previous_part_for_n_steps_)n #print(tp)n else:n scope_previous.reuse_variables()n tmp = Multi_CGRUs(tmp, parameter, layers, prefix=previous_part_for_n_steps_)n #print (tp)nPrevious_Part = tmp n

tape = tf.Variable(tf.zeros(shape=[batch_size, in_length, w, in_width], dtype=tf.float32), trainable=False)nnfor tl in range(in_length):n with tf.variable_scope(latter) as scope_latter:nn if tl == 0:n state_l = Multi_CGRUDs(Previous_Part, tape, parameter, layers, prefix=latter_part_for_n_steps_)n tmp_1 = tf.split(value=state_l, num_or_size_splits=in_length, axis=1)[0]n tmp_1 = tf.split(value=tmp_1, num_or_size_splits=w, axis=2)[0]n tmp_1 = tf.concat(values=[tmp_1]+[tf.zeros_like(tmp_1)]*(w-1), axis=2)n tmp_2 = tf.split(value=tape, num_or_size_splits=in_length, axis=1)n tmp_2[tl] = tmp_1n tape = tf.concat(values=tmp_2, axis=1)n #print (tl)n n else:n scope_latter.reuse_variables()n state_l = Multi_CGRUDs(state_l, tape, parameter, layers, prefix=latter_part_for_n_steps_)n tmp_1 = tf.split(value=state_l, num_or_size_splits=in_length, axis=1)[tl]n tmp_1 = tf.split(value=tmp_1, num_or_size_splits=w, axis=2)[0]n tmp_1 = tf.concat(values=[tmp_1]+[tf.zeros_like(tmp_1)]*(w-1), axis=2)n tmp_2 = tf.split(value=tape, num_or_size_splits=in_length, axis=1)n tmp_2[tl] = tmp_1n tape = tf.concat(values=tmp_2, axis=1)n #print (tl)nlen(tf.trainable_variables())n

推薦閱讀:

哪些股票值得持有 10 年?
什麼是金九銀十?
你連哄女生都不會,還怎麼去炒股?——首談消息面(上)
這次股災之前有哪些信號預示股災的來臨?
20151012市場如何看,有什麼特點呢?

TAG:量化 | 深度学习DeepLearning | 股票 |