LSTM和GRU網(wǎng)絡的高級運用實例

接著我們看看LSTM網(wǎng)絡更復雜的運用,那就是用來預測氣溫。在這個例子中,我們可以使用很多高級數(shù)據(jù)處理功能,例如我們可以看到如何使用"recurrent dropout"來預防過度擬合,第二我們會把多個LTSM網(wǎng)絡層堆積起來,增強怎個網(wǎng)絡的解析能力,第三我們還會使用到雙向反復性網(wǎng)絡,它會把同一種信息以不同的形式在網(wǎng)絡內(nèi)傳遞,從而增加網(wǎng)絡對信息的理解。

我們首先要做的重要一步,那就是獲取數(shù)據(jù),打開迅雷,輸入下面URL以便下載原始數(shù)據(jù):
https://s3.amazonaws.com/keras-datasets/jena_climate_2009_2016.csv.zip
下載后解壓,我們就可以用代碼將其加載到內(nèi)存中:

import os
data_dir = '/Users/chenyi/Documents/人工智能/'
fname = os.path.join(data_dir, 'jena_climate_2009_2016.csv')

f = open(fname)
data = f.read()
f.close()

lines = data.split('\n')
header = lines[0].split(',')
lines = lines[1:]

print(header)
print(len(lines))

上面代碼運行后結(jié)果如下:
['"Date Time"', '"p (mbar)"', '"T (degC)"', '"Tpot (K)"', '"Tdew (degC)"', '"rh (%)"', '"VPmax (mbar)"', '"VPact (mbar)"', '"VPdef (mbar)"', '"sh (g/kg)"', '"H2OC (mmol/mol)"', '"rho (g/m**3)"', '"wv (m/s)"', '"max. wv (m/s)"', '"wd (deg)"']
420551
數(shù)據(jù)總共有420551個條目,每個條目的內(nèi)容如上面顯示所示。接下來我們把所有條目轉(zhuǎn)換成可以被處理的數(shù)組格式:

import numpy as np
float_data = np.zeros((len(lines), len(header) - 1))
for i, line in enumerate(lines):
    values = [float(x) for x in line.split(',')[1:]]
    float_data[i, :] = values

from matplotlib import pyplot as plt
temp = float_data[:, 1] 
plt.plot(range(len(temp)), temp)

上面代碼轉(zhuǎn)換數(shù)據(jù)后,將數(shù)據(jù)描繪出來,結(jié)果如下:

屏幕快照 2018-09-11 下午5.18.57.png

從上圖可以看出,溫度呈現(xiàn)一種周期性的變化。由于數(shù)據(jù)記錄了2009年到2016年間每天的溫度變化,并且溫度記錄是每十分鐘完成一次,于是一天就有144個記錄點,我們截取10天的溫度信息,也就是總共1440個數(shù)據(jù)點,我們把這些數(shù)據(jù)圖繪制出來看看:

plt.plot(range(1440), temp[:1440])
屏幕快照 2018-09-11 下午5.22.18.png

我們將構(gòu)造一個網(wǎng)絡,分析當前的天氣數(shù)據(jù),然后預測未來天氣的可能狀況。當前數(shù)據(jù)格式比較理想,問題在于不同數(shù)據(jù)對應的單位不一樣,例如氣溫和氣壓采用不同的計量單位,因此我們需要對數(shù)據(jù)做歸一化處理。我們打算使用前200000個數(shù)據(jù)條目做訓練數(shù)據(jù),因此我們僅僅對這部分數(shù)據(jù)進行歸一化:

mean = float_data[:200000].mean(axis=0)
float_data -= mean
std = float_data[:200000].std(axis=0)
float_data /= std

接著我們用代碼把數(shù)據(jù)分成三組,一組用來訓練網(wǎng)絡,一組作為校驗數(shù)據(jù),最后一組作為測試數(shù)據(jù):

