Surrogate#
saealibは、目的関数を近似する予測モデルの責務をSurrogateという差し替え可能なコンポーネントに限定しています。
Surrogateはfit/predictだけを知り、予測値をどうスコアに変換するか(AcquisitionFunction)や、学習データをどこから集めるか(TrainingSet、SurrogateManager経由)は一切知りません。
Surrogateの役割#
Surrogateが実装を要求するメソッドは2つあります。
fit(train_x, train_y) -> None:形状(n_samples, n_features)の入力と、形状(n_samples, n_obj)(単目的では(n_samples,))の出力でモデルを学習します。
predict(test_x) -> SurrogatePrediction:形状(n_samples, n_features)の入力に対する予測を返します。
クラス属性provides_uncertainty: bool = Falseは、予測が不確実性(標準偏差)を伴うかどうかを示します。
既定はFalseで、ガウス過程の実装だけがTrueにオーバーライドします。
Surrogateとpredict()の間には2つのマーカー基底クラスがあります。
RegressionSurrogate:train_yが実数値の目的関数出力である回帰サロゲート向けのマーカー。
ComparisonSurrogate:train_yが{0, 1}の二値比較ラベルである比較サロゲート向け。
predict_proba(test_x) -> SurrogatePrediction(値は[0, 1]の勝率)が主インターフェースで、predict()は既定でpredict_proba()に委譲します。
SurrogatePrediction#
predict()の戻り値はSurrogatePredictionという統一データクラスです。
フィールド |
内容 |
|---|---|
|
予測値。形状 |
|
不確実性(標準偏差)。提供しないサロゲートでは |
|
分類モデルのみが持つクラスラベル |
|
SHAP値など実装固有の付加情報を格納する |
valueとstdは目的関数チャンネル向けの便利なプロパティです。
サロゲートの予測が目的関数値ではない量(新規性スコアなど)を表す場合、この仕組みによってpbestのような値が汚染されるのを防ぎます。
NoveltyAcquisitionなどのアーカイブベースの基準は、候補とアーカイブの設計点を直接受け取ります。
組み込みSurrogate#
RBFSurrogate(kernel, polynomial_degree="auto", solver="lstsq", alpha=1e-8):RBF補間によるサロゲートです[16, 17, 18](RBF補間自体の起源はHardy, 1971)。
kernelは既定値を持たない必須のRBFKernelオブジェクトです(組み込みカーネルは以下に示します)。カスタムカーネルはevaluate(r)を実装するサブクラスとして作ります。
predict()はstd=Noneを明示的に返します(RBF補間は不確実性を提供しません)。
パラメータ |
値 |
役割 |
|---|---|---|
|
|
補間系を多項式項で拡張します( |
|
|
線形系(多項式項で拡張されている場合を含む)の解法:最小二乗法(ランク落ちした系にも対応) / 直接法 / |
|
|
リッジ正則化の強さ。 |
kernelとpolynomial_degreeは設定した値そのものです。resolved_kernelとresolved_polynomial_degreeは、fit()が実際に解決して使う値を公開し、設定したRBFKernelインスタンス自体は不変に保ちます。
kernel/polynomial_degree/solver/alphaを再設定すると、fit済みの状態は無効になり、次のfit()までpredict()はRuntimeErrorを送出します。
length_scaleフィールドを持つカーネル(入力データと同じ距離単位)は、Noneのままにすると訓練点間のペアワイズ距離の中央値へ自動的に解決されます。
各カーネルは独立した2つの次数を宣言します。min_polynomial_degreeはそのカーネルが受け付ける最小の次数で、これを下回る値(Noneを含む)を渡すとValidationErrorになります。auto_polynomial_degreeはpolynomial_degree="auto"の解決先で、最小次数より高いことがあります。
カーネル |
式 |
|
|
|---|---|---|---|
|
\(\exp\left(-\dfrac{r^2}{2\,\ell^2}\right)\) |
なし |
|
|
\(r^2 \log r\)( |
|
|
|
\(r\)( |
|
|
|
\(r^3\)( |
|
|
|
\(\sqrt{r^2 + \ell^2}\) |
|
|
|
Matérn共分散。 |
なし |
|
6種類のカーネルと3種類のsolverはいずれもサポート対象です。それぞれテストで検証されており、そのまま利用できます。GaussianKernelやMaternKernelにpolynomial_degree=Noneを渡すこともサポートしており、"auto"が追加する定数項を落とせます。
PerObjectiveSurrogate(surrogates):RegressionSurrogateのサブクラスで、目的ごとに異なるサロゲートを割り当てる合成クラス。
fit時にtrain_yの列数とlen(surrogates)が一致しないとValueErrorになります。
provides_uncertaintyは、構成する全サロゲートがTrueの場合のみTrueを返す複合判定になっています。
外部ライブラリアダプタ#
scikit-learn互換API経由の回帰サロゲートにはSklearnという接頭辞が付きます。
クラス |
モデル |
|---|---|
|
|
|
ランダムフォレスト回帰 |
|
SVM |
|
MLP |
|
XGBoost( |
|
LightGBM( |
|
PyTorchベースのモデル( |
SklearnGPRSurrogateはreturn_std=TrueでGPカーネルから標準偏差を計算し、provides_uncertainty=Trueを返します。
実行可能性予測向けの分類サロゲートには次のクラスがあります。
クラス |
モデル |
|---|---|
|
scikit-learn互換の分類モデル全般 |
|
ランダムフォレスト分類 |
|
SVM分類 |
これらの分類サロゲートの学習データ抽出方法はTrainingSetのFeasibilityClassificationSetを参照してください。
ペア比較には、これらの分類サロゲートではなくComparisonSurrogate系の専用実装を使い、SurrogateManagerのPairwiseSurrogateManagerおよびPairwiseComparisonSetと組み合わせます。
各追加機能のインストール方法はインストールを参照してください。
拡張フック#
フィット後の後処理だけを足したい場合、サブクラスを新設せずにwith_post_fit(fn)で既存のSurrogateインスタンスへ処理を追加できます。
with_post_fitは元のインスタンスを変更せず、fnを追加したコピーを返します。
from saealib import GaussianKernel, RBFSurrogate
def log_fit(train_x, train_y, ctx=None):
print(f"fit on {len(train_x)} samples")
base = RBFSurrogate(kernel=GaussianKernel())
logged = base.with_post_fit(log_fit)
fnのシグネチャはfn(train_x, train_y, ctx) -> Noneです。
独自Surrogateの実装方法#
独自の予測モデルが必要な場合は、Surrogateを継承してfit()/predict()を実装します。
回帰ならRegressionSurrogate、比較ならComparisonSurrogate(predict_proba()を実装)を継承先に選びます。
次の例は、最近傍点の目的関数値をそのまま予測値として返す単純な回帰サロゲートです。
import numpy as np
from saealib import RegressionSurrogate, SurrogatePrediction
class NearestNeighborSurrogate(RegressionSurrogate):
"""A simple surrogate that returns the nearest point's objective value directly as the prediction."""
def fit(self, train_x, train_y):
self.train_x = np.asarray(train_x, dtype=float)
self.train_y = np.asarray(train_y, dtype=float)
def predict(self, test_x):
test_x = np.atleast_2d(test_x)
dists = np.linalg.norm(self.train_x[None, :, :] - test_x[:, None, :], axis=2)
nearest = dists.argmin(axis=1)
value = self.train_y[nearest]
return SurrogatePrediction(value=value)
不確実性対応表#
不確実性ベースのAcquisitionFunctionを使うには、Surrogateがstdを返す必要があります。
クラス |
|
|---|---|
|
|
|
|
|
構成する全サロゲートが |
Optimizer.validate()は、AcquisitionFunctionのrequires_uncertaintyとSurrogateのprovides_uncertaintyの不整合を検出して警告します。
関連コンポーネント#
SurrogateManager:
Surrogateのfit/predictを協調させるTrainingSet:
Surrogateに渡す学習データの抽出方法AcquisitionFunction:
predict()の結果をスコアへ変換するサロゲート精度評価と動的切り替え:サロゲートの汎化性能の評価
インストール:各追加機能のインストール方法