Documentation

Surrogate Modeling

Surrogate Modeling

surrogate 模块用已经评估过的输入输出数据训练廉价预测模型。

当原始模型很贵,而你已经有一张输入 X 和输出 Y 的数据表时,可以用代理模型做快速预测、验证、响应面绘图、筛选或代理辅助优化。

核心流程:

text
采样或收集 X -> 评估 Y -> model.fit(X, Y) -> model.predict(Xnew)

代理模型需要什么

代理模型不会自己调用你的仿真。它只从已有数据里学习。

对象形状含义
X(n_samples, n_input)输入表。每行是一个已评估参数向量。
Y(n_samples, n_output)输出表。每行必须与 X 同一行对应。
Xnew(n_new, n_input)需要预测的新输入行。
pred(n_new, n_output)预测输出。

单输出时,推荐把 Y 写成 (n_samples, 1) 的列。

基本 Fit 和 Predict

python
import numpy as np

from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)

X = np.linspace(0.0, 1.0, 8).reshape(-1, 1)
Y = np.sin(2 * np.pi * X)

model = RBF()
model.fit(X, Y)

pred = model.predict([[0.25], [0.75]])

print(X.shape, Y.shape)
print(pred.shape)
print(pred)

[[0.25], [0.75]] 表示两行、一个变量。对于二维输入,一行应该写成 [[0.2, 0.8]]

保持行对齐

XY 必须按同一顺序描述同一批模型运行。

输入输出
0X[0, :]Y[0, :]
1X[1, :]Y[1, :]
2X[2, :]Y[2, :]

不要分别打乱 XY。划分训练集和测试集时,对两个数组使用同一组索引。

选择模型

模型导入路径首选用途
RBFUQPyL.surrogate.rbf平滑数据的默认响应面模型。
GPRUQPyL.surrogate.gp需要预测不确定性的 Gaussian process。
KRGUQPyL.surrogate.krigingKriging 风格模型,支持趋势项和不确定性。
LinearRegressionUQPyL.surrogate.regression线性基线模型。
PolynomialRegressionUQPyL.surrogate.regression低阶平滑多项式关系。
MARSUQPyL.surrogate.mars可选依赖可用时的分段回归样条。
SVRUQPyL.surrogate.svr可选依赖可用时的支持向量回归。

实践默认:先用 RBF;需要 uncertainty 时用 GPRKRG;用回归模型做 baseline。

验证预测质量

训练后至少用 held-out data 检查一次。

python
import numpy as np

from UQPyL.surrogate import RandSelect, mse, r_square
from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)
np.random.seed(123)

X = np.linspace(0.0, 1.0, 24).reshape(-1, 1)
Y = np.sin(2 * np.pi * X) + 0.2 * X

trainIdx, testIdx = RandSelect(pTest=25).split(X)

model = RBF()
model.fit(X[trainIdx], Y[trainIdx])

pred = model.predict(X[testIdx])

print(trainIdx.shape, testIdx.shape)
print(np.round(r_square(Y[testIdx], pred), 4))
print(np.round(mse(Y[testIdx], pred), 6))
print(pred[:3])
指标方向含义
r_square越大越好,1.0 表示完美预测。预测解释输出变化的比例。
nse越大越好。Nash-Sutcliffe efficiency。
mse越小越好。均方误差。
rank_score越大越好。预测是否保留样本排序。
sort_score越小越好。真实排序和预测排序的距离。

缩放数据

变量单位或量级差异很大时,建议使用 scaler。

python
import numpy as np

from UQPyL.surrogate import StandardScaler
from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)

X = np.linspace(0.0, 100.0, 12).reshape(-1, 1)
Y = np.cos(X / 20.0)

model = RBF(scalers=(StandardScaler(0, 1), StandardScaler(0, 1)))
model.fit(X, Y)

pred = model.predict([[50.0], [75.0]])

print(pred.shape)
print(pred)
print(model.xTrain.mean(axis=0), model.xTrain.std(axis=0, ddof=1))

scalers=(xScaler, yScaler) 中,第一个 scaler 用于输入,第二个用于输出。预测结果会自动回到原始输出尺度。

带不确定性的预测

只有支持 uncertainty 的模型才能返回标准差或方差。当前公共模型中,通常使用 GPRKRG

python
import numpy as np

from UQPyL.surrogate import StandardScaler
from UQPyL.surrogate.gp import GPR
from UQPyL.surrogate.gp.kernel import RBF as RBFKernel

np.set_printoptions(precision=4, suppress=True)

X = np.array([[0.0], [0.25], [0.5], [0.75], [1.0]])
Y = X**2

model = GPR(scalers=(StandardScaler(0, 1), StandardScaler(0, 1)), kernel=RBFKernel(), nRestartTimes=1)
model.rng = np.random.default_rng(123)
model.fit(X, Y)

mean, std = model.predict([[0.3], [0.7]], returnStd=True)

