編者按:還認(rèn)為調(diào)參是“玄學(xué)”?快來看Mikko Kotila分享的調(diào)參心得。
TL;DR
只需采用正確的過程,為給定的預(yù)測(cè)任務(wù)找到頂尖的超參數(shù)配置并非難事。超參數(shù)優(yōu)化主要有三種方法:手工、機(jī)器輔助、基于算法。本文主要關(guān)注機(jī)器輔助這一方法。本文將介紹我是如何優(yōu)化超參數(shù)的,如何證實(shí)方法是有效的,理解為何起效。我把簡單性作為主要原則。
模型表現(xiàn)
關(guān)于模型表現(xiàn),首先需要指出的是,使用精確度(及其他魯棒性更好的測(cè)度)等衡量模型表現(xiàn)可能有問題。例如,假設(shè)一個(gè)二元預(yù)測(cè)任務(wù)中只有1%的樣本值為1,那么預(yù)測(cè)所有值為0的模型將達(dá)到近乎完美的精確度。采用更合適的測(cè)度可以克服這類問題,但限于本文的主題,我們不會(huì)詳細(xì)討論這些。我們想要強(qiáng)調(diào)的是,優(yōu)化超參數(shù)的時(shí)候,這是一個(gè)非常重要的部分。即使我們采用了世界上最酷炫的模型(通常是非常復(fù)雜的模型),但如果評(píng)估模型所用的是無意義的測(cè)度,那到頭來不過是白費(fèi)工夫。
別搞錯(cuò);即使我們確實(shí)正確使用了表現(xiàn)測(cè)度,我們?nèi)匀恍枰紤]優(yōu)化模型的過程中發(fā)生了什么。一旦我們開始查看驗(yàn)證集上的結(jié)果,并基于此做出改動(dòng),那么我們就開始制造傾向驗(yàn)證集的偏差。換句話說,模型的概括性可能不怎么好。
更高級(jí)的全自動(dòng)(無監(jiān)督)超參數(shù)優(yōu)化方法,首先需要解決以上兩個(gè)問題。一旦解決了這兩個(gè)問題——是的,存在解決這兩個(gè)問題的方法——結(jié)果測(cè)度需要實(shí)現(xiàn)為單一評(píng)分。該單一評(píng)分將作為超參數(shù)優(yōu)化過程所依據(jù)的測(cè)度。
工具
本文使用了Keras和Talos。Talos是我創(chuàng)建的超參數(shù)優(yōu)化方案,它的優(yōu)勢(shì)在于原樣暴露了Keras,沒有引進(jìn)任何新語法。Talos把超參數(shù)優(yōu)化的過程從若干天縮短到若干分鐘,也使得優(yōu)化過程更有意思,而不是充滿了痛苦的重復(fù)。
你可以親自嘗試Talos:
pip install talos
或者在GitHub上查看它的代碼和文檔:autonomio/talos
但我打算在本文中分享的信息,提出的觀點(diǎn),是關(guān)于優(yōu)化過程的,而不是關(guān)于工具的。你可以使用其他工具完成同樣的過程。
自動(dòng)化超參數(shù)優(yōu)化及其工具最主要的問題之一,是你常常偏離原本的工作方式。預(yù)測(cè)任務(wù)無關(guān)的超參數(shù)優(yōu)化的關(guān)鍵——也是所有復(fù)雜問題的關(guān)鍵——是擁抱人機(jī)之間的協(xié)作。每次試驗(yàn)都是一個(gè)學(xué)習(xí)更多(深度學(xué)習(xí)的)實(shí)踐經(jīng)驗(yàn)和技術(shù)(比如Keras)的機(jī)會(huì)。不應(yīng)該因?yàn)樽詣?dòng)化過程而失去這些機(jī)會(huì)。另一方面,我們應(yīng)該移除優(yōu)化過程中明顯多余的部分。想象一下在Jupyter notebook中按幾百次shift-enter(這一快捷鍵表示執(zhí)行代碼),然后在每次執(zhí)行時(shí)等待一兩分鐘??傊?,在現(xiàn)階段,我們的目標(biāo)不應(yīng)該是全自動(dòng)方法,而是最小化讓人厭煩的重復(fù)多余部分。
開始掃描超參數(shù)
在下面的例子中,我使用的是Wisconsin Breast Cancer數(shù)據(jù)集,并基于Keras構(gòu)建了以下模型:
def breast_cancer_model(x_train, y_train, x_val, y_val, params):
model = Sequential()
model.add(Dense(10, input_dim=x_train.shape[1],
activation=params['activation'],
kernel_initializer='normal'))
model.add(Dropout(params['dropout']))
hidden_layers(model, params, 1)
model.add(Dense(1, activation=params['last_activation'],
kernel_initializer='normal'))
model.compile(loss=params['losses'],
optimizer=params['optimizer'](lr=lr_normalizer(params['lr'],params['optimizer'])),
metrics=['acc', fmeasure])
history = model.fit(x_train, y_train,
validation_data=[x_val, y_val],
batch_size=params['batch_size'],
epochs=params['epochs'],
verbose=0)
return history, model
定義好Keras模型后,通過Python字典指定初始參數(shù)的邊界。
p = {'lr': (0.5, 5, 10),
'first_neuron':[4, 8, 16, 32, 64],
'hidden_layers':[0, 1, 2],
'batch_size': (1, 5, 5),
'epochs': [150],
'dropout': (0, 0.5, 5),
'weight_regulizer':[None],
'emb_output_dims': [None],
'shape':['brick','long_funnel'],
'optimizer': [Adam, Nadam, RMSprop],
'losses': [logcosh, binary_crossentropy],
'activation':[relu, elu],
'last_activation': [sigmoid]}
一切就緒,到了開始試驗(yàn)的時(shí)候了:
t = ta.Scan(x=x,
y=y,
model=breast_cancer_model,
grid_downsample=0.01,
params=p,
dataset_name='breast_cancer',
experiment_no='1')
注意,為了節(jié)省篇幅,代碼省略了引入語句等非關(guān)鍵性的代碼。下文修改超參數(shù)字典時(shí)也不再貼出代碼。
因?yàn)榻M合太多(超過180000種組合),我隨機(jī)從中抽取了1%的組合,也就是1800種組合。
在我的2015年MacBook Air上,試驗(yàn)1800種組合大約需要10800秒,也就是說,我可以和朋友見一面,喝上一兩杯咖啡。
可視化超參數(shù)掃描
試驗(yàn)了1800種組合后,讓我們看看結(jié)果,從而決定如何限制(或者調(diào)整)參數(shù)空間。
我們使用val_acc(驗(yàn)證精確度)作為評(píng)估模型表現(xiàn)的指標(biāo)。我們所用的數(shù)據(jù)集類別比較均衡,因此val_acc是個(gè)不錯(cuò)的測(cè)度。在類別顯著失衡的數(shù)據(jù)集上,精確度就不那么好了。
從上圖我們可以看到,似乎hidden_layers(隱藏層數(shù)目)、lr(學(xué)習(xí)率)、dropout對(duì)val_acc的影響較大(負(fù)相關(guān)性),而正相關(guān)性比較強(qiáng)的只有epoch數(shù)。
我們將val_acc、hidden_layers、lr、dropout這些單獨(dú)抽出來繪制柱狀圖:
其中,y軸為精確度,x軸為epoch數(shù),色彩濃淡表示dropout率,刻面(facet)表示學(xué)習(xí)率。
上面的兩張圖告訴我們,在這一任務(wù)上,看起來相對(duì)簡單的模型表現(xiàn)較好。
現(xiàn)在讓我們通過核密度估計(jì)仔細(xì)看看dropout??v軸為精確度,橫軸為dropout率。
從圖中我們可以看到,dropout為0到0.1時(shí),更可能得到較高的驗(yàn)證精確度(縱軸0.9附近),不太可能得到較低的精確度(縱軸0.6附近)。
所以我們下一回合掃描超參數(shù)的時(shí)候就可以去掉較高的dropout率,集中掃描0到0.2之間的dropout率。
接下來我們?cè)僮屑?xì)看看學(xué)習(xí)率(不同優(yōu)化算法的學(xué)習(xí)率經(jīng)過了歸一化處理)。這次我們將繪制箱形圖,縱軸為驗(yàn)證精確度,橫軸為學(xué)習(xí)率。
很明顯,在兩種損失函數(shù)上,都是較低的學(xué)習(xí)率表現(xiàn)更好。在logcosh上,高低學(xué)習(xí)率的差異尤為明顯。另一方面,在所有學(xué)習(xí)率水平上,交叉熵的表現(xiàn)都超過了logcosh,因此在之后的試驗(yàn)中,我們將選擇交叉熵作為損失函數(shù)。不過,我們?nèi)孕枰?yàn)證一下。因?yàn)槲覀兛吹降慕Y(jié)果可能是過擬合訓(xùn)練集的產(chǎn)物,也可能兩者的驗(yàn)證集損失(val_loss)都很大。所以我們進(jìn)行了簡單的回歸分析?;貧w分析表明,除了少數(shù)離散值外,絕大多數(shù)損失都聚集在左下角(這正是我們所期望的)。換句話說,訓(xùn)練損失和驗(yàn)證損失都接近零?;貧w分析打消了我們之前的疑慮。
我覺得我們已經(jīng)從初次試驗(yàn)中得到足夠多的信息,是時(shí)候利用這些信息開始第二次試驗(yàn)了。除了上面提到的改動(dòng)之外,我還額外增加了一個(gè)超參數(shù),kernel_initializer。在第一次的試驗(yàn)中,我們使用的都是默認(rèn)的高斯分布(normal),其實(shí)均勻分布(uniform)也值得一試。所以我在第二次試驗(yàn)中補(bǔ)上了這一超參數(shù)。
第二回合——進(jìn)一步關(guān)注結(jié)果
之前我們分析第一回合的結(jié)果時(shí),關(guān)注的是超參數(shù)和驗(yàn)證精確度的相關(guān)性,但并沒有提到驗(yàn)證精確度有多高。這是因?yàn)?,在一開始,我們更少關(guān)注結(jié)果(更多關(guān)注過程),我們最終取得較好結(jié)果的可能性就越高。也就是說,在開始階段,我們的目標(biāo)是了解預(yù)測(cè)任務(wù),而并不特別在意找到答案。而在第二回合,我們?nèi)匀徊粫?huì)把全部注意力放到結(jié)果上,但查看一下結(jié)果也是有必要的。
第一回合的驗(yàn)證精確度峰值是94.1%的,而第二回合的驗(yàn)證精確度峰值是96%的。看起來我們的調(diào)整還是有效的。當(dāng)然,峰值可能僅僅源于抽樣的隨機(jī)性,所以我們需要通過核密度分布估計(jì)來驗(yàn)證一下:
第一回合的核密度分布估計(jì)
第二回合的核密度分布估計(jì)
對(duì)比核密度分布估計(jì),我們看到,我們的調(diào)整確實(shí)有用。
下面我們?cè)俅卫L制相關(guān)性熱圖:
我們看到,除了epoch數(shù)以外,沒有什么對(duì)驗(yàn)證精確度影響非常大的因素了。在下一回合的試驗(yàn)中,我們?cè)撜{(diào)整下epoch數(shù)。
另外,熱圖并沒有包含所有超參數(shù),比如上一節(jié)中的損失函數(shù)。在第一次試驗(yàn)后,我們調(diào)整了損失函數(shù),移除了logcosh損失?,F(xiàn)在讓我們查看一下優(yōu)化算法。
首先,上面的箱形圖再次印證了我們之前提到的,較低的epoch數(shù)表現(xiàn)不好。
其次,由于在epoch數(shù)為100和150的情形下,RMSprop的表現(xiàn)都不怎么好,所以我們將在下一回合的試驗(yàn)中移除RMSprop。
第三回合——概括性和表現(xiàn)
經(jīng)過調(diào)整之后,第三回合試驗(yàn)的驗(yàn)證精確度峰值提高到了97.1%,看起來我們的方向沒錯(cuò)。在第三回合的試驗(yàn)中,epoch數(shù)我去掉了50,將最高epoch數(shù)增加到了175,另外還在100和150中間加了125。從下圖來看,我可能過于保守了,最高epoch數(shù)應(yīng)該再大一點(diǎn)。這讓我覺得……也許最后一回合步子可以邁得大一點(diǎn)?
正如我們一開始提到的,在優(yōu)化超參數(shù)時(shí),同時(shí)考慮概括性很重要。每次我們查看在驗(yàn)證集上的結(jié)果并據(jù)此調(diào)整時(shí),我們?cè)黾恿诉^擬合驗(yàn)證集的風(fēng)險(xiǎn)。模型的概括性可能因此下降,雖然在驗(yàn)證集上表現(xiàn)更好,但在“真實(shí)”數(shù)據(jù)集上的表現(xiàn)可能不好。優(yōu)化超參數(shù)的時(shí)候我們并沒有很好的測(cè)試這類偏差的方法,但至少我們可以評(píng)估下偽概括性(pseudo-generalization)。讓我們先看下訓(xùn)練精確度和驗(yàn)證精確度。
雖然這并不能確認(rèn)我們的模型概括性良好,但至少回歸分析的結(jié)果不錯(cuò)。接下來讓我們看下訓(xùn)練損失和驗(yàn)證損失。
這比訓(xùn)練精確度和驗(yàn)證精確度的回歸分析看起來還要漂亮。
在最后一回合,我將增加epoch數(shù)(之前提到,第三回合的增加太保守)。另外,我還會(huì)增加batch尺寸。到目前為止,我僅僅使用了很小的batch尺寸,這拖慢了訓(xùn)練速度。下一回合我將把batch尺寸增加到30,看看效果如何。
另外提下及早停止(early stopping)。Keras提供了非常方便的及早停止回調(diào)功能。但你可能注意到我沒有使用它。一般來說,我會(huì)建議使用及早停止,但在超參數(shù)優(yōu)化過程中加入及早停止不那么容易。正確配置及早停止,避免它限制你找到最優(yōu)結(jié)果,并不那么直截了當(dāng)。主要是測(cè)度方面的原因;首先定制一個(gè)測(cè)度,然后使用及早停止,效果比較好(而不是直接使用val_acc或val_loss)。雖然這么說,但對(duì)超參數(shù)優(yōu)化而言,及早停止和回調(diào)其實(shí)是很強(qiáng)大的方法。
第四回合——最終結(jié)果
在查看最終結(jié)果之前,先讓我們可視化一下剩下的超參數(shù)(核初始化、batch尺寸、隱藏層、epoch數(shù))的效果。
縱軸為驗(yàn)證精確度
大部分結(jié)果都是肩并肩的,但還是有一些東西突顯出來。如果因?yàn)殡[藏層層數(shù)不同(色彩濃淡)導(dǎo)致驗(yàn)證精確度下降,那么大多數(shù)情形下,下降的都是1個(gè)隱藏層的模型。至于batch尺寸(列)和核初始化(行)的差別,很難說出點(diǎn)什么。
下面讓我們看看縱軸為驗(yàn)證損失的情況:
縱軸為驗(yàn)證損失
在各種epoch數(shù)、batch尺寸、隱藏層層數(shù)的組合下,均勻核初始化都能將驗(yàn)證損失壓得很低。但因?yàn)榻Y(jié)果不是特別一致,而且驗(yàn)證損失也不如驗(yàn)證精確度那么重要,所以我最后同時(shí)保留了兩種初始化方案。
最后的贏家
我們?cè)谧詈髸r(shí)刻想到增加batch尺寸,這個(gè)主意不錯(cuò)。
較小的batch尺寸下,驗(yàn)證精確度的峰值是97.7%,而較大的batch尺寸(30)能將峰值提升至99.4%。另外,較大的batch尺寸也能使模型更快收斂(你可以在文末的視頻中親眼見證這一點(diǎn))。老實(shí)說,當(dāng)我發(fā)現(xiàn)較大的batch尺寸效果這么好時(shí),我其實(shí)又進(jìn)行了一次試驗(yàn)。因?yàn)橹恍枰膭?dòng)batch尺寸,不到一分鐘我就配置好了這次試驗(yàn),而超參數(shù)掃描則在60分鐘內(nèi)完成了。不過這次試驗(yàn)并沒有帶來什么新發(fā)現(xiàn),大部分結(jié)果都接近100%.
另外我還想分享下精確度熵和損失熵(基于驗(yàn)證/訓(xùn)練精確度、驗(yàn)證/訓(xùn)練損失的KL散度),它們是一種有效評(píng)估過擬合的方法(因此也是間接評(píng)估概括性的方法)。
總結(jié)
盡可能保持簡單和廣泛
從試驗(yàn)和假設(shè)中分析出盡可能多的結(jié)果
在初次迭代時(shí)不用在意最終結(jié)果
確保采用了恰當(dāng)?shù)谋憩F(xiàn)測(cè)度
記住表現(xiàn)本身并不是全部,提升表現(xiàn)的同時(shí)往往會(huì)削弱概括性
每次迭代都應(yīng)該縮減超參數(shù)空間和模型復(fù)雜性
別害怕嘗試,畢竟這是試驗(yàn)
使用你可以理解的方法,例如,清晰的可視化描述性統(tǒng)計(jì)
-
參數(shù)
+關(guān)注
關(guān)注
11文章
1754瀏覽量
32044 -
數(shù)據(jù)集
+關(guān)注
關(guān)注
4文章
1200瀏覽量
24619
原文標(biāo)題:調(diào)參心得:超參數(shù)優(yōu)化之旅
文章出處:【微信號(hào):jqr_AI,微信公眾號(hào):論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論