1. 遺傳算法簡介
遺傳算法(Genetic Algorithms,GA)是一種模擬自然中生物的遺傳、進化以適應環境的智能算法。由于其算法流程簡單,參數較少優化速度較快,效果較好,在圖像處理、函數優化、信號處理、模式識別等領域有著廣泛的應用。
在遺傳算法(GA)中,每一個待求問題的候選解被抽象成為種群中一個個體的基因。種群中個體基因的好壞由表示個體基因的候選解在待求問題中的所的得值來評判。種群中的個體通過與其他個體交叉產生下一代,每一代中個體均只進行一次交叉。兩個進行交叉的個體有一定幾率交換一個或者多個對應位的基因來產生新的后代。每個后代都有一定的概率發生變異。發生變異的個體的某一位或某幾位基因會變異成其他值。最終將以個體的適應度值為概率選取個體保留至下一代。
2. 算法流程
遺傳算法啟發于生物的繁殖與dna的重組,本次的主角選什么呢?還是根據大家熟悉的孟德爾遺傳規律選豌豆吧,選動物的話又會有人疑車,還是植物比較好,本次的主角就是它了。
遺傳算法包含三個操作(算子):交叉,變異和選擇操作。下面我們將詳細介紹這三個操作。
大多數生物的遺傳信息都儲存在DNA,一種雙螺旋結構的復雜有機化合物。其含氮堿基為腺嘌呤、鳥嘌呤、胞嘧啶及胸腺嘧啶。
遺傳算法的個體結構受DNA的分子結構啟發,基于計算機的二進制,其編碼內容如下:
編號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
基因 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
表格中表示了一個有10個基因的個體,它們每一個基因的值為0或者1。
2.1交叉
生物的有性生殖一般伴隨著基因的重組。遺傳算法中父輩和母輩個體產生子代個體的過程稱為交叉。
編號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
A豌豆基因 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
B豌豆基因 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
表中給出了兩個豌豆的基因,它們均有10個等位基因(即編號相同的基因)。
遺傳算法的交叉過程會在兩個個體中隨機選擇1位或者n位基因進行交叉,即這兩個個體交換等位基因。
如,A豌豆和B豌豆在第6位基因上進行交叉,則其結果如下
編號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
A豌豆基因 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 0 |
B豌豆基因 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
當兩個個體交叉的等位基因相同時,交叉過程也有可能沒有產生新的個體,如交叉A豌豆和B豌豆的第2位基因時,交叉操作并沒有產生新的基因。
編號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
A豌豆基因 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
B豌豆基因 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
一般的會給群體設定一個交叉率,crossRate,表示會在群體中選取一定比例的個體進行交叉,交叉率相對較大,一般取值為0.8。
2.2變異
基因的變異是生物進化的一個主要因素。
遺傳算法中變異操作相對簡單,只需要將一個隨機位基因的值修改就行了,因為其值只為0或1,那么當基因為0時,變異操作會將其值設為1,當基因值為1時,變異操作會將其值設為0。
編號 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
A豌豆基因 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
A變異后基因 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
上圖表示了A豌豆第3位基因變異后的基因編碼。
與交叉率相似,變異操作也有變異率,alterRate,但是變異率會遠低于交叉率,否則會產生大量的隨機基因。一般變異率為0.05。
2.3選擇
選擇操作是遺傳算法中的一個關鍵操作,它的主要作用就是根據一定的策略隨機選擇個體保留至下一代。適應度越優的個體被保留至下一代的概率越大。
實現上,我們經常使用“輪盤賭”來隨機選擇保留下哪個個體。
假設有4個豌豆A、B、C、D,它們的適應度值如下:
個體 | 適應度值 |
---|---|
A | 1 |
B | 2 |
C | 3 |
D | 4 |
適應度值越大越好,則它們組成的輪盤如下圖:
但由于輪盤賭選擇是一個隨機選擇過程,A、B、C、D進行輪盤賭選擇后產生的下一代也有可能出現A、A、A、A的情況,即雖然有些個體的適應度值不好,但是運氣不錯,也被選擇留到了下一代。
遺產算法的三個主要操作介紹完了,下面我們來看看遺傳算法的總體流程:
3.基因編碼及操作細節
前面我們說了遺傳算法的流程及各個操作,那么對于實際的問題我們應該如何將其編碼為基因呢?
3.1二進制編碼
對于計算機來所所有的數據都使用二進制數據進行存放,如float類型和double類型的數據。
float類型的數據將保存為32位的二進制數據:1bit(符號位) 8bits(指數位) 23bits(尾數位)
如-1.234567f,表示為二進制位10111111100111100000011001001011
類型 | 符號位1 | 指數位8 | 小數位23 |
---|---|---|---|
值 | 1 | 01111111 | 00111100000011001001011 |
Double類型的數據將保存為64位的二進制數據:1bit(符號位) 11bits(指數位) 53bits(尾數位)
如-1.234567d,表示為二進制為1011111111110011110000001100100101010011100110111000100010000111
類型 | 符號位1 | 指數位11 | 小數位52 |
---|---|---|---|
值 | 1 | 01111111111 | 001111000000110010010101001100110111000100010000111 |
可以看出同樣的數值不同的精度在計算機中存儲的內容也不相同。之前的適應度函數,由于有兩個double類型的參數,故其進行遺傳算法基因編碼時,將有128位基因。
雖然基因數較多,但好在每個基因都是0或者1,交叉及變異操作非常簡單。
3.2十進制編碼
相比二進制編碼,十進制編碼的基因長度更短,適應度函數有兩個輸入參數,那么一個個體就有2個基因,但其交叉、變異操作相對復雜。
交叉操作
方案1:將一個基因作為一個整體,交換兩個個體的等位基因。
交換前
編號 | 1 | 2 |
---|---|---|
A豌豆基因 | 10 | 20 |
B豌豆基因 | 30 | 40 |
交換第1位基因后
編號 | 1 | 2 |
---|---|---|
A豌豆基因 | 30 | 20 |
B豌豆基因 | 10 | 40 |
方案2:將兩個個體的等位基因作為一個整體,使其和不變,但是值隨機
交換前
編號 | 1 | 2 |
---|---|---|
A豌豆基因 | 10 | 20 |
B豌豆基因 | 30 | 40 |
交換第1位基因后
編號 | 1 | 2 |
---|---|---|
A豌豆基因 | 21 | 20 |
B豌豆基因 | 19 | 40 |
假設A、B豌豆的第一位基因的和為40,即,第一位基因的取值范圍為0-30,那么A、B豌豆的第一位基因的取值范圍為[10,30],即
為[0,30]的隨機數,
。
變異操作,將隨機的一位基因設置為該基因取值范圍內的隨機數即可。
3.3輪盤賭
這個過程說起來簡單但其實現并不容易。
個體 | 適應度值 |
---|---|
A | 1 |
B | 2 |
C | 3 |
D | 4 |
我們要將它們的值映射到一個軸上才能進行隨機選擇,畢竟我們無法去繪制一個輪盤來模擬這個過程
如圖,將ABCD根據其值按順序排列,取[0,10]內的隨機數r,若r在[0,1]內則選擇A,在(1,3]內則選擇B,在(3,6]內則選擇C,在(6,10]則選擇D。
當然這仍然會有問題,即當D>>A、B、C時,假如它們的值分布如下
個體 | 適應度值 |
---|---|
A | 1 |
B | 2 |
C | 3 |
D | 100 |
那么顯然,選D的概率明顯大于其他,根據輪盤賭的選擇,下一代極有可能全是D的后代有沒有辦法均衡一下呢?
首先我想到了一個函數,
不要問我為什么我不知道什么是神經什么網絡的,什么softmax、cnn統統沒聽說過。
取值為sigmod((fitness-mean)/(max-min)),現在再來計算一下ABCD的值,
個體 | 適應度值 |
---|---|
A | 0.435 |
B | 0.438 |
C | 0.441 |
D | 0.677 |
這樣一來,它們之間的差距沒有之前那么大了,只要個體適應度值在均值以上那么它被保留至下一代的概率會相對較大,當然這樣縮小了個體之間的差距,對真正優秀的個體來說不太公平,相對應,我們可以在每次選擇過程中保留當前的最優個體到下一代,不用參與輪盤賭這個殘酷的淘汰過程。
4.實驗
最令人高興的環節到了,又可以愉快的湊字數了。
由于遺傳算法的收斂速度實在是太慢,區區50代,幾乎得不到好的結果,so我們把它的最大迭代次數放寬到200代。
方案1.
使用二進制編碼來進行求解
參數如下:
參數 | 值 |
---|---|
問題維度(維度) | 2 |
豌豆的數量(種群數) | 20 |
繁殖次數(最大迭代次數) | 200 |
crossRate(交叉率) | 0.8 |
alterRate(變異率) | 0.05 |
取值范圍 | (-100,100) |
編碼方式 | 二進制 |
實驗次數 | 10 |
求解過程如上圖,可以看出基因收斂的很快,在接近20代時就圖中就只剩一個點了,之后的點大概是根據變異操作產生??匆幌伦詈蟮慕Y果。
值 | |
---|---|
最優值 | 0.0 |
最差值 | 1374.1828414659183 |
平均值 | 214.78194828105424 |
可以看出最好的結果已經得到了最優解,但是10次實驗的最差值和平均值都差的令人發指。為什么會這樣呢?
問題出在二進制編碼上,由于double類型的編碼有11位指數位和52位小數位,這會導致交叉、變異操作選到指數位和小數位的概率不均衡,在小數位上的修改對結果的影響太小而對指數為的修改對結果的影響太大,
如-1.234567d,表示為二進制為1011111111110011110000001100100101010011100110111000100010000111
類型 | 符號位1 | 指數位11 | 小數位52 |
---|---|---|---|
值 | 1 | 01111111111 | 0011110000001100100101010011100110111000100010000111 |
對指數為第5位進行變異操作后的結果為-2.8744502924382686E-10,而對小數位第5為進行變異操作后的結果為-1.218942??梢钥闯鲞@兩部分對數值結果的影響太不均衡,得出較好的結果時大概率是指數位與解非常相近,否則很難得出好的結果,就像上面的最差值和均值一樣。
所以使用上面的二進制編碼不是一個好的基因編碼方式,因此在下面的實驗中,將使用十進制來進行試驗。
方案2:
使用:十進制編碼來進行求解
參數如下:
參數 | 值 |
---|---|
問題維度(維度) | 2 |
豌豆的數量(種群數) | 20 |
繁殖次數(最大迭代次數) | 200 |
crossRate(交叉率) | 0.8 |
alterRate(變異率) | 0.05 |
取值范圍 | (-100,100) |
編碼方式 | 十進制 |
交叉方式 | 交換基因 |
實驗次數 | 10 |
我們可以看到直到40代時,所有的個體才收束到一點,但隨后仍不斷的新的個體出現。我們發現再后面的新粒子總是在同一水平線或者豎直線上,因為交叉操作直接交換了兩個個體的基因,那么他們會相互交換x坐標或者y坐標,導致新個體看起來像在一條直線上。
我們來看看這次的結果。
值 | |
---|---|
最優值 | 0.4998897017064181 |
最差值 | 101.50731384880558 |
平均值 | 26.879257652054093 |
這次最優值沒有得到最優解,但是最差值沒有二進制那么差,雖然也不容樂觀。使用交換基因的方式來進行交叉操作的搜索能力不足,加之輪盤賭的選擇會有很大概率選擇最優個體,個體總出現在矩形的邊上。
下面我們先改變輪盤賭的選擇策略,使用上面的sigmod函數方案,并且保留最優個體至下一代。
方案3:
使用:十進制編碼來進行求解
參數如下:
參數 | 值 |
---|---|
問題維度(維度) | 2 |
豌豆的數量(種群數) | 20 |
繁殖次數(最大迭代次數) | 200 |
crossRate(交叉率) | 0.8 |
alterRate(變異率) | 0.05 |
取值范圍 | (-100,100) |
編碼方式 | 十進制 |
交叉方式 | 交換基因 |
輪盤賭方式 | sigmod函數方案,保留最優至下一代 |
實驗次數 | 10 |
看圖好像跟之前的沒什么區別,讓我們們看看最終的結果:
值 | |
---|---|
最優值 | 0.4504701892811481 |
最差值 | 18.879980044723276 |
平均值 | 6.865234201226049 |
可以看出,最優值沒有什么變化,但是最差值和平均值有了較大的提升,說明該輪盤賭方案使算法的魯棒性有了較大的提升。在每次保留最優個體的情況下,對于其他的個體的選擇概率相對平均,sigmod函數使得即使適應度函數值相差不太大的個體被選到的概率相近,增加了基因的多樣性。
方案4:
使用:十進制編碼來進行求解,改變交叉方案,保持兩個個體等位基因和不變的情況下隨機賦值。
參數如下:
參數 | 值 |
---|---|
問題維度(維度) | 2 |
豌豆的數量(種群數) | 20 |
繁殖次數(最大迭代次數) | 200 |
crossRate(交叉率) | 0.8 |
alterRate(變異率) | 0.05 |
取值范圍 | (-100,100) |
編碼方式 | 十進制 |
交叉方式 | 修改基因使其和不變 |
輪盤賭方式 | sigmod函數方案,保留最優至下一代 |
實驗次數 | 10 |
上圖可以看出該方案與之前有明顯的不同,在整個過程中,個體始終遍布整個搜索空間,雖然新產生的個體大多還是集中在一個十字架型的位置上,但其他位置的個體比之前的方案要多。
看看結果,
值 | |
---|---|
最優值 | 0.011758796459006677 |
最差值 | 2.2756330462780725 |
平均值 | 0.8849388632252244 |
這次的結果明顯好于之前的所有方案,但仍可以看出,十進制的遺傳算法的精度不高,只能找到最優解的附近,也有可能是算法的收斂速度實在太慢,還沒有收斂到最優解。
5.總結
遺傳算法的探究到此也告一段落,在研究遺傳算法時總有一種力不從心的感覺,問題可能在于遺傳算法只提出了一個大致的核心思想,其他的實現細節都需要自己去思考,而每個人的思維都不一樣,一萬個人能寫出一萬種遺傳算法,其實不僅是遺傳算法,后面的很多算法都是如此。
為什么沒有對遺傳算法的參數進行調優,因為遺傳算法的參數過于簡單,對結果的影響的可解釋性較強,意義明顯,實驗的意義不大。
遺傳算法由于是模仿了生物的進化過程,因此我感覺它的求解速度非常的慢,而且進化出來的結果不一定是最適應環境的,就像人的闌尾、視網膜結構等,雖然不是最佳的選擇但是也被保留到了今天。生物的進化的隨機性較大,要不是恐龍的滅絕,也不會有人類的統治,要不是人類有兩只手,每只手有5根手指,也不會產生10進制。
以下指標純屬個人yy,僅供參考
指標 | 星數 |
---|---|
復雜度 | ★★★☆☆☆☆☆☆☆ |
收斂速度 | ★☆☆☆☆☆☆☆☆☆ |
全局搜索 | ★★★★★★★☆☆☆ |
局部搜索 | ★☆☆☆☆☆☆☆☆☆ |
優化性能 | ★★★★☆☆☆☆☆☆ |
跳出局部最優 | ★★★★★★☆☆☆☆ |
改進點 | ★★★★★★★☆☆☆ |