Optunaのver1.4.0より、多目的最適化(Multi-objective)機能が試験的に実装されたようなので、試しに使ってみました。
404 Not Found | Read the Docs
環境
Optuna 1.5.0
概観
単目的の時と同様に、以下のような流れで最適化が可能なようです。
- パラメータ範囲の設定とスコアの計算を行う関数objectivesを用意
- multi_objective.create_studyで最適化の設定
- optimizeで最適化を実行
def objectives(trial):
# optunaでのパラメータサーチ範囲の設定
# スコアの計算
return # スコアを返す
# optunaによる最適化呼び出し
study = optuna.multi_objective.create_study()
# 最適化の実行
study.optimize(objectives)
コード例
0から30の値をとる変数aとbからなる関数y1、y2において、y1を最小化し、y2は最大化する多目的最適化を試します。
y1とy2はトレードオフの関係のため、a=0で、bが適当な値がパレート解で望ましい値となる感じでしょうか。
変数範囲とスコアの計算
変数a,bの範囲とスコアを設定するobjectivesは以下のように書けます。
import optuna
def objectives(trial):
# optunaでのパラメータサーチ範囲の設定
a = trial.suggest_int('a', 0, 30)
b = trial.suggest_int('b', 0, 30)
# 評価関数
y1 = a**2 + b
y2 = b
return y1,y2
最適化の実行
optuna.multi_objective.create_studyで最適化の設定を行うようです。
directionsでスコア(y1,y2)は、最大化または最小化するかを設定します。
samplerには、遺伝的アルゴリズムなど以下のアルゴリズムが用意されているようです。
- optuna.multi_objective.samplers.BaseMultiObjectiveSampler
- optuna.multi_objective.samplers.NSGAIIMultiObjectiveSampler
- optuna.multi_objective.samplers.RandomMultiObjectiveSampler
optimizeで最適化を実行し、n_trialsで試行回数が設定されています。
# optunaによる最適化呼び出し
study = optuna.multi_objective.create_study(directions=["minimize", "maximize"],
sampler=optuna.multi_objective.samplers.NSGAIIMultiObjectiveSampler())
study.optimize(objectives, n_trials=200)
得られたパレート解の取得
get_pareto_front_trials()で試行結果のうちのパレート解を取得できるようです。
a=0または1で、b=0~30で、パレート解が得られているような感じがします。
# パレート解の表示
trials = {str(trial.values): trial for trial in study.get_pareto_front_trials()}
trials = list(trials.values())
trials.sort(key=lambda t: t.values)
for trial in trials:
print("Trial#{}".format(trial.number))
print(" Values: y1={}, y2={}".format(trial.values[0], trial.values[1]))
print(" Params: {}".format(trial.params))
実行結果
Trial#156 Values: y1=1.0, y2=0.0 Params: {'a': 1, 'b': 0} Trial#194 Values: y1=2.0, y2=1.0 Params: {'a': 1, 'b': 1} Trial#123 Values: y1=3.0, y2=3.0 Params: {'a': 0, 'b': 3} Trial#172 Values: y1=7.0, y2=6.0 Params: {'a': 1, 'b': 6} Trial#131 Values: y1=11.0, y2=10.0 Params: {'a': 1, 'b': 10} Trial#193 Values: y1=15.0, y2=14.0 Params: {'a': 1, 'b': 14} Trial#164 Values: y1=20.0, y2=19.0 Params: {'a': 1, 'b': 19} Trial#130 Values: y1=25.0, y2=25.0 Params: {'a': 0, 'b': 25} Trial#152 Values: y1=30.0, y2=30.0 Params: {'a': 0, 'b': 30}
コード例 全体
import optuna
def objectives(trial):
# optunaでのパラメータサーチ範囲の設定
a = trial.suggest_int('a', 0, 30)
b = trial.suggest_int('b', 0, 30)
# 評価関数
y1 = a**2 + b
y2 = b
return y1,y2
# optunaによる最適化呼び出し
study = optuna.multi_objective.create_study(directions=["minimize", "maximize"],
sampler=optuna.multi_objective.samplers.NSGAIIMultiObjectiveSampler())
study.optimize(objectives, n_trials=200)
# パレート解の表示
trials = {str(trial.values): trial for trial in study.get_pareto_front_trials()}
trials = list(trials.values())
trials.sort(key=lambda t: t.values)
for trial in trials:
print("Trial#{}".format(trial.number))
print(" Values: y1={}, y2={}".format(trial.values[0], trial.values[1]))
print(" Params: {}".format(trial.params))
コメント