Documentation

Calibration

Calibration

calibration 模块通过比较仿真结果和观测数据来估计模型参数。

当你有观测数据、仿真模型、参数边界,并且希望找到能让仿真接近观测的参数时,使用校准模块。

校准方法使用 ModelProblem,不是普通 Problem

选择校准方法

方法适合场景主要输出
GLUE已有候选参数,希望按阈值筛出 behavioral samples。behavioralDecs, behavioralSims
SUFI2需要 elite samples 和更新后的不确定性边界。eliteDecs, updatedLb, updatedUb, pfactor, rfactor
ES需要一次 ensemble smoother 更新。posteriorDecs, posteriorSims
IES需要多轮 ensemble smoother 更新。posteriorDecs, posteriorSims, 迭代历史

实践默认:已有候选样本时先用 GLUE;关心参数不确定性边界时用 SUFI2;做 ensemble smoothing 时用 ESIES

校准工作流

text
obs + simFunc + 参数边界 -> ModelProblem -> calibration.run(...) -> CalResult
步骤动作
准备观测obs 使用二维数组,shape 为 (n_time, n_series)
定义仿真simFunc(X),支持批量参数行。
构建 ModelProblem提供 nInputlbubsimFuncobs,可选 mask
选择方法使用 GLUESUFI2ESIES
读取结果查看 bestDecsbestSim、posterior、elite 或 behavioral samples。

构建 ModelProblem

这个 toy model 中,两个参数直接对应两个观测时刻:

text
params [p1, p2] -> simulation [p1, p2]
obs = [1.0, 2.0]
python
import numpy as np

from UQPyL.problem import ModelProblem

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


obs = np.array([[1.0], [2.0]])


def simFunc(X):
    X = np.atleast_2d(X)
    sim = np.zeros((X.shape[0], 2, 1))
    sim[:, 0, 0] = X[:, 0]
    sim[:, 1, 0] = X[:, 1]
    return sim


problem = ModelProblem(nInput=2, ub=3.0, lb=0.0, simFunc=simFunc, obs=obs, simLabels=["Q"], name="ToyModel")

sim = problem.simFunc([[1.0, 2.0]])

print(sim.shape)
print(problem.flattenObs())
print(problem.flattenMask())
对象形状含义
X(n_samples, n_input)候选参数行。
obs(n_time, n_series)观测数据。
simFunc(X)(n_samples, n_time, n_series)每个候选参数对应的仿真结果。
flattened simulation(n_samples, n_time * n_series)内部评分布局。

运行 GLUE

GLUE 会对每个候选参数评分,并保留通过阈值的 behavioral samples。

对于 rmse 这类越小越好的指标:

text
score <= threshold

对于 nse 这类越大越好的指标:

text
score >= threshold
python
import numpy as np

from UQPyL.calibration import GLUE
from UQPyL.problem import ModelProblem

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


obs = np.array([[1.0], [2.0]])


def simFunc(X):
    X = np.atleast_2d(X)
    sim = np.zeros((X.shape[0], 2, 1))
    sim[:, 0, 0] = X[:, 0]
    sim[:, 1, 0] = X[:, 1]
    return sim


problem = ModelProblem(nInput=2, ub=3.0, lb=0.0, simFunc=simFunc, obs=obs, simLabels=["Q"], name="ToyModel")
X = np.array([[1.0, 2.0], [1.0, 2.4], [0.0, 0.0]])

result = GLUE(metric="rmse", verboseFlag=False, logFlag=False, saveFlag=False).run(problem, X, threshold=0.3)

print(result.bestDecs)
print(result.bestSim)
print(result.behavioralDecs)
print(result.diagnostics["scores"])
print(result.diagnostics["behavioralMask"])
输出含义
bestDecs最优参数行。
bestSim最优参数对应的仿真输出。
behavioralDecs通过阈值的候选参数行。
scores每个候选参数的指标值。
behavioralMask每个候选参数是否通过阈值。

指标方向

指标更好方向
mse越小越好
mae越小越好
rmse越小越好
nse越大越好
r2越大越好
pbias越小越好
pearson_r越大越好
kge越大越好

阈值方向由指标决定。不要把 rmse 的阈值逻辑直接套到 nse 上。

使用 Mask

mask 用来在评分时忽略部分观测值,形状必须与 obs 一致。

python
import numpy as np

from UQPyL.problem import ModelProblem


obs = np.array([[1.0, 10.0], [2.0, 20.0]])
mask = np.array([[False, True], [False, True]])


