結果の評価¶
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
を使うことで、実施されたブラックボックス最適化に関する様々なヒストリー情報を取得することが可能です。
IterationResult
に含まれる最適化サイクル情報説明に記載の「ユニーク解」、「フォールバック解」については、こちらを参照してください。
アトリビュート名
説明
各サイクルのアニーリングで直接得られたベスト解(必ずしもユニーク解ではない)
各サイクルのアニーリングで得られたユニーク解(ユニーク解が見つからなかったサイクルでは
None
)フォールバック解(フォールバック処理が発生しなかったサイクルでは
None
)実行時間に関する情報 (
Timing
クラス)各サイクルにおけるアニーリングで得られた
amplify.Result
クラスオブジェクトサロゲートモデルに関する情報 (
SurrogateModelInfo
クラス)Timing
に含まれる実行時間情報最適化サイクル中の各ステップ における処理にかかった時間を記録します。
アトリビュート名
説明
Step 1 (
train_surrogate()
) の実行時間 (単位: 秒)Step 2 (
minimize_surrogate()
) の実行時間 (単位: 秒)Step 2a (
find_unique_solution()
) の実行時間 (単位: 秒)Step 2b (
fallback_solution()
) の実行時間 (単位: 秒)Step 3 の実行時間 (単位: 秒)
Step 4 の実行時間 (単位: 秒)
SurrogateModelInfo
に含まれるモデル情報アトリビュート名
説明
Step 1
train_surrogate()
で構築されるサロゲートモデル関数による予測値とブラックボックス関数真値の Pearson 相関係数(詳細)。対象のサンプルは、下位パーセンタイルで定義されたもの。
最適化履歴プロット例¶
ヒストリー情報から得られる情報を元に様々な履歴をプロットすることができます。
ブラックボックス関数値の推移¶
各最適化サイクルにおけるブラックボックス関数の評価値は以下のようにプロットすることが可能です。
# 初期学習データのサンプル数
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)

サイクル実行時間情報の推移¶
各最適化サイクル中の様々な時間情報のプロットは次のように構築することができます。ここでは、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)

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

アニーリング情報の推移¶
各最適化サイクルにおけるイジングマシン実行結果 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)
