遺傳算法


作者:sjyan
鏈接:https://www.zhihu.com/question/23293449/answer/120220974
來源:知乎
著作權歸作者所有,轉載請聯系作者獲得授權。

大三的時候上了一門人工智能,其中有一次作業就用到了遺傳算法 ,問題是這樣的:
求解函數 f(x) = x + 10*sin(5*x) + 7*cos(4*x) 在區間[0,9]的最大值。
這個函數大概長這樣:

那么如何應用遺傳算法如何來找到這個奇怪的函數的最大值呢?

事實上,不管一個函數的形狀多么奇怪,遺傳算法都能在很短的時間內找到它在一個區間內的(近似)最大值。

相當神奇,不是嗎?

接下來圍繞這個問題,講講我對遺傳算法的一些理解。實現代碼以及在Matlab中使用遺傳算法的小教程都附在最后。


1.介紹

遺傳算法(Genetic Algorithm)遵循『適者生存』、『優勝劣汰』的原則,是一類借鑒生物界自然選擇和自然遺傳機制的隨機化搜索算法。

遺傳算法模擬一個人工種群的進化過程,通過選擇(Selection)、交叉(Crossover)以及變異(Mutation)等機制,在每次迭代中都保留一組候選個體,重復此過程,種群經過若干代進化后,理想情況下其適應度達到 ***近似最優***的狀態。

自從遺傳算法被提出以來,其得到了廣泛的應用,特別是在函數優化、生產調度、模式識別、神經網絡、自適應控制等領域,遺傳算法發揮了很大的作用,提高了一些問題求解的效率。


2.遺傳算法組成
  • 編碼 -> 創造染色體
  • 個體 -> 種群
  • 適應度函數
  • 遺傳算子
    • 選擇
    • 交叉
    • 變異
  • 運行參數
    • 是否選擇精英操作
    • 種群大小
    • 染色體長度
    • 最大迭代次數
    • 交叉概率
    • 變異概率

2.1 編碼與解碼

實現遺傳算法的第一步就是明確對求解問題的編碼和解碼方式。

對於函數優化問題,一般有兩種編碼方式,各具優缺點
  • 實數編碼:直接用實數表示基因,容易理解且不需要解碼過程,但容易過早收斂,從而陷入局部最優
  • 二進制編碼:穩定性高,種群多樣性大,但需要的存儲空間大,需要解碼且難以理解

對於求解函數最大值問題,我選擇的是二進制編碼。
以我們的目標函數 f(x) = x + 10sin(5x) + 7cos(4x), x∈[0,9] 為例。

假如設定求解的精度為小數點后4位,可以將x的解空間划分為 (9-0)×(1e+4)=90000個等分。

2^16<90000<2^17,需要17位二進制數來表示這些解。換句話說,一個解的編碼就是一個17位的二進制串。

一開始,這些二進制串是隨機生成的。

一個這樣的二進制串代表一條染色體串,這里染色體串的長度為17。

對於任何一條這樣的染色體chromosome,如何將它復原(解碼)到[0,9]這個區間中的數值呢?

對於本問題,我們可以采用以下公式來解碼:
x = 0 + decimal(chromosome)×(9-0)/(2^17-1)
decimal( ): 將二進制數轉化為十進制數

一般化解碼公式:
f(x), x∈[lower_bound, upper_bound]
x = lower_bound + decimal(chromosome)×(upper_bound-lower_bound)/(2^chromosome_size-1)
lower_bound: 函數定義域的下限
upper_bound: 函數定義域的上限
chromosome_size: 染色體的長度

通過上述公式,我們就可以成功地將二進制染色體串解碼成[0,9]區間中的十進制實數解。

2.2 個體與種群

『染色體』表達了某種特征,這種特征的載體,稱為『個體』。

對於本次實驗所要解決的一元函數最大值求解問題,個體可以用上一節構造的染色體表示,一個個體里有一條染色體。

許多這樣的個體組成了一個種群,其含義是一個一維點集(x軸上[0,9]的線段)。

2.3 適應度函數

遺傳算法中,一個個體(解)的好壞用適應度函數值來評價,在本問題中,f(x)就是適應度函數。

適應度函數值越大,解的質量越高。

