1. 程式人生 > >遺傳演算法詳解(GA)(個人覺得很形象,很適合初學者)

遺傳演算法詳解(GA)(個人覺得很形象,很適合初學者)

本文是去年課題組週報中的一個專題講解,詳細講了GA,由於是週報,所以十分詳細。很適合初學者入門。文中也簡單提及了模擬退火演算法。文章綜合參考了一些網際網路資料。發部落格以備忘!

三:遺傳演算法

        照例先給出科學定義:

       遺傳演算法(Genetic Algorithm, GA)起源於對生物系統所進行的計算機模擬研究。它是模仿自然界生物進化機制發展起來的隨機全域性搜尋和優化方法,借鑑了達爾文的進化論和孟德爾的遺傳學說。其本質是一種高效、並行、全域性搜尋的方法,能在搜尋過程中自動獲取和積累有關搜尋空間的知識,並自適應地控制搜尋過程以求得最佳解。

     再給出相關術語:(各位看看就好,後面都會涉及到,再細說)

基因型(genotype):性狀染色體的內部表現;

表現型(phenotype):染色體決定的性狀的外部表現,或者說,根據基因型形成的個體的外部表現;

進化(evolution):種群逐漸適應生存環境,品質不斷得到改良。生物的進化是以種群的形式進行的。

適應度(fitness):度量某個物種對於生存環境的適應程度。

選擇(selection):以一定的概率從種群中選擇若干個個體。一般,選擇過程是一種基於適應度的優勝劣汰的過程。

複製(reproduction):細胞分裂時,遺傳物質DNA通過複製而轉移到新產生的細胞中,新細胞就繼承了舊細胞的基因。

交叉(crossover):兩個染色體的某一相同位置處DNA被切斷,前後兩串分別交叉組合形成兩個新的染色體。也稱基因重組或雜交;

變異(mutation):複製時可能(很小的概率)產生某些複製差錯,變異產生新的染色體,表現出新的性狀。

編碼(coding):DNA中遺傳資訊在一個長鏈上按一定的模式排列。遺傳編碼可看作從表現型到基因型的對映。

解碼(decoding):基因型到表現型的對映。

個體(individual):指染色體帶有特徵的實體;
種群(population):個體的集合,該集合內個體數稱為種群

                  的大小。        

       遺傳演算法的有趣應用很多,諸如尋路問題,8數碼問題,囚犯困境,動作控制,找圓心問題(在一個不規則的多邊形中,尋找一個包含在該多邊形內的最大圓圈的圓心),TSP問題,生產排程問題,人工生命模擬等。下面我以袋鼠為例子講講遺傳演算法。(因為袋鼠會跳)

     遺傳演算法中每一條染色體,對應著遺傳演算法的一個解決方案,一般我們用適應性函式(fitness function)來衡量這個解決方案的優劣。所以從一個基因組到其解的適應度形成一個對映。可以把遺傳演算法的過程看作是一個在多元函式裡面求最優解的過程。可以這樣想象,這個多維曲面裡面有數不清的“山峰”,而這些山峰所對應的就是區域性最優解。而其中也會有一個“山峰”的海拔最高的,那麼這個就是全域性最優解。而遺傳演算法的任務就是儘量爬到最高峰,而不是陷落在一些小山峰。(另外,值得注意的是遺傳演算法不一定要找“最高的山峰”,如果問題的適應度評價越小越好的話,那麼全域性最優解就是函式的最小值,對應的,遺傳演算法所要找的就是“最深的谷底”)

                                                          

問題的提出與解決方案:

   讓我們先來考慮考慮下面這個問題的解決辦法。

           已知一元函式:

現在要求在既定的區間內找出函式的最大值  

                                                    

“袋鼠跳”問題

        既然我們把函式曲線理解成一個一個山峰和山谷組成的山脈。那麼我們可以設想所得到的每一個解就是一隻袋鼠,我們希望它們不斷的向著更高處跳去,直到跳到最高的山峰(儘管袋鼠本身不見得願意那麼做)。所以求最大值的過程就轉化成一個“袋鼠跳”的過程。

