Python遺傳和進化算法框架(一)Geatpy快速入門

https://blog.csdn.net/qq_33353186/article/details/82014986python

Geatpy是一個高性能的Python遺傳算法庫以及開放式進化算法框架,由華南理工大學、華南農業大學、德州奧斯汀公立大學學生聯合團隊開發。git

Website (including documentation): http://www.geatpy.com 
Contact us: https://www.geatpy.com/supports
Source: https://github.com/geatpy-dev/geatpy
Bug reports: https://github.com/geatpy-dev/geatpy/issues
Geatpy提供了許多已實現的遺傳和進化算法相關算子的庫函數,如初始化種羣、選擇、交叉、變異、重插入、多種羣遷移、多目標優化非支配排序等,而且提供開放式的進化算法框架來實現多樣化的進化算法。其執行效率高於Matlab遺傳算法工具箱和Matlab第三方遺傳算法工具箱Gaot、gatbx、GEATbx,學習成本低。github

Geatpy支持二進制/格雷碼編碼種羣、實數值種羣、整數值種羣、排列編碼種羣。支持輪盤賭選擇、隨機抽樣選擇、錦標賽選擇。提供單點交叉、兩點交叉、洗牌交叉、部分匹配交叉(PMX)、線性重組、離散重組、中間重組等重組算子。提供簡單離散變異、實數值變異、整數值變異、互換變異等變異算子。支持隨機重插入、精英重插入。支持awGA、rwGA、nsga二、快速非支配排序等多目標優化的庫函數、提供進化算法框架下的經常使用進化算法模板等。算法

關於遺傳算法、進化算法的學習資料,在官網中https://www.geatpy.com 有詳細講解以及相關的學術論文連接。同時網上也有不少資料。編程

閒話少說……下面講一下怎麼安裝和使用:windows

先說一下安裝方法:框架

首先是要windows系統,Python要是3.5,3.6或3.7版本 ,而且安裝了pip。只需在控制檯執行函數

pip install geatpy
便可安裝成功。或者到github上下載:https://github.com/geatpy-dev/geatpy 推薦是直接用pip的方式安裝。由於這樣有利於後續的更新。我爲了方便運行demo代碼以及查看源碼和官方教程文檔,所以另外在github上也下載了(但仍用pip方式安裝)。工具

有些初學Python的讀者反映仍是不知道怎麼安裝,或者安裝以後不知道怎麼寫代碼。這裏推薦安裝Anaconda,它集成了Python的許多經常使用的運行庫,好比Numpy、Scipy等。其內置的Spyder風格跟Matlab相似,給人熟悉的感受,更容易上手。性能

再說一下更新方法:

Geatpy在持續更新。能夠經過如下命令使電腦上的版本與官方最新版保持一致:

pip install --upgrade geatpy
若在更新過程當中遇到"utf8 decode"錯誤的問題,是windows下用pip進行安裝時遇到的常見問題之一解決方法有不少。能夠改用下面的更新命令,並以管理員方式運行:

pip install --user --upgrade geatpy
或者以管理員方式運行cmd並進行更新。

Geatpy提供2種方式實現遺傳算法。先來說一下第一種最基本的實現方式:編寫編程腳本。

1. 編寫腳本實現遺傳算法:

用過謝菲爾德大學的Matlab遺傳算法庫Gatbx以及其升級版——GEATbx的朋友應該很是熟悉下面的Matlab腳本:

