The Nature of Code閱讀心得與Python實作:9.3 How Genetic Algorithms..

更新 發佈閱讀 17 分鐘
這一節的標題是
9.3 How Genetic Algorithms Work
因為方格子標題字數限制,所以沒完整顯現

在寫程式之前先來看一下,傳統的GA是透過哪些步驟來讓生物族群一代一代地演化下去的。要注意一下,這裡所指的「生物」,就只是個通稱,指的是要模擬的東西,而不一定是真正活生生的生物;它可以是模擬世界中的物件,也可以就只是字串。

要用程式寫出像自然界中的天擇(natural selection)效果,就必須把達爾文演化論的三個核心原則給寫進程式中。這三個核心原則是:

  • 遺傳(heredity):一定會有個機制,可以讓某一代的生物將其特徵傳遞給下一代。
  • 變異(variation):生物族群必定具有多種特徵,或者具有可以引入變異的手段,演化才能夠進行。一群長得一模一樣具有完全相同特徵的甲蟲,如果沒有任何變異,那它們所產下的下一代,就會跟父母長得一模一樣,而彼此之間也沒任何不同。因為永遠不會有新的特徵組合,所以也就沒什麼可以演化的。
  • 挑選(selection):一定有會個機制,可以只讓一部分生物成為父母,並將遺傳資訊傳遞給下一代。這個機制通常稱為「適者生存」(survival of the fittest)。例如,貓抓老鼠,警覺性高、跑得快、比較會躲的老鼠,比較有機會躲過一劫而倖存下來,也才有機會能繁衍下一代,並把遺傳訊息給傳遞下去。這裡要注意的是,不要誤以為「適者」兩個字,所指的就是最大、跑最快、最強壯的那些個體;它實際上指的是最能適應生存環境的個體。天擇的核心意義在於,任何特徵,只要能讓個體最佳地適應環境而生存下來,而最終得以繁衍下一代,就是會被挑選出來讓個體成為「適者」的特徵。所以,體型比較大的老鼠,雖然可能在同類中佔有優勢,但如果因此而比較容易讓貓兒發現而被抓,那這個特徵可就不一定能讓這些老鼠成為天擇下的「適者」了。所以,關於「適者」,比較能夠說明其意義的說法是:能夠繁衍下一代的個體。

有了上述演化論的觀念之後,就可以來看看GA是怎麼做的了。整個GA有好幾個步驟,這些步驟可以區分成設定起始條件,以及一再重複執行至找到解答等兩個部分。

Step 1: Population Creation

以電腦猴打字的例子來看,GA的第一步是造出片語族群。這裡的「片語」,泛指任何由字元所構成的字串,而這些片語,也就是這個例子中的「生物」。

在製造片語族群時,根據達爾文演化論的變異原則,這些片語之間必須存在變異,這樣演化才會進行。不過,在使用GA時,如果一開始所造出的族群變異程度不足,那會很難演化到產生最佳的解答。

什麼叫「族群變異程度不足」呢?來看個簡單的例子就知道了。

假設我們想讓片語族群演化出「cat」一詞,而我們造出來的片語族群是rid、won、hug這三個片語。這三個片語之間沒有任何相同的字母,它們之間顯然存在變異。不過,很明顯的,不管用什麼樣的排列組合方式,都沒辦法用這三個片語中的字母來拼出我們想要的「cat」這個片語;這就是族群變異不足所造成的結果。

那怎麼辦呢?要怎麼提高族群的變異程度呢?方法其實挺簡單的,用亂數造個含有幾千個片語的族群就可以了。幾千個由亂數造出的片語,總會有個片語第一個字母是c、總會有個片語第二個字母是a、總會有個片語第三個字母是a吧?族群越大,這個機率就會越高。這樣子就有足夠的變異來演化出「cat」這個片語了。

等等!那萬一運氣就這麼背,幾千個片語中,就是沒有一個含有字母c,那怎麼辦?把族群再造大一點?那還是不能保證一定有片語含有字母c啊!這個倒不用擔心,後面的Step 3中,有另一個可以增加變異的機制,可以補救一開始時變異不足的問題;到時再說。

由上面的說明,Step 1可以描述為:

製造一個由隨機產生的元素所組成的族群。