作為對比下面簡單介紹“袋鼠跳”的幾種方式。

 1. 爬山法(最速上升爬山法):

      從搜尋空間中隨機產生鄰近的點,從中選擇對應解最優的個體,替換原來的個體,不斷重複上述過程。因為爬山法只對“鄰近”的點作比較,所以目光比較“短淺”,常常只能收斂到離開初始位置比較近的區域性最優解上面。對於存在很多區域性最優點的問題,通過一個簡單的迭代找出全域性最優解的機會非常渺茫。(在爬山法中,袋鼠最有希望到達最靠近它出發點的山頂,但不能保證該山頂是珠穆朗瑪峰,或者是一個非常高的山峰。因為一路上它只顧上坡,沒有下坡。)

2. 模擬退火:

     這個方法來自金屬熱加工過程的啟發。在金屬熱加工過程中,當金屬的溫度超過它的熔點(Melting Point)時,原子就會激烈地隨機運動。與所有的其它的物理系統相類似,原子的這種運動趨向於尋找其能量的極小狀態。在這個能量的變遷過程中,開始時,溫度非常高, 使得原子具有很高的能量。隨著溫度不斷降低,金屬逐漸冷卻,金屬中的原子的能量就越來越小,最後達到所有可能的最低點。利用模擬退火的時候,讓演算法從較大的跳躍開始,使到它有足夠的“能量”逃離可能“路過”的區域性最優解而不至於限制在其中,當它停在全域性最優解附近的時候,逐漸的減小跳躍量,以便使其“落腳 ”到全域性最優解上。(在模擬退火中,袋鼠喝醉了,而且隨機地大跳躍了很長時間。運氣好的話,它從一個山峰跳過山谷,到了另外一個更高的山峰上。但最後,它漸漸清醒了並朝著它所在的峰頂跳去。)

3. 遺傳演算法:

    模擬物競天擇的生物進化過程,通過維護一個潛在解的群體執行了多方向的搜尋,並支援這些方向上的資訊構成和交換。是以面為單位的搜尋,比以點為單位的搜尋,更能發現全域性最優解。(在遺傳演算法中,有很多袋鼠,它們降落到喜瑪拉雅山脈的任意地方。這些袋鼠並不知道它們的任務是尋找珠穆朗瑪峰。但每過幾年,就在一些海拔高度較低的地方射殺一些袋鼠,並希望存活下來的袋鼠是多產的,在它們所處的地方生兒育女)(或者換個說法。從前,有一大群袋鼠,它們被莫名其妙的零散地遺棄於喜馬拉雅山脈。於是只好在那裡艱苦的生活。海拔低的地方瀰漫著一種無色無味的毒氣,海拔越高毒氣越稀薄。可是可憐的袋鼠們對此全然不覺,還是習慣於活蹦亂跳。於是,不斷有袋鼠死於海拔較低的地方,而越是在海拔高的袋鼠越是能活得更久,也越有機會生兒育女。就這樣經過許多年,這些袋鼠們竟然都不自覺地聚攏到了一個個的山峰上,可是在所有的袋鼠中,只有聚攏到珠穆朗瑪峰的袋鼠被帶回了美麗的澳洲。)

