1. 程式人生 > >長短期記憶(LSTM)系列_LSTM的建模方法(3)——如何判斷LSTM模型的過度擬合和欠擬合

長短期記憶(LSTM)系列_LSTM的建模方法(3)——如何判斷LSTM模型的過度擬合和欠擬合

導讀:

本文主要講了一些模型中一個常見的問題,訓練不足和過度擬合。

過度擬合指的是由於訓練資料過少,或者對訓練集訓練的次數過多,導致模型的結果不是找到所有資料的一般共有特性,而是僅對訓練資料進行了特徵提取。換句話說,這個模型已經記住了所有的訓練資料,對訓練資料的預測效果非常好,但對其他資料的預測效果非常差。

對於訓練不足的情況來說,可以通過增加網路中的節點,或者增加網路的訓練週期來達到。

對於過度擬合的情況來說,可以通多減少或控制訓練週期,在資料出現拐點前,停止對網路的訓練來達到。

最後為了檢驗訓練效果,我們可以多次訓練並將訓練結果的影象畫出來,最終診斷模型訓練的效果如何,是否穩定可行。

 

1.Keras模型訓練中的history

通過檢視模型的效能,您可以瞭解很多關於模型行為的知識。

通過呼叫fit()函式來訓練LSTM模型。此函式返回一個名為history的變數,該變數包含損失的跟蹤以及在編譯模型期間指定的任何其他度量,在週期結束時記錄資料。

例如,如果編譯模型以優化對數損失(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'])

 

 Keras還允許您在擬合模型時指定單獨的驗證資料集,也可以使用相同的損失和指標進行評估。這可以通過在fit()上設定validation_split引數來使用一部分訓練資料作為驗證資料集來完成。validation_split

引數指的是從訓練集中選出一部分比例的資料,來進行測試。

history = model.fit(X, Y, epochs=100, validation_split=0.33)

這也可以通過設定validation_data引數並傳遞X和y資料集的元組來完成。
history = model.fit(X, Y, epochs=100, validation_data=(valX, valY))

帶有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'])

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()

建立和檢視這些圖可以幫助您瞭解可能的新配置,以便從模型中獲得更好的效能。

接下來,我們將看一些例子。我們將考慮列車上的模型技能和最小化損失的驗證集。您可以使用對您的問題有意義的所有指標。

3.不合格的例子

欠適應模型被證明在訓練資料集上表現良好而在測試資料集上表現不佳。

這可以從訓練損失低於驗證損失的圖中診斷出來,並且驗證損失具有表明可以進一步改進的趨勢。

下面提供了一個不足的LSTM模型的小例子。程式碼中history = model.fit(X, y, epochs=100, validation_data=(valX, valY), shuffle=False)這一行epochs=100,訓練週期只有100個,這是明顯不夠的。

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()

執行此示例會生成列車和驗證損失圖,顯示欠裝模型的特徵。在這種情況下,可以通過增加訓練時期的數量來改善效能。

在這種情況下,可以通過增加訓練時期的數量來改善效能。

顯示一個適合模型的診斷線劇情

                                                                                        顯示一個適合模型的診斷線劇情

或者,如果訓練集上的表現優於驗證集並且效能已經趨於平穩,則模型可能不合適。以下是一個例子

以下是具有不足的儲存器單元的不合格模型的程式碼,很明顯程式碼中model.add(LSTM(1, input_shape=(1,1)))這一行標識的中間層節點只有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(LSTM(1, 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()

執行此示例顯示了看似欠配置的模型的特徵。在這種情況下,可以通過增加模型的節點容量來改善效能,例如隱藏層中的儲存器單元的數量或隱藏層的數量。

通過狀態顯示適合模型的診斷線圖

                                                                                通過狀態顯示適合模型的診斷線圖

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()

執行該示例會建立一個顯示列車和驗證丟失會議的線圖。

理想情況下,我們希望儘可能看到這樣的模型效能,儘管這可能無法解決大量資料的挑戰。

顯示適合模型的診斷線圖

                                                                                  顯示適合模型的診斷線圖

 

5.過度擬合示例

過度擬合模型是訓練組上的效能良好並且持續改進的模型,而驗證組上的效能改善到某一點然後開始降級。

這可以從訓練損失向下傾斜並且驗證損失向下傾斜,到達拐點並且再次開始向上傾斜的圖中診斷出來。

下面的示例演示了一個過度擬合的LSTM模型。在history = model.fit(X, y, epochs=1200, validation_data=(valX, valY), shuffle=False)這段程式碼中,epochs=1200,這個數值設定過大,導致了訓練出現過擬合現象。

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()

執行此示例會建立一個圖表,顯示過度擬合模型的驗證丟失中的特徵拐點。這可能是太多訓練週期的標誌。

在這種情況下,模型訓練可以在拐點處停止。或者,可以增加訓練資料的數量。

顯示適合模型的診斷線劇情

                                                                          顯示適合模型的診斷線劇情

6.多次執行示例

LSTM是隨機的,這意味著每次執行都會獲得不同的診斷圖。

多次重複診斷執行(例如5,10或30)可能很有用。然後可以繪製來自每次執行的訓練和驗證曲線,以更加穩健地瞭解模型隨時間的行為。

下面的示例在繪製每次執行的訓練資料圖和驗證損失之前多次執行相同的實驗。

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from matplotlib import pyplot
from numpy import array
from pandas import DataFrame

# 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

# collect data across multiple repeats
train = DataFrame()
val = DataFrame()
for i in range(5):
	# 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')
	X,y = get_train()
	valX, valY = get_val()
	# fit model
	history = model.fit(X, y, epochs=300, validation_data=(valX, valY), shuffle=False)
	# story history
	train[str(i)] = history.history['loss']
	val[str(i)] = history.history['val_loss']

# plot train and validation loss across multiple runs
pyplot.plot(train, color='blue', label='train')
pyplot.plot(val, color='orange', label='validation')
pyplot.title('model train vs validation loss')
pyplot.ylabel('loss')
pyplot.xlabel('epoch')
pyplot.show()

在得到的圖中,我們可以看到欠擬合的總趨勢在5次執行中保持不變,並且可能增加訓練時期的數量。

診斷線圖顯示模型的多個執行

                                                                       診斷線圖顯示模型的多次執行