%% matlab_gatbx_test.m
%遺傳算法求f(x)=x*sin(10*pi*x)+2.0,在[-1,2]上的最大值
figure(1);
fplot(@(variable)variable.*sin(10*pi*variable)+2.0,[-1,2]); %畫出函數曲線
tic %開始計時
%定義遺傳算法參數
NIND=40; %個體數目(Number of individuals)
MAXGEN=25; %最大遺傳代數(Maximum number of generations)
PRECI=19; %變量的二進制位數(Precision of variables)
GGAP=0.9; %代溝(Generation gap)說明子代與父代的重複率爲0.1
trace=zeros(MAXGEN,2); %尋優結果的初始值
FieldD=[19;-1;2;1;0;1;1]; %區域描述器(Build field descriptor),第二、3行爲自變量的下界和上界
Chrom=crtbp(NIND, PRECI); %定義初始種羣
gen=0; %代計數器
variable=bs2rv(Chrom, FieldD); %計算初始種羣的十進制轉換
ObjV=shang(variable); %計算目標函數值
while gen<MAXGEN %進化MAXGEN代
FitnV=ranking(-ObjV); %分配適應度值(Assign fitness values)ranking函數的功能就是目標值越小的分配值越大,
%本例求解最大值,應該要是他的適應度值更大,故必須使得ranking內的數越小,這樣分配的適應度值才能大
SelCh=select('sus', Chrom, FitnV, GGAP); %選擇,使用sus方式,也能夠改用rws方式
SelCh=recombin('xovsp', SelCh, 0.7); %重組,選用xovsp方式
SelCh=mut(SelCh); %變異
variable=bs2rv(SelCh, FieldD); %子代個體的十進制轉換,把染色體變爲十進制
ObjVSel=shang(variable); %計算子代的目標函數值
[Chrom ObjV]=reins(Chrom, SelCh, 1, 1, ObjV, ObjVSel); %重插入子代的新種羣
variable=bs2rv(Chrom, FieldD); %子代個體的十進制轉換,轉爲十進制
gen=gen+1; %代計數器增長
%輸出最優解及其序號,並在目標函數圖像中標出,Y爲最優解,I爲種羣的序號
[Y, I]=max(ObjV);hold on;
trace(gen,1)=max(ObjV); %遺傳算法性能跟蹤,把當代的最優值放入trace矩陣的第一行第目前代數列
trace(gen,2)=sum(ObjV)/length(ObjV); %把當代種羣目標函數的均值,放入trace矩陣的第二行第目前代數列
end
toc %結束計時
variable=bs2rv(Chrom, FieldD); %最優個體的十進制轉換,轉回十進制,以便輸出
result = max(trace(:,1)); %輸出搜索到的目標函數最大值
sprintf('result = %f',result)
hold on;
grid on;
plot(variable,ObjV,'b*');
figure(2);
plot(trace(:,1)); %把trace矩陣的第一列畫出來(記錄的是每一代的最優值)
hold on;
plot(trace(:,2),'-.');grid %把trace矩陣的第2列畫出來(記錄的是每一代種羣目標函數均值)
legend('解的變化','種羣均值的變化')

function z=shang(x) % 目標函數的核心部分(即缺省了優化目標的純函數)
z=x.*sin(10*pi*x)+2.0;
end
這是在Matlab的gatbx工具箱下實現簡單遺傳算法搜索f(x)=x*sin(10*pi*x)+2.0,在[-1,2]上的最大值的腳本程序,運行結果以下:

時間已過 0.051572 秒。

ans =

result = 3.850224

再看一下在Geatpy上如何編寫腳本:

"""demo.py"""
import numpy as np
import geatpy as ga # 導入geatpy庫
import matplotlib.pyplot as plt
import time