這裡改用「元素」這個詞來指稱族群的成員,這樣會比用「生物」一詞來得好一些;畢竟萬事萬物都可以是GA中族群的成員,如果成員是「片語」,用「生物」來指稱「片語」,還真是挺彆扭的。

元素有個特點,就是它們都具有虛擬DNA。什麼是DNA呢?就是一組用來描述元素長相和行為的性質;這些性質也稱為基因。例如,在電腦猴打字的例子中,元素是指「片語」,因而DNA就可以是由字元所組成的字串。

讓元素具備DNA之後,GA的Step 1可以進一步地描述為:

製造一個由N個元素所組成的族群,而每個元素都具有隨機產生的DNA。

要想活用GA,就必須能夠清楚地區分基因型(genotype)與表現型(phenotype)這兩個遺傳學領域的重要概念。基因型是生物DNA中特定的分子序列,是真正的遺傳密碼,也是會一代一代傳下去的東西。至於表現型,則是生物體可觀察到的,如大小、血型、毛色等特徵。

在設計模擬世界中的物件時,我們必須考慮要用什麼樣的資料結構來儲存物件的屬性,以及這些屬性所取得的值;這些就是物件的基因型。除此之外,我們也必須根據這些資訊來設計物件的表現型,也就是要決定這些變數所代表的,究竟是什麼東西。

又是基因型,又是表現型,講得很有學問,好像很難,但其實我們早就用這樣的方式在寫程式了。例如,在繪圖的時候,我們使用0~255的整數來代表灰階顏色的濃淡;0代表全黑、255代表全白。這些個0~255的整數,就是基因型;而這些數字所展現出來的顏色,就是表現型。

基因型提供的資訊要轉換成什麼樣的表現型,完全取決於我們。我們也可以讓0~255的整數代表紅色的濃淡,甚至於代表線段的長度。當然啦,你要讓0~255的整數就代表0~255的整數也可以。這也就是說,基因型和表現型並非一定要有所不同,它們也可以是完全相同的東西,就看我們怎麼設計。以電腦猴打字的例子來說,基因型是那一串字串,而表現型也同樣是那一串字串,兩者之間沒有任何不同。

Step 2: Selection

GA的第二個步驟要進行的,是依據達爾文演化論中的挑選原則,挑出族群中適合繁殖下一代的個體。挑選的過程可分為兩個步驟:

1. 評估適應度(fitness)
2. 建立交配群(mating pool)

要進行第一個步驟,我們需要先設計一個適應度函數(fitness function)。這個函數的主要用途,是要根據個體適應得好不好來幫它打分數;適應得越好,分數會越高。當然啦,在真實世界中,根本就不會用打分數的方式來決定個體適應得好不好。大自然採用的方式很直接也很簡單:能夠成功繁殖下一代的,就是適應得好的;沒辦法繁殖的,就是適應得不好的。傳統GA的主要功用,是用來找出問題的最佳解,所以才會需要用打分數的方式來評估眾多不同的解中,哪個比較好,哪個比較差。

那這個適應度函數要怎麼設計呢?看個例子就知道了。

假設我們希望電腦猴能夠打出「cat」這個片語,而現在族群中有三個個體:hut、car、box。很顯然的,這三個個體中,適應得最好的是car,因為有兩個正確的字母在正確的位置上;hut次之,因為只有一個正確的字母在正確的位置上;box最差,因為沒有任何正確的字母在正確的位置上。所以,適應度函數就可以設計成

fitness = 正確的字元數量

而這三個個體的適應度分數,也就是函數中的fitness,就會是

DNA fitness
car   2
hut   1
box   0  

這就是適應度函數的設計方式。不過要注意的是,這只是其中一種可行的設計方式;只要能達到幫個體適應程度打分數的目的,任何設計方式都是可行的。

幫個體打完分數之後,接下來的步驟就是要挑出適合繁殖下一代的個體,並把它們聚集起來準備交配。這些挑出來準備讓它們交配的個體所組成的群體,就叫做mating pool。很多人看到pool這個字,就直接翻譯成「交配池」。但這樣的翻法,其實並不怎麼好,會讓人誤以為就是個讓個體交配用的池子。「pool」這個英文單字,根據奇摩英英字典的解釋,有個意思是

a group of people available for work when required or considered as a resource

所以,把「mating pool」翻成「交配群」,應該會比較接近原意,也比較不容易產生誤解。

