Evaluator#

Layer 2: Compose

OptimizationStrategy は EvaluationPlan を作り、Evaluatorへ評価を委譲します。

Evaluatorの役割#

同期・非同期の二つの評価境界で受け取る値と返す値は次のとおりです。

境界

受け取る値

返す値

主な利用者

graph-native境界

GenomeBatch → EvaluationAdapter → EvaluationPayload、候補ID、提案関係、メタデータ

部分的・順不同・反復を含む ObservationBatch

Evaluator、非同期Scheduler、構造化ランタイム

Stage互換境界

x、Problem、EvaluationRequest

EvaluationResult(f、g、cv、任意の candidate_ids)

互換Stage、sequential compatibility ランタイム

Evaluatorまたは非同期Schedulerへ渡されるRequestは、候補IDと評価対象を識別する情報を持ちます。評価が同期か非同期かは、パイプライン側の候補生成契約を変えずにEvaluatorとランタイムプロバイダーで切り替えられます。EvaluationAdapterはGenomeBatchをEvaluatorが受け取るEvaluationPayloadへ変換します。Evaluatorはペイロードを評価し、観測の対応付けを候補ID、提案関係、順序、状態、出所、完了の意味論で行い、行位置を前提にしません。

Stage互換経路ではEvaluator.evaluate_batch(...) -> EvaluationResultを使います。EvaluationRequestはRequest ID、候補ID、GenomeBatch、メタデータを保持します。互換性境界でのみ、EvaluationResultはf、g、cvの形状と行数の規則を満たす必要があります。candidate_idsを指定した場合は一意で、結果の行数と一致しなければなりません。Evaluator.submitがcandidate_idsを返す場合、それらはリクエストの候補IDと完全に一致しなければなりません。外部のObservationBatchに行順を使わせる必要はありません。

EvaluationResult は、評価結果の配列と候補IDを保持するデータクラスです。

  • f:目的値。形状は (n, n_obj)。

  • g:生の制約値。形状は (n, n_constraints)。制約がない場合は (n, 0)。

  • cv:候補ごとの集約制約違反。形状は (n,)。制約がない場合はすべて 0。

  • candidate_ids:結果の各行に対応する候補ID。

組み込みEvaluator#

クラス

パラメータ

特徴

SerialEvaluator

なし

候補を1件ずつ逐次評価する。既定値

JoblibEvaluator

n_jobs=-1, backend="loky", **joblib_kwargs

joblib.Parallel経由で候補を並列評価する

ThreadPoolEvaluator

Executorのオプション

スレッドプールを使った同期バッチ評価

AsyncEvaluator

アダプターとスケジューラーのオプション

リクエストを送信し、ノンブロッキングなライフサイクル操作を公開します

JoblibEvaluatorを使うにはparallel追加機能(pip install saealib[parallel])が必要で、未インストールなら構築時にImportErrorが発生します。backendの既定値"loky"はcloudpickleでシリアライズするプロセスプールですが、1つのパラメータ変更で"dask"/"ray"などのサードパーティ製バックエンドに切り替えられます(対応パッケージとクラスタは別途必要です)。複数のJoblibEvaluatorを同時に使う構成(アイランドモデルなど)ではCPUコアを過剰予約することがあります。各アイランドのn_jobsを1に制限してアイランド間の並列性で全体を制御するか、joblib.parallel_backendをコンテキストマネージャとして使って内部ワーカー数を制限してください。完了時刻が独立している場合は、AsyncEvaluator、SteadyStateStrategy、AsyncEvaluationScheduler、Optimizer.set_async_evaluation_scheduler()を組み合わせます。各候補は保留中のRequestとして管理され、Schedulerは容量、予算、Requestの状態を管理します。collect(wait=False)は完了を待たずに進捗を返し、PopulationとArchiveの更新順序はRuntimeが管理します。

同期EvaluatorはOptimizer.set_evaluator(evaluator)で差し替えます。

EvaluationRequest.metadataは、明示的な実行プランナーを公開するEvaluatorが消費します。 RepeatedEvaluationは、安定した候補IDを持つリクエストを複製ごとに1つずつ含むEvaluationPlanを返します。 Schedulerが容量、予算、リクエストのライフサイクルを管理します。

独自Evaluatorの実装方法#

次の例は、evaluate_batch()を実装するStage互換の同期Evaluatorです。ベクトルでないGenomeでは、評価関数に渡すペイロードをEvaluationAdapterで定義します。

import numpy as np
from saealib import EvaluationResult, Evaluator


class ReversedOrderEvaluator(Evaluator):
    """An Evaluator that evaluates candidates in reverse order, from the end."""

    def evaluate_batch(self, x, problem):
        x = np.atleast_2d(np.asarray(x, dtype=float))
        n = len(x)
        f = np.empty((n, problem.n_obj), dtype=float)
        g = np.empty((n, problem.n_constraints), dtype=float)
        cv = np.zeros(n, dtype=float)
        for i in reversed(range(n)):
            g_i, cv_i = problem.evaluate_constraints(x[i])
            f[i] = problem.evaluate(x[i], g_i)
            g[i] = g_i
            cv[i] = cv_i
        return EvaluationResult(f=f, g=g, cv=cv)

problem.evaluate_constraints(xi) を problem.evaluate(xi, g_i) より先に呼び出す順序を維持します。ConstraintHandler は制約値を使って目的値を補正するため、この順序を逆にすると補正が正しく適用されません。

関連コンポーネント#

  • Problem:evaluate_batch が評価する目的関数と制約関数の定義

  • ConstraintHandler:problem.evaluate内で制約違反を集約し、目的値を補正します

  • Initializer:初期個体群の評価にEvaluatorを使う

  • strategies:各世代の候補評価にEvaluatorを使う

  • Feedback:評価結果をAlgorithmへ渡すFeedbackの構成

参照#