CallbackManager#
Optimizerは、実行経過を外部へ通知する処理をCallbackManagerに委譲します。
CallbackManagerは、ログ記録、収束履歴の収集、条件判断などの観測をサポートします。
Eventは実行境界を観測するものであり、Eventのフィールドを変更してもPipelineの入力は差し替わりません。
CallbackManagerの役割#
CallbackManagerは、イベント型ごとにハンドラのリストを保持します。
Method |
Description |
|---|---|
|
イベント型 |
|
登録順に、登録されたすべてのハンドラを呼び出します |
|
登録されたハンドラを削除します |
|
登録されたハンドラを別のハンドラに置き換えます |
Eventのctxは、archive、comparator、n_obj、gen、feなどの値を読み取るための_EventContext Protocolです。
通常のsequential実行では実体がOptimizationStateですが、Eventの公開契約はそれらを読み取る能力に限定されます。
ctxは読み取り専用として扱い、値を変更するときはwith_post、Component、Stageなどの正式な境界を使います。
利用可能なイベント一覧#
Event |
Fired when |
Main fields |
|---|---|---|
|
実行開始時に1回 |
— |
|
実行終了時に1回 |
— |
|
各世代の開始時 |
— |
|
各世代の終了時(stateがyieldされる前) |
— |
|
Surrogateベースのスコアリングの前後 |
|
|
acquisitionスコアリングの前後 |
開始時は |
|
crossoverとrepairの後 |
|
|
mutationとrepairの後 |
|
|
|
|
|
surrogateのfit後 |
|
|
選択された候補のtrue evaluation後 |
|
|
初期サンプリング後、初期評価前 |
|
|
初期評価後、archiveのソート前 |
|
PostSurrogateFitEventは、Surrogateのfit後に組み込みStageから発火します。
組み込みStageが発火するイベントでは、train_xとtrain_fが設定されない場合があります。
PostEvaluationEventには、評価済みのoffspringに加えてrequest_id、candidate_ids、statusが含まれる場合があります。
既定のログ出力#
Optimizerは構築時にlogging_generationをGenerationStartEventへ自動登録します。
標準ライブラリのloggingモジュールを設定すると、世代ごとの進捗(評価回数、最良目的値、または多目的の場合は第一フロントのサイズと範囲)がログに出力されます。
カスタムハンドラの登録と収束履歴の記録#
cbmanager.register(EventType, handler)で任意のハンドラを登録します。
収束履歴を記録するには、クロージャで蓄積するリストを保持するハンドラを登録します。
from saealib import GenerationEndEvent
history = []
def record_best(event):
f = event.ctx.archive.get_array("f")
history.append(float(f.min()))
optimizer.cbmanager.register(GenerationEndEvent, record_best)
ctx = optimizer.run()
print(history)
ハイパーボリュームの追跡#
logging_generation_hv(reference_point)は、指定したreference pointに対する第一フロントのhypervolumeを世代ごとにログへ出力するハンドラを返します。
from saealib import GenerationStartEvent, logging_generation_hv
optimizer.cbmanager.register(
GenerationStartEvent,
logging_generation_hv(reference_point=np.array([1.1, 1.1])),
)
既定ハンドラの差し替え#
自動登録されたlogging_generationはunregister(event_type, func)で削除でき、replace(event_type, old, new)で別のハンドラに置き換えられます。
from saealib import GenerationStartEvent, logging_generation
optimizer.cbmanager.unregister(GenerationStartEvent, logging_generation)
candidatesフィールドは観測専用#
PostCrossoverEvent/PostMutationEvent/PostAskEventのcandidatesフィールドは観測用です。ハンドラ内で再代入しても(event.candidates = new_array)、Pipelineの出力には影響しません。
Event発火後もGAは自身のローカルな配列参照を使い続けるため、インプレースの変更(event.candidates[:] = ...)はGAに反映されます。
一方、PSOはPopulation.extend()が候補をコピーし終えた後にこのイベントを発火するため、インプレースの変更でも遅すぎてまったく影響しません。
候補配列そのものを差し替えたい場合は、CallbackManagerではなくCrossover/Mutationのwith_post(fn)を使ってください。
CallbackManagerは設計上、観測(ログ、記録、条件付きの分岐判断)のための仕組みであり、Pipelineデータを書き換える手段ではありません。
実行時の構成切り替え#
Eventは観測用であり、CallbackクロージャからOptimizerの内部を直接変更するのは標準的な手順ではありません。
データフローを変更するにはwith_post()またはwith_post_fit()を使い、実行構成はiterate()またはrun()のステップ境界で切り替えます。
ステップ境界でoptimizer.set_*()またはコンポーネント属性が変更されると、実行環境が変更を検出してプランを再コンパイルし、次の世代から適用します。
この手順はStage互換パスとgraph-nativeパスの両方で機能します。
Componentが要求する再コンパイル経路については、OptimizationStrategyの「実行時の差し替えの動作」を参照してください。
CallbackハンドラはRuntimeCommandを返せません。
Callbackクロージャでoptimizer.set_*()を呼び出した変更は上述の経路で適用されますが、構成変更はiterate()側の手順として文書化されています。
CallbackManagerとiterate()の使い分け#
Aspect |
CallbackManager |
|
|---|---|---|
呼び出しの粒度 |
特定のイベントが発生したとき |
世代ごと(ホスト側の |
主な用途 |
ログ、観測、条件付きの副作用 |
ループ構造そのものへの介入(例:surrogateの精度に基づくコンポーネントの切り替え) |
|
|
|
Surrogate accuracy evaluation and dynamic switchingのswitcherクラスは、iterate()ループ内で使うことを想定しています。
チェックポイントコールバック#
CheckpointCallbackはCallback実装の例です。
npz形式ではOptimizationState.save()を使い、pickle形式ではOptimizer.save_pickle()を使います。
形式によって保存対象の値と再開条件が異なるため、詳細はCheckpointingを参照してください。
このCallbackをカスタムCallback登録の参考にしてください。
関連コンポーネント#
Extension guidelines:
with_post形式のフックを使う場面strategies: 実行時のコンポーネント差し替えが有効になる時点
Surrogate accuracy evaluation and dynamic switching:
iterate()ループ内での動的な切り替えCheckpointing:
CheckpointCallbackの使い方