建立交配群的做法有很多種,各有各的優缺點。例如,菁英法(elitist method)會挑出分數最高的兩個個體來產生下一代。這個方法很簡單,但卻會牴觸變異原則。整個群體中就只有兩個個體可以繁殖下一代,那下一代將不會有太大的變化,因而會阻礙演化的進行。

既然只挑前兩名太少,那挑前50%如何?這個方法也挺簡單的,不過結果也不會是最好的。這麼做的話,分數最高的個體和分數中間的個體,它們被選中來繁殖下一代的機會是一樣的;這明顯就會讓人覺得不合理。由1000個個體所組成的群體,第500名憑什麼和第1名平起平坐,擁有相同的機會被挑選出來?還有,第500名有實實在在的機會被挑中,而只差了一名的第501名,卻一丁點機會都沒有,這又是個什麼道理?

其實,小兵也可以立大功的。分數低的個體並非一無是處,它說不定擁有分數高的個體所沒有的東西。例如,如果我們想讓A、B、C三個元素所組成的群體演化出「to be or not to be」這個字串,而各個元素的DNA如下:

元素 DNA
A  to be or not to go
B to be or not to pi
C purrrrrrrrrrrrr be

用先前提到的適應函數來評分,顯然元素C的分數會遠低於元素A、B的分數。然而,元素C的DNA中,最後兩個字元卻恰好是正確的字元,而這是元素A、B所沒有的。就此來看,讓分數最低的元素C也能繁殖下一代,反而有助於演化出我們想要的答案。

所以,與其一刀切,只挑出分數比較高的而完全屏棄分數比較低的,那倒不如讓每個個體都有機會被挑中;當然啦,分數高的個體機會應該要多一些。

那要怎麼做,才能讓分數高的機會比較多,而分數低的也不至於機會全無呢?其實,根據分數的高低來決定被挑中的機率大小就可以了。

要根據分數的高低來決定被挑中的機率大小,最簡單的做法,就是把分數正規化;正規化後的分數,會介於0~1之間,所以這個正規化之後的分數,就可以作為元素被挑中的機率。來看個實際的例子會更清楚一些。假設有個由5個元素所組成的族群,各個元素的分數為:

元素 分數
A   3.0
B 4.0 
C 0.5
D 1.0
E 1.5

元素的分數除以所有元素分數的總和,就是這個元素正規化之後的分數。在這個例子中,元素分數的總和為10,所以算出來各個元素正規化後的分數為:

元素 分數 正規化分數
A   3.0   0.30
B  4.0   0.40
C  0.5   0.05
D  1.0   0.10
E  1.5 0.15

從上表可以看出來,每個元素都有被挑中的機率,而且分數越高的機率越高;分數最高的元素B,最有機會被挑中,而分數最低的元素C,儘管機率很低,還是有機會被挑中,不至於機會全無。

Step 3: Reproduction

挑選出適合繁殖下一代的個體建立交配群之後,接下來就是要讓它們繁殖產生下一代。繁殖時,根據達爾文演化論的遺傳原則,必須讓它們將特徵傳遞給下一代。有很多做法可以達到這個目的。例如,直接複製父母其中一個的特徵給下一代。這個做法挺合理的,程式寫起來也簡單,但卻與演化論的變異原則背道而馳。那要怎麼做比較好呢?GA的標準做法,是透過下列兩個步驟來產生下一代:

1. 交配(crossover)
2. 突變(mutation)

交配這個步驟要做的,是分別提取父母的一部分特徵來給下一代。例如,假設在交配群中有下列兩個元素:

元素 DNA
A  coding
B  nature

元素A、B的DNA是由6個字元所組成的字串,所以交配這個步驟要做的,就是分別從A、B的DNA中取出幾個字元,組成一個含有6個字元的字串。

那是要怎麼個取法呢?方式有很多,最直接會想到的,就是A的DNA取前半部3個字元、B的DNA取後半部3個字元,分別當作下一代DNA的前、後半部。所以,A、B交配之後所生出的下一代,其DNA會是「codure」。

另一種從前面那種切一半的做法所衍生出來的做法,是隨機選取要下刀的地方。例如,不切成3加3,而切成1加5,或者切成4加2。切成1加5所產生的下一代,其DNA會是cature;切成4加2所產生的下一代,其DNA則是codire。這種做法要比切一半的做法好,因為可以提高下一代變異的可能性。

