接著我們看看LSTM網(wǎng)絡(luò)更復(fù)雜的運(yùn)用,那就是用來(lái)預(yù)測(cè)氣溫扣草。在這個(gè)例子中佳头,我們可以使用很多高級(jí)數(shù)據(jù)處理功能,例如我們可以看到如何使用"recurrent dropout"來(lái)預(yù)防過(guò)度擬合注竿,第二我們會(huì)把多個(gè)LTSM網(wǎng)絡(luò)層堆積起來(lái)茄茁,增強(qiáng)怎個(gè)網(wǎng)絡(luò)的解析能力,第三我們還會(huì)使用到雙向反復(fù)性網(wǎng)絡(luò)巩割,它會(huì)把同一種信息以不同的形式在網(wǎng)絡(luò)內(nèi)傳遞裙顽,從而增加網(wǎng)絡(luò)對(duì)信息的理解。
我們首先要做的重要一步宣谈,那就是獲取數(shù)據(jù)愈犹,打開(kāi)迅雷,輸入下面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))
上面代碼運(yùn)行后結(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個(gè)條目漩怎,每個(gè)條目的內(nèi)容如上面顯示所示。接下來(lá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ù)描繪出來(lái)勋锤,結(jié)果如下:
從上圖可以看出,溫度呈現(xiàn)一種周期性的變化侥祭。由于數(shù)據(jù)記錄了2009年到2016年間每天的溫度變化叁执,并且溫度記錄是每十分鐘完成一次茄厘,于是一天就有144個(gè)記錄點(diǎn),我們截取10天的溫度信息谈宛,也就是總共1440個(gè)數(shù)據(jù)點(diǎn)次哈,我們把這些數(shù)據(jù)圖繪制出來(lái)看看:
plt.plot(range(1440), temp[:1440])
我們將構(gòu)造一個(gè)網(wǎng)絡(luò),分析當(dāng)前的天氣數(shù)據(jù)吆录,然后預(yù)測(cè)未來(lái)天氣的可能狀況亿乳。當(dāng)前數(shù)據(jù)格式比較理想,問(wèn)題在于不同數(shù)據(jù)對(duì)應(yīng)的單位不一樣径筏,例如氣溫和氣壓采用不同的計(jì)量單位葛假,因此我們需要對(duì)數(shù)據(jù)做歸一化處理。我們打算使用前200000個(gè)數(shù)據(jù)條目做訓(xùn)練數(shù)據(jù)滋恬,因此我們僅僅對(duì)這部分?jǐn)?shù)據(jù)進(jìn)行歸一化:
mean = float_data[:200000].mean(axis=0)
float_data -= mean
std = float_data[:200000].std(axis=0)
float_data /= std
接著我們用代碼把數(shù)據(jù)分成三組聊训,一組用來(lái)訓(xùn)練網(wǎng)絡(luò),一組作為校驗(yàn)數(shù)據(jù)恢氯,最后一組作為測(cè)試數(shù)據(jù):
'''
假設(shè)現(xiàn)在是1點(diǎn)带斑,我們要預(yù)測(cè)2點(diǎn)時(shí)的氣溫,由于當(dāng)前數(shù)據(jù)記錄的是每隔10分鐘時(shí)的氣象數(shù)據(jù)勋拟,1點(diǎn)到2點(diǎn)
間隔1小時(shí)勋磕,對(duì)應(yīng)6個(gè)10分鐘,這個(gè)6對(duì)應(yīng)的就是delay
要訓(xùn)練網(wǎng)絡(luò)預(yù)測(cè)溫度敢靡,就需要將氣象數(shù)據(jù)與溫度建立起對(duì)應(yīng)關(guān)系挂滓,我們可以從1點(diǎn)開(kāi)始倒推10天,從過(guò)去
10天的氣象數(shù)據(jù)中做抽樣后啸胧,形成訓(xùn)練數(shù)據(jù)赶站。由于氣象數(shù)據(jù)是每10分鐘記錄一次,因此倒推10天就是從
當(dāng)前時(shí)刻開(kāi)始回溯1440條數(shù)據(jù)纺念,這個(gè)1440對(duì)應(yīng)的就是lookback
我們無(wú)需把全部1440條數(shù)據(jù)作為訓(xùn)練數(shù)據(jù)贝椿,而是從這些數(shù)據(jù)中抽樣,每隔6條取一條陷谱,
因此有1440/6=240條數(shù)據(jù)會(huì)作為訓(xùn)練數(shù)據(jù)烙博,這就是代碼中的lookback//step
于是我就把1點(diǎn)前10天內(nèi)的抽樣數(shù)據(jù)作為訓(xùn)練數(shù)據(jù),2點(diǎn)是的氣溫作為數(shù)據(jù)對(duì)應(yīng)的正確答案烟逊,由此
可以對(duì)網(wǎng)絡(luò)進(jìn)行訓(xùn)練
'''
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ù)分成三組,一組用于訓(xùn)練焙格,一組用于校驗(yàn)图毕,最后一組用于測(cè)試,代碼如下:
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)絡(luò)要有效,它就必須做的比人預(yù)測(cè)的準(zhǔn)確度高眷唉。對(duì)于溫度預(yù)測(cè)而言予颤,人本能直覺(jué)會(huì)認(rèn)為溫度具有連續(xù)性,也就是下一刻的溫度應(yīng)該會(huì)比當(dāng)前時(shí)刻的溫度差別不了多少冬阳,根據(jù)人的經(jīng)驗(yàn)蛤虐,不可能現(xiàn)在溫度是20度,然后下一刻溫度里面變成60度肝陪,或零下20度驳庭,只有世界末日才會(huì)出現(xiàn)這樣的情形,于是如果要讓人來(lái)預(yù)測(cè)氯窍,他通常會(huì)認(rèn)為接下24小時(shí)內(nèi)的溫度與當(dāng)前溫度是一樣的饲常,基于這種邏輯,我們計(jì)算一下這種預(yù)測(cè)方法的準(zhǔn)確度:
def evaluate_naive_method():
batch_maes = []
for step in range(val_steps):
samples, targets = next(val_gen)
#preds是當(dāng)前時(shí)刻溫度狼讨,targets是下一小時(shí)溫度
preds = samples[:, -1, 1]
mae = np.mean(np.abs(preds - targets))
batch_maes.append(mae)
print(np.mean(batch_maes))
evaluate_naive_method()
上面代碼運(yùn)行后得到結(jié)果為0.29贝淤,注意到前面我們對(duì)數(shù)據(jù)的每一列都做了歸一化處理,因此0.29的解釋?xiě)?yīng)該是0.29*std[1]=2.57政供,也就是說(shuō)如果我們用前一個(gè)小時(shí)的溫度來(lái)預(yù)測(cè)下一個(gè)小時(shí)的溫度播聪,那么誤差是2.57度,這個(gè)誤差不算小布隔。如果我們的網(wǎng)絡(luò)要真有效离陶,那么它預(yù)測(cè)的溫度誤差應(yīng)該比2.57要小,小得越多就越有效衅檀。
為了比較不同網(wǎng)絡(luò)模型的效果招刨,我們將分別構(gòu)造幾個(gè)不同類別的網(wǎng)絡(luò)然后分別看看他們的預(yù)測(cè)效果,首先我們先建立前面幾章講過(guò)的全連接網(wǎng)絡(luò)看看效果如何:
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)
我們把上面代碼運(yùn)行結(jié)果繪制出來(lái)看看:
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()
上面代碼運(yùn)行后結(jié)果如下:
從上圖看哀军,網(wǎng)絡(luò)預(yù)測(cè)的結(jié)果在0.4和0.3之間计济,也就是說(shuō)網(wǎng)絡(luò)預(yù)測(cè)的精確度還不如人的直覺(jué)好。當(dāng)前網(wǎng)絡(luò)存在一個(gè)問(wèn)題排苍,就是它把有時(shí)間次序的數(shù)據(jù)條目一下子碾平沦寂,從而使得數(shù)據(jù)之間的時(shí)間聯(lián)系消失了,可是時(shí)間信息對(duì)結(jié)果的預(yù)測(cè)非常重要淘衙,如果像上面做法传藏,先把多條數(shù)據(jù)集合在一起傳入網(wǎng)絡(luò),就會(huì)使得數(shù)據(jù)的時(shí)間特性消失彤守,而時(shí)間是影響判斷結(jié)果的一個(gè)重要變量毯侦。
這回我們使用反復(fù)性神經(jīng)網(wǎng)絡(luò),因?yàn)檫@樣的網(wǎng)絡(luò)能夠利用數(shù)據(jù)間存在的時(shí)間聯(lián)系來(lái)分析數(shù)據(jù)潛在規(guī)律進(jìn)而提升預(yù)測(cè)的準(zhǔn)確性具垫,這次我們使用的反復(fù)性網(wǎng)絡(luò)叫GRU侈离,它是LSTM的變種,兩者基本原理一樣筝蚕,只不過(guò)前者是對(duì)后者的優(yōu)化卦碾,使得在訓(xùn)練時(shí)效率能夠加快铺坞,我們看看相關(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)
代碼運(yùn)行后,我們繪制出來(lái)的訓(xùn)練效果如下圖:
從上圖我們看到洲胖,藍(lán)色實(shí)線在循環(huán)次數(shù)為4的時(shí)候济榨,網(wǎng)絡(luò)對(duì)校驗(yàn)數(shù)據(jù)判斷的誤差達(dá)到了接近0.26,這已經(jīng)遠(yuǎn)遠(yuǎn)好于由人的直覺(jué)猜測(cè)的0.29錯(cuò)誤率绿映,這次改進(jìn)相當(dāng)明顯擒滑。這次改進(jìn)顯示出深度學(xué)習(xí)對(duì)數(shù)據(jù)模式的抽取能力比人的直覺(jué)要好很多,同時(shí)也表明反復(fù)性網(wǎng)絡(luò)對(duì)數(shù)據(jù)的識(shí)別能力要好于我們以前開(kāi)發(fā)的全連接網(wǎng)絡(luò)叉弦。0.26轉(zhuǎn)換為錯(cuò)誤值大概是2.3左右丐一,也就是網(wǎng)絡(luò)對(duì)一小時(shí)后的溫度預(yù)測(cè)與實(shí)際值相差2.3度。
從上圖我們也看出淹冰,網(wǎng)絡(luò)對(duì)訓(xùn)練數(shù)據(jù)的識(shí)別準(zhǔn)確率不斷提升库车,對(duì)校驗(yàn)數(shù)據(jù)的識(shí)別準(zhǔn)確率越來(lái)越差,兩種分道揚(yáng)鑣很明顯榄棵,也就是說(shuō)網(wǎng)絡(luò)出現(xiàn)了過(guò)度擬合凝颇。以前我們處理過(guò)度擬合時(shí)的辦法是把權(quán)重隨機(jī)清零,但是這種方式不能直接使用到反復(fù)性網(wǎng)絡(luò)上疹鳄,因?yàn)榫W(wǎng)絡(luò)中很多鏈路權(quán)重在用于記錄不同數(shù)據(jù)在時(shí)間上的內(nèi)在關(guān)聯(lián)拧略,如果隨機(jī)把這些權(quán)重清零,就會(huì)破壞網(wǎng)絡(luò)對(duì)數(shù)據(jù)在時(shí)間上關(guān)聯(lián)性的認(rèn)識(shí)瘪弓,從而造成準(zhǔn)確率的下降垫蛆。在2015年時(shí)研究貝葉斯深度學(xué)習(xí)的博士生Yarin Gal 發(fā)現(xiàn)了處理反復(fù)性網(wǎng)絡(luò)過(guò)度擬合的方法,那是每次都將同樣的若干比例權(quán)重清零腺怯,而不是隨機(jī)清零袱饭,而這種清零機(jī)制內(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)
上面代碼運(yùn)行后呛占,網(wǎng)絡(luò)的訓(xùn)練效果如下:
從上圖實(shí)現(xiàn)和點(diǎn)線的發(fā)展趨勢(shì)不斷重合虑乖,也就是網(wǎng)絡(luò)對(duì)校驗(yàn)數(shù)據(jù)的識(shí)別正確率跟訓(xùn)練數(shù)據(jù)的正確率一樣不斷提高,因此過(guò)度擬合的現(xiàn)象消失了晾虑。至此我們就把LSTM和GRU這兩種反復(fù)性網(wǎng)絡(luò)在具體實(shí)例上的應(yīng)用展示完成疹味,如果你運(yùn)行過(guò)上面代碼會(huì)發(fā)現(xiàn),普通CPU的機(jī)子運(yùn)行代碼起來(lái)效率很慢帜篇,它再次證明了算力和數(shù)據(jù)是人工智能中兩道極難邁過(guò)去的坎兒糙捺。
更詳細(xì)的講解和代碼調(diào)試演示過(guò)程,請(qǐng)點(diǎn)擊鏈接
更多技術(shù)信息笙隙,包括操作系統(tǒng)洪灯,編譯器,面試算法竟痰,機(jī)器學(xué)習(xí)签钩,人工智能掏呼,請(qǐng)關(guān)照我的公眾號(hào):