遺傳演算法的實現過程

        遺傳演算法的實現過程實際上就像自然界的進化過程那樣。首先尋找一種對問題潛在解進行“數字化”編碼的方案。(建立表現型和基因型的對映關係)然後用隨機數初始化一個種群(那麼第一批袋鼠就被隨意地分散在山脈上),種群裡面的個體就是這些數字化的編碼。接下來,通過適當的解碼過程之後(得到袋鼠的位置座標),用適應性函式對每一個基因個體作一次適應度評估(袋鼠爬得越高,越是受我們的喜愛,所以適應度相應越高)。用選擇函式按照某種規定擇優選擇(我們要每隔一段時間,在山上射殺一些所在海拔較低的袋鼠,以保證袋鼠總體數目持平。)。讓個體基因變異(讓袋鼠隨機地跳一跳)。然後產生子代(希望存活下來的袋鼠是多產的,並在那裡生兒育女)。遺傳演算法並不保證你能獲得問題的最優解,但是使用遺傳演算法的最大優點在於你不必去了解和操心如何去“找”最優解。(你不必去指導袋鼠向那邊跳,跳多遠。)而只要簡單的“否定”一些表現不好的個體就行了。(把那些總是愛走下坡路的袋鼠射殺,這就是遺傳演算法的精粹!

 所以我們總結出遺傳演算法的一般步驟:

       開始迴圈直至找到滿意的解。

1.評估每條染色體所對應個體的適應度。

2.遵照適應度越高,選擇概率越大的原則,從種群中選擇兩個個體作為父方和母方。

3.抽取父母雙方的染色體,進行交叉,產生子代。

4.對子代的染色體進行變異。

5.重複2,3,4步驟,直到新種群的產生。

結束迴圈。

                                                

接下來,我們將詳細地剖析遺傳演算法過程的每一個細節。

編制袋鼠的染色體----基因的編碼方式

      受到人類染色體結構的啟發,我們可以設想一下,假設目前只有“0”,“1”兩種鹼基,我們也用一條鏈條把他們有序的串連在一起,因為每一個單位都能表現出 1 bit的資訊量,所以一條足夠長的染色體就能為我們勾勒出一個個體的所有特徵。這就是二進位制編碼法,染色體大致如下:

010010011011011110111110

上面的編碼方式雖然簡單直觀,但明顯地,當個體特徵比較複雜的時候,需要大量的編碼才能精確地描述,相應的解碼過程(類似於生物學中的DNA翻譯過程,就是把基因型對映到表現型的過程。)將過分繁複,為改善遺傳演算法的計算複雜性、提高運算效率,提出了浮點數編碼。染色體大致如下:

1.2 –3.3 – 2.0 –5.4 – 2.7 – 4.3

(注:還有一種編碼方式叫符號編碼)

那麼我們如何利用這兩種編碼方式來為袋鼠的染色體編碼呢?因為編碼的目的是建立表現型到基因型的對映關係,而表現型一般就被理解為個體的特徵。比如人的基因型是46條染色體所描述的卻能解碼成一個眼,耳,口,鼻等特徵各不相同的活生生的人。所以我們要想為“袋鼠”的染色體編碼,我們必須先來考慮“袋鼠”的“個體特徵”是什麼。也許有的人會說,袋鼠的特徵很多,比如性別,身長,體重,也許它喜歡吃什麼也能算作其中一個特徵。但具體在解決這個問題的情況下,我們應該進一步思考:無論這隻袋鼠是長短,肥瘦,黑白只要它在低海拔就會被射殺,同時也沒有規定身長的袋鼠能跳得遠一些,身短的袋鼠跳得近一些。當然它愛吃什麼就更不相關了。我們由始至終都只關心一件事情:袋鼠在哪裡。因為只要我們知道袋鼠在那裡,我們就能做兩件必須去做的事情:

(1)通過查閱喜瑪拉雅山脈的地圖來得知袋鼠所在的海拔高度(通過自變數求適應函式的值。)以判斷我們有沒必要把它射殺。

(2)知道袋鼠跳一跳(交叉和變異)後去到哪個新位置。

如果我們一時無法準確的判斷哪些“個體特徵”是必要的,哪些是非必要的,我們常常可以用到這樣一種思維方式:比如你認為袋鼠的愛吃什麼東西非常必要,那麼你就想一想,有兩隻袋鼠,它們其它的個體特徵完全同等的情況下,一隻長得黑,另外一隻長得不是那麼黑。你會馬上發現,這不會對它們的命運有絲毫的影響,它們應該有同等的概率被射殺!只因它們處於同一個地方。(值得一提的是,如果你的基因編碼設計中包含了袋鼠黑不黑的資訊,這其實不會影響到袋鼠的進化的過程,而那隻攀到珠穆朗瑪峰的袋鼠黑與白什麼的也完全是隨機的,但是它所在的位置卻是非常確定的。)

   以上是對遺傳演算法編碼過程中經常經歷的思維過程,必須把具體問題抽象成數學模型,突出主要矛盾,捨棄次要矛盾。只有這樣才能簡潔而有效的解決問題。

     既然確定了袋鼠的位置作為個體特徵,具體來說位置就是橫座標。那麼接下來,我們就要建立表現型到基因型的對映關係。就是說如何用編碼來表現出袋鼠所在的橫座標。由於橫座標是一個實數,所以說透了我們就是要對這個實數編碼。回顧我們上面所介紹的兩種編碼方式,最先想到的應該就是,對於二進位制編碼方式來說,編碼會比較複雜,而對於浮點數編碼方式來說,則會比較簡潔。恩,正如你所想的,用浮點數編碼,僅僅需要一個浮點數而已。而下面則介紹如何建立二進位制編碼到一個實數的對映。

  明顯地,一定長度的二進位制編碼序列,只能表示一定精度的浮點數。譬如我們要求解精確到六位小數,由於區間長度為2 – (-1) = 3 ,為了保證精度要求,至少把區間[-1,2]分為3 × 106等份。又因為

           

所以編碼的二進位制串至少需要22位。

       把一個二進位制串(b0,b1,....bn)轉化位區間裡面對應的實數值通過下面兩個步驟。

    (1)將一個二進位制串代表的二進位制數轉化為10進位制數:

                 

    (2)對應區間內的實數:

                          

      (像極了模數轉換)

   例如一個二進位制串<1000101110110101000111>表示實數值0.637197。

         

(糾正一個錯誤,這裡是-1)  

       二進位制串<0000000000000000000000>和<1111111111111111111111>則分別表示區間的兩個端點值-1和2。

     好了,目前為止我們把袋鼠的染色體給研究透了,讓我們繼續跟進袋鼠的進化旅程

物競天擇--適應性評分與及選擇函式。

1.物競――適應度函式(fitness function)

   自然界生物競爭過程往往包含兩個方面:生物相互間的搏鬥與及生物與客觀環境的搏鬥過程。但在我們這個例項裡面,你可以想象到,袋鼠相互之間是非常友好的,它們並不需要互相搏鬥以爭取生存的權利。它們的生死存亡更多是取決於你的判斷。因為你要衡量哪隻袋鼠該殺,哪隻袋鼠不該殺,所以你必須制定一個衡量的標準。而對於這個問題,這個衡量的標準比較容易制定:袋鼠所在的海拔高度。(因為你單純地希望袋鼠爬得越高越好。)所以我們直接用袋鼠的海拔高度作為它們的適應性評分。即適應度函式直接返回函式值就行了。

2.天擇――選擇函式(selection)

    自然界中,越適應的個體就越有可能繁殖後代。但是也不能說適應度越高的就肯定後代越多,只能是從概率上來說更多。(畢竟有些所處海拔高度較低的袋鼠很幸運,逃過了你的眼睛。)那麼我們怎麼來建立這種概率關係呢?下面我們介紹一種常用的選擇方法――輪盤賭(Roulette Wheel Selection)選擇法。                                 

     比如我們有5條染色體,他們所對應的適應度評分分別為:5,7,10,13,15。

       所以累計總適應度為:

                                  

       所以各個個體被選中的概率分別為:

                                    

  

你可以想象一下,我們轉動輪盤,輪盤停下來的時候,指標會隨機地指向某一個個體所代表的區域,那麼非常幸運地,這個個體被選中了。(很明顯,適應度評分越高的個體被選中的概率越大。)

注:還有精英選擇機制

遺傳變異――基因重組(交叉)與基因突變。

  應該說這兩個步驟就是使得子代不同於父代的根本原因注意,我沒有說是子代優於父代,只有經過自然的選擇後,才會出現子代優於父代的傾向。)。對於這兩種遺傳操作,二進位制編碼和浮點型編碼在處理上有很大的差異,其中二進位制編碼的遺傳操作過程,比較類似於自然界裡面的過程,下面將分開講述。