除了前面那種一刀切的方式之外,也可以一個一個字元用隨機的方式選取,看是要用A的DNA字元,還是要用B的DNA字元。例如,如果丟6次銅板的結果是「正反反正反反」,那下一代的DNA就會是「catire」。

當下一代的DNA經由交配產生之後,針對這個DNA,還有個可做可不做的步驟:突變。

突變這個步驟的主要目的,是要進一步地確保繁殖過程能遵循變異原則。剛開始時,族群內的各個元素都是隨機產生的,這確保了族群元素的多樣性。然而,這雖然能讓元素間在一開始時存在差異,但這差異的程度會受限於族群的規模,而且隨著一次又一次的挑選,元素間的差異會越來越小,導致越來越難遵循變異原則進行演化。透過突變這個步驟,可以引進額外的多樣性,確保元素間仍存在一定的差異,使其仍能繼續遵循變異原則進行演化。

突變會以突變率來表示;例如突變率1%、5%等。那實際上要怎麼進行突變呢?假設完成交配步驟所得到的下一代DNA是「catire」,而突變率是0.1%。這就表示「catire」這個字串中的每個字元,都有0.1%的機率轉變成其他字元。至於要透過什麼方式轉變,又會轉變成什麼字元,則可以根據需要來設計。例如,可以利用亂數來決定要轉變成什麼字元。

突變率的高低影響系統的演化行為甚鉅;突變率越高,越會對系統的演化行為造成負面影響,而讓GA變得越來越像是暴力演算法;當突變率是100%時,下一代DNA中的所有字元都會是隨機產生的,這不十足就是暴力演算法嗎?!

從配對群中選出個體讓它們交配並生出下一代,這個過程會不斷地進行,直到下一代個體的數量跟這一代個體的數量相同為止。這時,新一代的族群出現了,而舊一代的族群個體,也完成了它們的演化工作。

Step 4: Repetition!

透過Step 2、Step 3所產生的族群,會再透過Step 2、Step 3產生下一代的族群,如此一代一代不斷地演化下去。透過這樣子不斷演化的方式,系統也會越來越接近我們所想要的答案。

以上就是傳統GA的運作方式。在介紹這些步驟時,原書是使用DNA來指稱要進行演化的個體特徵,而不是使用一般GA文獻資料中所使用的「染色體」(chromosome)一詞。在生物學上,染色體和DNA是兩種不同的東西。簡單來說,染色體、DNA、基因這三者的關係是:染色體中含有DNA,而DNA中又含有基因。不過,既然GA只是借用生物學上的概念,所以在實際運作時,染色體和DNA所指的,其實是同樣的東西。事實上,在GA中,個體、染色體、DNA都是指同樣的東西;而個體的特徵、性質、基因,也都是指同樣的東西。在閱讀GA相關的資料時,應該要能夠清楚地認知到,這些只是從生物學中借用的名詞,頂多在概念上有相同之處,並不一定會跟生物學中所指有嚴絲合縫的對應關係。