"""============================目標函數============================"""
def aim(x): # 傳入種羣染色體矩陣解碼後的基因表現型矩陣
return x * np.sin(10 * np.pi * x) + 2.0
x = np.linspace(-1, 2, 200)
plt.plot(x, aim(x)) # 繪製目標函數圖像
start_time = time.time() # 開始計時
"""============================變量設置============================"""
x1 = [-1, 2] # 自變量範圍
b1 = [1, 1] # 自變量邊界
codes = [1] # 變量的編碼方式,2個變量均使用格雷編碼
precisions =[5] # 變量的精度
scales = [0] # 採用算術刻度
ranges=np.vstack([x1]).T # 生成自變量的範圍矩陣
borders=np.vstack([b1]).T # 生成自變量的邊界矩陣
"""========================遺傳算法參數設置========================="""
NIND = 40; # 種羣個體數目
MAXGEN = 25; # 最大遺傳代數
GGAP = 0.9; # 代溝:說明子代與父代的重複率爲0.1
"""=========================開始遺傳算法進化========================"""
FieldD = ga.crtfld(ranges,borders,precisions,codes,scales) # 調用函數建立區域描述器
Lind = np.sum(FieldD[0, :]) # 計算編碼後的染色體長度
Chrom = ga.crtbp(NIND, Lind) # 根據區域描述器生成二進制種羣
variable = ga.bs2rv(Chrom, FieldD) #對初始種羣進行解碼
ObjV = aim(variable) # 計算初始種羣個體的目標函數值
pop_trace = (np.zeros((MAXGEN, 2)) * np.nan) # 定義進化記錄器,初始值爲nan
ind_trace = (np.zeros((MAXGEN, Lind)) * np.nan) # 定義種羣最優個體記錄器,記錄每一代最優個體的染色體,初始值爲nan
# 開始進化!!
for gen in range(MAXGEN):
FitnV = ga.ranking(-ObjV) # 根據目標函數大小分配適應度值(因爲遵循目標最小化約定,所以最大化問題要對目標函數值乘上-1)
SelCh=ga.selecting('sus', Chrom, FitnV, GGAP) # 選擇,採用'sus'隨機抽樣選擇
SelCh=ga.recombin('xovsp', SelCh, 0.7) # 重組(採用單點交叉方式,交叉機率爲0.7)
SelCh=ga.mutbin(SelCh) # 二進制種羣變異
variable = ga.bs2rv(SelCh, FieldD) # 對育種種羣進行解碼(二進制轉十進制)
ObjVSel = aim(variable) # 求育種個體的目標函數值
[Chrom,ObjV] = ga.reins(Chrom,SelCh,1,1,1,-ObjV,-ObjVSel,ObjV,ObjVSel) # 重插入獲得新一代種羣
# 記錄
best_ind = np.argmax(ObjV) # 計算當代最優個體的序號
pop_trace[gen, 0] = ObjV[best_ind] # 記錄當代種羣最優個體目標函數值
pop_trace[gen, 1] = np.sum(ObjV) / ObjV.shape[0] # 記錄當代種羣的目標函數均值
ind_trace[gen, :] = Chrom[best_ind, :] # 記錄當代種羣最優個體的變量值
# 進化完成
end_time = time.time() # 結束計時
"""============================輸出結果及繪圖================================"""
print('目標函數最大值:',np.max(pop_trace[:, 0])) # 輸出目標函數最大值
variable = ga.bs2rv(ind_trace, FieldD) # 解碼獲得表現型
print('用時:', end_time - start_time)
plt.plot(variable, aim(variable),'bo')
運行結果以下:

目標函數最大值: 3.850273756279405
用時: 0.04900471389770508

 

更多對比詳見:https://blog.csdn.net/qq_33353186/article/details/82082053

對比上述Matlab代碼和Python代碼,咱們會發現Geatpy提供風格極爲類似的庫函數,有Matlab相關編程經驗的基本上能夠無縫轉移到Python上利用Geatpy進行遺傳算法程序開發。

Geatpy提供了詳盡的API文檔,好比要查看上面代碼中的"ranking"函數是幹什麼的,能夠在python中執行

import geatpy as ga
help(ga.ranking)
便可看到"ranking"函數的相關使用方法。另外也能夠參見github上面的文檔:

https://github.com/geatpy-dev/geatpy/tree/master/geatpy/doc 

另外官網上也有更多詳盡的Geatpy教程,Geatpy官網http:www.geatpy.com

2. 利用框架實現遺傳算法。

Geatpy提供開放的進化算法框架。即「函數接口」+「進化算法模板」。對於一些複雜的進化算法,如多目標進化優化、改進的遺傳算法等,利用上面所說的編寫腳本是很是麻煩的,改用框架的方法能夠極大提升編程效率。

這裏給出一個利用框架實現NSGA-II算法求多目標優化函數ZDT-1的帕累託前沿面的例子:

首先編寫函數接口文件:

""" aimfuc.py """

# ZDT1
def ZDT1(Chrom, LegV):

ObjV1 = Chrom[:, 0]
gx = 1 + (9 / 29) * np.sum(Chrom[:, 1:30], 1)
hx = 1 - np.sqrt(ObjV1 / gx)
ObjV2 = gx * hx

return [np.array([ObjV1, ObjV2]).T, LegV]
而後編寫腳本,使用Geatpy提供的nsga2算法的進化算法模板(moea_nsga2_templet):

"""main.py"""
import numpy as np
import geatpy as ga # 導入geatpy庫

AIM_M = __import__('aimfuc') # 獲取函數接口地址
AIM_F = 'ZDT1' # 目標函數名

"""============================變量設置============================"""
ranges = np.vstack([np.zeros((1,30)), np.ones((1,30))]) # 生成自變量的範圍矩陣
borders = np.vstack([np.ones((1,30)), np.ones((1,30))]) # 生成自變量的邊界矩陣
precisions = [4] * 30 # 自變量的編碼精度
"""========================遺傳算法參數設置========================="""
NIND = 25 # 種羣規模
MAXGEN = 1000 # 最大遺傳代數
GGAP = 1; # 代溝:子代與父代的重複率爲(1-GGAP),因爲後面使用NSGA2算法,所以該參數無用
selectStyle = 'tour' # 遺傳算法的選擇方式
recombinStyle = 'xovdprs' # 遺傳算法的重組方式,設爲兩點交叉
recopt = 0.9 # 交叉機率
pm = 0.1 # 變異機率
SUBPOP = 1 # 設置種羣數爲1f
maxormin = 1 # 設置標記代表這是最小化目標
MAXSIZE = 1000 # 帕累托最優集最大個數
FieldDR = ga.crtfld(ranges, borders, precisions) # 生成區域描述器
"""=======================調用進化算法模板進行種羣進化==================="""
# 獲得帕累托最優解集NDSet以及解集對應的目標函數值NDSetObjV
[ObjV, NDSet, NDSetObjV, times] = ga.moea_nsga2_templet(AIM_M, AIM_F, None, None, FieldDR, 'R', maxormin, MAXGEN, MAXSIZE, NIND, SUBPOP, GGAP, selectStyle, recombinStyle, recopt, pm, distribute = True, drawing = 1)
運行結果以下:

 

用時: 7.359716176986694 秒
帕累託前沿點個數: 479 個
單位時間找到帕累託前沿點個數: 65 個

能夠改用moea_q_sorted_templet快速非支配排序的多目標優化進化算法模板,能夠獲得更好的效率和更好的結果:

 

進化算法的核心算法邏輯是寫在進化算法模板內部的,代碼是開源的,咱們能夠參考Geatpy進化算法模板的源代碼來自定義算法模板,以實現豐富多樣的進化算法,如差分進化算法、改進的遺傳算法等:

https://github.com/geatpy-dev/geatpy/tree/master/geatpy/source-code/templets

後面的博客將深刻理解Geatpy的庫函數用法,以及探討框架的核心——進化算法模板的實現。還會講一些使用Geatpy解決問題的案例。歡迎繼續跟進~感謝!--------------------- 做者:jazz_bin 來源:CSDN 原文:https://blog.csdn.net/qq_33353186/article/details/82014986 版權聲明:本文爲博主原創文章,轉載請附上博文連接!

相關文章
相關標籤/搜索