一个例子入坑布谷鸟算法(附完整py代码)
布谷鳥是比較新的啟發式最優化算法,但其與傳統的遺傳算法,退火算法等相比,被證明收斂速度更快,計算效率更高!
文章目錄
- 本文誕生的緣由
- 布谷鳥算法思想簡介
- 更新位置的方式
- 萊維飛行
- 局部隨機行走
- 拋出個栗子
- 一些參數的建議
- 完整的python實現
- 運行結果
- 參考文獻
本文誕生的緣由
? ? ? ?由于布谷鳥算法比較新,所以國內外的網上對于該算法的介紹都比較少,雖然算法整體的思想看起來簡單,但真正落實到實踐時往往發現有些細節還是不甚清楚。令人尷尬的是,我搜索了國內外對于布谷鳥算法的教程,這些教程恰恰點到算法思想上就止住了,并且給出的代碼千篇一律地還是Xin-She Yang(布谷鳥算法提出者之一)給出的matlab代碼1,對初學者很不友好,于是我就打算寫一篇教程,通過詳細地舉一個例子來帶大家入門布谷鳥算法,并且我寫了份python代碼(可直接運行),需要者可在下面的github鏈接中自取。
?
布谷鳥算法思想簡介
? ? ? ?布谷鳥算法的啟發當然來自于布谷鳥,因為布谷鳥這種鳥很有意思,生出來的孩子自己不養,直接被扔到其他鳥的鳥巢中去了,但有時候,這些布谷鳥蛋會被被寄宿的那些鳥媽媽發現,然后就被拋棄,有時候,這些宿主會直接放棄整個鳥巢尋找新住處。然而道高一尺魔高一丈,有些品種的布谷鳥生下來的布谷鳥蛋的顏色能和去寄宿的鳥的鳥蛋顏色很相似,并且布谷鳥的破殼時間往往比那些宿主的鳥蛋早,這樣,一旦小布谷鳥破殼,它就會將一些鳥蛋扔出鳥巢去以求獲得更多的食物,并且,小布谷鳥能模擬宿主鳥孩子的叫聲來騙取更多的食物!簡單來說,就是如何更高效地去騙吃騙喝。
圖1 寄宿到其他鳥的布谷鳥蛋? ? ? ?這時,心急的朋友可能會問,這和最優化有啥蛋關系呢?如果光讓我看到這種自然現象我也很難和最優化聯系起來,但有些細心的人做到了。我們現在來簡單概括一下他們是咋聯系起來的。
一頭霧水?別怕,后面一個例子就懂了!
?
更新位置的方式
? ? ? ?細心的朋友在看上面算法步驟時可能會問,以某種方式更新位置,是啥子方式呢?更新位置的算法同樣很重要,它也會關系到最后算法的收斂速度,在上述的算法步驟中,我們在第3步和第4步都需要更新點的位置,現在就來解答這個問題。其實這些更新點的方式說的直白些其實很簡單,就是讓這些點亂走,當然它有個洋氣的名字(random walk),亂走的方式也很簡單粗暴,隨機生成一個方向和長度,疊加到原有點上就成了新的點,但是需要指出的是,這個隨機生成的方向和長度都是有講究的,有研究發現通過萊維飛行(Levy Flight)的方式能比較有效地去尋找全局最優解而不至于陷入局部最優解中,并且它和布谷鳥算法配合達到了相當不錯的效果,接下來就是解答什么是萊維飛行了。
萊維飛行
? ? ? ?在介紹萊維飛行相關公式之前,我們先來簡單說一下它背后的思想,萊維飛行是由較長時間的短步長和較短時間的長步長組成,說起來很拗口,我們先來看一下它的演示圖吧:
圖2 萊維飛行動畫? ? ? ?從上面的動畫中我們可以看到,點大多數時間都只有小距離移動,偶爾會有大距離移動的情況。這和自然界中大多數動物覓食方式方式類似,也就是找到一塊區域后細致的查找獵物,如果沒找到,就換一片區域找。
? ? ? ?那么,該如何實現這種移動方式呢?我們現在假設我們就是捕食者,需要捕獵去了,但尚不清楚獵物在哪,那好,我們先隨機選個方向(服從均勻分布,因為在不知道任何信息前提下,對于我們來說各個方向存在獵物的可能性相等),接下來就得確定要走多遠了,根據上面的思想,Levy分布要求大概率落在值比較小的地方,而小概率落在值比較大的地方,Mantegna就提出了近似滿足這種分布的計算公式(levy分布很難滿足,有興趣的小伙伴可以查閱相關資料):
s = u ∣ v ∣ 1 β s=\frac{u}{\left | v \right |^{\frac{1}{\beta }}} s=∣v∣β1?u?
(說明:u服從 N ( 0 , σ u ) N(0,\sigma _{u}) N(0,σu?)正態分布,v服從 N ( 0 , σ v ) N(0,\sigma _{v}) N(0,σv?)正態分布,而 σ u = { Γ ( 1 + β ) sin ? ( π β 2 ) Γ [ ( 1 + β ) 2 β ? 2 ( β ? 1 ) 2 ] } 1 β \sigma _{u} = \left \{ \frac{\Gamma (1+\beta )\sin (\frac{\pi\beta }{2})}{\Gamma \left [ \frac{(1+\beta )}{2}\beta \cdot2^{\frac{(\beta -1)}{2}} \right ]}\right \}^{\frac{1}{\beta }} σu?=????Γ[2(1+β)?β?22(β?1)?]Γ(1+β)sin(2πβ?)?????β1?, σ v = 1 \sigma _{v}=1 σv?=1,其中 Γ ( z ) = ∫ 0 ∞ t z ? 1 e t d t \Gamma (z)=\int_{0}^{\infty }\frac{t^{z-1}}{e^{t}}dt Γ(z)=∫0∞?ettz?1?dt, β \beta β取值最好落在(1,2)上)。上面的公式乍一看十分復雜,但幸運的是,無論是matlab還是python,關于正態分布和 Γ \Gamma Γ函數都有現成的函數,我們做伸手黨即可。而這個公式咋來的便是數學家的事情了,我也不懂啊(?_?),但我們可以編個小程序直觀地感受到其生成的步長確實短步長多,長步長少(可見上面的動畫)。概括地來講,實現萊維飛行,一要通過均勻概率分布生成一個方向,二要確認步長!
局部隨機行走
? ? ? ?我們再來介紹一種隨機行走的方法(random walk),但這種方法只適用于局部,很容易陷入局部最優解,優點是比較穩定,因為是局部走嘛。它的計算公式如下:
x i t + 1 = x i t + α s ? H ( p a ? ? ) ? ( x j t ? x k t ) x_{i}^{t+1}=x_{i}^{t}+\alpha s\bigotimes H(p_{a}-\epsilon )\bigotimes (x_{j}^{t}-x_{k}^{t}) xit+1?=xit?+αs?H(pa???)?(xjt??xkt?)
(說明: x i t x_{i}^{t} xit?是第i個點t時刻的位置, α \alpha α是步長系數,也就是讓步長增量和你問題的規模相匹配,舉個例子,你的問題的規模是個位數級別的,你肯定不希望步長增量是十位數級別或者毫米數級別的,這就需要你適當縮小或擴大步長了,H是躍遷函數,也就是x大于等于1時數值為1,否則為0, ? \bigotimes ?代表點乘, x j t x_{j}^{t} xjt?和 x k t x_{k}^{t} xkt?是t時刻任意選取的兩個點)。
? ? ? ?相對于萊維飛行的隨機性,局部隨機行走時已有一定的方向性了,其最大程度地利用已有點的位置信息,新產生的點便是這些已有點的“折中”。
?
拋出個栗子
? ? ? ?看完上面一些理論知識,你可能更暈了,那么,接下來吃下這顆栗子,你可能便會豁然開朗了。
? ? ? ?我們要優化的問題是這樣的:
3 ( 1 ? x ) 2 ? e ? x 2 ? ( y + 1 ) 2 ? 10 ( x 5 ? x 3 ? y 5 ) ? e ? x 2 ? y 2 ? e ? ( x + 1 ) 2 ? y 2 3 3(1-x)^{2}\cdot e^{-x^{2}-(y+1)^{2}}-10(\frac{x}{5}-x^{3}-y^{5})\cdot e^{-x^{2}-y^{2}}-\frac{e^{-(x+1)^{2}-y^2}}{3} 3(1?x)2?e?x2?(y+1)2?10(5x??x3?y5)?e?x2?y2?3e?(x+1)2?y2?其中x和y都落在(-3,3)上,求其最大值。
? ? ? ?為了簡化起見,我們這里只取5個點。
?
第一步、我們現在先在可行域內隨機生成5個點:
第二步、計算它們的適應度(適應值函數我們就取為上面那個要優化的函數):
我們從中挑出最好的并記錄下來,我們可以看到,最好的適應值為下標4對應的點,為7.648。
第三步、利用萊維飛行更新點,萊維飛行公式中的 β \beta β我們取為1.5,剩下的把公式敲上去獲得步長,但是,這樣生成的步長的規格是大于問題的規模的,后面我們需要調參,但這里為了簡便我就把我后來調出來的結果擺出來,萊維飛行的步長需要乘以系數0.4才能讓萊維飛行不至于走的太放飛自我,也不至于走的太畏畏縮縮(多數情況下,系數取為0.1和0.01)。這里我們還用到了一個小技巧,我們當然是希望上一輪產生的最好點能在下一輪保留下來,所以我們可以在步長前乘以個系數 ( x i 上 一 輪 ? x b e s t 上 一 輪 ) (x_{i}^{上一輪}-x_{best}^{上一輪}) (xi上一輪??xbest上一輪?),這里的 i i i就是步長對應的點下標。當然,有了步長還不夠,還得有個步長方向,這個方向我們就用0-1均勻概率分布產生,步長方向(矢量)點乘步長(矢量)就是步長增量。這是萊特飛行更新后的結果:
第四步、接下來,一些布谷鳥蛋可能會被宿主發現并被拋棄,這個拋棄的概率 P a P_{a} Pa?我們設置為0.25,當有布谷鳥蛋被拋棄時,我們需要尋找新的寄宿地點,而尋找新的寄宿地點的算法就是上面提到的局部隨機行走算法,我們可以把 α \alpha α這個系數定為1,步長s我們也取為1,后面兩個隨機選取的點 x j t , x k t x_{j}^{t},x_{k}^{t} xjt?,xkt?,我們通過均勻概率分布選出,這里我們不使用躍遷函數H。更新后的結果如下:
第五步、計算這些新點的適應值,并挑出最大值和記錄的最好點的適應值比較,若該輪更新得到的最大值更好,則將該輪得到的最大點設為最好點并記錄下來。遺憾的是,這里,該輪點的最大值沒有比記錄的最好點好,所以我們不用更新最好點的值。
第六步、回到上面的第三步,繼續循環直至滿足迭代次數要求或精度要求。
補充:由于隨機行走(萊維飛行是隨機行走的一種特殊形式)可能會超出我們的可行域范圍,我們可以利用簡單的邊界條件,即當點超過下邊界時,則用下邊界的值代替,同理,當點超過上邊界時,則用上邊界的值代替。
?
一些參數的建議
? ? ? ?布谷鳥算法提出者之一的Xin-She Yang教授試了多組參數,發現種群規模在15到40,布谷鳥蛋被發現的概率 p a p_{a} pa?取0.25時1 2,對于大多數優化問題已足夠,并且結果和分析也表明收斂速度在一定程度上對所使用的參數不敏感。這意味著對于任何問題都不需要進行仔細地調整。至于迭代次數,我在實驗中發現100次的迭代次數已能很好地找到最優解,但迭代次數往往取決你問題的規模,并沒有一組所謂的萬能參數。
?
完整的python實現
? ? ? ?在這份代碼中,我寫了詳細的注釋,每個函數的功能和輸入輸出參數都有詳細的說明,如果對上面的一些講解還有些疑惑,可以直接查看代碼的相關部分,我想應該很快就能茅塞頓開了。下載地址如下:https://github.com/SJ2050SJ/Optimization_Algorithms(如果對你有幫助的話不要忘點個star哦 ! (^_ ^)
?
運行結果
上面那個優化函數的圖像在這篇文章中可以看到遺傳算法(白話文版)。在這次測試中,我們選擇種群規模為25,迭代次數為100。由精確分析可知,上述優化問題在可行域內的最大值為8.1062,在 [ ? 0.0093 , 1.5814 ] T [-0.0093,1.5814]^{T} [?0.0093,1.5814]T上取到,可以看到,我們優化的結果已經很接近精確答案了,并并且每次優化出來的結果很穩定!
3 4
?
?
?
?
?
?
?
參考文獻
Xin-She Yang. 《Nature Inspired Optimization Algorithm.2nd》 ?? ??
布谷鳥搜索算法 ??
布谷鳥算法詳細講解 ??
通俗易懂的布谷鳥算法與萊維飛行,(附求解函數最小值matlab源碼) ??
總結
以上是生活随笔為你收集整理的一个例子入坑布谷鸟算法(附完整py代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: S2ANet(Align Deep Fe
- 下一篇: 租车汽车租赁系统开发