1.基因重組/交叉(recombination/crossover)

   (1)二進位制編碼

    二進位制編碼的基因交換過程非常類似高中生物中所講的同源染色體的聯會過程――隨機把其中幾個位於同一位置的編碼進行交換,產生新的個體。



(2)浮點數編碼

     如果一條基因中含有多個浮點數編碼,那麼也可以用跟上面類似的方法進行基因交叉,不同的是進行交叉的基本單位不是二進位制碼,而是浮點數。而如果對於單個浮點數的基因交叉,就有其它不同的重組方式了,比如中間重組:隨機產生就能得到介於父代基因編碼值和母代基因編碼值之間的值作為子代基因編碼的值。比如5.5和6交叉,產生5.7,5.6。

   考慮到“袋鼠跳”問題的具體情況――袋鼠的個體特徵僅僅表現為它所處的位置。可以想象,同一個位置的袋鼠的基因是完全相同的,而兩條相同的基因進行交叉後,相當於什麼都沒有做,所以我們不打算在這個例子裡面使用交叉這一個遺傳操作步驟。(當然硬要這個操作步驟也不是不行的,你可以把兩隻異地的袋鼠捉到一起,讓它們交配,然後產生子代,再把它們送到它們應該到的地方。)

2.基因突變(Mutation)

  (1)二進位制編碼

     基因突變過程:基因突變是染色體的某一個位點上基因的改變。基因突變使一個基因變成它的等位基因,並且通常會引起一定的表現型變化。正如上面所說,二進位制編碼的遺傳操作過程和生物學中的過程非常相類似,基因串上的“ 0”或“ 1”有一定機率變成與之相反的“ 1”或“ 0”。例如下面這串二進位制編碼:

