乱数と再現性
探索のいくつかの段階で乱数を使います。random_search での候補の選択、
ハイパーパラメータ学習の初期値とミニバッチ、ベイズ線形モデル
(num_rand_basis > 0)のランダムフーリエ基底、Thompson sampling
(score="TS")の事後サンプル、1 ステップに複数点を提案するとき
(num_search_each_probe > 1)の仮想観測値、range 系 policy における
獲得関数のランダム最適化、ParEGO の重みです。
これらの乱数はすべて、policy がコンストラクタの rng 引数で選ぶ
乱数生成器から引かれます。rng 引数はすべての policy
(discrete、discrete_multi、discrete_unified、range、
range_multi、range_unified)が受け付けます。
2 つのモード
legacy モード(デフォルト)。
rng を与えない(または rng="legacy")場合、policy は従来の
PHYSBO と同じくグローバルな numpy.random の状態から乱数を引きます。
set_seed() はこのグローバル状態に seed を設定するので、
numpy.random.seed や policy.set_seed を呼ぶスクリプトは
これまでと同じ結果を与え続けます。この状態は、プロセス内で
numpy.random を使う他のすべてのコードと共有されます。
Generator モード。
rng に整数の seed、numpy.random.SeedSequence、または
numpy.random.Generator を与えると、policy は自分専用の
numpy.random.Generator を持ち、乱数をそこからだけ引きます。
グローバルな numpy.random の状態は読みも書きもしないので、
プロセスの他の部分が numpy.random をどう使っても探索は再現され、
生成器は policy オブジェクトの一部になります。policy を pickle すると
その状態も保存されます(チェックポイントと再開 を参照)。
このモードでは set_seed(seed) は seed から生成器を作り直します。
乱数列は legacy モードとは異なるので、Generator モードでの実行は
同じ seed を使っても以前のバージョンの実行を再現しません。
# legacy モード: グローバルな numpy.random の状態を set_seed() で設定
policy = physbo.search.discrete.Policy(test_X=X)
policy.set_seed(0)
# Generator モード: seed 12345 で初期化した policy 専用の生成器
policy = physbo.search.discrete.Policy(test_X=X, rng=12345)
# Generator モード: 呼び出し側で作った生成器を渡す
rng = numpy.random.default_rng(12345)
policy = physbo.search.discrete.Policy(test_X=X, rng=rng)
どちらのモードでも、同じ PHYSBO のバージョンを同じ環境 (Python、NumPy、SciPy のバージョン、BLAS/LAPACK ライブラリ)で使えば、 同じ seed は同じ探索を与えます。
補助オブジェクト
policy に渡すオブジェクトのうち自身で乱数を引くものは、独自の生成器を 与えられていない限り policy の生成器に従います。
physbo.search.unify.ParEGOはrng属性を通して重みを引きます。rng引数なしでbayes_searchのunify_methodに渡すと policy の生成器を使い、ParEGO(..., rng=...)とすれば与えた生成器を 使い続けます。range 系 policy のデフォルトのランダム最適化器は policy の生成器で 作られます。呼び出し側で作る最適化器は自身の
rng引数を取ります。 例:physbo.search.optimize.random.Optimizer(min_X, max_X, nsamples=1000, rng=policy.rng)組み込みの Thompson sampling オブジェクト (
physbo.search.score.ThompsonSamplingとphysbo.search.score_multi.ThompsonSampling)も同様にrng属性を 通して乱数を引きます。名前"TS"とrngなしで作ったインスタンスは policy の生成器を使い、ThompsonSampling(..., rng=...)とすれば与えた 生成器を使い続けます。ユーザー定義のスコア(アルゴリズムの章を参照)は 自身が使う乱数源から引き、policy の生成器とは結び付きません。
並列実行
並列実行(comm にコミュニケータを渡した場合)では、すべての rank で
policy に同じ rng 指定を与えてください。全 rank が一致させる必要の
ある量は rank 0 で引いてブロードキャストします。モデルのハイパー
パラメータ、ランダムフーリエ基底、ベイズ線形モデルでの Thompson
sampling の事後サンプル、離散 policy における複数点提案の仮想観測値、
ランダム最適化器が返す点、シミュレータの結果がこれにあたります。それ以外の乱数は各 rank
が自分の担当する候補について引きます。その結果、各 rank の乱数列は
互いに揃いません(rank 0 が他より多く引きます)が、複数の rank の探索に
影響する量はすべてブロードキャストされるので問題ありません。
したがってベイズ線形モデル(num_rand_basis > 0)では、Thompson
sampling は rank 数によらず、同じ seed の逐次実行と同じ点を提案します。
ガウス過程の predictor(num_rand_basis == 0)では事後サンプルに
ブロードキャストできる有限次元の表現がないため、各 rank は自分の候補に
ついてだけ事後分布からサンプルします。異なる rank 上の候補間の相関は
無視され、提案は rank 数に依存します。並列実行で Thompson sampling を
使う場合はベイズ線形モデルを推奨します。
get_score は parallel=True``(デフォルト)では候補を rank に分割し、
Thompson sampling のサンプルを rank 0 で引きます。``parallel=False では
各 rank が与えられた候補を自分のサンプルで採点します。