遺傳算法(Genetic Algorithm)

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下寫了個測試程序。
附上代碼https://github.com/yanshengjia/artificial-intelligence/tree/master/genetic-algorithm-for-functional-maximum-problem

測試結果

  • 最優個體: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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章