Initializer#
実行の開始時に、Optimizerは初期Population、Archive、ParetoArchive、OptimizationStateの構築をInitializerへ委譲します。
サンプリング方法を変える場合は、Optimizer全体ではなくInitializerを差し替えます。
現行の標準経路では、GenomeInitializer が Problem.space からGenomeをサンプリングします。
LHSInitializer、RandomInitializer、SobolInitializer は、ベクトルの x 配列を使う互換性用Initializerとして残っています。
Initializerの役割#
Initializer の実装境界は initialize(provider, problem) -> OptimizationState です。
provider は、AlgorithmやEvaluatorなど、すでに構築されたComponentへアクセスするためのProviderです。
problem は対象となる Problem です。
組み込みInitializer#
クラス |
サンプリング方法 |
|---|---|
|
|
|
|
|
|
|
|
GenomeInitializerは、SearchSpaceが提供するGenomeを直接Archiveへ登録します。
他の3クラスはコンストラクタ(n_init_archive, n_init_population, seed=None)を共有し、ベクトル形式で初期点を生成します。
4クラスとも、初期Archiveを評価し、Comparatorでランク付けしたうえで、上位の候補を初期Populationへ渡します。
Sample (n_init_archive points)
-> Evaluate via provider.evaluator.evaluate_batch
-> add to archive / pareto_archive
-> Rank via problem.comparator.rank_population
-> Feed the top n_init_population into population
これは、前回の選択の状態を再利用するのではなく新しく組み立てたArchiveをランク付けするため、sort_populationを直接ではなくrank_populationを呼び出します——両者の違いはComparatorを参照してください。
SPEA2ComparatorのようなComparatorにとっては、これが初期Populationにその永続化されたランキング状態(spea2_fitness)を最初に書き込む場所でもあります。
3クラスの実装はサンプリング方法の1行以外ほぼ重複していますが、これは意図的な単純さの選択であり、共通処理を過度に抽象化しない設計になっています。
基底クラスのヘルパーメソッド#
Initializer基底には、独自実装で再利用できる2つのヘルパーメソッドが用意されています。
_create_attrs(problem, provider):PopulationとArchive用のPopulationAttribute値を構築します。
レガシーなベクトル経路ではx/f/g/cv/idを使い、続けてAlgorithm(Algorithm.get_required_attrs)とComparator(Comparator.get_required_attrs)の両方が要求する補助属性を統合します——例えばSPEA2Comparatorのspea2_fitness属性がスキーマに加わるのはこの仕組みによるものです。
GenomeInitializerはGenomeを専用カラムで管理するため、標準属性にxは含まれません。
_create_context(problem, archive, pareto_archive, population, rng):OptimizationState を構築します。
Comparatorが NSGA3Comparator で内部乱数生成器をまだ持たない場合は、ここで rng.spawn(1)[0] を設定します。
独自Initializerの実装方法#
独自のベクトルサンプリングを追加する場合は Initializer を継承して initialize() を実装します。
新しいGenome表現を使う場合は、Problem.space.sample() と Problem.space.validate() を使うInitializerを実装します。
Genome-nativeな初期化では、次の順序を保ちます。
Algorithmの
population_class、archive_class、create_pareto_archive()で入れ物を作る。OptimizationStateを構築する。problem.space.sample(n, rng)でGenomeを生成し、problem.space.validate()で検証する。provider.evaluator.evaluate_batch(genomes, problem)で評価する。候補ID、Genome、評価結果をArchiveとParetoArchiveへ登録する。
評価回数を更新し、Comparatorで並べた候補をPopulationへ渡す。
次の骨格は、Genome-nativeなInitializerが使う入力と出力の境界を示しています。
from saealib import GenomeInitializer
class CustomGenomeInitializer(GenomeInitializer):
def initialize(self, provider, problem):
# Replace problem.space.sample() with custom sampling.
# Validate each generated Genome with space.validate() before passing it to the Evaluator.
...
初期評価の開始と終了は CallbackManager から観測できます。
評価Requestの候補IDとGenomeを維持する必要があるため、Genomeを x 配列へ暗黙に変換して管理しません。
Optimizer.set_initializer(initializer) でInitializerを差し替えます。
関連コンポーネント#
OptimizationState:
initialize()が最終的に返す状態オブジェクトPopulation:構築対象の
Population/Archive/ParetoArchiveEvaluator:初期サンプルの評価に使う
CallbackManager:
InitialEvaluationStartEvent/InitialEvaluationEndEventの観察Comparator:初期Archiveのランク付けに使う
rank_population