重みの動的調整

MultiOptimizer を使った多目的最適化では、各目的関数のサロゲートモデルが合算されて 1 つの多項式となり、その和が最小になる解をイジングマシンで探索します。デフォルトでは各サロゲートモデルの重み weight1.0 です。

この重みを動的に変化させたい場合は、最適化サイクルをカスタマイズすることで実装することができます。

実装方法

各イテレーションで train_surrogate() を呼んだ後、各サロゲートモデルの weight を更新してから minimize_surrogate() を実行します。

下記の例では、各目的関数のそれまでの最大絶対値で正規化することで、スケールが異なる目的関数を均等に扱っています。

import numpy as np
from amplify_bbopt import KMTrainer, MultiOptimizer, blackbox, RealVariable

@blackbox
def bbfunc(
    x: float = RealVariable((0, 1)),
    y: float = RealVariable((0, 1)),
    z: float = RealVariable((0, 1)),
) -> list[float]:
    return [g(x, y), h(y, z)]

optimizer = MultiOptimizer(
    blackbox=bbfunc,
    trainer=[KMTrainer(), KMTrainer()],
    client=my_client,
)
optimizer.add_random_training_data(num_data=10)

num_cycles = 10

for n_iter in range(num_cycles):
    # Step 1: サロゲートモデル関数の構築
    optimizer.train_surrogate()

    # 学習済みモデルに適用する重み(スケーリング)を計算して適用
    # optimizer.surrogate_model は SurrogateModel のリスト(目的関数ごとに 1 要素)
    for i, sm in enumerate(optimizer.surrogate_model):
        # 今までの目的関数値に基づき、動的に重みを決定
        scale = np.abs(optimizer.training_data.y[:, i]).max()
        if scale > 0:
            sm.weight = 1 / scale

    # Step 2: イジングマシンによるサロゲートモデル関数の最適化 (最小化)
    solutions, _ = optimizer.minimize_surrogate()
    if len(solutions) == 0:
        raise RuntimeError(f"No feasible solution was found in iteration {n_iter}")

    # Step 3: データセットの更新
    new_solution = solutions[0]
    new_objective = optimizer.evaluate_objective(new_solution)
    optimizer.add_solution(new_solution, new_objective)

重みを変えた場合のベスト解の扱い

best は、各目的関数値にサロゲートモデルの現在の重みを掛けた加重和が最小の解を返します。しかし重みを動的に更新する場合、各イテレーションで異なる重みが使われていたにもかかわらず、best は全サンプルを現在の重みで一律に再評価するため、一貫した比較にはなりません。

独自の基準でベスト解を選定したい場合は、history を参照してください。