print(mean.shape, std.shape)
print(mean)
print(std)

调用形式:

text
model.predict(Xnew)                 -> mean only
model.predict(Xnew, returnStd=True) -> mean, standard deviation
model.predict(Xnew, returnVar=True) -> mean, variance

RBF 不提供 uncertainty 输出。

多输出代理模型

多输出时,可以用 MultiSurrogate 为每个输出列训练一个模型。

python
import numpy as np

from UQPyL.surrogate import MultiSurrogate
from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)

X = np.linspace(0.0, 1.0, 10).reshape(-1, 1)
Y = np.hstack([np.sin(2 * np.pi * X), X**2])

model = MultiSurrogate(2, models_list=[RBF(), RBF()])
model.fit(X, Y)

pred = model.predict([[0.25], [0.75]])

print(Y.shape)
print(pred.shape)
print(pred)

n_surrogates 必须与 Y.shape[1] 一致,models_list 的长度也必须一致。

调参

AutoTuner 用验证集搜索参数。gridTune() 显式、容易检查,适合先用。

python
import numpy as np

from UQPyL.surrogate import AutoTuner, StandardScaler
from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)
np.random.seed(123)

X = np.linspace(0.0, 1.0, 16).reshape(-1, 1)
Y = X**2 + 0.1

model = RBF(
    scalers=(StandardScaler(0, 1), StandardScaler(0, 1)),
    C_smooth_attr={"ub": 0.1, "lb": 0.0, "type": "float", "log": False},
)
tuner = AutoTuner(model=model)

bestParams, bestScore = tuner.gridTune(X, Y, paraGrid={"C_smooth": [0.0, 1e-6, 1e-4]}, ratio=25)

print(bestParams)
print(round(float(bestScore), 4))
print(model.predict([[0.5]]))
print(model.getParameterValues("C_smooth"))

调参后,AutoTuner 会把最优参数应用到模型,并用全量数据重新拟合。

Problem 结合

代理模型的训练数据通常来自 DOE 样本和 Problem.evaluate()

python
import numpy as np

from UQPyL.doe import LHS
from UQPyL.problem import Problem
from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)


def objFunc(X):
    X = np.atleast_2d(X)
    y = X[:, 0] ** 2 + 0.5 * X[:, 1] ** 2
    return y.reshape(-1, 1)


problem = Problem(nInput=2, nObj=1, lb=-1.0, ub=1.0, objFunc=objFunc, optType="min", name="WeightedSphere2D")

X = LHS("classic").sample(problem, nSamples=20, seed=123)
Y = problem.evaluate(X).objs

model = RBF()
model.fit(X, Y)

pred = model.predict([[0.0, 0.0], [0.5, 0.5]])

print(X.shape, Y.shape)
print(pred)

在优化中使用代理模型

拟合完成后,可以把 model.predict() 包装成新的 Problem,让优化器搜索代理模型。

python
import numpy as np

from UQPyL.doe import LHS
from UQPyL.optimization.soea import GA
from UQPyL.problem import Problem
from UQPyL.surrogate.rbf import RBF

np.set_printoptions(precision=4, suppress=True)


def realObjFunc(X):
    X = np.atleast_2d(X)
    y = X[:, 0] ** 2 + 0.5 * X[:, 1] ** 2
    return y.reshape(-1, 1)


realProblem = Problem(nInput=2, nObj=1, lb=-1.0, ub=1.0, objFunc=realObjFunc, optType="min", name="RealModel")
X = LHS("classic").sample(realProblem, nSamples=20, seed=123)
Y = realProblem.evaluate(X).objs

model = RBF()
model.fit(X, Y)


def surrogateObjFunc(X):
    return model.predict(X)


surrogateProblem = Problem(nInput=2, nObj=1, lb=-1.0, ub=1.0, objFunc=surrogateObjFunc, optType="min", name="SurrogateModel")
result = GA(nPop=8, maxFEs=32, maxIters=4, verboseFlag=False, logFlag=False, saveFlag=False).run(surrogateProblem, seed=123)

print(result.bestDecs)
print(result.bestObjs)
print(realProblem.evaluate(result.bestDecs).objs)

最后一行很重要:代理模型是近似,关键候选点必须回到真实模型验证。

常见错误

错误修正
XY 行不匹配从采样、评估到切分都保持同一行顺序。
一维输入预测写错形状一个变量两行写 [[0.2], [0.8]]
只看训练误差使用 held-out validation 或交叉验证。
期待 RBF 返回 uncertainty使用 GPRKRG
忘记代理模型只是近似重要候选点必须用原始模型复核。
手动缩放了 X 但忘记缩放 Xnew优先使用模型自带 scalers

下一步

目标阅读
查模型构造参数、核函数和 scalerSurrogate API
定义被评估系统Problem
生成训练样本Design of Experiment
优化拟合后的代理模型Optimization
查看端到端示例Examples