101101001011001

經過基因突變後,可能變成以下這串新的編碼:

001101011011001

(2)浮點型編碼

      浮點型編碼的基因突變過程一般是對原來的浮點數增加或者減少一個小隨機數。比如原來的浮點數串如下:

1.2,3.4,5.1, 6.0, 4.5

變異後,可能得到如下的浮點數串:

1.3,3.1,4.9, 6.3, 4.4

  當然,這個小隨機數也有大小之分,我們一般管它叫“步長”。(想想“袋鼠跳”問題,袋鼠跳的長短就是這個步長。)一般來說步長越大,開始時進化的速度會比較快,但是後來比較難收斂到精確的點上。而小步長卻能較精確的收斂到一個點上。所以很多時候為了加快遺傳演算法的進化速度,而又能保證後期能夠比較精確地收斂到最優解上面,會採取動態改變步長的方法。其實這個過程與前面介紹的模擬退火過程比較相類似。

  到此為止,基因編碼,基因適應度評估,基因選擇,基因變異都一一實現了,剩下來的就是把這些遺傳過程的“零件”裝配起來了。(寫成程式碼)

下面是上例的執行結果:


紅點代表真實的最大點,由求導法可求的為f(1.85)=3.85






總結:

編碼原則
完備性(completeness):問題空間的所有解都能表示為所設計的基因型;
健全性(soundness):任何一個基因型都對應於一個可能解;
非冗餘性(non-redundancy):問題空間和表達空間一一對應。

適應度函式的重要性
     適應度函式的選取直接影響遺傳演算法的收斂速度以及能否找到最優解。一般而言,適應度函式是由目標函式變換而成的。

適應度函式設計不當有可能出現欺騙問題:
(1)進化初期,個別超常個體控制選擇過程;
(2)進化末期,個體差異太小導致陷入區域性極值。

欺騙問題舉例:

還是袋鼠問題,如果低海拔的地方出現毒霧,會殺死袋鼠,只有爬上珠穆朗瑪峰頂端的袋鼠才能生存下來。

因為喜馬拉雅山脈有很多山峰,我們以高度作為適應度,case(1):如果不在珠峰的猴子若比在珠峰半山腰的猴子要高,因為種群大小不變,在珠峰的猴子可能就會被淘汰;case(2):100只猴子都不在珠峰;

1. 選擇的作用:優勝劣汰,適者生存;

2. 交叉的作用:保證種群的穩定性,朝著最優解的方向進化;

3. 變異的作用:保證種群的多樣性,避免交叉可能產生的區域性收斂。