結果の評価

Amplify-BBOpt では最適化結果や種々の履歴を取得することが可能です。

ここでは、『テスト関数に対する最適化例』で紹介の以下のサンプルプログラムに基づき結果情報等の取得方法を説明します。

from amplify_bbopt import Optimizer

#
# ...(rastrigin_function の定義や前処理、インポートなど)...
#

# ブラックボックス関数の定義
@blackbox
def func(input_x: list[float] = x_list) -> float:  # type: ignore
    return rastrigin_function(input_x)

#
# ...(クライアント定義など)...
#

# 最適化クラスのインスタンス化
optimizer = Optimizer(blackbox=func, trainer=KMTrainer(), client=client)

# 初期学習データの作成(最適化クラスのメソッド利用)
num_init_data = 10
optimizer.add_random_training_data(num_data=num_init_data)

# 最適化を実行
optimizer.optimize(num_iterations=100)

ベスト解の取得

実施した最適化サイクルの中で発見された、ブラックボックス関数の評価値が最小であるベスト解(ブラックボックス関数への入力)とそれに対応するブラックボックス関数値は、Optimizer.best を使って以下のようにして取得できます。

# 最適化結果の表示
print(f"{optimizer.best.values}")  # {'input_x': [0.12, 0.0, 0.0, -1.98, 0.0]}
print(f"{optimizer.best.objective}")  # 6.723966712641115

Tip

以下のように、ベスト解(入力値)に基づき、ブラックボックス関数を評価することも可能です。

# 最適化結果の表示
print(func(**optimizer.best.values))

ここで、** は、「辞書 (optimizer.best.values) の中身をキーワード引数として展開して渡す」という処理です。上記の場合、func(input_x=[0.12, 0.0, 0.0, -1.98, 0.0]) と同じ意味となります。

ヒストリー情報の取得

Optimizer.history は、全最適化サイクルの履歴であり、各最適化サイクルに関する様々な情報を格納した IterationResult のリストとなっています。history を使うことで、実施されたブラックボックス最適化に関する様々なヒストリー情報を取得することが可能です。

最適化履歴プロット例

ヒストリー情報から得られる情報を元に様々な履歴をプロットすることができます。

ブラックボックス関数値の推移

各最適化サイクルにおけるブラックボックス関数の評価値は以下のようにプロットすることが可能です。

# 初期学習データのサンプル数
num_initial_data = 10

# 初期学習データ
objectives_init = optimizer.training_data.y[:num_initial_data]

# アニーリングから直接得られたベスト解の履歴
objectives_annealing_best = [
    float(h.annealing_best_solution.objective) for h in optimizer.history
]

# フォールバック解も含めた最良解の履歴
objectives_all = [
    float(h.annealing_new_solution.objective)
    if h.fallback_solution is None
    else float(h.fallback_solution.objective)
    for h in optimizer.history
]

plt.plot(range(-num_initial_data + 1, 1), objectives_init, "blue")
plt.plot(range(1, len(objectives_all) + 1), objectives_all, "lightgrey")
plt.plot(range(1, len(objectives_annealing_best) + 1), objectives_annealing_best, "-r")

plt.xlabel("Cycle")
plt.ylabel("Objective value")

plt.grid(True)
_images/example_history.png

サイクル実行時間情報の推移

各最適化サイクル中の様々な時間情報のプロットは次のように構築することができます。ここでは、1サイクル当たりの総経過時間とアニーリング時間に要した時間、フォールバック処理に要した時間を表示します。

cycles = range(1, len(optimizer.history) + 1)

# 各サイクルの総経過時間
elapsed_total = [sum(h.timing) for h in optimizer.history]

# 各サイクルでアニーリングに要した時間
elapsed_annealing = [h.timing.minimization for h in optimizer.history]

# 各サイクルでフォールバック処理に要した時間
elapsed_fallback = [h.timing.fallback for h in optimizer.history]

plt.plot(cycles, elapsed_total, "-k")
plt.plot(cycles, elapsed_annealing, "-r")
plt.plot(cycles, elapsed_fallback, "lightgrey")

plt.xlabel("Cycle")
plt.ylabel("Elapsed time (s)")

plt.grid(True)
_images/example_history_timing.png

モデル情報の推移

各最適化サイクルにおいて考慮されるサロゲートモデル関数の性能(以下の例では相関係数)の推移は以下のようにプロットできます。

cycles = range(1, len(optimizer.history) + 1)

# 目的関数値の下位 25% サンプルに対する相関係数
tail_correlations = [
    h.surrogate_model_info.corrcoef[25] for h in optimizer.history
]

# 全サンプルに対する相関係数
all_correlations = [
    h.surrogate_model_info.corrcoef[100] for h in optimizer.history
]

plt.plot(cycles, tail_correlations, "-k")
plt.plot(cycles, all_correlations, "-r")

plt.xlabel("Cycle")
plt.ylabel("Correlation coefficient")

plt.grid(True)

_images/example_history_corrcoef.png

アニーリング情報の推移

各最適化サイクルにおけるイジングマシン実行結果 amplify.Result オブジェクトも取得可能です。amplify.Result 内に格納されている各種アニーリング実行情報(例:イジングマシンにおけるアニーリング実行時間)の推移は以下のようにプロットできます。

annealing_times = [
    h.amplify_result.client_result.execution_time.annealing_time.total_seconds()
    for h in optimizer.history
]

plt.plot(range(len(optimizer.history)), annealing_times)
plt.xlabel("Cycles")
plt.ylabel("Annealing time (s)")
plt.grid(True)
_images/example_history_annealing_time.png