[最適化問題]Optuna vs Hyperopt

#はじめに
最適化フレームワークとして、<font color="red">Optuna</font>と<font color="red">Hyperopt</font>があります。一体どちらが優れているのか気になったので、関数最適化問題を使って比較してみようと思います。
2つのフレームワークに関しては別記事で紹介しているので、そちらを参考にしてください。
[Optunaを使って関数最適化をしてみる](https://qiita.com/pontyo4/items/0a56528988c1e9e3a65e)
[Hyperoptを使って関数最適化をしてみる](https://qiita.com/pontyo4/items/31aa1d4527c7bf99759e)

#比較実験
今回は

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

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

```python
# -*- 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
<img width="400" alt="Figure_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319132/d19c2ebc-1306-9928-8057-a900de362676.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
<img width="400" alt="Figure_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319132/e974198a-b070-96f9-4513-9d79b41278dd.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
<img width="400" alt="Figure_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319132/1d5463e1-e48b-d23b-c9e7-c2ec596bb5ae.png">

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

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