@@ -3,9 +3,10 @@ using EnsembleKalmanProcesses.DataContainers
33using DocStringExtensions
44
55# [1] For GaussianProcesses
6- import GaussianProcesses: predict
6+ import GaussianProcesses: predict, get_params, get_param_names
77using GaussianProcesses
8-
8+ export get_params
9+ export get_param_names
910# [2] For SciKitLearn
1011using PyCall
1112using ScikitLearn
@@ -23,7 +24,7 @@ using KernelFunctions
2324# exports (from Emulator)
2425export GaussianProcess
2526
26- export GPJL, SKLJL
27+ export GPJL, SKLJL, AGPJL
2728export YType, FType
2829
2930"""
@@ -63,7 +64,7 @@ $(DocStringExtensions.TYPEDFIELDS)
6364"""
6465struct GaussianProcess{GPPackage, FT} <: MachineLearningTool
6566 " The Gaussian Process (GP) Regression model(s) that are fitted to the given input-data pairs."
66- models:: Vector{Union{<:GaussianProcesses.GPE, <:PyObject, Nothing}}
67+ models:: Vector{Union{<:GaussianProcesses.GPE, <:PyObject, <:AbstractGPs.PosteriorGP, Nothing}}
6768 " Kernel object."
6869 kernel:: Union{<:GaussianProcesses.Kernel, <:PyObject, <:AbstractGPs.Kernel, Nothing}
6970 " Learn the noise with the White Noise kernel explicitly?"
@@ -100,7 +101,7 @@ function GaussianProcess(
100101}
101102
102103 # Initialize vector for GP models
103- models = Vector{Union{<: GaussianProcesses.GPE , <: PyObject , Nothing}}(undef, 0 )
104+ models = Vector{Union{<: GaussianProcesses.GPE , <: PyObject , <: AbstractGPs.PosteriorGP , <: Nothing }}(undef, 0 )
104105
105106 # the algorithm regularization noise is set to some small value if we are learning noise, else
106107 # it is fixed to the correct value (1.0)
@@ -112,6 +113,15 @@ function GaussianProcess(
112113end
113114
114115# First we create the GPJL implementation
116+ function get_params(gp:: GaussianProcess{GPJL} )
117+ return [get_params(model. kernel) for model in gp. models]
118+ end
119+
120+ function get_param_names(gp:: GaussianProcess{GPJL} )
121+ return [get_param_names(model. kernel) for model in gp. models]
122+ end
123+
124+
115125"""
116126$(DocStringExtensions. TYPEDSIGNATURES)
117127
318328function build_models!(
319329 gp::GaussianProcess{AGPJL},
320330 input_output_pairs::PairedDataContainer{FT};
321- log_constant_value = nothing,
322- rbf_len = nothing,
331+ kernel_params = nothing,
323332 kwargs...,
324333) where {FT <: AbstractFloat}
325334 # get inputs and outputs
@@ -332,8 +341,42 @@ function build_models!(
332341 @warn "GaussianProcess already built. skipping..."
333342 return
334343 end
344+
345+ ##############################################################################
346+ # Notes on borrowing hyperparameters optimised within GPJL:
347+ # optimisation of the GPJL with default kernels produces kernel parameters
348+ # in the way of [a b c], where:
349+ # c is the log_const_value
350+ # [a b] is the rbf_len: lengthscale parameters for SEArd kernel
351+ # const_value = exp.(2 .* log_const_value)
352+ ##############################################################################
353+ ## For example A 2D->2D sinusoid input example:
354+ #=
355+ log_const_value = [2.9031145778344696; 3.8325906110973795]
356+ rbf_len = [1.9952706691900783 3.066374123568536; 5.783676639895112 2.195849064147456]
357+ =#
358+ if isnothing(kernel_params)
359+ throw(ArgumentError("""
360+ AbstractGP currently does not (yet) learn hyperparameters internally. The following can be performed instead:
361+ 1. Create and optimize a GPJL emulator and default kernel.
362+ 2. Obtain kernel parameters from this, given as [a b], where:
363+ - a is the `rbf_len`: lengthscale parameters for SEArd kernel [output_dim x input_dim] matrix
364+ - b is the `log_std_sqexp` of the SQexp kernel Vector [output_dim]
365+ - c is the `log_std_noise` of the noise kernel Float
366+ 3. Create a Dict with
367+ kernel_params = Dict(
368+ "log_rbf_len" => (output_dim x input_dim)-Matrix,
369+ "log_std_sqexp" => (output_dim)-Vector,
370+ "log_std_noise" => Float,
371+ )
372+ 4. Build a new Emulator with kwargs `kernel_params=kernel_params`
373+ """))
374+ end
375+
376+
335377 N_models = size(output_values, 1) #size(transformed_data)[1]
336- if gp.kernel === nothing
378+ regularization_noise = gp.alg_reg_noise
379+ #= if gp.kernel === nothing
337380 println("Using default squared exponential kernel, learning length scale and variance parameters")
338381 # Create default squared exponential kernel
339382 const_value = 1.0
@@ -349,12 +392,10 @@ function build_models!(
349392 if gp.noise_learn
350393 # Add white noise to kernel
351394 white_noise_level = 1.0
352- white = KernelFunctions.WhiteKernel(white_noise_level )
395+ white = white_noise_level * KernelFunctions.WhiteKernel()
353396 kern += white
354397 println("Learning additive white noise")
355398 end
356-
357- regularization_noise = gp.alg_reg_noise
358399 for i in 1:N_models
359400 kernel_i = deepcopy(kern)
360401 # In contrast to the GPJL and SKLJL case "data_i = output_values[i, :]"
@@ -372,50 +413,31 @@ function build_models!(
372413 end
373414 println(" created GP: " , i)
374415 end
375-
376- # #############################################################################
377- # Notes on borrowing hyperparameters optimised within GPJL:
378- # optimisation of the GPJL with default kernels produces kernel parameters
379- # in the way of [a b c], where:
380- # c is the log_const_value
381- # [a b] is the rbf_len: lengthscale parameters for SEArd kernel
382- # const_value = exp.(2 .* log_const_value)
383- # #############################################################################
384- # # For example A 2D->2D sinusoid input example:
385- #=
386- log_const_value = [2.9031145778344696; 3.8325906110973795]
387- rbf_len = [1.9952706691900783 3.066374123568536; 5.783676639895112 2.195849064147456]
388- =#
389- if isnothing(log_const_value) || isnothing(rbf_len)
390- throw(ArgumentError("""
391- AbstractGP currently does not (yet) learn hyperparameters internally. The following can be performed instead:
392- 1. Create and optimize a GPJL emulator and default kernel.
393- 2. Obtain kernel parameters from this, given as [a b], where:
394- - a is the `rbf_len`: lengthscale parameters for SEArd kernel [output_dim x input_dim] matrix
395- - b is the `log_const_value` Vector [output_dim]
396- 3. Create a new emulator with AGPJL kwargs `log_const_value`(Vector) and `rbf_len` (Matrix), `input_output_pairs`
397- """ ))
398- else
399- const_value = exp.(2 .* log_const_value)
400- for i in 1 : N_models
401- opt_kern = const_value[i] * (KernelFunctions. SqExponentialKernel() ∘ ARDTransform(1 ./ exp.(rbf_len[i, :])))
402- opt_f = AbstractGPs. GP(opt_kern)
403- opt_fx = opt_f(input_values' , regularization_noise)
404-
405- data_i = output_values[i, :]
406- opt_post_fx = posterior(opt_fx, data_i)
407- println("optimised GP: ", i)
408- push!(models, opt_post_fx)
409- println(opt_post_fx.prior.kernel)
410- end
416+ = #
417+ # now obtain the values
418+ var_sqexp = exp.(2 .* kernel_params[" log_std_sqexp" ]) # Vec [out]
419+ var_noise = exp.(2 .* kernel_params[" log_std_noise" ]) # Float
420+ rbf_invlen = 1 ./ exp.(kernel_params[" log_rbf_len" ])# rbf_len # mat [out x in]
421+
422+ for i in 1 : N_models
423+ opt_kern = var_sqexp[i] * (KernelFunctions. SqExponentialKernel() ∘ ARDTransform(rbf_invlen[i, :])) + var_noise * KernelFunctions. WhiteKernel()
424+ opt_f = AbstractGPs. GP(opt_kern)
425+ opt_fx = opt_f(input_values' , regularization_noise)
426+
427+ data_i = output_values[i, :]
428+ opt_post_fx = posterior(opt_fx, data_i)
429+ println("optimised GP: ", i)
430+ push!(models, opt_post_fx)
431+ println(opt_post_fx.prior.kernel)
411432 end
433+
412434end
413435
414436function optimize_hyperparameters!(gp::GaussianProcess{AGPJL}, args...; kwargs...)
415437 @info "AbstractGP already built. Continuing..."
416438end
417439
418- function predict(gp::GaussianProcess{AGPJL}, new_inputs::AbstractMatrix{Dual}) where {FT <: AbstractFloat, Dual}
440+ function predict(gp::GaussianProcess{AGPJL}, new_inputs::AbstractMatrix{Dual}) where {Dual}
419441
420442 N_models = length(gp.models)
421443 N_samples = size(new_inputs, 2)
0 commit comments