nekonookangae / SummarizePapers

個人用。翻訳した論文をIssuesにまとめていきます。
1 stars 0 forks source link

pymoo: Getting Started #19

Open nekonookangae opened 4 years ago

nekonookangae commented 4 years ago

Getting Started

以下では、最適化シナリオの例を提示してpymooを紹介します。 このガイドでは、フレームワークを使い始めるための基本的な手順を説明します。 このガイドは次のように構成されています。

  1. 多目的最適化の紹介と模範的なテスト問題
  2. 問題の実装(ベクトル化、要素ごとまたは関数の)
  3. アルゴリズムの初期化(このガイドではNSGA2)
  4. 終了基準の定義
  5. 最適化(最小化関数、もしくはnext()を呼び出してオブジェクト指向にする)
  6. 結果と収束の可視化
  7. 概要
  8. ソースコード(一つ)

独自の最適化問題の最適化を開始するために従う必要のある重要な手順をカバーするように努めており、多目的最適化で特に重要であることが知られているいくつかの事後分析も含まれています。

1.はじめに

多目的最適化

一般に、多目的最適化にはいくつかの目的関数があり、最適化するために不等式と等式の制約を受けます。 目標は、制約違反がなく、そのすべての目的値に関して可能な限り優れた一連の解集合を見つけることです。 一般的な形式での問題の定義は、次のようになります。

スクリーンショット 2020-09-06 8 38 49

上記の定式化は、𝑁個の変数、𝑀個の目的、𝐽個の不等式、および𝐾個の等式制約を持つ多目的最適化問題を定義します。 さらに、変数𝑥𝑖ごとに、変数の上限と下限(𝑥𝐿𝑖および𝑥𝑈𝑖)が定義されます。

テスト問題

以下では、2つの制約を使用した二目的最適化を例として調査します。 実証のために十分な複雑さを持ちながらも、全体の考え方を見失うことがないように、適切な最適化問題を選択することを試みました。問題の定義は次のように与えられます。

スクリーンショット 2020-09-06 8 39 51

これは、𝑓1(𝑥)が最小化、𝑓2(𝑥)が最大化の2つの目的(𝑀= 2)で構成されます。 最適化には、2つの不等式制約(𝐽= 2)が適用されます。 ここで、𝑔1(𝑥)は「より小さい(内側)」として、𝑔2(𝑥)は「より大きい(外側)」制約として定式化されます。 問題は2つの変数(𝑁= 2)𝑥1と𝑥2に関して定義され、どちらも[-2,2]の範囲にあります。 問題には等式制約が含まれていません(𝐾= 0)。

image

上の図は、問題の輪郭を示しています。 目的関数𝑓1(𝑥)の等高線は実線で、𝑓2(𝑥)は破線で表されます。 制約𝑔1(𝑥)および𝑔2(𝑥)は、(0.1,0.9)および(0.4,0.6)で𝑥1軸と交差する放物線です。 オレンジ色の太い線は、パレート最適セットを示しています。 両方の制約の組み合わせにより、パレートセットは2つの部分に分割されます。 分析的に、パレート最適セットは𝑃𝑆= {(𝑥1、𝑥2) | (0.1≤𝑥1≤0.4) ∨ (0.6≤𝑥1≤0.9) ∧ 𝑥2= 0}で与えられ、パレートフロントは𝑓2=(√(𝑓1) −1)^2で定義されます。 ここで、𝑓1は[0.01,0.16]および[0.36,0.81]です。

2.問題の実装

pymooでは、すべてのモジュールで最適化のために最小化問題を考慮します。 ただし、一般性を失うことなく、最大化されるはずの目標に-1を掛けて最小化することができます。 したがって、最適化問題では𝑓2(𝑥)を最大化する代わりに、−𝑓2(𝑥)を最小化します。 さらに、すべての制約関数は ≤0 制約として定式化する必要があります。 したがって、解集合の実現可能性は次のように表すことができます。

image