適應度函數是遺傳算法進化的驅動力,也是進行自然選擇的唯一標准,它的設計應結合求解問題本身的要求而定。

2.4 遺傳算子

我們希望有這樣一個種群,它所包含的個體所對應的函數值都很接近於f(x)在[0,9]上的最大值,但是這個種群一開始可能不那么優秀,因為個體的染色體串是隨機生成的。

如何讓種群變得優秀呢?

不斷的進化。

每一次進化都盡可能保留種群中的優秀個體,淘汰掉不理想的個體,並且在優秀個體之間進行染色體交叉,有些個體還可能出現變異。

種群的每一次進化,都會產生一個最優個體。種群所有世代的最優個體,可能就是函數f(x)最大值對應的定義域中的點。

如果種群無休止地進化,那總能找到最好的解。但實際上,我們的時間有限,通常在得到一個看上去不錯的解時,便終止了進化。

對於給定的種群,如何賦予它 進化的能力呢?
  • 首先是選擇(selection)
    • 選擇操作是從前代種群中選擇***多對***較優個體,一對較優個體稱之為一對父母,讓父母們將它們的基因傳遞到下一代,直到下一代個體數量達到種群數量上限
    • 在選擇操作前,將種群中個體按照適應度從小到大進行排列
    • 采用輪盤賭選擇方法(當然還有很多別的選擇方法),各個個體被選中的概率與其適應度函數值大小成正比
    • 輪盤賭選擇方法具有隨機性,在選擇的過程中可能會丟掉較好的個體,所以可以使用精英機制,將前代最優個體直接選擇
  • 其次是交叉(crossover)
    • 兩個待交叉的不同的染色體(父母)根據交叉概率(cross_rate)按某種方式交換其部分基因
    • 采用單點交叉法,也可以使用其他交叉方法
  • 最后是變異(mutation)
    • 染色體按照變異概率(mutate_rate)進行染色體的變異
    • 采用單點變異法,也可以使用其他變異方法

一般來說,交叉概率(cross_rate)比較大,變異概率(mutate_rate)極低。像求解函數最大值這類問題,我設置的交叉概率(cross_rate)是0.6,變異概率(mutate_rate)是0.01。

因為遺傳算法相信2條優秀的父母染色體交叉更有可能產生優秀的后代,而變異的話產生優秀后代的可能性極低,不過也有存在可能一下就變異出非常優秀的后代。這也是符合自然界生物進化的特征的。


3.遺傳算法流程
在matlab下寫了個測試程序。
附上代碼

測試結果
  • 最優個體:00011111011111011
  • 最優適應度:24.8554
  • 最優個體對應自變量值:7.8569
  • 達到最優結果需要的迭代次數:多次實驗后發現,達到收斂的迭代次數從20次到一百多次不等

迭代次數與平均適應度關系曲線(橫軸:迭代次數,縱軸:平均適應度)


有現成的工具可以直接使用遺傳算法,比如Matlab。
最后就再介紹一下如何在Matlab中使用遺傳算法。

在MATLAB中使用GA

1. 打開 Optimization 工具,在 Solver 中選擇 ga - genetic algorithm,在 Fitness function 中填入 @target

2. 在你的工程文件夾中新建 target.m,注意MATLAB的當前路徑是你的工程文件夾所在路徑

3. 在 target.m 中寫下適應度函數,比如
function [ y ] = target(x)
y = -x-10*sin(5*x)-7*cos(4*x);
end
*MATLAB中的GA只求解函數的(近似) 最小值,所以先要將目標函數 取反。

4. 打開 Optimization 工具,輸入 變量個數(Number of variables) 和 自變量定義域(Bounds) 的值,點擊 Start,遺傳算法就跑起來了。最終在輸出框中可以看到函數的(近似)最小值,和達到這一程度的迭代次數(Current iteration)和最終自變量的值(Final point)

5. 在 Optimization - ga 工具中,有許多選項。通過這些選項,可以設置下列屬性
  • 種群(Population)
  • 選擇(Selection)
  • 交叉(Crossover)
  • 變異(Mutation)
  • 停止條件(Stopping criteria)
  • 畫圖函數(Plot functions)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM