Python遺傳演算法框架使用例項(二)多目標優化問題Geatpy for Python與Matlab的對比學習

jazz_bin發表於2019-09-01

在前面幾篇文章中,我們已經介紹了高效能Python遺傳和進化演算法框架——Geatpy的使用及一些案例。

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

https://blog.csdn.net/qq_33353186/article/details/82020507

https://blog.csdn.net/qq_33353186/article/details/82047692

詳細的Geatpy官方教程文件在官網可以檢視:

http://geatpy.com/index.php/geatpy%E6%95%99%E7%A8%8B/

本篇就一個多目標優化例項進行展開講述,並且與使用Matlab工具箱進行對比:

回顧一下更新方法:

pip install --upgrade --user geatpy

下面對一個兩個目標的最小化問題進行求解:

先用Geatpy嘗試求解,先定義問題類MyProblem,然後編寫執行程式碼直接套用內建的moea_nsga2_templet進化演算法模板對問題進行求解:

# -*- coding: utf-8 -*-
import numpy as np
import geatpy as ea
"""
問題類定義
"""
class MyProblem(ea.Problem): # 繼承Problem父類
    def __init__(self):
        name = 'MyProblem' # 初始化name(函式名稱,可以隨意設定)
        # 定義需要匹配的句子
        M = 2 # 初始化M(目標維數)
        maxormins = [1] * M # 初始化maxormins(目標最小最大化標記列表,1:最小化該目標;-1:最大化該目標)
        Dim = 2 # 初始化Dim(決策變數維數)
        varTypes = [0] * Dim # 初始化varTypes(決策變數的型別,元素為0表示對應的變數是連續的;1表示是離散的)
        lb = [-5] * Dim # 決策變數下界
        ub = [5] * Dim # 決策變數上界
        lbin = [1] * Dim # 決策變數下邊界
        ubin = [1] * Dim # 決策變數上邊界
        # 呼叫父類構造方法完成例項化
        ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)
    def aimFunc(self, pop): # 目標函式
        x1 = pop.Phen[:, [0]]
        x2 = pop.Phen[:, [1]]
        pop.ObjV = np.zeros((pop.Phen.shape[0], self.M))
        pop.ObjV[:,[0]] = x1**4-10*x1**2+x1*x2+x2**4-x1**2*x2**2
        pop.ObjV[:,[1]] = x2**4-x1**2*x2**2+x1**4+x1*x2
"""
執行指令碼
"""
if __name__ == "__main__":
    """================================例項化問題物件============================="""
    problem = MyProblem()     # 生成問題物件
    """==================================種群設定================================"""
    Encoding = 'RI'           # 編碼方式
    NIND = 1000               # 種群規模
    Field = ea.crtfld(Encoding, problem.varTypes, problem.ranges, problem.borders) # 建立區域描述器
    population = ea.Population(Encoding, Field, NIND) # 例項化種群物件(此時種群還沒被初始化,僅僅是完成種群物件的例項化)
    """=================================演算法引數設定=============================="""
    myAlgorithm = ea.moea_NSGA2_templet(problem, population) # 例項化一個演算法模板物件
    myAlgorithm.MAXGEN = 100  # 最大進化代數
    """============================呼叫演算法模板進行種群進化========================="""
    NDSet = myAlgorithm.run() # 執行演算法模板,得到帕累托最優解集NDSet
    NDSet.save()              # 把結果儲存到檔案中
    # 輸出
    print('用時:%s 秒'%(myAlgorithm.passTime))
    print('非支配個體數:%s 個'%(NDSet.sizes))
    print('單位時間找到帕累託前沿點個數:%s 個'%(int(NDSet.sizes // myAlgorithm.passTime)))

執行結果如下:

其中moea_nsga2_templet的演算法模板原始碼可以參見:

https://github.com/geatpy-dev/geatpy/blob/master/geatpy/templates/moeas/nsga2/moea_NSGA2_templet.py

程式碼有詳細註釋,可以清晰看到多目標優化NSGAII演算法的詳細流程。

下面將用Matlab的遺傳演算法工具箱進行對比實驗:

clc,clear
% 定義目標函式
fun1 = @(x) x(1)^4-10*x(1)^2+x(1)*x(2)+x(2)^4-x(1)^2*x(2)^2; %min f1(x1,x2)
fun2 = @(x) x(2)^4-x(1)^2*x(2)^2+x(1)^4+x(1)*x(2); %min f2(x1,x2)

aimfuc = @(x) [fun1(x) fun2(x)]; %獲取目標函式控制程式碼
nvars=2;      %變數個數
lb=[-5,-5];   %下限
ub=[5,5];     %上限
A=[];b=[];    %線性不等式約束
Aeq=[];beq=[];%線性等式約束
tic           %開始計時
options=gaoptimset('paretoFraction',1,'populationsize',1000,'generations',100,'stallGenLimit',1,'TolFun',1e-100);
[x,fval] = gamultiobj(aimfuc,nvars,A,b,Aeq,beq,lb,ub,options);
time = toc    %結束計時
plot(fval(:,1),fval(:,2),'k.') %繪圖
fprintf('找到的前沿點數: %d\n', size(fval,1));
fprintf('平均每秒找到的前沿點數: %f\n', size(fval,1)/time);

執行結果如下:

對比發現Geatpy的效率比Matlab高出了一個數量級。嘗試增大所需要搜尋的帕累託前沿點的數量,Matlab變慢了一個數量級,而Geatpy的耗時基本穩定。如果把上面的1000個個體改為1萬,則Python耗時13.3秒,Matlab耗時55.25秒:

除了NSGA-II演算法外,Geatpy還支援適應性權法重法(awGA)、隨機權重法(rwGA)、NSGA-III、RVEA等。除了多目標優化,Geatpy還支援單目標優化、差分進化、組合優化、複雜約束優化、混合編碼優化等。相應的演算法均整合在演算法模板內,原始碼參見:

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

歡迎繼續跟進,感謝!

相關文章