留言
avatar-img
留言分享你的想法!
avatar-img
ysf的沙龍
19會員
157內容數
寫點東西自娛娛人
ysf的沙龍的其他內容
2025/08/11
GA可以在不知道正確答案的情況下,隨機地找個起點,然後透過模擬演化的方式,以遠比暴力法更快的速度找出正確的答案,是個可實際解決問題的好工具。
2025/08/11
GA可以在不知道正確答案的情況下,隨機地找個起點,然後透過模擬演化的方式,以遠比暴力法更快的速度找出正確的答案,是個可實際解決問題的好工具。
2025/08/04
在開發具備演化能力的程式系統時,所使用的主要手段,就是受到達爾文演化論啟發所發展出來的基因演算法(genetic algorithm),簡稱GA。在GA中,會讓問題可能的解答形成一個族群,然後這個族群會透過模仿自然界生物演化時的天擇方式,一代一代地進行演化。
2025/08/04
在開發具備演化能力的程式系統時,所使用的主要手段,就是受到達爾文演化論啟發所發展出來的基因演算法(genetic algorithm),簡稱GA。在GA中,會讓問題可能的解答形成一個族群,然後這個族群會透過模仿自然界生物演化時的天擇方式,一代一代地進行演化。
2025/07/28
這章的內容,是要介紹自然界生物演化方式的原理,並把這些原理應用到程式設計上。如此一來,模擬世界中的物件也可以具有演化的能力。
2025/07/28
這章的內容,是要介紹自然界生物演化方式的原理,並把這些原理應用到程式設計上。如此一來,模擬世界中的物件也可以具有演化的能力。
看更多
你可能也想看
Thumbnail
特徵工程是機器學習中的核心技術,通過將原始數據轉換為有意義的特徵,以提升模型的準確性和穩定性。常見的特徵工程方法包括異常值檢測、特徵轉換、特徵縮放、特徵表示、特徵選擇和特徵提取。本文將深入探討這些方法的適用情況及具體實施流程,以幫助讀者有效利用特徵工程來優化機器學習模型表現。
Thumbnail
特徵工程是機器學習中的核心技術,通過將原始數據轉換為有意義的特徵,以提升模型的準確性和穩定性。常見的特徵工程方法包括異常值檢測、特徵轉換、特徵縮放、特徵表示、特徵選擇和特徵提取。本文將深入探討這些方法的適用情況及具體實施流程,以幫助讀者有效利用特徵工程來優化機器學習模型表現。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
呈上篇介紹如何訓練模型,此篇就主要介紹如何利用訓練好的模型來生成圖片 [深度學習][Python]DCGAN訓練生成手寫阿拉伯數字_生成篇 生成的結果 生成的圖片大小會根據,當初設置的生成器輸出大小來決定,當你使用生成對抗網絡(GAN)生成圖像時,生成器模型的最後一層通常會決定生成圖
Thumbnail
呈上篇介紹如何訓練模型,此篇就主要介紹如何利用訓練好的模型來生成圖片 [深度學習][Python]DCGAN訓練生成手寫阿拉伯數字_生成篇 生成的結果 生成的圖片大小會根據,當初設置的生成器輸出大小來決定,當你使用生成對抗網絡(GAN)生成圖像時,生成器模型的最後一層通常會決定生成圖
Thumbnail
本文將延續上一篇文章,經由訓練好的GAN模型中的生成器來生成圖片 [深度學習][Python]訓練MLP的GAN模型來生成圖片_訓練篇 [深度學習][Python]訓練CNN的GAN模型來生成圖片_訓練篇 相較之下CNN的GAN生成的效果比較好,但模型也相對比較複雜,訓練時間花的也比較
Thumbnail
本文將延續上一篇文章,經由訓練好的GAN模型中的生成器來生成圖片 [深度學習][Python]訓練MLP的GAN模型來生成圖片_訓練篇 [深度學習][Python]訓練CNN的GAN模型來生成圖片_訓練篇 相較之下CNN的GAN生成的效果比較好,但模型也相對比較複雜,訓練時間花的也比較
Thumbnail
GNN發展背景 傳統的深度學習模型如在計算機視覺(CV)和自然語言處理(NLP)領域中極為成功,主要是處理結構化數據如影像和文本。這些數據類型通常具有固定且規律的結構,例如影像是由有序的像素點組成。然而,在真實世界中,許多數據是非結構化的,如化合物結構(原子和分子)。這些數據雖然具有一定的規則性,
Thumbnail
GNN發展背景 傳統的深度學習模型如在計算機視覺(CV)和自然語言處理(NLP)領域中極為成功,主要是處理結構化數據如影像和文本。這些數據類型通常具有固定且規律的結構,例如影像是由有序的像素點組成。然而,在真實世界中,許多數據是非結構化的,如化合物結構(原子和分子)。這些數據雖然具有一定的規則性,
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
在模擬自然界中的事物時導入隨機性,可以讓結果看起來比較自然,但如果導入的隨機性都是uniform distribution,那未免也太呆板了。這時候,我們需要nonuniform distribution亂數,來讓模擬出來的結果,更像真的一樣。
Thumbnail
在模擬自然界中的事物時導入隨機性,可以讓結果看起來比較自然,但如果導入的隨機性都是uniform distribution,那未免也太呆板了。這時候,我們需要nonuniform distribution亂數,來讓模擬出來的結果,更像真的一樣。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
Thumbnail
本文介紹了Python中的物件導向程式設計的重要概念,包括類別、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda表達式、泛型和反射。每個概念都有對應的程式碼範例來說明其用法和功能。這些概念對於理解和使用Python進行物件導向程式設計至關重要。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News