'''
假設現(xiàn)在是1點,我們要預測2點時的氣溫,由于當前數(shù)據(jù)記錄的是每隔10分鐘時的氣象數(shù)據(jù),1點到2點
間隔1小時,對應6個10分鐘,這個6對應的就是delay

要訓練網(wǎng)絡預測溫度,就需要將氣象數(shù)據(jù)與溫度建立起對應關(guān)系,我們可以從1點開始倒推10天,從過去
10天的氣象數(shù)據(jù)中做抽樣后,形成訓練數(shù)據(jù)。由于氣象數(shù)據(jù)是每10分鐘記錄一次,因此倒推10天就是從
當前時刻開始回溯1440條數(shù)據(jù),這個1440對應的就是lookback

我們無需把全部1440條數(shù)據(jù)作為訓練數(shù)據(jù),而是從這些數(shù)據(jù)中抽樣,每隔6條取一條,
因此有1440/6=240條數(shù)據(jù)會作為訓練數(shù)據(jù),這就是代碼中的lookback//step

于是我就把1點前10天內(nèi)的抽樣數(shù)據(jù)作為訓練數(shù)據(jù),2點是的氣溫作為數(shù)據(jù)對應的正確答案,由此
可以對網(wǎng)絡進行訓練
'''
def generator(data, lookback, delay, min_index, max_index, shuffle=False,
             batch_size=128, step=6):
    if max_index is None:
        max_index = len(data) - delay - 1
    i = min_index + lookback
    while 1:
        if shuffle:
            rows = np.random.randint(min_index + lookback, max_index, size=batch_size)
        else:
            if i + batch_size >= max_index:
                i = min_index + lookback
            rows = np.arange(i, min(i + batch_size, max_index))
            i += len(rows)
        samples = np.zeros((len(rows), lookback//step, data.shape[-1]))
        targets = np.zeros((len(rows), ))
        for j, row in enumerate(rows):
            indices = range(rows[j] - lookback, rows[j], step)
            samples[j] = data[indices]
            targets[j] = data[rows[j] + delay][1]
        yield samples, targets

有了上面的數(shù)據(jù)處理函數(shù),我們就可以調(diào)用它將原始數(shù)據(jù)分成三組,一組用于訓練,一組用于校驗,最后一組用于測試,代碼如下:

lookback = 1440
step = 6
delay = 144
batch_size = 128

train_gen = generator(float_data, lookback=lookback, 
                      delay=delay, min_index=0,
                      max_index=200000, shuffle=True,
                      step=step,batch_size=batch_size)
val_gen = generator(float_data, lookback=lookback,
                   delay=delay, min_index=200001,
                   max_index=300000,
                   step=step, batch_size=batch_size)
test_gen = generator(float_data, lookback=lookback,
                   delay=delay, min_index=300001,
                   max_index=400000,
                   step=step, batch_size=batch_size)

val_steps = (300000 - 200001 - lookback) // batch_size
test_steps = (len(float_data) - 300001 - lookback) //batch_size

神經(jīng)網(wǎng)絡要有效,它就必須做的比人預測的準確度高。對于溫度預測而言,人本能直覺會認為溫度具有連續(xù)性,也就是下一刻的溫度應該會比當前時刻的溫度差別不了多少,根據(jù)人的經(jīng)驗,不可能現(xiàn)在溫度是20度,然后下一刻溫度里面變成60度,或零下20度,只有世界末日才會出現(xiàn)這樣的情形,于是如果要讓人來預測,他通常會認為接下24小時內(nèi)的溫度與當前溫度是一樣的,基于這種邏輯,我們計算一下這種預測方法的準確度:

def  evaluate_naive_method():
    batch_maes = []
    for step in range(val_steps):
        samples, targets = next(val_gen)
        #preds是當前時刻溫度,targets是下一小時溫度
        preds = samples[:, -1, 1]
        mae = np.mean(np.abs(preds - targets))
        batch_maes.append(mae)
    print(np.mean(batch_maes))
evaluate_naive_method()

上面代碼運行后得到結(jié)果為0.29,注意到前面我們對數(shù)據(jù)的每一列都做了歸一化處理,因此0.29的解釋應該是0.29*std[1]=2.57,也就是說如果我們用前一個小時的溫度來預測下一個小時的溫度,那么誤差是2.57度,這個誤差不算小。如果我們的網(wǎng)絡要真有效,那么它預測的溫度誤差應該比2.57要小,小得越多就越有效。

為了比較不同網(wǎng)絡模型的效果,我們將分別構(gòu)造幾個不同類別的網(wǎng)絡然后分別看看他們的預測效果,首先我們先建立前面幾章講過的全連接網(wǎng)絡看看效果如何:

from keras.models import Sequential
from keras import layers
from keras.optimizers import RMSprop

model = Sequential()
model.add(layers.Flatten(input_shape=(lookback // step, 
                                      float_data.shape[-1])))
model.add(layers.Dense(32, activation='relu'))
model.add(layers.Dense(1))

model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen, steps_per_epoch=500,
                             epochs=20,
                             validation_data=val_gen,
                             validation_steps=val_steps)

我們把上面代碼運行結(jié)果繪制出來看看:

import matplotlib.pyplot as plt
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)
plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and Validation loss')

plt.show()

上面代碼運行后結(jié)果如下:

屏幕快照 2018-09-14 上午11.43.26.png

從上圖看,網(wǎng)絡預測的結(jié)果在0.4和0.3之間,也就是說網(wǎng)絡預測的精確度還不如人的直覺好。當前網(wǎng)絡存在一個問題,就是它把有時間次序的數(shù)據(jù)條目一下子碾平,從而使得數(shù)據(jù)之間的時間聯(lián)系消失了,可是時間信息對結(jié)果的預測非常重要,如果像上面做法,先把多條數(shù)據(jù)集合在一起傳入網(wǎng)絡,就會使得數(shù)據(jù)的時間特性消失,而時間是影響判斷結(jié)果的一個重要變量。

