Metamodels
Linear Basis Function Models
Linear basis function models are a simple class of metamodels that express the predicted output as a linear combination of basis functions evaluated for the input variables defined as
where
Monomial Basis
Monomial basis functions are defined as the powers, or products of powers in the multivariate case, of the input variables with a total degree of less than or equal to
The construction of this MonomialBasis is presented next.
φ = MonomialBasis(2, 3)MonomialBasis(2, 3, Monomials.Monomial[1, x2, x1, x2², x1x2, x1², x2³, x1x2², x1²x2, x1³])By default the MonomialBasis includes the constant (zero degree) term. This behaviour can be changed by passing the include_zero=false keyword.
Radial Basis
A radial basis function (RBF) is a real-valued function
Gaussian
here, GaussianRadialBasis struct.
Polyharmonic
Note, that polyharmonic radial basis functions do not require a shape parameter. These RBs can be constructed using the PolyharmonicRadialBasis type.
Least Squares
Despite the nonlinearity of the basis functions, the model remains linear in its parameters, which allows efficient estimation of the weights using ordinary least squares. Given
The optimal weight vector is found by minimizing the sum-of-squares error
yielding the closed-form solution via
where
Example
Consider the function
where
We use HaltonSampling to sample 150 data points from the input variable, evaluate the model, and fit a LinearBasisFunctionModel using a MonomialBasis of degree
x = RandomVariable(Uniform(-5, 5), :x)
y = Model(
df -> df.x .* cos.(df.x),
:y,
)
data = sample(x, HaltonSampling(150))
evaluate!(y, data)
lbfm = LinearBasisFunctionModel(data, :y, MonomialBasis(1, 9))ResponseSurface(MonomialBasis(1, 9, Monomials.Monomial[1, x1, x1², x1³, x1⁴, x1⁵, x1⁶, x1⁷, x1⁸, x1⁹]), [0.00018241593646902075, 0.9878644609495059, -0.00018150970456987044, -0.48925985169682223, 4.747249404303626e-5, 0.038987490233917725, -3.913393749589379e-6, -0.0011115728398402001, 9.668870671278248e-8, 1.1603496934147144e-5], [:x], :y)A plot comparing the resulting model to the data points is presented next.
Response Surface
A linear basis function model constructed from a MonomialBasis is also known as a polynomial Response Surface [ DocumenterCitations.CitationSiteNode("khuriResponseSurfaceMethodology2010-cite-1")
]. For this reason we provide a convenient alias ResponseSurface. Using this alias the previous example can be adapted as follows.
rs = ResponseSurface(data, :y, 9)ResponseSurface(MonomialBasis(1, 9, Monomials.Monomial[1, x1, x1², x1³, x1⁴, x1⁵, x1⁶, x1⁷, x1⁸, x1⁹]), [0.00018241593646902075, 0.9878644609495059, -0.00018150970456987044, -0.48925985169682223, 4.747249404303626e-5, 0.038987490233917725, -3.913393749589379e-6, -0.0011115728398402001, 9.668870671278248e-8, 1.1603496934147144e-5], [:x], :y)Design Of Experiments
Several experimental designs have been developed to efficiently estimate ResponseSurface models [ DocumenterCitations.CitationSiteNode("khuriResponseSurfaceMethodology2010-cite-2")
]. Although designed for response surface methodology these designs can be used to fit any metamodel. However, for more complex models we suggest using Quasi Monte Carlo sampling schemes instead.
The designs implemented in UncertaintyQuantification are TwoLevelFactorial, FullFactorial, FractionalFactorial, CentralComposite, BoxBehnken, and PlackettBurman.
Interval Predictor Model
An interval predictor model (IPM)[ DocumenterCitations.CitationSiteNode("crespoIntervalPredictorModels2016-cite-1")
] is a function that returns an interval instead of a precise value for the dependent variable given as
where
Using the defining vertices of P
with
and
Here,
The distance between the lower and upper bound given by
is known as the spread of the IPM. The optimal defining vertices for a given data set are found by minimizing the average spread such that all data points fall into the IPM by solving the following convex constrained optimization problem.
Example
Consider the function
where IntervalPredictorModel using a MonomialBasis of sixth degree.
x = RandomVariable(Uniform(-5.5, 5.5), :x)
data = sample(x, HaltonSampling(150))
m = Model(
df ->
df.x .^ 2 .* cos.(df.x) .- sin.(3 * df.x) .* exp.(-df.x .^ 2) .- df.x .-
cos.(df.x .^ 2) .+ df.x .* randn(size(df, 1)),
:y,
)
evaluate!(m, data)
b = MonomialBasis(1,6)
ipm = IntervalPredictorModel(data, :y, b)IntervalPredictorModel{MonomialBasis}(MonomialBasis(1, 6, Monomials.Monomial[1, x1, x1², x1³, x1⁴, x1⁵, x1⁶]), [-1.2720546724495774, -2.547509011220345, -1.8441520363249984, 0.03628854681653243, 0.04630398819605291, -6.102061289813858e-5, 0.0013326512447875813], [6.780543527846371, -0.5173681859439141, -1.8441520363249966, 0.036288546816527135, 0.04630398819605069, -6.102061289878519e-5, 0.0013326512447874406], [:x], :y, 150)The following figure presents the bounds of the resulting IPM and the corresponding least squares solution. Note, that the least squares solution is not guaranteed to be between the bounds of the IPM.
IPM reliability
The reliability of the IPM, that is the probability that and unobserved data point reliability function. The function reliability(ipm, ϵ) returns the confidence parameter
1 - reliability(ipm, 0.1548)0.9898502075787752Reliability analysis
As the IPM is an imprecise model, it can only be applied in a reliability analysis using the DoubleLoop or RandomSlicing. For more information, see Imprecise Reliability Analysis.
Gaussian Process Regression
Theoretical Background
A Gaussian Process (GP) is a collection of random variables, any finite subset of which has a joint Gaussian distribution. It is fully specified by a mean function
This prior GP specifies that any finite collection of function values follows a multivariate normal distribution.
To define a prior GP we use AbstractGPs.jl for the GP interface and mean function, and KernelFunctions.jl for the definition of a covariance kernel. Below, we construct a simple prior GP with a constant zero mean function and a scaled squared exponential kernel:
using UncertaintyQuantification
kernel = SqExponentialKernel() ∘ ScaleTransform(3.0)Note that the definition of a prior GP is handled by UncertaintyQuantification if no prior GP is specified. The construction of a GaussianProcess is flexible. Mean functions, kernels and many other parameters can be specified later directly in the constructor of the GaussianProcess.
Posterior Gaussian Process
The posterior GP represents the distribution of functions after incorporating observed data. We denote the observation data as:
where
For a new input location
where:
is the covariance matrix with entries , is the covariance matrix with entries ,and
is the variance at the unknown input location.
We can then obtain the posterior distribution of
]), by conditioning the joint Gaussian on the observed outputs
with
In the noisy observation case, the covariance between training points is adjusted by adding the noise variance:
The computation of the posterior predictive distribution generalizes straightforwardly to multiple input locations, providing both the posterior mean, which can serve as a regression estimate of the unknown function, and the posterior variances, which quantify the uncertainty at each point. Because the posterior is multivariate Gaussian, one can also sample function realizations at specified locations to visualize possible functions consistent with the observed data.
To construct a posterior GP, we need to define training data in form of a DataFrame. Constructing a GaussianProcess model will then automatically compute the posterior GP to predict requested the modeled output learn_hyperparameters=false can be set.
The following creates a standard GP with mean function ConstMean(), kernel SqExponentialKernel(), and directly optimizes the hyperparameters. Note that while ConstMean(0.0) and ZeroMean() provide the same zero-mean prior GP, using ConstMean() also allows for optimization of the mean. We also equip the GP with small observation noise
x = collect(range(0, 10, 10))
y = sin.(x) + 0.3 * cos.(2 .* x)
df = DataFrame(x = x, y = y)
mean_fct = ConstMean(0.0)
kernel = SqExponentialKernel() ∘ ScaleTransform(3.0)
gp_prior = GP(mean_fct, kernel)
σ² = 1e-5
# these are equivalent
gp_model = GaussianProcess(gp_prior, df, :y; σ²=σ²)
gp_model = GaussianProcess(df, :y; σ²=σ², mean_fct=mean_fct, kernel=kernel)
# providing the input learn_noise=true also optimizes the data noiseNow we can use our GP model to predict at new input locations x_test:
x_test = collect(range(0, 5, 500))
prediction = DataFrame(:x => x_test)
evaluate!(gp_model, prediction; mode=:mean_and_var)
plot!(
x_test, prediction_mean, ribbon=2 .* prediction_std,
color=:grey, alpha=0.5, label="Confidence band"Hyperparameter optimization
GP models typically contain hyperparameters in their mean functions
A common approach to selecting hyperparameters is maximum likelihood estimation (MLE) (see, e.g. [ DocumenterCitations.CitationSiteNode("rasmussen2005gaussian-cite-2")
]), where we maximize the likelihood of observing the training data
The marginal likelihood of the observed training outputs
where
For numerical reasons, the logarithm of the marginal likelihood is typically used. Maximizing the log marginal likelihood with respect to the hyperparameters then yields the parameters that best explain the observed data. After obtaining the optimal hyperparameters, the posterior GP can be constructed as described above.
UncertaintyQuantification.jl provides a default optimizer for the hyperparameters based on the MaximumLikelihoodEstimation constructor.
optimizer::AbstractHyperparameterOptimization=MaximumLikelihoodEstimation(Optim.LBFGS(), Optim.Options(; iterations=100, show_trace=false))If other options are desired, a different optimizer can be constructed based on Optim.jl. The script below shows the difference between an optimized and unoptimized GP.
using Optim
optimization = MaximumLikelihoodEstimation(
Optim.LBFGS(),
Optim.Options(; iterations=10, show_trace=false)
)
gp_model = GaussianProcess(df, :y;
σ²=σ²,
mean_fct=mean_fct,
kernel=kernel,
optimizer=optimization
)
gp_model_unoptimized = GaussianProcess(df, :y;
σ²=σ²,
mean_fct=mean_fct,
kernel=kernel,
learn_hyperparameters=false
)
prediction = DataFrame(:x => x_test)
prediction_unopt = DataFrame(:x => x_test)
evaluate!(gp_model, prediction; mode=:mean_and_var)
evaluate!(gp_model_unoptimized, prediction_unopt; mode=:mean_and_var)Internally, MaximumLikelihoodEstimation() defaults to using LBFGS optimizer that performs 100 optimization steps with standard optimization hyperparameters as defined Optim.jl. Note that any other first-order optimizer supported by Optim.jl, along with its corresponding hyperparameters, can also be used when constructing MaximumLikelihoodEstimation.
During optimization, GP hyperparameters
We support the automatic extraction of hyperparameters from mean functions provided by AbstractGPs.jl, with the exception of:
- Custom mean functions
CustomMean. These are defined with a custom function that itself could depend on hyperparameters. These additional hyperparameters are ignored in the optimization.
Kernel functions are defined with the kernels and transformations provided by KernelFunctions.jl. For similar reasons as with CustomMean, we do not extract potential function hyperparameters from the following kernels or transforms:
Transforms defined with custom functions
FunctionTransform,The
GibbsKernel, which models a kernel lengthscale parameter with the help of a function.
Further, GP models containing the following kernels are not supported for hyperparameter optimization currently:
Multi-output kernels
MOKernel,Neural kernel networks [
NeuralKernelNetwork].
Adaptive Gaussian Process Regression
Fitting a good GP surrogate can require many expensive model evaluations if the initial experimental design is chosen naively. Adaptive (or active learning) Gaussian process regression instead starts from a small initial design and iteratively enriches the training data: at each iteration a set of candidate points is sampled from the input space, an acquisition function (also called a learning function) scores every candidate, the most promising candidate is evaluated with the true (expensive) model, and the GP is refitted with the enlarged training set. This is repeated for a fixed number of iterations, or until the acquisition function's own convergence criterion is met.
The AdaptiveGaussianProcess function drives this loop. It first constructs (or accepts) an initial GaussianProcess, then calls evaluate! on the supplied model for each newly selected point.
x = RandomVariable(Uniform(-10, 10), :x1)
model = Model(df -> sin.(df.x1) .* df.x1 .^ 2, :y)
mean_f = ConstMean(0.0)
kernel = Matern52Kernel()
gp_prior = GP(mean_f, kernel)
n_design_points = 10
n_added_points = 5
adaptive_gp = AdaptiveGaussianProcess(
gp_prior,
x,
model,
:y,
MaximumVariance(),
n_added_points,
n_design_points,
)As with GaussianProcess, the initial n_design_points are sampled with an experimental_design (LatinHypercubeSampling by default), while the n_added_points adaptively selected candidates are drawn from candidate_sampling, a Monte Carlo sampling scheme (MonteCarlo(100_000) by default). Hyperparameters can be re-optimized after every added point via learn_hyperparameters (default true).
The resulting adaptive_gp is a regular GaussianProcess and can be evaluated as usual:
using DataFrames
using Plots
test_data = DataFrame(x1 = -10:0.1:10)
evaluate!(adaptive_gp, test_data; mode = :mean_and_var)
evaluate!(model, test_data)
p = plot(test_data.x1, test_data.y_mean; ribbon = 2 .* sqrt.(test_data.y_var), label = "GP mean ± 2σ", xlabel = "x₁", ylabel = "y", color = :blue, alpha = 0.5)
plot!(p, test_data.x1, test_data.y; label = "True function", color = :red, linestyle = :dash)
scatter!(p, adaptive_gp.training_data.x1[1:n_design_points], adaptive_gp.training_data.y[1:n_design_points]; label = "Initial design", color = :black)
scatter!(p, adaptive_gp.training_data.x1[(n_design_points + 1):end], adaptive_gp.training_data.y[(n_design_points + 1):end]; label = "Adaptively added")
Acquisition Functions
The acquisition function determines which candidate point is added next, and therefore what the adaptive scheme optimizes for. Given the posterior mean
].
UncertaintyQuantification.jl provides the following acquisition functions to adapatively refine GP regression models; we separate them by there main area of application:
General active learning
Goal: improve the global fit of the GP
MaximumVariancesimply adds the point of maximum posterior variance,
MaximinDistanceis a space-filling criterion that adds the candidate farthest (in input space) from every existing training point ,
ExpectedImprovementForGlobalFit(EIGF) trades off the local discrepancy to the nearest training observation (with ) against the posterior variance,
Bayesian optimization
Goal: refine the global minimum
ExpectedImprovementwith exploration parameter ,
where
UpperConfidenceBoundwith exploration weight minimizes a lower confidence bound (for a minimization objective),
Reliability analysis
Goal: refine the limit-state surface
DeviationNumber, the -function used in AK-MCS, adds the point closest to the limit state relative to its uncertainty,
ExpectedFeasibility(EFF) integrates the probability that the true response lies within an -band around the limit state,