LSTM是一種時間遞迴神經網路,適合於處理和預測時間序列中間隔和延遲相對較長的重要事件。在自然語言處理、語言識別等一系列的應用上都取得了很好的效果。
《Long Short Term Memory Networks with Python》是澳大利亞機器學習專家Jason Brownlee的著作,裡面詳細介紹了LSTM模型的原理和使用。
該書總共分為十四個章節,具體如下:
第一章:什麼是LSTMs?
第二章:怎麼樣訓練LSTMs?
第三章:怎麼樣準備LSTMs的資料?
第四章:怎麼樣在Keras中開發LSTMs?
第五章:序列預測建模
第六章:如何開發一個Vanilla LSTM模型?
第七章:怎麼樣開發Stacked LSTMs?
第八章:開發CNN LSTM模型(本期內容)
第九章:開發Encoder-Decoder LSTMs
第十章:開發Bidirectional LSTMs
第十一章:開發生成LSTMs
第十二章:診斷和除錯LSTMs(本期內容)
第十三章:怎麼樣用LSTMs做預測?(下週一發布)
第十四章:更新LSTMs模型
本文的作者對此書進行了翻譯整理之後,分享給大家,本文是第十二期內容。
第一期內容為:一萬字純乾貨|機器學習博士手把手教你入門LSTM(附程式碼資料)
第二期內容為:乾貨推薦|如何基於時間的反向傳播演算法來訓練LSTMs?
第三期內容為:乾貨推薦|如何準備用於LSTM模型的資料並進行序列預測?(附程式碼)
第四期內容為:機器學習博士帶你入門|一文學會如何在Keras中開發LSTMs(附程式碼)
第五期內容為:初學者如何避免在序列預測問題中遇到的陷阱?
第六期內容為:如何開發和評估Vanilla LSTM模型?
第七期內容為:博士帶你學LSTM|怎麼樣開發Stacked LSTMs?(附程式碼)
第八期內容為:博士帶你學LSTM|手把手教你開發CNN LSTM模型,並應用在Keras中(附程式碼)
第九期內容為:博士帶你學LSTM|開發Encoder-Decoder LSTM模型的簡單教程(附程式碼)
第十期內容為:博士帶你學LSTM|開發Bidirectional LSTM模型的簡單教程(附程式碼)
第十一期內容為:博士帶你學LSTM|怎麼開發一個LSTM模型來生成形狀?(附程式碼)
我們還將繼續推出一系列的文章來介紹裡面的詳細內容,和大家一起來共同學習。
12.0 前言
12.0.1 課程目標
本課程的目標是學習怎麼樣調優LSTM超引數。完成本課程之後,你將會學到:
怎麼樣開發一個針對你的LSTM模型學習能力的健壯的評估;
怎麼樣使用學習曲線來診斷你的LSTM模型的行為;
怎麼樣調整LSTM模型的框架、結構和學習行為。
12.0.2 課程概覽
本課程被分為5個部分,它們是:
評估LSTM模型;
診斷過擬合和欠擬合;
調優問題的框架;
調優模型結構;
調優學習行為。
讓我們開始吧!
12.1 評估LSTM模型
在本章節中,你將發現用於開發對未知資料的LSTM模型的學習能力的檔案估計的過程。
12.1.1 初學者的錯誤
你將模型擬合到你的訓練資料並在測試資料集上進行評估,然後報告該學習能力。也許你用K折交叉驗證來評估模型,然後報告模型的學習能力。這是初學者犯的錯誤。
看起來你做的是正確的事情,但是一個關鍵問題是你沒有考慮過:深度學習模型是隨機的。人工神經網路(如LSTM)在資料集上使用的隨機性,例如在隨機梯度下降期間每個訓練週期的隨機初始權重和資料的隨機洗牌。這意味著,每次相同的模型適合於相同的資料,它可以給出不同的預測,進而具有不同的整體技能。
12.1.2 評估模型學習能力
我們沒有所有可能的資料;如果我們做了,我們就不需要做預測。我們有一個有限的資料樣本,從中我們需要發現最好的模型。
我通過將資料分割成兩個部分,即對資料的第一部分進行模型或者特定模型配置,並使用擬合模型對其餘部分進行預測,然後評估這些預測的技巧。這被稱為訓練-測試分割,我們使用這一技巧來估計模型在預測新資料時在實踐中的表現。例如,這裡有一些虛擬碼用於使用訓練-測試分割來評估模型:
train, test = random_split(data)
model = fit(train.X, train.y)
predictions = model.predict(test.X)
skill = compare(test.y, predictions)
表 12.1 評估模型技能的虛擬碼
如果你有很多的資料或者一個很慢的模型來訓練,訓練-測試分割是一個很好的方法,但是,由於資料中的隨機性(模型的方差),模型的技能得分將是嘈雜的。這意味著相同的模型在不同資料上的擬合將會給不同模型技能分數。如果我們有資源,我們將會使用k折交叉驗證。但是,在深度學習中使用大資料集合訓練模型的速度慢,這通常是不可能的。
12.1.3 評估一個隨機模型的技能
隨機模型,如深度神經網路,新增一個額外的隨機性來源。這種附加的隨機性使得模型在學習時具有更高的靈活性,但可以使模型不太穩定(例如,當同一模型在同一資料上訓練時會有不同的結果)。這是不同的模型方差,當不同的資料訓練相同的模型時,給出不同的結果。
為了得到一個隨機模型的技能的魯棒估計,我們必須考慮這個額外的方差來源,我們必須控制它。一種穩健的方法是重複多次隨機模型的評估實驗。例如:
scores = list()
for i in repeats:
train, test = random_split(data)
model = fit(train.X, train.y)
predictions = model.predict(test.X)
skill = compare(test.y, predictions)
scores.append(skill)
final_skill = mean(scores)
表 12.2 評估隨機模型技能的虛擬碼
這是我推薦的用於評估深度學習模型的模型技能的虛擬碼。
12.1.4 神經網路有多步穩定?
這取決於你的問題,取決於網路,以及它的配置。我建議進行敏感性分析來找出答案。在同一資料上對同一模型進行多次評估(30,100次或者數千次),只改變了隨機數生成器的種子。然後回顧所產生的技能得分的平均值和標準差。標準差(平均得分與平均分數的距離)會讓你知道你的模型有多不穩定。
12.1.5 多少次迴圈?
我建議至少30次,或許100次,甚至是上千次,限制的因素只有你的時間和電腦的資源(例如,平均技能的標準錯誤)。更嚴格地說,我將推薦一個實驗,該實驗著眼於估計模型技能對重複次數和標準誤差計算的影響(平均估計效能與真實基礎種群平均值的差異)。
12.1.6 模型估計之後
評估你的模型是達到目的的一種手段。它幫助你選擇使用哪個模型以及使用哪些超引數來配置它。一旦你選擇了一個模型,你就必須初始化它。這包括將模型擬合在所有可能的資料上,並儲存在以後用於預測新資料的位置上,我們不知道實際結果。在後面的章節中,我們將更詳細地介紹模型最終的過程。
12.2 診斷欠擬合和過擬合
在本章節中,你將會發現如何在訓練期間使用LSTM模型的學習曲線圖來診斷多擬合和欠擬合。
12.2.1 在Keras中訓練歷史
你可以通過回顧模型的效能來了解模型的行為。通過呼叫fit()函式來訓練LSTM模型。此函式返回一個名為history的變數,它包括損失的蹤跡以及在編譯模型期間指定的任何其他度量。這些分數記錄在每一個週期的末尾。
...
history = model.fit(...)
表 12.3 在擬合一個LSTM模型之後分配歷史的例子
例如,如果你的模型被編譯來優化對數損失(binary_crossentropy)並衡量每個週期的準確率,那麼對數損失和準確率將被計算並記錄在每個訓練週期的歷史軌跡中。每一個分數由呼叫fit()函式返回。預設情況下,當擬合模型被稱為損失和準確率時,損失被稱為acc。
...
model.compile(loss= 'binary_crossentropy' , optimizer= adam , metrics=[ 'accuracy' ])
history = model.fit(X, Y, epochs=100)
print(history.history[ 'loss' ])
print(history.history[ 'acc' ])
表 12.4 在擬合LSTM模型之後列印歷史的例子
Keras還允許你指定一個單獨的驗證資料集,同時也可以使用相同的損失和度量來評估模型。這可以通過在fit()函式上設定validation_split引數來實現,將訓練資料的一部分用作驗證資料集(特別是0到1之間的常量)。
...
history = model.fit(X, Y, epochs=100, validation_split=0.33)
表 12.5 在訓練資料子集計算驗證損失的例子歷史
這也可以通過設定驗證資料引數和傳遞X和y資料集的元組來完成。
...
history = model.fit(X, Y, epochs=100, validation_data=(valX, valY))
表 12.6 在新資料集上包含驗證損失的例子歷史
在驗證資料集上評估的度量使用相同的名稱和val_字首。
...
model.compile(loss= binary_crossentropy , optimizer= adam , metrics=[ accuracy ])
history = model.fit(X, Y, epochs=100, validation_split=0.33)
print(history.history[ 'loss' ])
print(history.history[ 'acc' ])
print(history.history[ 'val_loss' ])
print(history.history[ 'val_acc' ])
表 12.7 列印訓練和驗證損失和準確率的例子
12.2.2 診斷圖
你的LSTM模型的訓練歷史可以用來診斷模型的行為。可以使用Matplotlib庫繪製模型的效能。例如,你可以將訓練損失和測試損失計分如下:
from matplotlib import pyplot
...
history = model.fit(X, Y, epochs=100, validation_data=(valX, valY)) pyplot.plot(history.history[ loss ])
pyplot.plot(history.history[ val_loss ])
pyplot.title( 'model train vs validation loss' )
pyplot.ylabel( 'loss' )
pyplot.xlabel( 'epoch' )
pyplot.legend([ 'train' , 'validation' ], loc= 'upper right' )
pyplot.show()
表 12.8 顯示訓練和驗證損失和準確率的例子
建立和審閱這些圖可以幫助你瞭解可能的新配置以嘗試從模型中獲得更好的效能。接下來,我們來看一些例子。我們將考慮在損失最小化的訓練和驗證集的模型技能。
12.2.3 欠擬合
欠擬合模型是一個在訓練集上表現很好,但是在測試集上表現很差的模型。這可以從訓練損失低於驗證損失的圖中診斷,驗證損失有一個趨勢,表明進一步的改進是可能的。下面提供了一個小型的LSTM模型。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# return validation data
def get_val():
seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation= 'linear' ))
# compile model
model.compile(loss= 'mse' , optimizer= 'adam')
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=100, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history[ 'loss' ])
pyplot.plot(history.history[ 'val_loss' ])
pyplot.title( 'model train vs validation loss' )
pyplot.ylabel( 'loss' )
pyplot.xlabel( 'epoch' )
pyplot.legend([ 'train' , 'validation' ], loc= 'upper right' )
pyplot.show()
表 12.9 欠擬合LSTM顯示訓練和驗證損失的例子
執行例子產生訓練和驗證損失的圖,該圖顯示了一個欠擬合的模型。在這種情況下,表現將會通過增加訓練的週期增加。
圖 12.1 需要更多訓練的欠擬合診斷模型線圖
另一方面,如果訓練集上的效能優於驗證集,效能已經趨於穩定,則模型可能欠擬合。下面是一個儲存單元不足的欠擬合的模型。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((5, 1, 1))
return X, y
# return validation data
def get_val():
seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# define model
model = Sequential()
model.add(LSTM1, input_shape=(1,1)))
model.add(Dense(1, activation= 'linear' ))
# compile model
model.compile(loss= 'mae' , optimizer= 'sgd' )
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=300, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history[ 'loss' ])
pyplot.plot(history.history[ 'val_loss' ])
pyplot.title( 'model train vs validation loss' )
pyplot.ylabel( 'loss' )
pyplot.xlabel( 'epoch' )
pyplot.legend([ 'train' , 'validation' ], loc= 'upper right' )
pyplot.show()
表 12.10 一個欠擬合LSTM顯示訓練和驗證損失的例子
執行這個例子顯示了欠擬合模型供應不足的特徵。在這種情況下,可以通過增加模型的容量來提高效能,例如隱藏層中的儲存單元的數目或者隱藏層的數目。
圖 12.2 需要較大模型的欠擬合模型的診斷圖
12.2.4 剛好擬合
剛好擬合的情況是模型的效能在訓練集和測試集上都很好。這可以從訓練和驗證損失減少和穩定在同一個點附近的圖中被診斷出來。下面的小例子演示了一個適合的LSTM模型。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((5, 1, 1))
return X, y
# return validation data
def get_val():
seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation= 'linear' ))
# compile model
model.compile(loss= 'mse' , optimizer= 'adam' )
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=800, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history[ 'loss' ])
pyplot.plot(history.history[ 'val_loss' ])
pyplot.title( 'model train vs validation loss' )
pyplot.ylabel( 'loss' )
pyplot.xlabel( 'epoch' )
pyplot.legend([ 'train' , 'validation' ], loc= 'upper right' )
pyplot.show()
表 12.11 剛好擬合顯示訓練和驗證損失的例子
執行例子建立了一個顯示訓練和驗證損失相遇的線圖。理想情況下,我們希望看到模型效能,如果可能的話,雖然在很多的資料上這可能是不可能的挑戰性問題。
圖 12.3 剛好擬合模型的診斷線圖
12.2.5 過擬合
過擬合模型是在訓練集上的效能是良好的,並持續改善,而驗證集上的效能提高到一個點,然後開始下降。這可以從訓練損失斜率下降,驗證損失斜率下降,達到拐點,並開始再次上升的情節中被診斷出來。下面的例子演示了一個過擬合的LSTM模型。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((5, 1, 1))
return X, y
# return validation data
def get_val():
seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation= 'linear' ))
# compile model
model.compile(loss= 'mse' , optimizer= 'adam' )
# fit model
X,y = get_train()
valX, valY = get_val()
history = model.fit(X, y, epochs=1200, validation_data=(valX, valY), shuffle=False)
# plot train and validation loss
pyplot.plot(history.history[ 'loss' ][500:])
pyplot.plot(history.history[ 'val_loss' ][500:])
pyplot.title( 'model train vs validation loss' )
pyplot.ylabel( 'loss' )
pyplot.xlabel( 'epoch' )
pyplot.legend([ 'train' , 'validation' ], loc= 'upper right' )
pyplot.show()
表 12.12 一個擬合LSTM顯示訓練和驗證損失的例子
圖 12.4 顯示過擬合的診斷線圖
12.2.6 多次執行
LSTM是隨機的,這意味著每一次執行的時候你都會得到一個不同的診斷圖。重複多次的診斷執行是有用的(例如5,10或30)。然後,可以從每次執行中繪製出訓練和驗證軌跡,以得出隨著時間推移模型的行為的更穩健的思想。下面的例子執行相同的實驗多次,然後繪製每一次執行的訓練軌跡和驗證損失。
圖 12.5 多次執行模型的診斷線圖
12.3 構建調參問題
本節概述了調整序列預測問題框架要考慮的最大槓桿作用的區域。
12.3.1 值縮放
評估不同資料值縮放方案對你的模型技能的影響。請記住在第一個隱藏層和/或輸出層上更新啟用函式,以處理作為輸入或預測輸出的值的範圍。嘗試的一些方案包括:
規範化值;
標準化值;
12.3.2 值編碼
評估不同值編碼對你模型技能的影響。標籤序列,如字元或單詞,通常是整數編碼和one hot編碼。假設這是對序列預測問題最熟練的方法。嘗試一些編碼方案包括:
實值編碼;
整數編碼
one hot編碼。
12.3.3 穩定性
當使用一系列實際值,如時間序列時,考慮使序列平穩。
刪除趨勢。如果該系列包含均值的方差(例如趨勢),則可以使用差分。
刪除季節性。如果該系列包含週期性的週期(例如季節性),則可以使用季節性調整。
刪除方差。如果該系列包含一個遞增或遞減的方差,可可以使用日誌或者Box-Cox變換。
12.3.4 輸入序列長度
輸入序列長度的選擇困難 針對你的問題域,儘管有時它可能是你選擇LSTM框架的一部分。評估使用不同輸入序列長度對你模型技能的影響。記住,輸入序列的長度也會影響在更新權重時用於估計誤差梯度的時間的反向傳播。它可以影響模型學習的速度和所學的知識。
12.3.5 序列模型型別
對於給定的序列預測問題有4個主要的模型序列型別:
One-to-one;
One-to-many;
Many-to-one;
Many-to-many。
Keras支援所有這些型別。使用每個序列模型型別來對問題進行構建,並評估模型技能,以幫助為你的問題選擇框架。
12.4 模型結構調優
本節概述了調整LSTM模型結構時最大槓桿作用的一些方面。
12.4.1 結構
正如我們所看到的,有許多的LSTM體系結構可供選擇。一些體系結構適用於某些序列預測問題,儘管大多數是足夠的,以使它們適合於序列預測問題。測試你對結構實用性的假設。在你的序列預測問題中,評估本書中列出的每一個LSTM結構的技能(也許超出了)。
12.4.2 儲存單元
對於給定的序列預測問題或者LSTM體系結構,我們不能知道儲存單元的最佳數目是多少。必須在LSTM隱藏層中測試一組不同的儲存單元,以檢視哪些工作最有效。
嘗試網格搜尋儲存單元的數目為100s、10s或者更細;
嘗試事宜在研究論文中引用的單元數量;
嘗試隨機搜尋1到1000之間的單元格數量。
我經常看到像100或1000那樣的原先儲存單元。我想這些都是一時興起選擇的。下面是網格搜尋的第一個隱藏LSTM層中儲存單元1,5或10的數目的小例子,其中有少量的重複(5)。你可以用這個作為你自己試驗的模板。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from pandas import DataFrame
from numpy import array
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((5, 1, 1))
return X, y
# return validation data
def get_val():
seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# fit an LSTM model
def fit_model(n_cells):
# define model
model = Sequential()
model.add(LSTM(n_cells, input_shape=(1,1)))
model.add(Dense(1, activation= 'linear' ))
# compile model
model.compile(loss= 'mse' , optimizer= 'adam' )
# fit model
X,y = get_train()
history = model.fit(X, y, epochs=500, shuffle=False, verbose=0)
# evaluate model
valX, valY = get_val()
loss = model.evaluate(valX, valY, verbose=0)
return loss
# define scope of search
params = [1, 5, 10]
n_repeats = 5
# grid search parameter values
scores = DataFrame()
for value in params:
# repeat each experiment multiple times
loss_values = list()
for i in range(n_repeats):
loss = fit_model(value)
loss_values.append(loss)
print( '>%d/%d param=%f, loss=%f' % (i+1, n_repeats, value, loss))
# store results for this parameter
scores[str(value)] = loss_values
# summary statistics of results
print(scores.describe())
# box and whisker plot of results
scores.boxplot()
pyplot.show()
表 12.14 網格搜尋儲存單元的數量的例子
執行例子列印搜尋每次迭代的過程。每一個儲存單元的結果的彙總統計在末尾顯示。
>1/5 param=1.000000, loss=0.047335
>2/5 param=1.000000, loss=0.146885
>3/5 param=1.000000, loss=0.104599
>4/5 param=1.000000, loss=0.345472
>5/5 param=1.000000, loss=0.115182
>1/5 param=5.000000, loss=0.020112
>2/5 param=5.000000, loss=0.084113
>3/5 param=5.000000, loss=0.042612
>4/5 param=5.000000, loss=0.070742
>5/5 param=5.000000, loss=0.038660
>1/5 param=10.000000, loss=0.040568
>2/5 param=10.000000, loss=0.009704
>3/5 param=10.000000, loss=0.064492
>4/5 param=10.000000, loss=0.017800
>5/5 param=10.000000, loss=0.012813
1 5 10
count 5.000000 5.000000 5.000000
mean 0.151895 0.051248 0.029075
std 0.114033 0.025801 0.023202
min 0.047335 0.020112 0.009704
25% 0.104599 0.038660 0.012813
50% 0.115182 0.042612 0.017800
75% 0.146885 0.070742 0.040568
max 0.345472 0.084113 0.064492
表 12.15 網格搜尋儲存單元的數量輸出的例子
最後結果的箱線圖被建立來比較每種不同的模型配置的模型技能分佈。
圖 12.6 調整儲存單元結果的箱線圖
12.4.3 隱藏層
與儲存單元的數目一樣,對於給定的序列預測問題或LSTM體系結構,我們不能知道LSTM隱藏層的最佳數量。當你有很多資料時,越深越好。
嘗試一起網格搜尋層數和儲存單元;
嘗試使用堆疊LSTM層在研究論文中引用的模式;
嘗試一起隨機搜尋層數和儲存單元。
建立深度卷積神經網路(CNNs)是有模式的。我沒有看見過任何複雜的模式,LSTM超出encoder-decoder模式。我認為這是一個有待探索的大問題。你能設計出總體上工作良好的stacked LSTM嗎?
12.4.4 權重初始化
Keras的LSTM層預設使用 glorot_uniform做權重的初始化。總體來說,這個權重初始化執行得很好,但是我已經使用LSTM的正常型別權重初始化取得了很大的成功。評估不同的權重初始化方案對您的模型技能的影響。Keras提供了一個很好的權重初始化列表供您嘗試。至少,比較這始終方法的技巧:
random_uniform
random_normal
glorot_uniform
glorot_normal
12.4.5 啟用函式
啟用函式(技術上是傳遞神經元的加權啟用時的傳遞函式)通常由輸入層或輸出層的框架和尺度來固定。例如,LSTM使用sigmoid啟用函式作為輸入並且因此輸入通常在0-1的刻度中。序列預測問題的分類或者回歸性質決定了在輸出層中使用啟用函式的型別。挑戰LSTM層中預設的sigmoid啟用函式。也許在重新調整輸入值的同時,嘗試使用其他的方法。例如,嘗試:
sigmoid
tanh
relu
此外,挑戰在一個stacked LSTM中所有的LSTM層是否需要使用相同的啟用函式。在實踐中,我很少看到一個模型比使用sigmoid更好,但是這個假設應該需要得到證實。
12.5 調優學習行為
本章節概述了調整LSTM模型學習行為時的最大槓桿作用的一些方面。
12.5.1 優化演算法
梯度下降的一個很好的預設實現是用Adam演算法。這是因為它結合AdaGrad和RMSProp方法的最佳屬性自動為模型中的每個引數(權重)使用自定義學習率。此外,在Keras中使用每個配置引數的最佳實踐初始值實現Adam。
然而,挑戰Adam是你的模型的正確的梯度下降演算法。用不同的梯度下降演算法評估模型的效能。現代演算法的一些思想包括:
Adam
RMSprop
Adagrad
12.5.2 學習率
學習率控制權重更新多少,作為在每個批次結束時響應估計的梯度。這會對模型的學習率和模型之間的權衡產生很大的影響。考慮使用經典隨機梯度下降(SGD)優化器,並探索不同的學習率和動量值,你可以評估不同的學習率的制度。
網格搜尋學習速率值(例如0.1, 0.001、0.0001);
學習速率衰減的週期(epoch)的實驗(例如通過回撥);
訓練模型更新與訓練的學習率越來越小的實驗。
學習率和週期(通過訓練樣本的傳遞次數)緊密耦合。一般來說,學習率(例如0.0001)越小,就需要更多的訓練週期。這是一個線性關係,所以反過來也是正確的,在更大的學習率需要更少的週期(例如0.1)。
12.5.3 批次大小
批次大小是模型權重更新之間的樣本數。一個磨的預設批次大小是32個樣本。
批次大小典型的選擇是從1到幾千,例如批次大小為32是一個好的預設值,利用矩陣成績加速到矩陣向量乘積的值大於10。
— Practical Recommendations For Gradient-based Training Of Deep Architectures, 2012.
序列預測問題的資料量和幀的大小可能取決於批次大小的選擇。然而,挑戰你的最佳猜想並嘗試一些替代的配置。
隨機梯度下降的批次大小為1;
批次大小為n,其中n是批次梯度下降的樣本數;
網格搜尋批大小為2的平方,從2到256不等。
較大的批次大小通吃會導致模型更快收斂,但可能會導致一個不太理想的權重集。批次大小為1(隨機梯度下降)更新後,每個樣本往往導致非常嘈雜的學習過程。下面是網格搜尋的一個小例子,該批次大小為1、2和3,具有少量的重複(5)。你可以用這個例子作為自己試驗的模板。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from pandas import DataFrame
from numpy import array
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((5, 1, 1))
return X, y
# return validation data
def get_val():
seq = [[0.5, 0.6], [0.6, 0.7], [0.7, 0.8], [0.8, 0.9], [0.9, 1.0]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# fit an LSTM model
def fit_model(n_batch):
# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation= 'linear' ))
# compile model
model.compile(loss= 'mse' , optimizer= 'adam' )
# fit model
X,y = get_train()
history = model.fit(X, y, epochs=500, shuffle=False, verbose=0, batch_size=n_batch)
# evaluate model
valX, valY = get_val()
loss = model.evaluate(valX, valY, verbose=0)
return loss
# define scope of search
params = [1, 2, 3]
n_repeats = 5
# grid search parameter values
scores = DataFrame()
for value in params:
# repeat each experiment multiple times
loss_values = list()
for i in range(n_repeats):
loss = fit_model(value)
loss_values.append(loss)
print( '>%d/%d param=%f, loss=%f' % (i+1, n_repeats, value, loss))
# store results for this parameter
scores[str(value)] = loss_values
# summary statistics of results
print(scores.describe())
# box and whisker plot of results
scores.boxplot()
pyplot.show()
表 12.16 網格搜尋批次大小的例子
執行這個例子列印搜尋每次迭代的進度。最後對每個配置結果進行彙總統計。
>1/5 param=1.000000, loss=0.000524
>2/5 param=1.000000, loss=0.003064
>3/5 param=1.000000, loss=0.000918
>4/5 param=1.000000, loss=0.001103
>5/5 param=1.000000, loss=0.002519
>1/5 param=2.000000, loss=0.000851
>2/5 param=2.000000, loss=0.000069
>3/5 param=2.000000, loss=0.000339
>4/5 param=2.000000, loss=0.000048
>5/5 param=2.000000, loss=0.001156
>1/5 param=3.000000, loss=0.013446
>2/5 param=3.000000, loss=0.001138
>3/5 param=3.000000, loss=0.006436
>4/5 param=3.000000, loss=0.002005
>5/5 param=3.000000, loss=0.011653
1 2 3
count 5.000000 5.000000 5.000000
mean 0.001626 0.000493 0.006936
std 0.001102 0.000492 0.005541
min 0.000524 0.000048 0.001138
25% 0.000918 0.000069 0.002005
50% 0.001103 0.000339 0.006436
75% 0.002519 0.000851 0.011653
max 0.003064 0.001156 0.013446
表 12.17 網格搜尋批次大小輸出的例子
最後結果的箱線圖建立來用於比較每個不同配置的模型技能的分佈。
圖 12.7 調整批次大小結果的箱線圖
12.5.4 正則化
在某些序列預測問題上,LSTM可以快速收斂,甚至過擬合。為了解決這個問題,可以使用正則化方法。Dropout在訓練過程隨機跳過神經元,迫使該層中的其他神經元來收拾殘局。它簡單有效。從dropout開始。Dropout率在0(不dropout)和1(完全dropout)之間,可以在通過兩個不同的引數在LSTM層上設定:
dropout。dropout應用於輸入連線。
recurrent_dropout。dropout應用於迴圈連線。
例如:
model.add(LSTM(..., dropout=0.4))
表 12.18 用輸入連線dropout新增一層的例子
一些需要去嘗試的例子包括:
網格搜尋不同的dropout百分比;
在輸入、隱藏和輸出層中進行dropout實驗。
LSTM還支援其他形式的正則化,如權重規則化,施加壓力以減少網路權重的大小。同樣,這些引數可以在LSTM層上設定:
偏置正則化:對偏置的正則化;
核正則化:對輸入權重的正則化;
迴圈正則化:對迴圈權重的正則化。
你可以使用正則化類,如L1、L2或者L1L2正則化,而不是dropout的百分比。我建議使用L1L2,使用0和1之間的值,也允許模擬T1和T2方法。例如,你可以試試:
L1L2(0.0, 0.0),例如,基準線或者無正則化;
L1L2(0.01, 0.0),例如,L1;
L1L2(0.0, 0.01),例如,L2;
L1L2(0.01, 0.01),例如,L1L2也稱為彈性網。
model.add(LSTM(..., kernel_regularizer=L1L2(0.01, 0.01)))
表 12.19 用輸入權重正則化新增一層的例子
在實踐中,我們發現輸入連線上的dropout和輸入權重的正則化,從而導致更好的執行模型。
12.5.5 早停
訓練週期的數量調優會非常的耗時間。另外一種方法是使大量的訓練週期(epoch)稱為可能。然後設定一些東西來檢查模型在訓練和驗證資料集上的效能,如果模型看起來開始過度學習,停止訓練。因此,早期停止是一種正則化,以抑制過度擬合。
你可以在Keras的早期停止實驗中用一個EarlyStopping回撥。它需要你指定一些引數配置,例如用於監視的度量(例如val-損失),在所觀察到的次數上沒有到的監視度量的改進(例如100)。在對模型進行訓練時,將回撥列表提供給fit()函式。例如:
from keras.callbacks import EarlyStopping
es = EarlyStopping(monitor= val_loss , min_delta=100)
model.fit(..., callbacks=[es])
表 12.20 使用EarlyStopping回撥的例子
12.6 擴充套件閱讀
本章節提供了一些用於擴充套件閱讀的資源:
12.6.1 書籍
Empirical Methods for Artificial Intelligence, 1995.
12.6.2 論文
Practical recommendations for gradient-based training of deep architectures, 2012.
Recurrent Neural Network Regularization, 2014.
12.6.3 APIs
Sequential Model API in Keras.
LSTM Layer API in Keras.
Weight Initializers API in Keras.
Optimized API in Keras.
Callbacks API in Keras.
12.7 總結
本課程中, 你學習到了怎麼樣對LSTM的超引數調優。特別地,你學習到了:
怎麼樣開發一個針對你的LSTM模型學習能力的健壯的評估;
怎麼樣使用學習曲線來診斷你的LSTM模型的行為;
怎麼樣調整LSTM模型的框架、結構和學習行為。
在下面的課程中,你將會學習到怎麼樣完成LSTM模型,並使用它來對資料進行預測。
作者介紹:邵洲,在讀博士。研究興趣:資料探勘、學者遷徙研究。