LoginSignup
22
30

More than 3 years have passed since last update.

多目的最適化ライブラリのplatypusを使ってみる

Last updated at Posted at 2020-01-02

多目的最適化

多目的最適化とは, トレードオフの関係にある複数の目的関数を同時に最適化することです.
単目的最適化の場合は最適解は一つですが, 多目的最適化の場合は最適解は一つとは限りません. 多目的最適化における最適解はパレート最適解と呼ばれます. パレート最適解に関する図を下に示します.
multi.png

platypus

platypusは, 多目的最適化用のライブラリの一つであるようです.
具体的には, NSGA-II, NSGA-III, MOEA/D, IBEA, Epsilon-MOEA, SPEA2, GDE3, OMOPSO, SMPSO, Epsilon-NSGA-IIなど数多くの手法が使用可能なようです.

使用するにはpipでインストールしましょう.

pip install platypus-opt

テスト問題

Platypusには, テスト問題も用意されています.
今回は, DTLZ2というテスト問題を使用してみましょう.

from platypus import NSGAII, Problem, Real, nondominated, Integer
import matplotlib.pyplot as plt
from platypus.problems import DTLZ2

def main():
    # 問題, アルゴリズムを設定し, 探索実行
    problem = DTLZ2(2)
    algorithm = NSGAII(problem, population_size=100)
    algorithm.run(10000)

    # 非劣解をとりだす
    nondominated_solutions = nondominated(algorithm.result)

    # グラフを描画
    plt.scatter([s.objectives[0] for s in nondominated_solutions if s.feasible],
               [s.objectives[1] for s in nondominated_solutions if s.feasible])
    plt.show()

if __name__ == '__main__':
    main()

DTLZ2(2)として2目的問題として最適化した結果は以下のようになりました. パレート最適解が獲得されたのが確認できました.
pareto1.png

DTLZ2(3)として3目的問題としても最適化してみました.
pareto2.png

問題を作って最適化

Platypusでは, 自分で設定した問題を最適化することもできます.
まずは目的関数の設定をしましょう.
今回は2変数2目的最小化問題を最適化していきます. 以下2つを目的関数とします.

f(x)=2x_1^2+x_2^2
g(x)=-x_1^2-2x_2^2
# 目的関数の設定
def objective(vars):
    x1 = int(vars[0])
    x2 = int(vars[1])
    return [2*(x1**2) + x2**2, -x1**2 -2*(x2**2)]

目的関数の設定が終われば, 探索の設定をしていきましょう.
Problem(変数の数, 目的関数の数)で問題の設定ができます.

# 2変数2目的の問題
problem = Problem(2, 2)

problem.directions[:] = Problem.MINIMIZEで最小化問題として設定しています. 最大化問題としたいならProblem.MAXIMIZEで設定できます.
最小化, 最大化を混在させたいなら, 目的変数ごとに設定することもできます.
例えば, problem.directions[:] = [Problem.MINIMIZE, Problem.MAXIMIZE]などとすることができます.

# 最小化or最大化を設定
problem.directions[:] = Problem.MINIMIZE

次に決定変数の設定をしましょう.
今回は$x_1$と$x_2$ともに整数として, 範囲は$0\leq x_1\leq100$と$0\leq x_2\leq50$としています.
今回は決定変数を整数としていますが, 実数で扱いたい場合はIntegerをRealに変更すれば大丈夫です.

# 決定変数の範囲を設定
int1 = Integer(0, 100)
int2 = Integer(0, 50)
problem.types[:] = [int1, int2]

以上のコードをまとめると以下のようになります.

def main():
    # 2変数2目的の問題
    problem = Problem(2, 2)
    # 最小化or最大化を設定
    problem.directions[:] = Problem.MINIMIZE
    # 決定変数の範囲を設定
    int1 = Integer(0, 100)
    int2 = Integer(0, 50)
    problem.types[:] = [int1, int2]
    problem.function = objective
    # アルゴリズムを設定し, 探索実行
    algorithm = NSGAII(problem, population_size=50)
    algorithm.run(1000)

以下のような結果が得られました.
DTLZ2()のような滑らかな曲線ではないですが, パレート最適解を獲得することができました.
multi3.png

ちなみに以下のコードを追加することで, パレート最適解の情報をDataFrameに追加することができます.

df = pd.DataFrame(columns=("x1", "x2", "f1", "f2"))
for i in range(len(nondominated_solutions)):
    df.loc[i, "x1"] = int1.decode(nondominated_solutions[i].variables[0])
    df.loc[i, "x2"] = int2.decode(nondominated_solutions[i].variables[1])
    df.loc[i, "f1"] = nondominated_solutions[i].objectives[0]
    df.loc[i, "f2"] = nondominated_solutions[i].objectives[1]
df.to_csv("NSGAII.csv")

参考サイト

Platypus - Multiobjective Optimization in Python

22
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
30