LycorisNet之超參數(shù)自動搜尋策略
在設(shè)計(jì)Lycoris的伊始冀续,就沒有考慮過為用戶留下太多的接口來調(diào)整超參數(shù)裆蒸,畢竟對現(xiàn)代框架調(diào)參的厭煩也是獨(dú)立開發(fā)這個(gè)庫的動力之一熔萧。于是,自動搜尋最佳超參數(shù)的策略便成為了一個(gè)相當(dāng)重要的需求僚祷。
但凡提到自動調(diào)整超參數(shù)佛致,“網(wǎng)格搜索”、“隨機(jī)搜索”辙谜、“貝葉斯優(yōu)化”等等便習(xí)慣性地被提及晌杰。Grid Search是一種調(diào)參手段,也稱為窮舉搜索:在所有候選的參數(shù)選擇中筷弦,通過循環(huán)遍歷,嘗試每一種可能性抑诸,表現(xiàn)最好的參數(shù)就是最終的結(jié)果烂琴,其原理就像是在數(shù)組里找最大值;隨機(jī)搜索顧名思義就是隨機(jī)的搜索蜕乡,沒有特別的要說的奸绷,舉個(gè)例子:有十億個(gè)數(shù)字,我想搜索十萬次就找出一個(gè)比較理想的最胁懔帷(大)數(shù)号醉。這就是一個(gè)簡單的應(yīng)用隨機(jī)搜索的一個(gè)場景反症。這時(shí)候我們需要設(shè)計(jì)一個(gè)隨機(jī)取樣的函數(shù),然后在十億個(gè)數(shù)里取出十萬個(gè)數(shù)進(jìn)行比較獲取最信吓伞(大)的數(shù)铅碍。雖然后最的結(jié)果不精確,但是如果并不需要知道確切的最優(yōu)值的時(shí)候线椰,這還是非常棒的提高程序效率的算法胞谈;貝葉斯優(yōu)化其實(shí)就是在函數(shù)方程不知的情況下根據(jù)已有的采樣點(diǎn)預(yù)估函數(shù)最大值的一個(gè)算法,貝葉斯優(yōu)化會選取未知函數(shù)的中數(shù)個(gè)已知點(diǎn)憨愉,作為先驗(yàn)(prior)烦绳,假設(shè)這些點(diǎn)是GP中的一部分,即他們服從多變量高斯分布配紫。根據(jù)多變量高斯分布的一些性質(zhì)径密,可以計(jì)算出這些點(diǎn)中每一個(gè)點(diǎn)的均值(mean)和方差(variance) 。
在Lycoris中這三種優(yōu)化方案均不能直接用于策略中躺孝,主要原因還是增強(qiáng)拓?fù)涞倪^程帶來的不穩(wěn)定性享扔,這種情況下,項(xiàng)目組采用了一種近似隨機(jī)搜索思想的優(yōu)化方案括细,對NEAT的超參數(shù)實(shí)現(xiàn)自動化調(diào)整伪很,這一部分的代碼如下:
void Lycoris::autoParameter() {
? ? if (args->checkFlag) {
? ? ? ? auto length = uint32_t(args->gapList->size());
? ? ? ? auto lastValue = args->gapList->back();
? ? ? ? uint32_t count = 0;
? ? ? ? for (auto iter = args->gapList->begin(); iter != args->gapList->end(); ++iter) {
? ? ? ? ? ? if (lastValue > (*iter)) {
? ? ? ? ? ? ? ? count++;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if (count < (length / 2 + 1)) {
? ? ? ? ? ? args->miss++;
? ? ? ? ? ? args->hit = 0;
? ? ? ? ? ? if (args->miss == 2) {
? ? ? ? ? ? ? ? if (args->tock > 1) {
? ? ? ? ? ? ? ? ? ? args->tock /= 2;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? args->miss = 1;
? ? ? ? ? ? }
? ? ? ? ? ? args->p1 = args->p1B;
? ? ? ? ? ? args->p2 = args->p2B;
? ? ? ? ? ? args->p3 = args->p3B;
? ? ? ? ? ? args->p4 = args->p4B;
? ? ? ? ? ? args->p5 = args->p5B;
? ? ? ? ? ? args->p6 = args->p6B;
? ? ? ? ? ? args->mateOdds = args->mateOddsB;
? ? ? ? ? ? args->mutateOdds = args->mutateOddsB;
? ? ? ? ? ? args->mutateTime = args->mutateTimeB;
? ? ? ? } else {
? ? ? ? ? ? args->hit++;
? ? ? ? ? ? args->miss = 0;
? ? ? ? ? ? if (args->hit == 2) {
? ? ? ? ? ? ? ? if (args->tock < args->maxTock) {
? ? ? ? ? ? ? ? ? ? args->tock *= 2;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? args->hit = 1;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? args->checkFlag = false;
? ? }
? ? if (args->tick == args->tock) {
? ? ? ? emergeArgs();
? ? ? ? args->checkFlag = true;
? ? ? ? args->tick = 0;
? ? } else {
? ? ? ? args->tick += 1;
? ? }
}
從代碼可以看出還借鑒了少許的“tick-tock”思想。