R語言自學日記(23)-深度學習(二):長短期記憶模型

Edward Tung
R 語言自學系列
7 min readSep 26, 2018

Recurrent Neural Networks & Long-Short Term Memory Model

遞迴神經網絡(Recurrent Neural Networks)

神經網絡的預測路徑是單向的,也就是從輸入資料,透過隱藏層計算之後傳送成輸出資料,然而,對於有些資料來說這會產生一個問題,這些資料的出現實際上有高度的時間性,也就是這期的值很大一部分受到上期的影響。

我們因此對神經網絡做出一些修正:

「RNN」的圖片搜尋結果
Source:https://towardsdatascience.com/recurrent-neural-networks-and-lstm-4b601dd822a5

我們利用上一次的預測結果作為一組新的特徵輸入到神經網絡之中,這就構成了遞迴神經網絡(RNN模型),這樣做的好處不僅在於提供時間資料或前後相關資料更好的預測結果,同時它可以支援多種輸出如下:

透過回傳前次的輸出結果,我們可以組合出非常多種輸出方式,這樣的架構在語言處理上非常好用,前不久流行的TF-IDF算法,即是把文本中的辭彙拆解成向量,並根據辭彙在文本中出現的頻率作相對運算來做分類的一種方法,這時候輸入的資料維度就會變得非常大(想像一下一份文本中可能用到的單字數量)。好在文字的出現通常都有一定的規則,當你說了 “我今天想吃...” ,後面不太可能出現泥土、水泥這類的單字,這時候就仰賴RNN模型來更精準地得到預測結果。

圖片來源:https://brohrer.mcknote.com/zh-Hant/how_machine_learning_works/how_rnns_lstm_work.html

但這樣做會遭遇到一個瓶頸,也就是梯度消失問題,我們知道神經網絡的基礎是建構在透過梯度下降去搜索權重,但如果今天在很初期的時候我們的梯度就接近平坦,則沒有辦法最佳化損失函數(更正確地說,即使最佳化了,效果也不甚理想)

長短期記憶模型(Long-Short Term Memory)

上世紀末,也就是二十年前, S. Hochreiter and J. Schmidhuber. 提出了長短期記憶模型來有效解決這個問題,把從輸出端反饋進來的特徵(也就是記憶)新增了一個閘門以控制它的流入流出,換言之,我們可以選擇性地遺忘某些記憶,讓它們不要干擾現有的模型擬合,從而更有用地找到權重更新。

想像一個原始的RNN模型要回答時間相關的問題,舉例來說“我今天想吃…”,這句話可以根據吃這個單字去猜測出後期的意思,但有時,這個時間軸會被拉得很長。舉例來說“前兩天才吃了一堆漢堡,所以我今天想吃…” 這個句子,如果模型能夠精確抓到漢堡這個詞語,就能更精確地去猜測今天想吃的東西可能也不會是類似的油炸食品。但要這麼做的話,RNN就需要被加入一些機制,也就是我們要談的LSTM模型。模型的建立分成兩個步驟:遺忘與儲存,透過Activation Function來實現這件事。

假設我們今天有一個Sigmoid函數,把輸出值壓在0到1之間,其中0代表不允許通過,1代表完全可通過,0~1之間則代表部分通過。此時我們就創造了一個簡單的遺忘與儲存閘門,圖示如下:

Source:https://www.zybuluo.com/hanbingtao/note/581764

原始的RNN只有當期輸出的x(t)以及上期輸出的h(t-1)來運行神經網絡,但我們在這之上加入了一個長期記憶的Cell,舉例來說這個Cell代表了,在出現新的主詞之前,我都記住這個主詞的資訊,每次預測的結果都會跟這個主詞有關直到新的主詞出現。因此這個有用的資訊就被保存了下來,接著就可以進入到神經網絡,並且運用我們說的黑箱作業(就是程式自己調整權重但根本沒人知道發生了甚麼事,所以我們通常會說程序人員必須事後檢驗模型,來取得這台機器思考的方法),來執行預測分析。

*要注意的是,這整個LSTM會有兩種地方出現Activation Function,除了大神經網絡的輸出端以外,還有各個閘門自己的輸出端。

訓練LSTM模型

LSTM模型可以用在時間資料的預測上,我們先來實際操作看看,首先因為模型對於Scale問題比較敏感,一般的數據上我們先對其做標準化,而這邊我們則使用diff方法差分後轉換成Scaled Data,這樣可以將資料壓在活化函數的輸出範圍(上一篇沒有提到,詳細的理由可以參考最下方的延伸閱讀):

接下來我們要導入LSTM模型,但是在這之前,我們必須先介紹幾個比較特別的參數:

  1. Sample:也就是我們上一篇提到過的Batch Size
  2. TimeStep:這邊也就是RNN的重點,我們要回頭取多少的過去預測結果當作新的感知器輸入值,這邊我們就先假定為1
  3. Features:有點像是input shape,以我們的資料而言就是1

因此,我們的模型summary會像是這樣:

其中units參數代表輸出維度數量(某種程度上可以想像成幾個Nodes),最後一層代表輸出變數,以迴歸問題而言我們都把最後一層設定為1,中間層的節點數量我們可以留待之後調參再調整。接著我們要對資料做出一些處理。

這邊要將資料切分成Train與Test,這是我們很久以前提到過為了檢驗模型效度以及避免Overfitting所使用的方法,我們這邊比例設定為8:2。

另外要注意的是,LSTM輸入的維度必須是三維度資料,所以我們這邊需要多一個dim()方法去將數組劃分維度,接下來,把數據塞進去模型:

這樣一來我們就可以得到RMSE值,這個結果在1.567,優於一般的線性迴歸(1.7),而劣於XGBoost(1.475)。不過一來我們還可以透過參數調整的方式來得到更好的結果,此外因為這組數據經過Train_Test_Split,得到的數據應該比前兩個模型更可靠一點。具體的參數調整包括調整Timestep, Optimizer等等,這邊就不一一示範。

結尾

終於!把這一篇自學日記告一個段落,後期也不知道寫甚麼了。雖然感覺時間序列分析實際上還有很多方向值得探索,但目前為止也算是整體性地瀏覽過了整體樣貌。整個系列一直沒有提到一些很精細的模型原理或是比較深入的比較,一來是演算法以及分析模型的確是非常廣大,現階段很難做到精通大多數,另一方面則是本文的目的一直是以商業角度出發的自學紀錄,很多東西也就點到為止。

當然我並不鼓勵對模型背後的數學概念或是基礎的資訊知識潦草帶過,但更多時候,我們必須對一個學科建立綜觀的認識以後再深入探討,以避免見樹不見林的窘境。接下來兩篇都是一些心得說明了,如果你喜歡我的文章,還請下方不吝按Clap喔!

延伸閱讀:

--

--

Edward Tung
R 語言自學系列

Columbia Student || 2 yrs of data scientist and 1 yr of business consultant experience