利用Keras中的權(quán)重約束減少深度神經(jīng)網(wǎng)絡(luò)中的過擬合
權(quán)重約束提供了一種方法,用于減少深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)模型對訓(xùn)練數(shù)據(jù)的過度擬合,并改善模型對新數(shù)據(jù)(例如測試集)的性能。有多種類型的權(quán)重約束,例如最大和單位向量規(guī)范,有些需要必須配置的超參數(shù)。
在本教程中,您將發(fā)現(xiàn)Keras API,用于向深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)模型添加權(quán)重約束以減少過度擬合。
完成本教程后,您將了解:
- 如何使用Keras API創(chuàng)建向量范數(shù)約束。
- 如何使用Keras API為MLP,CNN和RNN層添加權(quán)重約束。
- 如何通過向現(xiàn)有模型添加權(quán)重約束來減少過度擬合。
教程概述
本教程分為三個部分,他們是:
- Keras的重量約束
- 圖層上的權(quán)重約束
- 體重約束案例研究
Keras的重量約束
Keras API支持權(quán)重限制。約束是按層指定的,但是在層中應(yīng)用和強(qiáng)制執(zhí)行每個節(jié)點(diǎn)。
使用約束通常涉及在圖層上為輸入權(quán)重設(shè)置kernel_constraint參數(shù),并為偏差權(quán)重設(shè)置bias_constraint。
通常,權(quán)重約束不用于偏差權(quán)重。一組不同的向量規(guī)范可以用作約束,作為keras.constraints模塊中的類提供。他們是:
- 最大范數(shù)(max_norm),用于強(qiáng)制權(quán)重等于或低于給定限制。
- 非負(fù)規(guī)范(non_neg),強(qiáng)制權(quán)重具有正數(shù)。
- 單位范數(shù)(unit_norm),強(qiáng)制權(quán)重為1.0。
- Min-Max范數(shù)(min_max_norm),用于強(qiáng)制權(quán)重在一個范圍之間。
例如,一個簡單的約束可以這樣被引入和實(shí)例化:
- # import norm
- from keras.constraints import max_norm
- # instantiate norm
- norm = max_norm(3.0)
- # import norm
- from keras.constraints import max_norm
- # instantiate norm
- norm = max_norm(3.0)
圖層上的權(quán)重約束
權(quán)重規(guī)范可用于Keras的大多數(shù)層。在本節(jié)中,我們將看一些常見的例子。
MLP加權(quán)約束
以下示例在密集完全連接層上設(shè)置最大范數(shù)權(quán)重約束。
- # example of max norm on a dense layer
- from keras.layers import Dense
- from keras.constraints import max_norm
- ...
- model.add(Dense(32, kernel_constraint=max_norm(3), bias_constraint==max_norm(3)))
- ...
- # example of max norm on a dense layer
- from keras.layers import Dense
- from keras.constraints import max_norm
- ...
- model.add(Dense(32, kernel_constraint=max_norm(3), bias_constraint==max_norm(3)))
- ...
CNN加權(quán)約束
下面的示例在卷積層上設(shè)置最大范數(shù)權(quán)重約束。
- # example of max norm on a cnn layer
- from keras.layers import Conv2D
- from keras.constraints import max_norm
- ...
- model.add(Conv2D(32, (3,3), kernel_constraint=max_norm(3), bias_constraint==max_norm(3)))
- ...
RNN權(quán)重約束
與其他圖層類型不同,遞歸神經(jīng)網(wǎng)絡(luò)允許您對輸入權(quán)重和偏差以及循環(huán)輸入權(quán)重設(shè)置權(quán)重約束。通過圖層的recurrent_constraint參數(shù)設(shè)置重復(fù)權(quán)重的約束。以下示例在LSTM圖層上設(shè)置最大范數(shù)權(quán)重約束。
- # example of max norm on an lstm layer
- from keras.layers import LSTM
- from keras.constraints import max_norm
- ...
- model.add(LSTM(32, kernel_constraint=max_norm(3), recurrent_constraint=max_norm(3), bias_constraint==max_norm(3)))
- ...
- # example of max norm on an lstm layer
- from keras.layers import LSTM
- from keras.constraints import max_norm
- ...
- model.add(LSTM(32, kernel_constraint=max_norm(3), recurrent_constraint=max_norm(3), bias_constraint==max_norm(3)))
- ...
現(xiàn)在我們知道如何使用權(quán)重約束API,讓我們看一個有效的例子。
加權(quán)約束案例研究
在本節(jié)中,我們將演示如何使用權(quán)重約束來減少M(fèi)LP對簡單二元分類問題的過度擬合。此示例提供了一個模板,用于將權(quán)重約束應(yīng)用于您自己的神經(jīng)網(wǎng)絡(luò)以進(jìn)行分類和回歸問題。
二元分類問題
我們將使用標(biāo)準(zhǔn)二進(jìn)制分類問題來定義兩個半圓數(shù)據(jù)集,每個類一個半圓。每個觀測值都有兩個輸入變量,它們具有相同的比例,類輸出值為0或1.該數(shù)據(jù)集稱為“月球”數(shù)據(jù)集,因?yàn)槔L制時每個類中的觀測值的形狀。我們可以使用make_moons()函數(shù)從這個問題中生成觀察結(jié)果。我們將為數(shù)據(jù)添加噪聲并為隨機(jī)數(shù)生成器播種,以便每次運(yùn)行代碼時生成相同的樣本。
- # generate 2d classification dataset
- X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
我們可以繪制兩個變量在圖表上作為x和y坐標(biāo)的數(shù)據(jù)集,并將類值作為觀察的顏色。下面列出了生成數(shù)據(jù)集并繪制數(shù)據(jù)集的完整示例。
- # generate two moons dataset
- from sklearn.datasets import make_moons
- from matplotlib import pyplot
- from pandas import DataFrame
- # generate 2d classification dataset
- X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
- # scatter plot, dots colored by class value
- df = DataFrame(dict(x=X[:,0], y=X[:,1], label=y))
- colors = {0:'red', 1:'blue'}
- fig, ax = pyplot.subplots()
- grouped = df.groupby('label')
- for key, group in grouped:
- group.plot(axax=ax, kind='scatter', x='x', y='y', label=key, color=colors[key])
- pyplot.show()
- # generate two moons dataset
- from sklearn.datasets import make_moons
- from matplotlib import pyplot
- from pandas import DataFrame
- # generate 2d classification dataset
- X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
- # scatter plot, dots colored by class value
- df = DataFrame(dict(x=X[:,0], y=X[:,1], label=y))
- colors = {0:'red', 1:'blue'}
- fig, ax = pyplot.subplots()
- grouped = df.groupby('label')
- for key, group in grouped:
- group.plot(axax=ax, kind='scatter', x='x', y='y', label=key, color=colors[key])
- pyplot.show()
運(yùn)行該示例會創(chuàng)建一個散點(diǎn)圖,顯示每個類中觀察的半圓形或月亮形狀。我們可以看到點(diǎn)的分散中的噪音使得衛(wèi)星不太明顯。
這是一個很好的測試問題,因?yàn)轭惒荒苡靡恍衼矸指?,例如不是線性可分的,需要非線性方法,如神經(jīng)網(wǎng)絡(luò)來解決。我們只生成了100個樣本,這對于神經(jīng)網(wǎng)絡(luò)而言很小,提供了過度擬合訓(xùn)練數(shù)據(jù)集的機(jī)會,并且在測試數(shù)據(jù)集上具有更高的誤差:使用正則化的一個好例子。此外,樣本具有噪聲,使模型有機(jī)會學(xué)習(xí)不一致的樣本的各個方面。
過度多層感知器
我們可以開發(fā)一個MLP模型來解決這個二進(jìn)制分類問題。該模型將具有一個隱藏層,其具有比解決該問題所需的節(jié)點(diǎn)更多的節(jié)點(diǎn),從而提供過度擬合的機(jī)會。我們還將訓(xùn)練模型的時間超過確保模型過度所需的時間。在我們定義模型之前,我們將數(shù)據(jù)集拆分為訓(xùn)練集和測試集,使用30個示例來訓(xùn)練模型,使用70個示例來評估擬合模型的性能。
- X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
- # split into train and test
- n_train = 30
- trainX, testX = X[:n_train, :], X[n_train:, :]
- trainy, testy = y[:n_train], y[n_train:]
接下來,我們可以定義模型。隱藏層使用隱藏層中的500個節(jié)點(diǎn)和整流的線性激活函數(shù)。在輸出層中使用S形激活函數(shù)以預(yù)測0或1的類值。該模型使用二元交叉熵?fù)p失函數(shù)進(jìn)行優(yōu)化,適用于二元分類問題和梯度下降的有效Adam版本。
- # define model
- model = Sequential()
- model.add(Dense(500, input_dim=2, activation='relu'))
- model.add(Dense(1, activation='sigmoid'))
- model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
然后,定義的模型擬合4,000個訓(xùn)練數(shù)據(jù),默認(rèn)批量大小為32。我們還將使用測試數(shù)據(jù)集作為驗(yàn)證數(shù)據(jù)集。
- # fit model
- history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
我們可以在測試數(shù)據(jù)集上評估模型的性能并報告結(jié)果。
- # evaluate the model
- _, train_acc = model.evaluate(trainX, trainy, verbose=0)
- _, test_acc = model.evaluate(testX, testy, verbose=0)
- print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
最后,我們將在每個時期的訓(xùn)練集和測試集上繪制模型的性能。如果模型確實(shí)過度擬合訓(xùn)練數(shù)據(jù)集,我們將期望訓(xùn)練集上的準(zhǔn)確度線圖繼續(xù)增加并且測試設(shè)置上升然后隨著模型在訓(xùn)練數(shù)據(jù)集中學(xué)習(xí)統(tǒng)計(jì)噪聲而再次下降。
- # plot history
- pyplot.plot(history.history['acc'], label='train')
- pyplot.plot(history.history['val_acc'], label='test')
- pyplot.legend()
- pyplot.show()
我們可以將所有這些部分組合在一起; 下面列出了完整的示例。
- # mlp overfit on the moons dataset
- from sklearn.datasets import make_moons
- from keras.layers import Dense
- from keras.models import Sequential
- from matplotlib import pyplot
- # generate 2d classification dataset
- X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
- # split into train and test
- n_train = 30
- trainX, testX = X[:n_train, :], X[n_train:, :]
- trainy, testy = y[:n_train], y[n_train:]
- # define model
- model = Sequential()
- model.add(Dense(500, input_dim=2, activation='relu'))
- model.add(Dense(1, activation='sigmoid'))
- model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
- # fit model
- history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
- # evaluate the model
- _, train_acc = model.evaluate(trainX, trainy, verbose=0)
- _, test_acc = model.evaluate(testX, testy, verbose=0)
- print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
- # plot history
- pyplot.plot(history.history['acc'], label='train')
- pyplot.plot(history.history['val_acc'], label='test')
- pyplot.legend()
- pyplot.show()
運(yùn)行該示例報告列車和測試數(shù)據(jù)集上的模型性能。我們可以看到模型在訓(xùn)練數(shù)據(jù)集上的性能優(yōu)于測試數(shù)據(jù)集,這是過度擬合的一個可能標(biāo)志。鑒于神經(jīng)網(wǎng)絡(luò)和訓(xùn)練算法的隨機(jī)性,您的具體結(jié)果可能會有所不同。因?yàn)槟P褪沁^度擬合的,所以我們通常不會期望在相同數(shù)據(jù)集上重復(fù)運(yùn)行模型的精度差異(如果有的話)。
- Train: 1.000, Test: 0.914
創(chuàng)建一個圖,顯示訓(xùn)練集和測試集上模型精度的曲線圖。我們可以看到過度擬合模型的預(yù)期形狀,其中測試精度增加到一個點(diǎn)然后再次開始減小。
具有加權(quán)約束的Overfit MLP
我們可以更新示例以使用權(quán)重約束。有一些不同的加權(quán)限制可供選擇。這個模型的一個很好的簡單約束是簡單地標(biāo)準(zhǔn)化加權(quán),使得范數(shù)等于1.0。此約束具有強(qiáng)制所有傳入權(quán)重較小的效果。我們可以通過在Keras中使用unit_norm來實(shí)現(xiàn)??梢詫⒋思s束添加到第一個隱藏層,如下所示:
- model.add(Dense(500, input_dim=2, activation='relu', kernel_constraint=unit_norm()))
我們也可以通過使用min_max_norm并將min和maximum設(shè)置為1.0來實(shí)現(xiàn)相同的結(jié)果,例如:
- model.add(Dense(500, input_dim=2, activation='relu', kernel_constraint=min_max_norm(min_value=1.0, max_value=1.0)))
我們無法通過最大范數(shù)約束獲得相同的結(jié)果,因?yàn)樗试S規(guī)范等于或低于指定的限制; 例如:
- model.add(Dense(500, input_dim=2, activation='relu', kernel_constraint=max_norm(1.0)))
下面列出了具有單位規(guī)范約束的完整更新示例:
- # mlp overfit on the moons dataset with a unit norm constraint
- from sklearn.datasets import make_moons
- from keras.layers import Dense
- from keras.models import Sequential
- from keras.constraints import unit_norm
- from matplotlib import pyplot
- # generate 2d classification dataset
- X, y = make_moons(n_samples=100, noise=0.2, random_state=1)
- # split into train and test
- n_train = 30
- trainX, testX = X[:n_train, :], X[n_train:, :]
- trainy, testy = y[:n_train], y[n_train:]
- # define model
- model = Sequential()
- model.add(Dense(500, input_dim=2, activation='relu', kernel_constraint=unit_norm()))
- model.add(Dense(1, activation='sigmoid'))
- model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
- # fit model
- history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=4000, verbose=0)
- # evaluate the model
- _, train_acc = model.evaluate(trainX, trainy, verbose=0)
- _, test_acc = model.evaluate(testX, testy, verbose=0)
- print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
- # plot history
- pyplot.plot(history.history['acc'], label='train')
- pyplot.plot(history.history['val_acc'], label='test')
- pyplot.legend()
- pyplot.show()
運(yùn)行該示例報告訓(xùn)練集和測試數(shù)據(jù)集上的模型性能。我們可以看到,對權(quán)重大小的嚴(yán)格限制確實(shí)提高了模型在測試集上的性能,而不會影響訓(xùn)練集的性能。
- Train: 1.000, Test: 0.943
回顧訓(xùn)練集的曲線和測試精度,我們可以看到模型已經(jīng)過度擬合訓(xùn)練數(shù)據(jù)集了。訓(xùn)練集和測試集的模型精度繼續(xù)提高到穩(wěn)定水平。
擴(kuò)展
本節(jié)列出了一些擴(kuò)展您可能希望探索的教程的想法。
- 報告加權(quán)標(biāo)準(zhǔn)。更新示例以計(jì)算網(wǎng)絡(luò)權(quán)重的大小,并證明約束確實(shí)使得幅度更小。
- 約束輸出層。更新示例以將約束添加到模型的輸出層并比較結(jié)果。
- 約束偏差。更新示例以向偏差權(quán)重添加約束并比較結(jié)果。
- 反復(fù)評估。更新示例以多次擬合和評估模型,并報告模型性能的均值和標(biāo)準(zhǔn)差。