LoginSignup
8
4

More than 3 years have passed since last update.

[最適化問題]Optuna vs Hyperopt

Last updated at Posted at 2019-12-04

はじめに

最適化フレームワークとして、OptunaHyperoptがあります。一体どちらが優れているのか気になったので、関数最適化問題を使って比較してみようと思います。
2つのフレームワークに関しては別記事で紹介しているので、そちらを参考にしてください。
Optunaを使って関数最適化をしてみる
Hyperoptを使って関数最適化をしてみる

比較実験

今回は

x^2+y^2+z^2

の最小化問題を最適化していきます。
試行ごとに結果が異なるため, 3回試行してみようと思います。

コード

今回、実験するために使用したコードは以下になります。

# -*- coding: utf-8 -*-
import optuna
import hyperopt
from hyperopt import hp
from hyperopt import fmin
from hyperopt import tpe
from hyperopt import Trials
import matplotlib.pyplot as plt

# optuna用の目的関数を設定(今回はx^2+y^2+z^2)
def objective_optuna(trial):
    # 最適化するパラメータを設定
    param = {
        'x': trial.suggest_uniform('x', -100, 100),
        'y': trial.suggest_uniform('y', -100, 100),
        'z': trial.suggest_uniform('z', -100, 100)
    }
    # 評価値を返す(デフォルトで最小化するようになっている)
    return param['x'] ** 2 + param['y'] ** 2 + param['z'] ** 2

# optunaで最適化実行
def optuna_exe():
    # studyオブジェクト生成
    study = optuna.create_study()
    # 最適化実行
    study.optimize(objective_optuna, n_trials=500)
    # ベストパラメータ表示
    print(study.best_params)
    # ベスト目的関数値を表示
    print(study.best_value)

    epoches = []    # 試行回数格納用
    values = []    # ベストvalue格納用
    best = 100000
    # best更新
    for i in study.trials:
        if best > i.value:
            best = i.value
        epoches.append(i.number + 1)
        values.append(best)
    return epoches, values

# hyperopt用の目的関数を設定
def objective_hyperopt(args):
    x, y, z = args
    return x ** 2 + y ** 2 + z ** 2

# hyperoptで最適化実行
def hyperopt_exe():
    # 探索空間の設定
    space = [
        hp.uniform('x', -100, 100),
        hp.uniform('y', -100, 100),
        hp.uniform('z', -100, 100)
    ]
    # 探索の様子を記録するためのオブジェクト
    trials = Trials()
    # 探索開始
    best = fmin(objective_hyperopt, space, algo=tpe.suggest, max_evals=500, trials=trials)
    # 結果を出力する
    print(best)
    epoches = [] # 試行回数格納用
    values = [] # ベストvalue格納用
    best = 100000
    # best更新
    for i, n in zip(trials.trials, range(500)):
        if best > i['result']['loss']:
            best = i['result']['loss']
        epoches.append(n+1)
        values.append(best)

    return epoches, values

def plot_graph():
    result_optuna = optuna_exe()
    result_hyperopt = hyperopt_exe()
    epoch_optuna = result_optuna[0]
    value_optuna = result_optuna[1]
    epoch_hyperopt = result_hyperopt[0]
    value_hyperopt = result_hyperopt[1]

    # グラフの描画
    fig, ax = plt.subplots()
    ax.set_xlabel("trial")
    ax.set_ylabel("value")
    ax.set_title("Optuna vs Hyperopt")
    ax.grid() # グリッド線を入れる
    ax.plot(epoch_optuna, value_optuna, color="red", label="Optuna")
    ax.plot(epoch_hyperopt, value_hyperopt, color="blue", label="Hyperopt")
    ax.legend(loc=0) # 凡例
    plt.show() # グラフ表示

if __name__ == '__main__':
    plot_graph()

実験結果1回目

Optuna:
'x': 0.2690396239515218,
'y': -1.75236444646743,
'z': 0.3724308175904496,
best_value:3.2818681863901693

Hyperopt:
'x': -2.9497423868903834,
'y': 0.13662455602710644,
'z': -3.844496541052724,
best_value:23.499800072493738
Figure_1.png

最終的なbest_valueはOptunaが優れていますね。
グラフより収束速度もOptunaが優れているかなといった感じですかね。

実験結果2回目

Optuna:
'x': 0.7811129871251672,
'y': 0.4130867942356189,
'z': 0.6953642534092288,
best_value:1.2643096431468364

Hyperopt:
'x': -3.7838067947126675,
'y': -2.595648793357423,
'z': -2.683504623035553,
best_value:28.255783580024783
Figure_2.png

2回目も1回目と同様、最終的なbest_valueと収束速度の面でOptunaが優れていますかね。

実験結果3回目

Optuna:
'x': -0.19339325990518663,
'y': -0.0030977352573082623,
'z': 0.4961595538587318,
best_value:0.2835848518257752

Hyperopt:
'x': 2.810074634010315,
'y': -1.2603362587820195,
'z': -0.7356174272489406,
best_value:10.026099933181214
Figure_3.png

3回目も最終的なbest_valueの値はOptunaが優れていました。収束速度はあまり変わらない気がしますね。

結論

最終的な最良目的関数値、収束速度の面でOptunaが優れている、との結論に至りました。
最適化問題をもう少し難しくしたら、差も大きく出るのだろうか...

8
4
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
8
4