https://mooseframework.inl.gov
Loading...
Searching...
No Matches
LMC.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9#ifdef MOOSE_LIBTORCH_ENABLED
10
11#include "LMC.h"
12#include "MooseRandom.h"
13#include "MathUtils.h"
14
15registerMooseObject("StochasticToolsApp", LMC);
16
19{
21 params.addClassDescription("Covariance function for multioutput Gaussian Processes based on the "
22 "Linear Model of Coregionalization (LMC).");
23 params.addParam<unsigned int>(
24 "num_latent_funcs", 1., "The number of latent functions for the expansion of the outputs.");
25 params.makeParamRequired<unsigned int>("num_outputs");
26 params.makeParamRequired<std::vector<UserObjectName>>("covariance_functions");
27 return params;
28}
29
30LMC::LMC(const InputParameters & parameters)
31 : CovarianceFunctionBase(parameters),
32 _num_expansion_terms(getParam<unsigned int>("num_latent_funcs"))
33{
34 // We use a random number generator to obtain the initial guess for the
35 // hyperparams
36 MooseRandom generator_latent;
37 generator_latent.seed(0, 1980);
38
39 // First add and initialize the a A coefficients in the (aa^T+lambda*I) matrix
40 for (const auto exp_i : make_range(_num_expansion_terms))
41 {
42 const std::string a_coeff_name = "acoeff_" + std::to_string(exp_i);
43 std::vector<Real> acoeff_values(_num_outputs);
44 for (const auto out_i : make_range(_num_outputs))
45 acoeff_values[out_i] = 3.0 * generator_latent.rand(0) + 1.0;
46 auto & acoeff_vector = addVectorRealHyperParameter(a_coeff_name, acoeff_values, true);
47 _a_coeffs.push_back(&acoeff_vector);
48 }
49
50 // Then add and initialize the lambda coefficients in the (aa^T+lambda*I) matrix
51 for (const auto exp_i : make_range(_num_expansion_terms))
52 {
53 const std::string lambda_name = "lambda_" + std::to_string(exp_i);
54 std::vector<Real> lambda_values(_num_outputs);
55 for (const auto out_i : make_range(_num_outputs))
56 lambda_values[out_i] = 3.0 * generator_latent.rand(0) + 1.0;
57 auto & lambda_vector = addVectorRealHyperParameter(lambda_name, lambda_values, true);
58 _lambdas.push_back(&lambda_vector);
59 }
60}
61
62void
64 const torch::Tensor & x,
65 const torch::Tensor & xp,
66 const bool is_self_covariance) const
67{
68 const auto options = x.options().dtype(at::kDouble);
69 // Create temporary vectors for constructing the covariance matrix
70 torch::Tensor K_params = torch::zeros({x.sizes()[0], xp.sizes()[0]}, options);
71 torch::Tensor B = torch::zeros({_num_outputs, _num_outputs}, options);
72 K = torch::zeros({x.sizes()[0] * _num_outputs, xp.sizes()[0] * _num_outputs}, options);
73 torch::Tensor K_working;
74
75 // For every expansion term we add the contribution to the covariance matrix
76 for (const auto exp_i : make_range(_num_expansion_terms))
77 {
78 _covariance_functions[exp_i]->computeCovarianceMatrix(K_params, x, xp, is_self_covariance);
79 computeBMatrix(B, exp_i);
80 K_working = torch::kron(B, K_params);
81 K += K_working;
82 }
83}
84
85bool
86LMC::computedKdhyper(torch::Tensor & dKdhp,
87 const torch::Tensor & x,
88 const std::string & hyper_param_name,
89 unsigned int ind) const
90{
91 // Early return in the paramter name is longer than the expected [name] prefix.
92 // We prefix the parameter names with the name of the covariance function.
93 if (name().length() + 1 > hyper_param_name.length())
94 return false;
95
96 // Strip the prefix from the given parameter name
97 const std::string name_without_prefix = hyper_param_name.substr(name().length() + 1);
98
99 // Check if the parameter is tunable
100 if (_tunable_hp.find(hyper_param_name) != _tunable_hp.end())
101 {
102 const std::string acoeff_prefix = "acoeff_";
103 const std::string lambda_prefix = "lambda_";
104
105 // Allocate storage for the factors of the total gradient matrix
106 const auto options = x.options().dtype(at::kDouble);
107 torch::Tensor dBdhp = torch::zeros({_num_outputs, _num_outputs}, options);
108 torch::Tensor K_params = torch::zeros({x.sizes()[0], x.sizes()[0]}, options);
109
110 if (name_without_prefix.find(acoeff_prefix) != std::string::npos)
111 {
112 // Automatically grab the expansion index
113 const int number = std::stoi(name_without_prefix.substr(acoeff_prefix.length()));
114 computeAGradient(dBdhp, number, ind);
115 _covariance_functions[number]->computeCovarianceMatrix(K_params, x, x, true);
116 }
117 else if (name_without_prefix.find(lambda_prefix) != std::string::npos)
118 {
119 // Automatically grab the expansion index
120 const int number = std::stoi(name_without_prefix.substr(lambda_prefix.length()));
121 computeLambdaGradient(dBdhp, number, ind);
122 _covariance_functions[number]->computeCovarianceMatrix(K_params, x, x, true);
123 }
124 dKdhp = torch::kron(dBdhp, K_params);
125 return true;
126 }
127 else
128 {
129 // Allocate storage for the matrix factors
130 const auto options = x.options().dtype(at::kDouble);
131 torch::Tensor B_tmp = torch::zeros({_num_outputs, _num_outputs}, options);
132 torch::Tensor B = torch::zeros({_num_outputs, _num_outputs}, options);
133 torch::Tensor dKdhp_sub = torch::zeros({x.sizes()[0], x.sizes()[0]}, options);
134
135 // First, check the dependent covariances
136 bool found = false;
137 for (const auto dependent_covar : _covariance_functions)
138 if (!found)
139 found = dependent_covar->computedKdhyper(dKdhp_sub, x, hyper_param_name, ind);
140
141 if (!found)
142 mooseError("Hyperparameter ", hyper_param_name, "not found!");
143
144 // Then we compute the output covariance
145 for (const auto exp_i : make_range(_num_expansion_terms))
146 {
147 computeBMatrix(B_tmp, exp_i);
148 B += B_tmp;
149 }
150
151 dKdhp = torch::kron(B, dKdhp_sub);
152
153 return true;
154 }
155
156 return false;
157}
158
159void
160LMC::computeBMatrix(torch::Tensor & Bmat, const unsigned int exp_i) const
161{
162 const auto & a_coeffs = *_a_coeffs[exp_i];
163 const auto & lambda_coeffs = *_lambdas[exp_i];
164 Bmat = torch::outer(a_coeffs, a_coeffs) + torch::diag(lambda_coeffs);
165}
166
167void
168LMC::computeAGradient(torch::Tensor & grad,
169 const unsigned int exp_i,
170 const unsigned int index) const
171{
172 const auto & a_coeffs = *_a_coeffs[exp_i];
173 mooseAssert(cast_int<int64_t>(index) < a_coeffs.numel(), "Incorrect LMC coefficient index.");
174 auto basis = torch::zeros_like(a_coeffs);
175 const auto index_tensor =
176 torch::tensor({cast_int<int64_t>(index)},
177 torch::TensorOptions().dtype(torch::kLong).device(a_coeffs.device()));
178 basis.index_fill_(0, index_tensor, 1.0);
179 grad = torch::outer(basis, a_coeffs) + torch::outer(a_coeffs, basis);
180}
181
182void
183LMC::computeLambdaGradient(torch::Tensor & grad,
184 const unsigned int exp_i,
185 const unsigned int index) const
186{
187 mooseAssert(index < _num_outputs, "Incorrect LMC lambda index.");
188 auto basis = torch::zeros_like(*_lambdas[exp_i]);
189 const auto index_tensor =
190 torch::tensor({cast_int<int64_t>(index)},
191 torch::TensorOptions().dtype(torch::kLong).device(_lambdas[exp_i]->device()));
192 basis.index_fill_(0, index_tensor, 1.0);
193 grad = torch::diag(basis);
194}
195
196#endif
const std::vector< double > x
registerMooseObject("StochasticToolsApp", LMC)
void ErrorVector unsigned int
Base class for covariance functions that are used in Gaussian Processes.
std::vector< CovarianceFunctionBase * > _covariance_functions
Vector of pointers to the dependent covariance functions.
const unsigned int _num_outputs
The number of outputs this covariance function is used to describe.
static InputParameters validParams()
std::unordered_set< std::string > _tunable_hp
list of tunable hyper-parameters
torch::Tensor & addVectorRealHyperParameter(const std::string &name, const std::vector< Real > &value, const bool is_tunable)
Register a vector hyperparameter to this covariance function.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void makeParamRequired(const std::string &name)
Covariance function for multi-output Gaussian Processes based on the linear model of coregionalizatio...
Definition LMC.h:20
void computeAGradient(torch::Tensor &grad, const unsigned int exp_i, const unsigned int index) const
Computes the gradient of $B$ with respect to the entries in $a_i$ in the following expression: $B = \...
Definition LMC.C:168
std::vector< const torch::Tensor * > _a_coeffs
The vectors in the $B = \sum_i a_i a_i^T + diag(lambda_i)$ expansion.
Definition LMC.h:72
void computeBMatrix(torch::Tensor &Bmat, const unsigned int exp_i) const
Computes the covariance matrix for the outputs (using the latent coefficients) We use a $B = \sum_i a...
Definition LMC.C:160
static InputParameters validParams()
Definition LMC.C:18
LMC(const InputParameters &parameters)
Definition LMC.C:30
std::vector< const torch::Tensor * > _lambdas
Definition LMC.h:73
bool computedKdhyper(torch::Tensor &dKdhp, const torch::Tensor &x, const std::string &hyper_param_name, unsigned int ind) const override
Redirect dK/dhp for hyperparameter "hp".
Definition LMC.C:86
const unsigned int _num_expansion_terms
The number of expansion terms in the output ovariance matrix.
Definition LMC.h:67
void computeCovarianceMatrix(torch::Tensor &K, const torch::Tensor &x, const torch::Tensor &xp, const bool is_self_covariance) const override
Generates the Covariance Matrix given two sets of points in the parameter space.
Definition LMC.C:63
void computeLambdaGradient(torch::Tensor &grad, const unsigned int exp_i, const unsigned int index) const
Computes the gradient of $B$ with respect to the entries in $lambda_i$ in the following expression: $...
Definition LMC.C:183
const std::string & name() const
void mooseError(Args &&... args) const
void seed(std::size_t i, unsigned int seed)
Real rand(std::size_t i)