このため、≥を≤の関係に反転するには、𝑔2(𝑥)に-1を掛ける必要があります。 それぞれに同等の重要性を与えるために、制約の正規化をお勧めします。 𝑔1(𝑥)の場合、係数の結果はそれぞれ2・(-0.1)・(-0.9) = 0.18になり、𝑥2(𝑥)の場合は20⋅(-0.4)⋅(-0.6) = 4.8になります。 𝑔1(𝑥)と𝑔2(𝑥)を対応する係数で除算することにより、制約の正規化を実現します。

最後に、pymooを使用して最適化される最適化問題は、次のように定義されます。 この入門ガイドは、問題を定義する3つの異なる方法を示しています。

・クラス  ・ベクトル化された評価:解のセットが直接評価されます。  ・要素ごとの評価:一度に評価される解は1つだけです。 ・関数:他の最適化ライブラリで一般的に定義されている関数インターフェース。

オプション:最適化問題のパレートセットとフロントを定義して、分析的に導出された最適化/最適化への収束を追跡します。

目的に最も適した実装を選択してください。

クラス

クラスを通じて問題を定義すると、変数や目的の数などのメタデータが既知であると仮定して、問題を非常に自然に定義できます。 問題はProblemクラスから継承されます。 コンストラクタinitでsuper()関数を呼び出すことにより、変数の数n_var、目的関数n_obj、制約n_constrなどの問題のプロパティが初期化されることになっています。 さらに、下限xlと上限変数の境界xuは、NumPy配列として提供されます。 私たちのフレームワークのほとんどのアルゴリズムでは、下限と上限を指定する必要があり、負または正の無限大に等しくないことに注意してください。 最後に、評価関数_evaluateを上書きして、目的値と制約値を計算する必要があります。

ベクトル化された評価

_evaluateメソッドは、n行とm列の2次元のNumPy配列Xを入力として受け取ります。 各行は個体を表し、各列は最適化変数を表します。 必要な計算を行った後、目的の値をキーFで辞書に追加し、キーGで制約を追加する必要があります。

注:ほとんどのアルゴリズムでは、このメソッドはiterationごとに1回だけ呼び出されます。   これにより、独自の並列化を自由に実装できます。

import numpy as np from pymoo.model.problem import Problem

class MyProblem(Problem):

def __init__(self):
    super().__init__(n_var=2,
                     n_obj=2,
                     n_constr=2,
                     xl=np.array([-2,-2]),
                     xu=np.array([2,2]))

def _evaluate(self, X, out, *args, **kwargs):
    f1 = X[:,0]**2 + X[:,1]**2
    f2 = (X[:,0]-1)**2 + X[:,1]**2

    g1 = 2*(X[:, 0]-0.1) * (X[:, 0]-0.9) / 0.18
    g2 = - 20*(X[:, 0]-0.4) * (X[:, 0]-0.6) / 4.8

    out["F"] = np.column_stack([f1, f2])
    out["G"] = np.column_stack([g1, g2])

vectorized_problem = MyProblem()

要素ごとの評価

_evaluateメソッドは、n_varに等しい1次元のNumPy配列xエントリ数を受け取ります。 この動作は、super()メソッドを呼び出すときにelementwise_evaluation = Trueを設定することで有効になります。

注:このメソッドは、各解の各反復で1回だけ呼び出されます。

import numpy as np from pymoo.util.misc import stack from pymoo.model.problem import Problem

class MyProblem(Problem):

def __init__(self):
    super().__init__(n_var=2,
                     n_obj=2,
                     n_constr=2,
                     xl=np.array([-2,-2]),
                     xu=np.array([2,2]),
                     elementwise_evaluation=True)

def _evaluate(self, x, out, *args, **kwargs):
    f1 = x[0]**2 + x[1]**2
    f2 = (x[0]-1)**2 + x[1]**2

    g1 = 2*(x[0]-0.1) * (x[0]-0.9) / 0.18
    g2 = - 20*(x[0]-0.4) * (x[0]-0.6) / 4.8

    out["F"] = [f1, f2]
    out["G"] = [g1, g2]

elementwise_problem = MyProblem()