前言
看了很多,發現這個遺傳算法,進化算法是一個非常有用的一個方法。而且可解釋性遠遠強於神經網絡。之前寫了一篇博文,專門講解基於DEAP庫的python編程,來編寫遺傳算法,但是那一篇主要偏重代碼,出於想要深入理解代碼的含義,因此專門記下這篇博文,既是筆記,也是分享。
所有的用python實現的代碼,請看這個博文:
GEAP 遺傳算法/遺傳編程 genetic programming + python(deap庫)實現
如果需要還有這兩個:
遺傳算法GA和遺傳編程GP有什么不同?
粒子群算法PSO 和 遺傳算法GA 的相同點和不同點
概述
“物競天擇,優勝劣汰”, 達爾文提出了著名的生物進化理論,即所有的動植物都是由較早期、較原始的形式演變而來的。而遺傳編程(遺傳規划)則在數學和計算機科學領域應用了這一演化過程:從基數較為龐大的原始、粗糙的程序種群中通過評估適應性選擇父系、進行遺傳操作生成新一代種群,再判斷終止條件決定是否再次迭代、生成下一代種群。類比如下:
講到這里可否理解了,進化算法的本質就是模擬優勝劣汰,下面進入正題
啟發式的理解(重點)
整個包含以下幾個方面!一定要看一下
- 個體編碼(Individual representation): 將問題的解空間編碼映射到搜索空間的過程。常用的編碼方式有二值編碼(Binary),格雷編碼(Gray),浮點編碼(Floating-point)等。
簡單的說就是你怎么表示一個個體,使用01010101010101來表示一個個體,還是用1238583241來表示一個個體 - 評價(Evaluation): 設定一定的准則評價族群內每個個體的優秀程度。這種優秀程度通常稱為適應度(Fitness)。
基於你的個體編碼,判斷你的個體編碼好不好的一個評價函數 - 配種選擇(Mating selection): 建立准則從父代中選擇個體參與育種。盡可能選擇精英個體的同時也應當維護種群的多樣性,避免算法過早陷入局部最優。
你要選擇哪些個體參與育種,也就是參與下面那一個環節 - 變異(Variation): 變異過程包括一系列受到生物啟發的操作,例如重組(Recombination),突變(mutation)等。通過變異操作,父代的個體編碼以一定方式繼承和重新組合后,形成后代族群。
保留下來的個體,進行重組,突變等等 - 環境選擇(Environmental selection): 將父代與子代重組成新的族群。這個過程中育種得到的后代被重新插入到父代種群中,替換父代種群的部分或全體,形成具有與前代相近規模的新族群。
生下來的個體 按道理講應該是比父類數量少的,一般都會補全到和父類的size相同,補全的方案就叫做環境選擇 - 停止准則(Stopping crieterion): 確定算法何時停止,通常有兩種情況:算法已經找到最優解或者算法已經選入局部最優,不能繼續在解空間內搜索。
咱們看個流程圖理解理解:
優化問題的定義
這個不再理解范圍內,但是,如果要用python編程進化算法的話,就需要先設置這個問題。
有單優化問題:creator.create('FitnessMin', base.Fitness, weights=(-1.0, ))
- 在創建單目標優化問題時,weights用來指示最大化和最小化。此處-1.0即代表問題是一個最小化問題,對於最大化,應將weights改為正數,如1.0。
- 另外即使是單目標優化,weights也需要是一個tuple,以保證單目標和多目標優化時數據結構的統一。
- 對於單目標優化問題,weights 的絕對值沒有意義,只要符號選擇正確即可。
和多優化問題:creator.create('FitnessMulti', base.Fitness, weights=(-1.0, 1.0))
- 對於多目標優化問題,weights用來指示多個優化目標之間的相對重要程度以及最大化最小化。如示例中給出的(-1.0, 1.0)代表對第一個目標函數取最小值,對第二個目標函數取最大值。
個體編碼
- 實數編碼(Value encoding):直接用實數對變量進行編碼。優點是不用解碼,基因表達非常簡潔,而且能對應連續區間。但是實數編碼后搜索區間連續,因此容易陷入局部最優。
- 二進制編碼(Binary encoding):在二進制編碼中,用01兩種數字模擬人類染色體中的4中鹼基,用一定長度的01字符串來描述變量。其優點在於種群多樣性大,但是需要解碼,而且不連續,容易產生Hamming cliff(例如0111=7, 1000=8,改動了全部的4位數字之后,實際值只變動了1),在接近局部最優位置時,染色體稍有變動,就會使變量產生很大偏移(格雷編碼(Gray coding)能夠克服漢明距離的問題,但是實際問題復雜度較大時,格雷編碼很難精確描述問題)。
- 序列編碼(Permutation encoding):通常在求解順序問題時用到,例如TSP問題。序列編碼中的每個染色體都是一個序列。
- 粒子(Particles):粒子是一種特殊個體,主要用於粒子群算法。相比普通的個體,它額外具有速度、速度限制並且能記錄最優位置。
初始族群的創建
- 一般族群:這是最常用的族群類型,族群中沒有特別的順序或者子族群。
toolbox.register('population', tools.initRepeat, list, toolbox.individual)
- 同類群(Demes):同類群即一個族群中包含幾個子族群。在有些算法中,會使用本地選擇(Local selection)挑選育種個體,這種情況下個體僅與同一鄰域的個體相互作用。
toolbox.register("deme", tools.initRepeat, list, toolbox.individual)
DEME_SIZES = 10, 50, 100
population = [toolbox.deme(n=i) for i in DEME_SIZES]
- 粒子群:粒子群中的所有粒子共享全局最優。在實現時需要額外傳入全局最優位置與全局最優適應度給族群。
creator.create("Swarm", list, gbest=None, gbestfit=creator.FitnessMax)
toolbox.register("swarm", tools.initRepeat, creator.Swarm, toolbox.particle)
評價
評價部分是根據任務的特性高度定制的,DEAP庫中並沒有預置的評價函數模版。
這里給一個例子
from deap import base, creator, tools
import numpy as np
# 定義問題
creator.create('FitnessMin', base.Fitness, weights=(-1.0,)) #優化目標:單變量,求最小值
creator.create('Individual', list, fitness = creator.FitnessMin) #創建Individual類,繼承list
# 生成個體
IND_SIZE = 5
toolbox = base.Toolbox()
toolbox.register('Attr_float', np.random.rand)
toolbox.register('Individual', tools.initRepeat, creator.Individual, toolbox.Attr_float, n=IND_SIZE)
# 生成初始族群
N_POP = 10
toolbox.register('Population', tools.initRepeat, list, toolbox.Individual)
pop = toolbox.Population(n = N_POP)
# 定義評價函數
def evaluate(individual):
return sum(individual), #注意這個逗號,即使是單變量優化問題,也需要返回tuple
# 評價初始族群
toolbox.register('Evaluate', evaluate)
fitnesses = map(toolbox.Evaluate, pop)
for ind, fit in zip(pop, fitnesses):
ind.fitness.values = fit
print(ind.fitness.values)
# 結果:
# (2.593989197511478,)
# (1.1287944225903104,)
# (2.6030877077096717,)
# (3.304964061515382,)
# (2.534627558467466,)
# (2.4697149450205536,)
# (2.344837782191844,)
# (1.8959030773060852,)
# (2.5192475334239,)
# (3.5069764929866585,)
配種選擇
錦標賽
deap.tools.selTournament(individuals, k, tournsize, fit_attr = 'fitness')
錦標賽選擇顧名思義,就是模擬錦標賽的方式,首先在族群中隨機抽取tournsize個個體,然后從中選取具有最佳適應度的個體,將此過程重復k次,獲得育種族群。tournsize越大,選擇強度(selection intensity)越高,在選擇之后留下的育種族群的平均適應度也就越高。比較常用的tournsize是2。
假設tournsize是2,就是在原來的種群中取出來2個,然后再這兩個中選一個最適應的,然后重復k次,我們就可以得到k個最適應的,這個就是育種族群,用來后面生孩子重組基因的;
如圖,假設這個族群有5個人,tournsize為3,就是選出來3個人,然后在3個人中選取一個最好的
錦標賽選擇相比於輪盤賭選擇,通常能夠有更快的收斂速度,在實際場景中應用較多。
輪盤賭選擇
deap.tools.selRoulette(individuals, k, fit_attr = 'fitness')
在輪盤賭選擇中,每個個體a被選中的概率P(a)與他的評價函數f(a)成正比
但是如果評價函數出現負數,就不適用
並且很多文章指出來,輪盤賭選擇的效果並不好
隨機普遍抽樣選擇
deap.tools.selStochasticUniversalSampling(individuals, k, fit_attr = 'fitness')
隨機普遍抽樣選擇是一種有多個指針的輪盤賭選擇,其優點是能夠保存族群多樣性,而不會像輪盤賭一樣,有較大幾率對重復選擇最優個體。
在與前文相同的例子中使用隨機普遍抽樣選擇,設定指針數k為3,那么指針間距即為,如下圖所示:
就是我一選就選3個個體,一選選3個,保證了多樣性
變異
單點交叉
deap.tools.cxOnePoint(ind1, ind2)
- 最簡單的交叉方式,選擇一個切口,將兩條基因切開之后,交換尾部基因段。盡管該方法非常簡單,但是多篇文章指出,該算法在各種實驗中性能都被其他交叉算法吊打,因此算是一種不建議使用的loser algorithm
兩點交叉
deap.tools.cxTwoPoint(ind1, ind2)
- 用兩個點切開基因之后,交換切出來的基因段
均勻交叉
deap.tools.cxUniform(ind1, ind2, indpb)
- 指定一個變異幾率,兩父代中的每個基因都以該幾率交叉。
部分匹配交叉
deap.tools.cxPartialyMatched(ind1, ind2)
- 部分匹配交叉主要用於序列編碼的個體
- 這個太難敘述了,能看懂就看,看不懂就記住在哪里用就好了,就是上面那句話
突變
高斯突變
tools.mutGaussian(individual, mu, sigma, indpb)
- 對個體序列中的每一個基因按概率變異,變異后的值為按均值為mu,方差為sigma的高斯分布選取的一個隨機數。如果不希望均值發生變化,則應該將設mu為0。
亂序突變
tools.mutShuffleIndexes(individual, indpb)
- 將個體序列打亂順序,每個基因位置變動的幾率由indpb給出。
位翻轉突變
tools.mutFlipBit(individual, indpb)
對個體中的每一個基因按給定對變異概率取非。
均勻整數突變
tools.mutUniformInt(individual, low, up, indpb)
對序列中的每一位按概率變異,變異后的值為[low, up]中按均勻分布隨機選取的一個整數。
環境選擇
完全重插入(Pure reinsertion)
- 產生與父代個體數量相當的配種個體,直接用配種個體生成新一代族群。
均勻重插入(Uniform reinsertion)
- 產生比父代個體少的配種個體,用配種個體隨機均勻地替換父代個體。
精英重插入(Elitist reinsertion)
- 產生比父代個體少的配種個體,選取配種后代中適應度最好的一些個體,插入父代中,取代適應度較低的父代個體。
精英保留重插入(Fitness-based reinsertion)
- 產生比父代個體多的配種個體,選取其中適應度最大的配種個體形成新一代族群。
通常來說后兩種方式由於精英保留的緣故,收斂速度較快,因此比較推薦。
進化算法的python實現
GEAP 遺傳算法/遺傳編程 genetic programming + python(deap庫)實現
進化算法的優缺點
優點
-
泛用性強,對連續變量和離散變量都能適用;
-
不需要導數信息,因此不要求適應度函數的連續和可微性質(或者說不需要問題內在機理的相關信息);
-
可以在解空間內大范圍並行搜索;
-
不容易陷入局部最優;
-
高度並行化,並且容易與其他優化方法整合。
-
對於凸優化問題,相對基於梯度的優化方法(例如梯度下降法,牛頓/擬牛頓法)收斂速度更慢;
-
進化算法需要在搜索空間投放大量個體來搜索最優解。對於高維問題,由於搜索空間隨維度指數級膨脹,需要投放的個體數也大幅增長,會導致收斂速度變慢;
-
設計編碼方式、適應度函數以及變異規則需要大量經驗。
簡單說最大的缺點就是慢
參考:
GEAP 遺傳算法/遺傳編程 genetic programming + python(deap庫)實現
【遺傳編程/基因規划】Genetic Programming