文章代碼來源:《deep learning on keras》依溯,非常好的一本書老厌,大家如果英語好,推薦直接閱讀該書黎炉,如果時(shí)間不夠枝秤,可以看看此系列文章,文章為我自己翻譯的內(nèi)容加上自己的一些思考慷嗜,水平有限淀弹,多有不足,請多指正庆械,翻譯版權(quán)所有薇溃,若有轉(zhuǎn)載,請先聯(lián)系本人缭乘。
個(gè)人方向?yàn)閿?shù)值計(jì)算沐序,日后會(huì)向深度學(xué)習(xí)和計(jì)算問題的融合方面靠近,若有相近專業(yè)人士忿峻,歡迎聯(lián)系薄啥。
系列文章:
一、搭建屬于你的第一個(gè)神經(jīng)網(wǎng)絡(luò)
二逛尚、訓(xùn)練完的網(wǎng)絡(luò)去哪里找
三垄惧、【keras實(shí)戰(zhàn)】波士頓房價(jià)預(yù)測
四、keras的function API
五绰寞、keras callbacks使用
六到逊、機(jī)器學(xué)習(xí)基礎(chǔ)Ⅰ:機(jī)器學(xué)習(xí)的四個(gè)標(biāo)簽
七、機(jī)器學(xué)習(xí)基礎(chǔ)Ⅱ:評估機(jī)器學(xué)習(xí)模型
八滤钱、機(jī)器學(xué)習(xí)基礎(chǔ)Ⅲ:數(shù)據(jù)預(yù)處理觉壶、特征工程和特征學(xué)習(xí)
九、機(jī)器學(xué)習(xí)基礎(chǔ)Ⅳ:過擬合和欠擬合
十件缸、機(jī)器學(xué)習(xí)基礎(chǔ)Ⅴ:機(jī)器學(xué)習(xí)的一般流程十一铜靶、計(jì)算機(jī)視覺中的深度學(xué)習(xí):卷積神經(jīng)網(wǎng)絡(luò)介紹
十二、計(jì)算機(jī)視覺中的深度學(xué)習(xí):從零開始訓(xùn)練卷積網(wǎng)絡(luò)
十三他炊、計(jì)算機(jī)視覺中的深度學(xué)習(xí):使用預(yù)訓(xùn)練網(wǎng)絡(luò)
十四争剿、計(jì)算機(jī)視覺中的神經(jīng)網(wǎng)絡(luò):可視化卷積網(wǎng)絡(luò)所學(xué)到的東西
在之前的例子中已艰,我們注意到我們模型的表現(xiàn)都會(huì)在極少的訓(xùn)練批次后達(dá)到峰值,此后開始下降蚕苇,即我們的模型會(huì)很快過擬合到訓(xùn)練數(shù)據(jù)哩掺。過擬合發(fā)生在每一個(gè)單獨(dú)的機(jī)器學(xué)習(xí)問題中。學(xué)會(huì)如何解決過擬合問題對于掌控機(jī)器學(xué)習(xí)尤為重要涩笤。
在機(jī)器學(xué)習(xí)中最基礎(chǔ)的主題就是優(yōu)化和泛化的張力嚼吞。“優(yōu)化”代表著通過調(diào)整模型來在訓(xùn)練數(shù)據(jù)上表現(xiàn)最好蹬碧,“泛化”則代表模型在未見過的數(shù)據(jù)上的表現(xiàn)舱禽。這場游戲的目標(biāo)就是取得好的泛化,當(dāng)然恩沽,你控制不了泛化呢蔫,你只能基于訓(xùn)練數(shù)據(jù)調(diào)節(jié)模型。
在訓(xùn)練的一開始飒筑,優(yōu)化和泛化是相關(guān)的:你在訓(xùn)練數(shù)據(jù)中的損失越低,你在測試函數(shù)中的損失也就越低绽昏。當(dāng)這種情況發(fā)生時(shí)协屡,你的模型就叫做欠擬合:這里還有可進(jìn)步的空間;網(wǎng)絡(luò)還沒有將訓(xùn)練數(shù)據(jù)中的相關(guān)的數(shù)據(jù)建模完全全谤。但是在訓(xùn)練數(shù)據(jù)進(jìn)行相當(dāng)次數(shù)的迭代以后肤晓,泛化就停止上升了,驗(yàn)證指標(biāo)就停滯并開始下降:模型開始過擬合认然,比如說补憾,它可能會(huì)開始學(xué)習(xí)一些對于訓(xùn)練數(shù)據(jù)很特別的特征,但是對于新來的數(shù)據(jù)可能完全不相關(guān)卷员。
為了防止模型被訓(xùn)練數(shù)據(jù)中不相關(guān)的特征誤導(dǎo)盈匾,最好地方法當(dāng)然是弄更多的訓(xùn)練數(shù)據(jù)。一個(gè)模型用更多的數(shù)據(jù)去喂理所當(dāng)然會(huì)有更好的泛化性毕骡。當(dāng)增加數(shù)據(jù)行不通的時(shí)候削饵,最好地方法是調(diào)節(jié)你模型存儲(chǔ)的信息的質(zhì)量,或者對于什么樣的信息是允許被存儲(chǔ)的加以限制未巫。如果一個(gè)網(wǎng)絡(luò)只能記住很少的特征窿撬,這個(gè)優(yōu)化進(jìn)程則主要集中于最突出的特征,這將會(huì)對于提高泛化性有很大的幫助叙凡。
用來解決過擬合的方法我們叫做正則化劈伴,讓我們回顧一下一些常用的正則化方法并應(yīng)用這些方法來提高之前章節(jié)提的電影分類模型的性能。
狙擊過擬合
減少網(wǎng)絡(luò)大小
最簡單的預(yù)防過擬合的方法就是減少模型的大小握爷,例如模型中可學(xué)習(xí)的參數(shù)數(shù)量(這有層數(shù)數(shù)量和每一層的單元數(shù)所決定)在深度學(xué)習(xí)中跛璧,模型中可學(xué)習(xí)參數(shù)的數(shù)量被稱為模型的“容量”严里。直觀來講,一個(gè)有更多參數(shù)的模型將會(huì)有更多的“記憶容量”赡模,因此這就很容易學(xué)習(xí)到一個(gè)像字典一樣的映射關(guān)系田炭,這樣的映射關(guān)系沒有任何的泛化能力。例如漓柑,一個(gè)有500000二進(jìn)制參數(shù)的模型能夠很容易的學(xué)習(xí)到MNIST訓(xùn)練集每一個(gè)數(shù)字的類別:我們對于每一個(gè)數(shù)字只需要一個(gè)二進(jìn)制參數(shù)教硫。這樣一個(gè)模型對于分類i性能的數(shù)字樣本沒什么用。永遠(yuǎn)記琢静肌:深度學(xué)習(xí)模型趨向于擬合訓(xùn)練集瞬矩,但是真正的挑戰(zhàn)在于泛化,而不是擬合锋玲。
換句話來說景用,如果網(wǎng)絡(luò)被記憶資源所限制,它就無法學(xué)習(xí)到那樣的映射了惭蹂,因此為了最小化損失伞插,它就必須專注于學(xué)習(xí)壓縮表示,預(yù)測的效果就取決于我們的目標(biāo)了盾碗。同時(shí)媚污,記住你應(yīng)該使用有足夠參數(shù)的模型使得它不會(huì)欠擬合:你的模型不應(yīng)渴望記憶資源,在容量太大和容量不足之間需要尋找平衡廷雅。
不幸的是耗美,沒有什么有魔力的公式能夠決定層所需的正確數(shù)量,以及每一層的正確大小航缀。你必須評估一系列不同的結(jié)構(gòu)(在你的驗(yàn)證集上而不是測試集上)來找出你的數(shù)據(jù)的正確模型大小商架。一般的找到合適大小的流程是從一些相關(guān)的比較少的層數(shù)和參數(shù)開始,然后開始提高層的大小并增加新的層知道你看到驗(yàn)證集的損失開始下降為止芥玉。
讓我們來在電影評論分類網(wǎng)絡(luò)中試一下蛇摸。我們原始網(wǎng)絡(luò)如下所示:
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
讓我們用一個(gè)更小的網(wǎng)絡(luò)來替換它
model = models.Sequential()
model.add(layers.Dense(4, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
這里比較了原始網(wǎng)絡(luò)和更小網(wǎng)絡(luò)中驗(yàn)證集的損失。
可以觀察到小的網(wǎng)絡(luò)過擬合遲于原始的灿巧,且其在過擬合后表現(xiàn)變差的比較慢皇型。
接下來我們給模型加很多容量使得超過問題所需:
model = models.Sequential()
model.add(layers.Dense(512, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
這個(gè)大一點(diǎn)的網(wǎng)絡(luò)幾乎是在一開始就已經(jīng)過擬合了,在一個(gè)批次以后過擬合就很嚴(yán)重了砸烦。其驗(yàn)證集的損失也充滿了噪聲弃鸦。同時(shí),給出兩種網(wǎng)絡(luò)的訓(xùn)練誤差:
如你所見幢痘,大一點(diǎn)的網(wǎng)絡(luò)訓(xùn)練損失很快就到了0.網(wǎng)絡(luò)的容量越大唬格,對訓(xùn)練數(shù)據(jù)建模就越快,但它就越容易過擬合。
增加正則化權(quán)重
或許你很熟悉奧卡姆剃刀原則:對一個(gè)事情給定兩個(gè)解釋购岗,“簡單的”那個(gè)看上去更像是對的汰聋,其做了最少的假設(shè)。這也被應(yīng)用到了神經(jīng)網(wǎng)絡(luò)上了:給定一些訓(xùn)練數(shù)據(jù)和網(wǎng)絡(luò)結(jié)構(gòu)喊积,有大量的權(quán)重值可以解釋數(shù)據(jù)烹困,簡單的模型會(huì)有更小的概率過擬合。
一個(gè)“簡單的模型”在這里就是一個(gè)參數(shù)值有更少的熵的模型乾吻,(或者說是參數(shù)總數(shù)更少的)髓梅。因此一個(gè)常用減輕過擬合的方法是采取小的值,讓權(quán)重值更加正則绎签。這就叫做權(quán)重正則化枯饿,這通過在損失函數(shù)加一個(gè)花費(fèi)來做到的,這花費(fèi)可以有以下兩種類型:
- L1正則化诡必,花費(fèi)取決于權(quán)重系數(shù)的絕對值奢方。
- L2正則化,花費(fèi)取決于權(quán)重系數(shù)的平方爸舒。L2正則化在神經(jīng)網(wǎng)絡(luò)中也稱為權(quán)重衰減蟋字。不要讓不同的名字迷惑到你:權(quán)重衰減在數(shù)學(xué)形式上和L2正則化是一回事。
在keras里面扭勉,權(quán)重正則化通過權(quán)重正則化實(shí)例加進(jìn)來作為關(guān)鍵詞參數(shù)愉老。讓我們在電影評論分類網(wǎng)絡(luò)中加入L2去那種正則化。
from keras import regularizers
model = models.Sequential()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001),
activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
其中l(wèi)2(0.001)意味著圖層的權(quán)重矩陣將會(huì)乘以0.001加入到最終網(wǎng)絡(luò)的損失中剖效。注意乘法只在訓(xùn)練的時(shí)候加進(jìn)去,也就是說網(wǎng)絡(luò)的損失在訓(xùn)練的時(shí)候要比測試的時(shí)候高很多焰盗。
這里給出了L2正則化的懲罰:
如你所見璧尸,L2正則化以后模型更加耐過擬合了,盡管每一個(gè)模型都有相同數(shù)量的參數(shù)熬拒。
作為l2的替代爷光,你可以看到如下的keras權(quán)重正則化:
from keras import regularizers
# L1 regularization
regularizers.l1(0.001)
# L1 and L2 regularization at the same time
regularizers.l1_l2(l1=0.001, l2=0.001)
添加drop out
dropout在是為了里面是一項(xiàng)最常用的正則化方法,由Hinton和他的學(xué)生在Toronto大學(xué)提出澎粟。dropout應(yīng)用到“層”里面蛀序,由隨機(jī)"dropping out"層在訓(xùn)練中學(xué)習(xí)到的要輸出的特征。在測試的時(shí)候活烙,沒有單元被dropped out徐裸,層的輸出值會(huì)按照dropout rate來縮放,以平衡在測試時(shí)和訓(xùn)練的時(shí)比有更多的單元啸盏。
給定layer_out的shape為(batch_size,features)
在訓(xùn)練的時(shí)候:
# At training time: we drop out 50% of the units in the output
layer_output *= np.randint(0, high=2, size=layer_output.shape)
在測試時(shí):
# At test time:
layer_output *= 0.5
還有一種方法是在訓(xùn)練的時(shí)候兩個(gè)操作都弄重贺,然后在test 的時(shí)候output就不用變了。
# At training time:
layer_output *= np.randint(0, high=2, size=layer_output.shape)
# Note that we are scaling *up* rather scaling *down* in this case
layer_output /= 0.5
處理過程如圖所示:
這樣的方法看起來似乎有點(diǎn)奇怪和任意。為什么這樣子可以幫助減少過擬合呢气笙?hinton說他是被其它的事情激發(fā)的靈感次企,通過銀行里的防欺詐機(jī)器,用他的話來說:“我去了我的銀行潜圃。出納員不斷地變化, 我問他們中的一個(gè)為什么缸棵。他說他不知道, 但他們經(jīng)常被轉(zhuǎn)移。我想這一定是因?yàn)檫@需要員工之間的合作才能成功詐騙銀行谭期。這讓我意識(shí)到, 在每個(gè)例子上隨機(jī)刪除不同的神經(jīng)元子集, 可以防止陰謀, 從而減少過度擬合堵第。”
其中的核心思想就是在輸出值引入噪聲來打破當(dāng)噪聲不存在時(shí)網(wǎng)絡(luò)會(huì)記住的一些不重要的偶然模式崇堵。
在keras里面型诚,你能使用dropout層來直接引入dropout。
model.add(layers.Dropout(0.5))
在之前的IMDB網(wǎng)絡(luò)中加入兩個(gè)dropout層鸳劳,去看他們對于減少過擬合的效果有多好狰贯。
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation='sigmoid'))
畫出結(jié)果:
我們又一次得到了網(wǎng)絡(luò)的提升。
總結(jié)一下在神經(jīng)網(wǎng)絡(luò)里面防止過擬合的常用的方法:
- 更多的訓(xùn)練數(shù)據(jù)
- 減少網(wǎng)絡(luò)的容量
- 增加權(quán)重正則化
- 增加dropout