def simFunc(X):
    X = np.atleast_2d(X)
    sim = np.zeros((X.shape[0], 2, 2))
    sim[:, 0, 0] = X[:, 0]
    sim[:, 1, 0] = X[:, 1]
    sim[:, :, 1] = 999.0
    return sim


problem = ModelProblem(nInput=2, ub=3.0, lb=0.0, simFunc=simFunc, obs=obs, mask=mask, simLabels=["Q", "Ignored"], name="MaskedToyModel")

print(problem.obs.shape)
print(problem.mask.shape)
print(problem.flattenMask())

被 mask 的位置不会参与校准评分。

运行 SUFI2

SUFI2 会选择 elite samples,并根据 elite samples 更新参数不确定性边界。

python
import numpy as np

from UQPyL.calibration import SUFI2
from UQPyL.problem import ModelProblem

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


obs = np.array([[1.0], [2.0]])


def simFunc(X):
    X = np.atleast_2d(X)
    sim = np.zeros((X.shape[0], 2, 1))
    sim[:, 0, 0] = X[:, 0]
    sim[:, 1, 0] = X[:, 1]
    return sim


problem = ModelProblem(nInput=2, ub=3.0, lb=0.0, simFunc=simFunc, obs=obs, simLabels=["Q"], name="ToyModel")
X = np.array([[1.0, 2.0], [1.0, 2.4], [0.0, 0.0]])

result = SUFI2(verboseFlag=False, logFlag=False, saveFlag=False).run(problem, X, eliteSize=2)

print(result.bestDecs)
print(result.eliteDecs)
print(result.diagnostics["updatedLb"])
print(result.diagnostics["updatedUb"])
print(result.diagnostics["pfactor"], result.diagnostics["rfactor"])
输出含义
eliteDecs排名前 eliteSize 的参数行。
updatedLb, updatedUb从 elite samples 得到的新边界。
pfactor观测被不确定性带包住的比例。
rfactor不确定性带宽度相对观测变化的大小。

运行 ES / IES

ES 执行一次 ensemble smoother 更新;IES 执行多轮更新。

python
import numpy as np

from UQPyL.calibration import ES, IES
from UQPyL.problem import ModelProblem

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


obs = np.array([[1.0], [2.0]])


def simFunc(X):
    X = np.atleast_2d(X)
    sim = np.zeros((X.shape[0], 2, 1))
    sim[:, 0, 0] = X[:, 0]
    sim[:, 1, 0] = X[:, 1] ** 2
    return sim


problem = ModelProblem(nInput=2, ub=3.0, lb=0.0, simFunc=simFunc, obs=obs, simLabels=["Q"], name="NonlinearToyModel")
X = np.array([[0.0, 0.5], [2.0, 1.0], [1.5, 2.0]])

esResult = ES(verboseFlag=False, logFlag=False, saveFlag=False).run(problem, X)
iesResult = IES(maxIters=4, lam=1e-6, verboseFlag=False, logFlag=False, saveFlag=False).run(problem, X)

print(iesResult.bestDecs)
print(iesResult.posteriorDecs.shape)
print(iesResult.posteriorSims.shape)
print(len(iesResult.history.metricsHistory))
print(np.mean(esResult.diagnostics["scores"]), np.mean(iesResult.diagnostics["scores"]))

history.metricsHistory 查看迭代级摘要。

读取 CalResult

字段含义
bestDecs当前指标下最优参数行。
bestSimbestDecs 对应仿真,按观测向量布局展平。
behavioralDecs, behavioralSimsGLUE 通过阈值的样本。
eliteDecs, eliteSimsSUFI2 elite samples。
posteriorDecs, posteriorSimsES 或 IES 的 posterior ensemble。
diagnostics方法相关的分数、mask、边界和摘要。
history.metricsHistory迭代方法的每轮摘要。
summary()适合报告的紧凑字典。

常见错误

错误修正
用普通 Problem 做校准使用带 simFuncobsModelProblem
simFunc 返回形状错误返回 (n_samples, n_time, n_series)
obs 是一维数组使用二维数组,例如 obs.reshape(-1, 1)
忘记指标方向对越小越好的指标用 <= threshold,对越大越好的指标用 >= threshold
GLUE 阈值过严查看 diagnostics["scores"] 后调整阈值。
mask 形状不对保证 mask.shape == obs.shape
期待 bestSim 保持三维结果中仿真通常是评分布局;需要时间序列时按 obs.shape reshape。

下一步

目标阅读
构建仿真问题Problem
生成候选参数集Design of Experiment
查构造参数和结果字段Calibration API
对比推断工作流Inference
查看完整工作流Examples