這回我們使用反復性神經(jīng)網(wǎng)絡,因為這樣的網(wǎng)絡能夠利用數(shù)據(jù)間存在的時間聯(lián)系來分析數(shù)據(jù)潛在規(guī)律進而提升預測的準確性,這次我們使用的反復性網(wǎng)絡叫GRU,它是LSTM的變種,兩者基本原理一樣,只不過前者是對后者的優(yōu)化,使得在訓練時效率能夠加快,我們看看相關(guān)代碼:

model = Sequential()
model.add(layers.GRU(32, input_shape=(None, float_data.shape[-1])))
model.add(layers.Dense(1))

model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen, steps_per_epoch=500,
                       epochs = 20, validation_data=val_gen,
                       validation_steps=val_steps)

代碼運行后,我們繪制出來的訓練效果如下圖:

屏幕快照 2018-09-17 下午3.35.21.png

從上圖我們看到,藍色實線在循環(huán)次數(shù)為4的時候,網(wǎng)絡對校驗數(shù)據(jù)判斷的誤差達到了接近0.26,這已經(jīng)遠遠好于由人的直覺猜測的0.29錯誤率,這次改進相當明顯。這次改進顯示出深度學習對數(shù)據(jù)模式的抽取能力比人的直覺要好很多,同時也表明反復性網(wǎng)絡對數(shù)據(jù)的識別能力要好于我們以前開發(fā)的全連接網(wǎng)絡。0.26轉(zhuǎn)換為錯誤值大概是2.3左右,也就是網(wǎng)絡對一小時后的溫度預測與實際值相差2.3度。

從上圖我們也看出,網(wǎng)絡對訓練數(shù)據(jù)的識別準確率不斷提升,對校驗數(shù)據(jù)的識別準確率越來越差,兩種分道揚鑣很明顯,也就是說網(wǎng)絡出現(xiàn)了過度擬合。以前我們處理過度擬合時的辦法是把權(quán)重隨機清零,但是這種方式不能直接使用到反復性網(wǎng)絡上,因為網(wǎng)絡中很多鏈路權(quán)重在用于記錄不同數(shù)據(jù)在時間上的內(nèi)在關(guān)聯(lián),如果隨機把這些權(quán)重清零,就會破壞網(wǎng)絡對數(shù)據(jù)在時間上關(guān)聯(lián)性的認識,從而造成準確率的下降。在2015年時研究貝葉斯深度學習的博士生Yarin Gal 發(fā)現(xiàn)了處理反復性網(wǎng)絡過度擬合的方法,那是每次都將同樣的若干比例權(quán)重清零,而不是隨機清零,而這種清零機制內(nèi)內(nèi)嵌在keras框架中。相關(guān)代碼如下:

model = Sequential()
model.add(layers.GRU(32, dropout=0.2, recurrent_dropout=0.2, 
                    input_shape=(None, float_data.shape[-1])))
model.add(Dense(1))
model.compile(optimizer=RMSprop(), loss='mae')
history = model.fit_generator(train_gen, steps_per_epoch=500,
                             epochs = 40, validation_data=val_gen,
                             validation_steps = val_steps)

上面代碼運行后,網(wǎng)絡的訓練效果如下:

屏幕快照 2018-09-18 下午4.08.09.png

從上圖實現(xiàn)和點線的發(fā)展趨勢不斷重合,也就是網(wǎng)絡對校驗數(shù)據(jù)的識別正確率跟訓練數(shù)據(jù)的正確率一樣不斷提高,因此過度擬合的現(xiàn)象消失了。至此我們就把LSTM和GRU這兩種反復性網(wǎng)絡在具體實例上的應用展示完成,如果你運行過上面代碼會發(fā)現(xiàn),普通CPU的機子運行代碼起來效率很慢,它再次證明了算力和數(shù)據(jù)是人工智能中兩道極難邁過去的坎兒。

更詳細的講解和代碼調(diào)試演示過程,請點擊鏈接

更多技術(shù)信息,包括操作系統(tǒng),編譯器,面試算法,機器學習,人工智能,請關(guān)照我的公眾號:


這里寫圖片描述
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,315評論 2 89
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,291評論 25 708
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 14,085評論 2 59
  • HashMap鏈表轉(zhuǎn)為紅黑樹的臨界值為8的原因 參考文章:深入理解哈希表Jdk1.8中的HashMap實現(xiàn)原理Ja...
    青年馬土豆閱讀 1,707評論 0 2
  • 今天天氣不錯心情也好 但是沒有暴飲暴食哈 還是管住了自己的嘴 總感覺自己身體輕快了 沒有以前那么沉重 這是一個好現(xiàn)...
    沒困落夫斯基閱讀 272評論 1 1

友情鏈接更多精彩內(nèi)容