完整的工作代碼可在github.com/lilianweng/stock-rnn找到。如果你不知道什么是循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)或長(zhǎng)短期記憶網(wǎng)絡(luò)(LSTM)單元,可以翻閱作者之前的文章,或者查看云棲翻譯小組其他文章 互聯(lián)網(wǎng)上也有很多類似教程,比如:
但是作者仍然堅(jiān)持寫出這篇文章主要有三個(gè)原因: 1.技術(shù)在發(fā)展,早期的教程不能應(yīng)付新版本。 2.大多數(shù)教程使用的事例是合成數(shù)據(jù),而作者在這該文中所用事例數(shù)據(jù)皆來(lái)源于現(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)中會(huì)有些難度,為此,作者建立了易于理解的圖表。 數(shù)據(jù)準(zhǔn)備:股票價(jià)格是長(zhǎng)度為N的時(shí)間序列,定義為p0,p1,... ,pN- 1,其中pi是指在第i日的收盤價(jià),0≤i<> 上圖為標(biāo)準(zhǔn)普爾500價(jià)格。我們?cè)谝粋€(gè)滑動(dòng)窗口中使用內(nèi)容來(lái)預(yù)測(cè)下一個(gè),而在兩個(gè)連續(xù)的窗口之間沒有重疊。 將建立的RNN模型中LSTM單元作為基本的隱藏單元。我們使用在時(shí)間t內(nèi)從第一個(gè)滑動(dòng)窗口W0到窗口Wt的值: W0=(p0,p1,...,pw-1) W1=(pw,pw+1,...p2w-1) ... Wt=(ptw,ptw+1,...,p(t+1)w-1) 來(lái)預(yù)測(cè)下一個(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)練的“非滾動(dòng)”版本的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ù)作為測(cè)試數(shù)據(jù)。S&P500指數(shù)隨著時(shí)間的推移而增加,導(dǎo)致測(cè)試集中大部分?jǐn)?shù)值超出訓(xùn)練集的范圍,也就是說(shuō)該模型必須預(yù)測(cè)一些以前從未見過(guò)的數(shù)字。 圖: RNN模型必須預(yù)測(cè)訓(xùn)練數(shù)據(jù)的規(guī)模之外的數(shù)字 為解決這一問(wèn)題,作者將任務(wù)變成預(yù)測(cè)相對(duì)變化率而不是絕對(duì)值。在t時(shí)刻的標(biāo)準(zhǔn)化滑動(dòng)窗口W't中,所有的值除以最后一個(gè)滑動(dòng)窗口Wt-1中的未知價(jià)格價(jià)格: 建立模型:定義參數(shù): lstm_size:一個(gè)LSTM圖層中的單元數(shù)量。 num_layers:堆疊的LSTM層的數(shù)量。 keep_prob:?jiǎn)卧駟卧谕顺霾僮髦斜A舻陌俜直取?/p> 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:滑動(dòng)窗口的大小/一個(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)烈具有依賴性維度,以防止過(guò)度擬合。 訓(xùn)練總共需要max_epoch 時(shí)期(epoch);一個(gè)時(shí)期(epoch)指所有訓(xùn)練數(shù)據(jù)點(diǎn)的一個(gè)完整通過(guò)。在一個(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。如果感到困惑,請(qǐng)查看輸入格式示例。 2.targets:訓(xùn)練標(biāo)簽y,形狀張量(#數(shù)據(jù)例子input_size)。 3.learning_rate:一個(gè)簡(jiǎn)單的浮點(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有無(wú)退出操作。 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è)簡(jiǎn)單單元來(lái)組成一個(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)建圖形,非常模糊和容易出錯(cuò)。Tensorboard提供的圖形結(jié)構(gòu)和學(xué)習(xí)過(guò)程簡(jiǎn)單可視,查看這個(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ù)測(cè)時(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 上圖是在測(cè)試數(shù)據(jù)中最近200天的預(yù)測(cè)結(jié)果。使用input_size = 1和lstm_size = 32來(lái)訓(xùn)練模型。 上圖是在測(cè)試數(shù)據(jù)中最近200天的預(yù)測(cè)結(jié)果。模型使用input_size = 1和lstm_size = 128進(jìn)行訓(xùn)練。 上圖在測(cè)試數(shù)據(jù)中的最近200天的預(yù)測(cè)結(jié)果。使用input_size = 5,lstm_size = 128和max_epoch = 75(替代50)訓(xùn)練模型。 如果您想進(jìn)一步了解本教程中的示例代碼可在github.com/lilianweng/stock-rnn:scripts中找到。 |
|
來(lái)自: 萬(wàn)皇之皇 > 《IT互聯(lián)》