<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深度運(yùn)用LSTM神經(jīng)網(wǎng)絡(luò)并與經(jīng)典時(shí)序模型對(duì)比

          共 7618字,需瀏覽 16分鐘

           ·

          2021-12-17 12:23

          點(diǎn)擊上方“程序員大白”,選擇“星標(biāo)”公眾號(hào)

          重磅干貨,第一時(shí)間送達(dá)

          ?作者 |?馮太濤

          單位 | 上海理工大學(xué)

          研究方向 | 概率論與數(shù)理統(tǒng)計(jì)




          前言

          RNN(循環(huán)神經(jīng)網(wǎng)絡(luò))是一種節(jié)點(diǎn)定向連接成環(huán)的人工神經(jīng)網(wǎng)絡(luò)。不同于前饋神經(jīng)網(wǎng)絡(luò),RNN 可以利用內(nèi)部的記憶來處理任意時(shí)序的輸入序列,即不僅學(xué)習(xí)當(dāng)前時(shí)刻的信息,也會(huì)依賴之前的序列信息,所以在做語音識(shí)別、語言翻譯等等有很大的優(yōu)勢。RNN 現(xiàn)在變種很多,常用的如 LSTM、Seq2SeqLSTM,還有其他變種如含有 Attention 機(jī)制的 Transformer 模型等等。這些變種原理結(jié)構(gòu)看似很復(fù)雜,但其實(shí)只要有一定的數(shù)學(xué)和計(jì)算機(jī)功底,在學(xué)習(xí)的時(shí)候認(rèn)認(rèn)真真搞懂一個(gè),后面的都迎刃而解。

          本文將對(duì) LSTM 里面知識(shí)做高度濃縮介紹(包括前饋推導(dǎo)和鏈?zhǔn)椒▌t),然后再建立時(shí)序模型和優(yōu)化模型,最后評(píng)估模型并與 ARIMA 或 ARIMA-GARCH 模型做對(duì)比。



          RNN神經(jīng)網(wǎng)絡(luò)底層邏輯介紹

          (注:下面涉及的所有模型解釋圖來源于百度圖片)

          1.1 輸入層、隱藏層和輸出層

          ▲ 圖1

          從上圖 1,假設(shè) 是序列中第 個(gè)批量輸入(這里的 是樣本個(gè)數(shù), 是樣本特征維度),對(duì)應(yīng)隱藏層狀態(tài)為 為隱藏層長度),最終輸出 為輸出向量維度,即輸出向量到底含幾個(gè)元素?。?。那么在計(jì)算 時(shí)刻 ,有公式:


          這里的 為某一特定激活函數(shù), 為需要學(xué)習(xí)的權(quán)重, 為要學(xué)習(xí)的偏差值,那么同理輸出結(jié)果為 參數(shù)解釋如上!

          1.2 損失函數(shù)定義

          根據(jù)誤差函數(shù)性質(zhì),對(duì)于回歸問題,大多數(shù)建立的是基于距離形式的均方誤差函數(shù)或者絕對(duì)誤差函數(shù),如果是分類問題,我們一般會(huì)選擇交叉熵這類函數(shù)!

          時(shí)刻有誤差 ,這里的 為真實(shí)值, 為預(yù)測值。那么整個(gè)時(shí)間長度 ,我們有 ,我們的目的就是更新所有的參數(shù) 使 最小。

          1.3 梯度下降與鏈?zhǔn)椒▌t求導(dǎo)

          這里的推導(dǎo)比較復(fù)雜,為了讓大家能理解到整個(gè)模型思想而不是存粹學(xué)術(shù)研究,只做重點(diǎn)介紹!且激活函數(shù)簡化!
          對(duì)于參數(shù) 的更新,經(jīng)典的梯度下降格式為: ,根據(jù)微積分知識(shí),我們知道鏈?zhǔn)椒▌t公式為:若 ,那么 可以表示為鏈?zhǔn)角髮?dǎo)過程!
          現(xiàn)在開始推導(dǎo)各個(gè)函數(shù)的鏈?zhǔn)角髮?dǎo)結(jié)果,對(duì)于任意 時(shí)刻的輸出 ,由損失函數(shù)定義很容易知: ,那么對(duì)于 的更新,由 步才能到 ,求和可得:


          對(duì)于終端時(shí)刻 ,我們很容易有:


          但對(duì)于 時(shí)刻而言,對(duì)于隱藏層的求導(dǎo)比較復(fù)雜,因?yàn)橛袀€(gè)時(shí)間前后關(guān)系,所以我們有:

          那么同理,很容易我們將解決:




          對(duì)于梯度消散(爆炸)的原理解釋


          一般 RNN 模型,會(huì)因?yàn)樵阪準(zhǔn)椒▌t中存在梯度消散(爆炸)的問題,所以我們要發(fā)展新的變種來解決這種問題,那么這梯度問題到底在哪呢?仔細(xì)發(fā)現(xiàn)在上一節(jié)的(*)式推導(dǎo)過程中,對(duì)于隱藏層求導(dǎo),我們繼續(xù)對(duì)(*)式改寫可得:


          我們再對(duì) 往后推一步,然后依次推到 時(shí)刻,最終由數(shù)學(xué)歸納法很容易得到:?


          由此式我們知道當(dāng) 、 變大或變小,對(duì)于冪次計(jì)算,結(jié)果會(huì)突變大或者趨于平穩(wěn)消散不見!由此一般 RNN 理論介紹到此,想具體了解的可以查閱相關(guān)論文。


          LSTM底層理論介紹


          為了更好的捕獲時(shí)序中間隔較大的依賴關(guān)系,基于門控制的長短記憶網(wǎng)絡(luò)(LSTM)誕生了!

          ▲ 圖2

          所謂“門”結(jié)構(gòu)就是用來去除或者增加信息到細(xì)胞狀態(tài)的能力。這里的細(xì)胞狀態(tài)是核心,它屬于隱藏層,類似于傳送帶,在整個(gè)鏈上運(yùn)行,信息在上面流傳保持不變會(huì)變得很容易!

          上圖 2 非常形象生動(dòng)描繪了 LSTM 核心的“三門結(jié)構(gòu)”。紅色圈就是所謂的遺忘門,那么在 時(shí)刻如下公式表示(如果我們真理解了 RNN 邏輯,LSTM 理解起來將變得比較輕松):



          藍(lán)圈輸入門有


          綠圈輸出門有


          同理以上涉及的參數(shù) 為需要通過鏈?zhǔn)椒▌t更新的參數(shù)!那么最后黃圈的細(xì)胞信息計(jì)算公式:



          其中



          這里涉及的雙曲正切函數(shù) 一般是固定的,那么費(fèi)這么大事,搞這么多信息控制過程是為了什么?當(dāng)然是為了更新細(xì)胞 值從而為了獲取下一步隱藏層的值:


          3.1 sigmoid激活函數(shù)的意義

          當(dāng) 激活函數(shù)選擇 sigmoid 屬于 0~1 的函數(shù)時(shí),對(duì)于遺忘門近似等于 1,輸入門近似等于 0,其實(shí) 是不更新的,那么過去的細(xì)胞信息一直保留到現(xiàn)在,解決了梯度消散問題。

          同理,輸出門可以近似等于 1,也可以近似等于 0,那么近似等于 1 時(shí)細(xì)胞信息將傳遞給隱藏層;近似等于 0 時(shí),細(xì)胞信息只自己保留。至此所有參數(shù)更新一遍并繼續(xù)向下走。。。


          PS:也許初學(xué)者看到這么多符號(hào)會(huì)比較頭疼,但邏輯是從簡到復(fù)雜的,RNN 徹底理解有助于理解后面的深入模型。這里本人也省略了很多細(xì)節(jié),大體模型框架就是如此,對(duì)于理解模型如何工作已經(jīng)完全夠了。至于怎么想出來的以及更為詳細(xì)的推導(dǎo)過程,由于作者水平有限,可參考相關(guān) RNN 論文,可多交流學(xué)習(xí)!



          建模預(yù)測存在“右偏移”怎么辦!


          為了做對(duì)比實(shí)驗(yàn),我們還會(huì)選擇之前時(shí)序文章所對(duì)應(yīng)的實(shí)際銷量數(shù)據(jù)!我們將基于 keras 模塊構(gòu)建自己的 LSTM 網(wǎng)絡(luò)進(jìn)行時(shí)序預(yù)測。

          ▲ 圖3:實(shí)際銷量數(shù)據(jù)

          4.1 構(gòu)建一般LSTM模型,當(dāng)我們選擇步長為1時(shí),先給出結(jié)果如下

          ▲ 圖4

          正常建立 LSTM 模型預(yù)測會(huì)出現(xiàn)如上預(yù)測值右偏現(xiàn)象,盡管 r2 或者 MSE 很好,但這建立的模型其實(shí)是無效模型!

          4.2 原因與改進(jìn)

          當(dāng)模型傾向于把上一時(shí)刻的真實(shí)值作為下一時(shí)刻的預(yù)測值,導(dǎo)致兩條曲線存在滯后性,也就是真實(shí)值曲線滯后于預(yù)測值曲線,如圖 4 那樣。之所以會(huì)這樣,是因?yàn)樾蛄写嬖谧韵嚓P(guān)性,如一階自相關(guān)指的是當(dāng)前時(shí)刻的值與其自身前一時(shí)刻值之間的相關(guān)性。因此,如果一個(gè)序列存在一階自相關(guān),模型學(xué)到的就是一階相關(guān)性。而消除自相關(guān)性的辦法就是進(jìn)行差分運(yùn)算,也就是我們可以將當(dāng)前時(shí)刻與前一時(shí)刻的差值作為我們的回歸目標(biāo)。

          而且從之前文章做的白噪聲檢驗(yàn)也發(fā)現(xiàn),該序列確實(shí)存在很強(qiáng)的自相關(guān)性!如下圖 5 所示。

          ▲ 圖5



          改進(jìn)模型輸出


          我們看下模型最終輸出結(jié)果:


          ▲?圖6:LSTM結(jié)果

          5.1 經(jīng)典時(shí)序模型下的最優(yōu)輸出結(jié)果

          ARIMA 模型的定階原理與建模分析:
          https://zhuanlan.zhihu.com/p/417232759


          ▲ 圖7:ARIMA結(jié)果

          此結(jié)果的全局 MSE=4401.02 大于 LSTM 網(wǎng)絡(luò)的 MSE=2521.30,由此可見當(dāng)我們優(yōu)化 LSTM 模型后,一定程度上時(shí)序建模比 ARIMA 或者 ARIMA-GARCH 要優(yōu)!

          LSTM 預(yù)測理論跟 ARIMA 也是有區(qū)別的,LSTM 主要是基于窗口滑動(dòng)取數(shù)據(jù)訓(xùn)練來預(yù)測滯后數(shù)據(jù),其中的 cell 機(jī)制會(huì)由于權(quán)重共享原因減少一些參數(shù);ARIMA 模型是根據(jù)自回歸理論,建立與自己過去有關(guān)的模型。兩者共同點(diǎn)就是能很好運(yùn)用序列數(shù)據(jù),而且通過不停迭代能無限預(yù)測下去,但預(yù)測模型還是基于短期預(yù)測有效,長期預(yù)測必然會(huì)導(dǎo)致偏差很大,而且有可能出現(xiàn)預(yù)測值趨于不變的情況。



          最終代碼


          from?keras.callbacks?import?LearningRateScheduler
          from?sklearn.metrics?import?mean_squared_error
          from?keras.models?import?Sequential
          import?matplotlib.pyplot?as?plt
          from?keras.layers?import?Dense
          from?keras.layers?import?LSTM
          from?keras?import?optimizers
          import?keras.backend?as?K
          import?tensorflow?as?tf
          import?pandas?as?pd
          import?numpy?as?np

          plt.rcParams['font.sans-serif']=['SimHei']##中文亂碼問題!
          plt.rcParams['axes.unicode_minus']=False#橫坐標(biāo)負(fù)號(hào)顯示問題!

          ###初始化參數(shù)
          my_seed?=?369#隨便給出個(gè)隨機(jī)種子
          tf.random.set_seed(my_seed)##運(yùn)行tf才能真正固定隨機(jī)種子

          sell_data?=?np.array([2800,2811,2832,2850,2880,2910,2960,3023,3039,3056,3138,3150,3198,3100,3029,2950,2989,3012,3050,3142,3252,3342,3365,3385,3340,3410,3443,3428,3554,3615,3646,3614,3574,3635,3738,3764,3788,3820,3840,3875,3900,3942,4000,4021,4055])
          num_steps?=?3##取序列步長
          test_len?=?10##測試集數(shù)量長度
          S_sell_data?=?pd.Series(sell_data).diff(1).dropna()##差分
          revisedata?=?S_sell_data.max()
          sell_datanormalization?=?S_sell_data?/?revisedata##數(shù)據(jù)規(guī)范化

          ##數(shù)據(jù)形狀轉(zhuǎn)換,很重要!!
          def?data_format(data,?num_steps=3,?test_len=5):
          ????#?根據(jù)test_len進(jìn)行分組
          ????X?=?np.array([data[i:?i?+?num_steps]
          ??????????????????for?i?in?range(len(data)?-?num_steps)])
          ????y?=?np.array([data[i?+?num_steps]
          ??????????????????for?i?in?range(len(data)?-?num_steps)])

          ????train_size?=?test_len
          ????train_X,?test_X?=?X[:-train_size],?X[-train_size:]
          ????train_y,?test_y?=?y[:-train_size],?y[-train_size:]
          ????return?train_X,?train_y,?test_X,?test_y

          transformer_selldata?=?np.reshape(pd.Series(sell_datanormalization).values,(-1,1))
          train_X,?train_y,?test_X,?test_y?=?data_format(transformer_selldata,?num_steps,?test_len)
          print('\033[1;38m原始序列維度信息:%s;轉(zhuǎn)換后訓(xùn)練集X數(shù)據(jù)維度信息:%s,Y數(shù)據(jù)維度信息:%s;測試集X數(shù)據(jù)維度信息:%s,Y數(shù)據(jù)維度信息:%s\033[0m'%(transformer_selldata.shape,?train_X.shape,?train_y.shape,?test_X.shape,?test_y.shape))

          def?buildmylstm(initactivation='relu',ininlr=0.001):

          ????nb_lstm_outputs1?=?128#神經(jīng)元個(gè)數(shù)
          ????nb_lstm_outputs2?=?128#神經(jīng)元個(gè)數(shù)
          ????nb_time_steps?=?train_X.shape[1]#時(shí)間序列長度
          ????nb_input_vector?=?train_X.shape[2]#輸入序列
          ????model?=?Sequential()
          ????model.add(LSTM(units=nb_lstm_outputs1,?input_shape=(nb_time_steps,?nb_input_vector),return_sequences=True))
          ????model.add(LSTM(units=nb_lstm_outputs2,?input_shape=(nb_time_steps,?nb_input_vector)))
          ????model.add(Dense(64,?activation=initactivation))
          ????model.add(Dense(32,?activation='relu'))
          ????model.add(Dense(test_y.shape[1],?activation='tanh'))

          ????lr?=?ininlr
          ????adam?=?optimizers.adam_v2.Adam(learning_rate=lr)
          ????def?scheduler(epoch):##編寫學(xué)習(xí)率變化函數(shù)
          ????????#?每隔epoch,學(xué)習(xí)率減小為原來的1/10
          ????????if?epoch?%?100?==?0?and?epoch?!=?0:
          ????????????lr?=?K.get_value(model.optimizer.lr)
          ????????????K.set_value(model.optimizer.lr,?lr?*?0.1)
          ????????????print('lr?changed?to?{}'.format(lr?*?0.1))
          ????????return?K.get_value(model.optimizer.lr)
          ????model.compile(loss='mse',?optimizer=adam,?metrics=['mse'])##根據(jù)損失函數(shù)性質(zhì),回歸建模一般選用”距離誤差“作為損失函數(shù),分類一般選”交叉熵“損失函數(shù)
          ????reduce_lr?=?LearningRateScheduler(scheduler)
          ????###數(shù)據(jù)集較少,全參與形式,epochs一般跟batch_size成正比
          ????##callbacks:回調(diào)函數(shù),調(diào)取reduce_lr
          ????##verbose=0:非冗余打印,即不打印訓(xùn)練過程
          ????batchsize?=?int(len(sell_data)?/?5)
          ????epochs?=?max(128,batchsize?*?4)##最低循環(huán)次數(shù)128
          ????model.fit(train_X,?train_y,?batch_size=batchsize,?epochs=epochs,?verbose=0,?callbacks=[reduce_lr])

          ????return?model

          def?prediction(lstmmodel):

          ????predsinner?=?lstmmodel.predict(train_X)
          ????predsinner_true?=?predsinner?*?revisedata
          ????init_value1?=?sell_data[num_steps?-?1]##由于存在步長關(guān)系,這里起始是num_steps
          ????predsinner_true?=?predsinner_true.cumsum()??##差分還原
          ????predsinner_true?=?init_value1?+?predsinner_true

          ????predsouter?=?lstmmodel.predict(test_X)
          ????predsouter_true?=?predsouter?*?revisedata
          ????init_value2?=?predsinner_true[-1]
          ????predsouter_true?=?predsouter_true.cumsum()??##差分還原
          ????predsouter_true?=?init_value2?+?predsouter_true

          ????#?作圖
          ????plt.plot(sell_data,?label='原始值')
          ????Xinner?=?[i?for?i?in?range(num_steps?+?1,?len(sell_data)?-?test_len)]
          ????plt.plot(Xinner,?list(predsinner_true),?label='樣本內(nèi)預(yù)測值')
          ????Xouter?=?[i?for?i?in?range(len(sell_data)?-?test_len?-?1,?len(sell_data))]
          ????plt.plot(Xouter,?[init_value2]?+?list(predsouter_true),?label='樣本外預(yù)測值')
          ????allpredata?=?list(predsinner_true)?+?list(predsouter_true)
          ????plt.legend()
          ????plt.show()

          ????return?allpredata

          mymlstmmodel?=?buildmylstm()
          presult?=?prediction(mymlstmmodel)

          def?evaluate_model(allpredata):

          ????allmse?=?mean_squared_error(sell_data[num_steps?+?1:],?allpredata)
          ????print('ALLMSE:',allmse)

          evaluate_model(presult)


          上述代碼可直接復(fù)制使用,關(guān)鍵地方本人都有注釋,如有不清楚地方可以多多交流,也許此模型還有優(yōu)化地方,可多多交流。對(duì)于 LSTM 建模,數(shù)據(jù)維度轉(zhuǎn)換是必要步驟,大家要認(rèn)真理解!



          總結(jié)


          任何模型都不是萬能的,重點(diǎn)是要有發(fā)現(xiàn)問題和解決問題的能力。

          小數(shù)據(jù)建模往往比大數(shù)據(jù)要更難,更要思考。

          對(duì)于深度模型學(xué)習(xí),本人還是強(qiáng)烈建議要大致懂模型的內(nèi)涵和原理,有條件甚至可以自己推導(dǎo)一遍或者簡單實(shí)現(xiàn)下梯度下降算法、損失函數(shù)構(gòu)建等等,否則很難解決真正的問題。

          13個(gè)你一定要知道的PyTorch特性

          解讀:為什么要做特征歸一化/標(biāo)準(zhǔn)化?

          一文搞懂 PyTorch 內(nèi)部機(jī)制

          張一鳴:每個(gè)逆襲的年輕人,都具備的底層能力


          關(guān)


          ,學(xué),西學(xué)學(xué)運(yùn)護(hù)號(hào),質(zhì),結(jié)識(shí),關(guān)[],學(xué)習(xí)進(jìn)


          瀏覽 81
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉视频在伊98 | 婷婷五月天天爽 | 黑人大香蕉伊人 | 婷婷爱丁香 | 日韩动态视频 |