完整的工作代碼可在github.com/lilianweng/stock-rnn找到,。如果你不知道什么是循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)或長短期記憶網(wǎng)絡(luò)(LSTM)單元,可以翻閱作者之前的文章,,或者查看云棲翻譯小組其他文章 互聯(lián)網(wǎng)上也有很多類似教程,,比如:
但是作者仍然堅(jiān)持寫出這篇文章主要有三個(gè)原因: 1.技術(shù)在發(fā)展,,早期的教程不能應(yīng)付新版本。 2.大多數(shù)教程使用的事例是合成數(shù)據(jù),,而作者在這該文中所用事例數(shù)據(jù)皆來源于現(xiàn)實(shí)生活,。 3.有些教程如果你事先了解關(guān)于Tensorflow API的一些信息,這將使得在理解它們時(shí)存在困難,。 文中,,作者以賓夕法尼亞大學(xué)(Penn Tree Bank,PTB)數(shù)據(jù)集上的官方例子為起點(diǎn),。雖然PTB示例以漂亮的模塊化設(shè)計(jì)模式展示RNN模型,,但在理解模型結(jié)構(gòu)中會有些難度,為此,,作者建立了易于理解的圖表,。 數(shù)據(jù)準(zhǔn)備:股票價(jià)格是長度為N的時(shí)間序列,定義為p0,,p1,,... ,pN- 1,,其中pi是指在第i日的收盤價(jià),,0≤i<> 上圖為標(biāo)準(zhǔn)普爾500價(jià)格。我們在一個(gè)滑動窗口中使用內(nèi)容來預(yù)測下一個(gè),,而在兩個(gè)連續(xù)的窗口之間沒有重疊,。 將建立的RNN模型中LSTM單元作為基本的隱藏單元。我們使用在時(shí)間t內(nèi)從第一個(gè)滑動窗口W0到窗口Wt的值: W0=(p0,p1,...,pw-1) W1=(pw,pw+1,...p2w-1) ... Wt=(ptw,ptw+1,...,p(t+1)w-1) 來預(yù)測下一個(gè)窗口Wt+1的值: Wt+1=(p(t+1)w,p(t+1)w+1,...,p(t+2)w-1) 以上類似于在學(xué)習(xí)一個(gè)近似函數(shù)f(W0,,W1,,... ,Wt)≈Wt+1,。 考慮到反向傳播(BPTT)的工作方式的,,我們通常將RNN訓(xùn)練成一個(gè)“展開”版本,這樣我們就不需要做太多的傳播計(jì)算,,而且可以節(jié)省訓(xùn)練的復(fù)雜性,。 價(jià)格的順序首先被分成不重疊的小窗口,。每個(gè)都包含input_size數(shù)字,每個(gè)都被認(rèn)為是一個(gè)獨(dú)立的輸入元素,。然后,,任何num_steps連續(xù)的輸入元素被分組到一個(gè)訓(xùn)練輸入中,形成一個(gè)在Tensorfow上進(jìn)行訓(xùn)練的“非滾動”版本的RNN,。相應(yīng)的標(biāo)簽就是它們后面的輸入元素,。 例如,如果input_size=3和num_steps=2,,前幾個(gè)訓(xùn)練的示例如下所示: 準(zhǔn)備數(shù)據(jù)的完整代碼在這里,。 數(shù)據(jù)標(biāo)準(zhǔn)化以下我們以最新的10%的數(shù)據(jù)作為測試數(shù)據(jù)。S&P500指數(shù)隨著時(shí)間的推移而增加,,導(dǎo)致測試集中大部分?jǐn)?shù)值超出訓(xùn)練集的范圍,,也就是說該模型必須預(yù)測一些以前從未見過的數(shù)字,。 圖: RNN模型必須預(yù)測訓(xùn)練數(shù)據(jù)的規(guī)模之外的數(shù)字 為解決這一問題,,作者將任務(wù)變成預(yù)測相對變化率而不是絕對值。在t時(shí)刻的標(biāo)準(zhǔn)化滑動窗口W't中,,所有的值除以最后一個(gè)滑動窗口Wt-1中的未知價(jià)格價(jià)格: 建立模型:定義參數(shù): lstm_size:一個(gè)LSTM圖層中的單元數(shù)量,。 num_layers:堆疊的LSTM層的數(shù)量。 keep_prob:單元格單元在退出操作中保留的百分比,。 init_learning_rate:開始學(xué)習(xí)的速率,。 learning_rate_decay:后期訓(xùn)練時(shí)期的衰減率。 init_epoch:使用常量init_learning_rate的時(shí)期數(shù),。 max_epoch:訓(xùn)練中的時(shí)期總數(shù) input_size:滑動窗口的大小/一個(gè)訓(xùn)練數(shù)據(jù)點(diǎn) batch_size:在一個(gè)小批量中使用的數(shù)據(jù)點(diǎn)的數(shù)量,。 LSTM模型是具有num_layers堆疊的LSTM層,每層包含lstm_size數(shù)量的LSTM單元,。然后將保留概率為keep_prob的退出掩碼應(yīng)用于每個(gè)LSTM單元的輸出,。退出的目標(biāo)是消除潛在的強(qiáng)烈具有依賴性維度,以防止過度擬合,。 訓(xùn)練總共需要max_epoch 時(shí)期(epoch),;一個(gè)時(shí)期(epoch)指所有訓(xùn)練數(shù)據(jù)點(diǎn)的一個(gè)完整通過。在一個(gè)時(shí)期(epoch)中,,訓(xùn)練數(shù)據(jù)點(diǎn)被分成小批量batch_size的規(guī)模,。我們發(fā)送一小批量的到一個(gè)BPTT學(xué)習(xí)的模型。學(xué)習(xí)速率在第一個(gè)init_epoch時(shí)期被設(shè)置為init_learning_rate,,然后在每個(gè)后續(xù)時(shí)期learning_rate_decay使學(xué)習(xí)速率衰減,。 # Configuration is wrapped in one object for easy tracking and passing.class RNNConfig(): input_size=1 num_steps=30 lstm_size=128 num_layers=1 keep_prob=0.8 batch_size = 64 init_learning_rate = 0.001 learning_rate_decay = 0.99 init_epoch = 5max_epoch = 50config = RNNConfig() 定義圖形tf.Graph沒有依附于任何真實(shí)的數(shù)據(jù)。它主要用于處理數(shù)據(jù)和運(yùn)行計(jì)算流程,。如果用tf.session提供的數(shù)據(jù),,這時(shí)計(jì)算的數(shù)據(jù)是真實(shí)的,。 (1)首先初始化一個(gè)新的圖表。 import tensorflow as tftf.reset_default_graph()lstm_graph = tf.Graph() (2)圖表的工作原理應(yīng)在其范圍內(nèi)定義,。 with lstm_graph.as_default(): (3)定義計(jì)算所需的數(shù)據(jù),。在這里需要三個(gè)輸入變量,全部定義為tf.placeholder,。 1.inputs:訓(xùn)練數(shù)據(jù)X,,形狀張量(#數(shù)據(jù)例子num_steps,input_size); 數(shù)據(jù)示例的數(shù)量是未知的,,所以是None,。就這個(gè)示例而言,在訓(xùn)練中它將是batch_size,。如果感到困惑,,請查看輸入格式示例。 2.targets:訓(xùn)練標(biāo)簽y,,形狀張量(#數(shù)據(jù)例子input_size),。 3.learning_rate:一個(gè)簡單的浮點(diǎn)數(shù)。 # Dimension = ( # number of data examples, # number of input in one computation step, # number of numbers in one input # ) # We don't know the number of examples beforehand, so it is None. inputs = tf.placeholder(tf.float32, [None, config.num_steps, config.input_size]) targets = tf.placeholder(tf.float32, [None, config.input_size]) learning_rate = tf.placeholder(tf.float32, None) (4)該函數(shù)返回一個(gè)LSTMCell有無退出操作,。 def _create_one_cell(): return tf.contrib.rnn.LSTMCell(config.lstm_size,state_is_tuple=True) if config.keep_prob < 1.0:="" return="" tf.contrib.rnn.dropoutwrapper(lstm_cell,="" output_keep_prob=""> (5)如果需要的話,,我們可以將單元格堆疊成多層。MultiRNNCell有助于依次連接多個(gè)簡單單元來組成一個(gè)單元,。 cell = tf.contrib.rnn.MultiRNNCell( [_create_one_cell() for _ in range(config.num_layers)], state_is_tuple=True ) if config.num_layers > 1 else _create_one_cell() (6)tf.nn.dynamic_rnn是由cell(RNNCell)指定的循環(huán)神經(jīng)網(wǎng)絡(luò)構(gòu)建的,。狀態(tài)是指LSTM單元的當(dāng)前狀態(tài),在這里沒有消耗,。 val, _ = tf.nn.dynamic_rnn(cell, inputs, dtype=tf.float32) (7)tf.transpose輸出的維度從(batch_size,,num_steps,lstm_size)轉(zhuǎn)換為(num_steps,,batch_size,,lstm_size),然后將其輸出,。 # Before transpose, val.get_shape() = (batch_size, num_steps, lstm_size) # After transpose, val.get_shape() = (num_steps, batch_size, lstm_size) val = tf.transpose(val, [1, 0, 2]) # last.get_shape() = (batch_size, lstm_size) last = tf.gather(val, int(val.get_shape()[0]) - 1, name='last_lstm_output') (8)定義隱藏層和輸出層之間的權(quán)重和偏差,。 weight = tf.Variable(tf.truncated_normal([config.lstm_size, config.input_size])) bias = tf.Variable(tf.constant(0.1, shape=[targets_width])) prediction = tf.matmul(last, weight) + bias (9)我們使用均方誤差作為損失度量和RMSPropOptimizer算法進(jìn)行梯度下降優(yōu)化。 loss = tf.reduce_mean(tf.square(prediction - targets)) optimizer = tf.train.RMSPropOptimizer(learning_rate) minimize = optimizer.minimize(loss) 訓(xùn)練階段(1)要開始用真實(shí)數(shù)據(jù)訓(xùn)練圖表,,我們需要先從一個(gè)tf.session開始,。 with tf.Session(graph=lstm_graph) as sess: (2)按照定義初始化變量。 tf.global_variables_initializer().run() (3)訓(xùn)練時(shí)期的學(xué)習(xí)率應(yīng)該預(yù)先計(jì)算好,。指數(shù)是指epoch指數(shù),。 learning_rates_to_use = [ config.init_learning_rate * ( config.learning_rate_decay ** max(float(i + 1 - config.init_epoch), 0.0) ) for i in range(config.max_epoch)] (4)下面的每個(gè)循環(huán)完成一次epoch訓(xùn)練。 for epoch_step in range(config.max_epoch): current_lr = learning_rates_to_use[epoch_step] # Check https://github.com/lilianweng/stock-rnn/blob/master/data_wrapper.py # if you are curious to know what is StockDataSet and how generate_one_epoch() # is implemented. for batch_X,batch_y in stock_dataset.generate_one_epoch(config.batch_size): train_data_feed = { inputs: batch_X, targets: batch_y, learning_rate: current_lr } train_loss, _ = sess.run([loss, minimize], train_data_feed) (5)下面的每個(gè)循環(huán)完成一次epoch訓(xùn)練,。 saver = tf.train.Saver() saver.save(sess, 'your_awesome_model_path_and_name', global_step=max_epoch_step) 使用TensorBoard 在沒有可視化的情況下構(gòu)建圖形,,非常模糊和容易出錯,。Tensorboard提供的圖形結(jié)構(gòu)和學(xué)習(xí)過程簡單可視,查看這個(gè)實(shí)踐教程,。 小結(jié)1.用于with [tf.name_scope] (https://www./api_docs/python/tf/name_scope)('your_awesome_module_name'):將包含在類似目標(biāo)上的元素一起打包,。 2.許多tf.*方法接受name=參數(shù)。分配一個(gè)定制的名字可以讓你閱讀圖表時(shí)更容易,。 3.類似tf.summary.scalar和tf.summary.histogram的方法可以幫助跟蹤迭代期間圖中變量的值,。 4.在訓(xùn)練課程中,用tf.summary.FileWriter定義一個(gè)日志文件: with tf.Session(graph=lstm_graph) as sess: merged_summary = tf.summary.merge_all() writer = tf.summary.FileWriter('location_for_keeping_your_log_files', sess.graph) writer.add_graph(sess.graph) 之后,,將訓(xùn)練進(jìn)度和總結(jié)結(jié)果寫入文件,。 _summary = sess.run([merged_summary], test_data_feed)writer.add_summary(_summary, global_step=epoch_step) # epoch_step in range(config.max_epoch) 上圖由示例代碼構(gòu)建的RNN圖?!坝?xùn)練”模塊已經(jīng)“從主圖表中刪除”,,因?yàn)樗陬A(yù)測時(shí)間內(nèi)不是模型的實(shí)際部分。 單擊“output_layer”模塊將其展開并詳細(xì)檢查結(jié)構(gòu),。 完整的工作代碼可在github.com/lilianweng/stock-rnn中找到,。 結(jié)果 作者在示例中使用了以下配置。 num_layers=1 keep_prob=0.8 batch_size = 64 init_learning_rate = 0.001 learning_rate_decay = 0.99 init_epoch = 5 max_epoch = 100 num_steps=30 上圖是在測試數(shù)據(jù)中最近200天的預(yù)測結(jié)果,。使用input_size = 1和lstm_size = 32來訓(xùn)練模型,。 上圖是在測試數(shù)據(jù)中最近200天的預(yù)測結(jié)果,。模型使用input_size = 1和lstm_size = 128進(jìn)行訓(xùn)練,。 上圖在測試數(shù)據(jù)中的最近200天的預(yù)測結(jié)果。使用input_size = 5,,lstm_size = 128和max_epoch = 75(替代50)訓(xùn)練模型,。 如果您想進(jìn)一步了解本教程中的示例代碼可在github.com/lilianweng/stock-rnn:scripts中找到。 |
|