遺傳演算法 (Genetic Algorithm)

發表於2016-11-19

遺傳演算法(Genetic Algorithm)又叫基因進化演算法,或進化演算法。屬於啟發式搜尋演算法一種,這個演算法比較有趣,並且弄明白後很簡單,寫個100-200行程式碼就可以實現。在某些場合下簡單有效。本文就花一些篇幅,儘量白話方式講解一下。 

首先說一下問題。在我們學校資料結構這門功課的時候,時常會有一些比較經典的問題(而且比較複雜問題)作為學習素材,如八皇后,揹包問題,染色問題等等。上面列出的幾個問題都可以通過遺傳演算法去解決。本文列舉的問題是TSP(Traveling Salesman Problem)類的問題。

TSP問題實際上是哈密頓迴路問題中的哈密頓最短迴路問題”.如下圖,就是要把下面8個城市不重複的全部走一遍。有點像小時候玩的畫筆畫遊戲,一筆到底不能重複。TSP不光是要求全部走一遍,並且是要求路徑最短。就是有可能全部走一遍有很多走法,要找出其中總路程最短的走法。 

27105712_13783609253umh

和這個問題有點相似的是尤拉回路(下圖)問題,它不是要求把每個點都走一遍,而是要求把每個邊都不重複走一遍(點可以重複),當然尤拉回路不是本演算法研究的範疇。

clip_image003

本文會從TSP引申出下面系列問題

1、  TSP問題:要求每個點都遍歷到,而且要求每個點只被遍歷一次,並且總路程最短。

2、  最短路徑問題:要求從城市1 到城市8,找一條最短路徑。

3、  遍歷m個點,要求找出其距離最短的路線。(如果m=N總數,其實就是問題1了,所以問題1可以看成是問題3的特例 ) 

遺傳演算法的理論是根據達爾文進化論而設計出來的演算法: 人類是朝著好的方向(最優解)進化,進化過程中,會自動選擇優良基因,淘汰劣等基因。

在上面tsp問題中,一個城市節點可以看成是一個基因,一個最優解就是一條路徑,包含若干個點。就類似一條染色體有若干基因組成一樣。所以求最短路徑問題,可以抽象成求最優染色體的問題。

遺傳演算法很簡單,沒有什麼分支判斷,只有兩個大迴圈,流程大概如下 

流程中有幾個關鍵元素:

27105712_1378363275lalg

1、  適度值評估函式。這個函式是演算法的關鍵,就是對這個繁衍出來的後代進行評估打分,是優秀,還是一般,還是很差的畸形兒。用這個函式進行量化。在tsp中,路徑越短,分數越高。函式可以可以這樣 fitness = 1/total_distance.  或者 fitness = MAX_DISTANCE – total_distance. 不同的計算方法會影響演算法的收斂速度,直接影響結果和效能。 

2、  選擇運算規則: 又稱選擇運算元。對應著達爾文理論中適者生存,也有地方叫著精英主義原則,意思就是隻有優秀的人才有更大的機率存活下來,擁有交配權。有權利擁有更多後代,傳承下自己血脈基因。和現實中很相像,皇帝權臣遺留下來的子孫後代比較多。選擇方法比較多。最常見的是round robin selection 演算法,即輪盤賭演算法, 這個演算法比較簡單有效。選擇演算法目前已有的有10來種之多。各種不同業務可以按需選擇。 

clip_image007

選擇公式如下:

clip_image008  

3、  交叉運算規則:又稱交配規則,交叉運算元。對應遺傳學中的精子和卵子產生的受精卵含有精子的部分基因,也含有卵子的部分基因的現象。就像孩子有點像父親,又有點像母親的規律。交叉運算演算法更多。作者可以天馬行空的自己去想象。只要達到交叉結果中含有父母的基因就可以。最常見的是k-opt 交換。其中k可以是 1,2,3….等等。簡稱單點交換,兩點交換,3點交換等等:

單點交換

27105712_1378361302t0cj

其中修復重複基因根據業務需要看是否需要。 

點交換

27105712_1378361388b27b

4、  變異運算規則:又叫變異運算元。在人類遺傳進化過程中。會發生一些基因突變。這些突變有可能是好的突變,有可能是壞的突變。像癌細胞就是壞的突變。愛因斯坦的大腦估計是好的突變。突變方法也是可以天馬行空的自己去發揮創造。 

這裡討論一下,為什麼要有突變這道流程呢。從人類進化角度來說。人類基因有數十萬種,在遠古交流比較少的年代。都是部落內部通婚,但是整個部落內部居民可能都缺少某種好的基因,這樣無論他們怎麼交配,都不會產生好的基因,那麼他們需要引入好的基因,於是和其他部落通婚。引入其他自己沒有的基因,其實對於這個種群來說這就是一次基因變異。如果是好的變異,那麼這個後代就很優秀,結果就是會產生更多子孫,把這個好的變異基因傳承下去,如果不是好的變異基因,自然而然會在前面選擇運算元下淘汰,就是現實生活中的所謂的年幼夭折,痴呆無後,或先天畸形被淘汰,不會傳承下去。 

從計算機演算法角度看:所有的啟發式演算法無外乎2種手段結合。局域搜尋和全域搜尋。局域搜尋是在鄰域範圍內找出最優解。對應的是選擇運算元和交叉運算元。在自己部落裡面找最優秀的人。如果只有局域搜尋的話,就容易陷入局域最優解。演算法結果肯定是要找出全域最優解。這就要求跳出局域搜尋。我們稱之為創新。創新就是一次打破常規的突破——就是我們的“變異運算元。 

這裡拿最短路徑路徑舉例子,求點1到點8之間的最短路徑, 初始解是1——2——3——6——8

 

  遺傳演算法 (Genetic Algorithm)

內變異:所謂內變異就是在自己內部發生變異。嚴格來說其實不是一種變異。但是它又是一種比較有效的手段。

遺傳演算法 (Genetic Algorithm)

外變異:外變異是引入創新,突破傳統的質的飛躍, 也是啟發演算法中所謂的全域搜尋。下面是充當前基因中引入外部基因(當前集合的補集)。 

遺傳演算法 (Genetic Algorithm)

結尾:遺傳演算法除了上述這些幾個主要運算元之外,還有一些細節。如交叉概率pc,變異概率pm,這些雖然都是輔助手段,但是有時候對整個演算法結果和效能帶來截然不同的效果。這也是啟發式演算法的一個缺點。引數需要不停的在實踐中摸索,沒有萬能的推薦引數。 

還有細心的讀者可能發現幾個疑問,就是最短路徑中變異或交叉結果可能產生無效解,如前面最短路徑 1——6——3——2——8.  其中16之間根本沒有通路。碰到這種情況,可以拋棄這條非法解,重新生成一條隨機新解(其實這也是一次變異創新)。或者自己修復成可行解。反正框框在那裡。具體手段可以自己天馬行空發揮。 

另一個比較實際的問題是:在最短路徑中並不知道染色體長度是多少,不錯。大部分人還是用定長染色體去解決問題,這樣效能低下。演算法不直觀。這時候可以使用變長染色體來解決。其實我建議不管何種情況,都設計變長染色體模式。因為定長也是變長的一種特例。使用變長可以解決任何問題。不管是tsp還是最短路徑問題。 

還有一個編解碼問題,就是把現實問題轉換成基因,這些問題都比較容易解決,最簡單的就是直接用陣列下標表示。

相關文章