Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://www.mooseframework.org
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 :
10 : #pragma once
11 :
12 : #include "GeneralReporter.h"
13 : #include "GenericActiveLearningSampler.h"
14 : #include "ActiveLearningGaussianProcess.h"
15 : #include "GaussianProcess.h"
16 : #include "SurrogateModel.h"
17 : #include "SurrogateModelInterface.h"
18 : #include "GaussianProcessSurrogate.h"
19 : #include "ParallelAcquisitionFunctionBase.h"
20 : #include "ParallelAcquisitionInterface.h"
21 :
22 : // forward declarations
23 : template <typename SamplerType>
24 : class GenericActiveLearnerTempl;
25 :
26 : typedef GenericActiveLearnerTempl<GenericActiveLearningSampler> GenericActiveLearner;
27 :
28 : /**
29 : * A generic reporter to support parallel active learning: re-trains GP and picks the next best
30 : * batch
31 : */
32 : template <typename SamplerType>
33 : class GenericActiveLearnerTempl : public GeneralReporter,
34 : public ParallelAcquisitionInterface,
35 : public SurrogateModelInterface
36 :
37 : {
38 : public:
39 : static InputParameters validParams();
40 : GenericActiveLearnerTempl(const InputParameters & parameters);
41 156 : virtual void initialize() override {}
42 156 : virtual void finalize() override {}
43 : virtual void execute() override;
44 :
45 : protected:
46 : /**
47 : * Sets up the training data for the GP model
48 : * @param data_out The data vector containing the outputs to train the GP
49 : * @param data_in The data matrix containing the inputs to train the GP
50 : */
51 : virtual void setupGPData(const std::vector<Real> & data_out, const DenseMatrix<Real> & data_in);
52 :
53 : /**
54 : * Computes the outputs of the trained GP model
55 : * @param eval_outputs The outputs predicted by the GP model
56 : */
57 : virtual void computeGPOutput(std::vector<Real> & eval_outputs);
58 :
59 : /**
60 : * Computes the convergence value during active learning
61 : */
62 : virtual Real computeConvergenceValue();
63 :
64 : /**
65 : * Evaluate the GP on all the test samples sent by the Sampler
66 : */
67 : virtual void evaluateGPTest();
68 :
69 : /**
70 : Setup the generic variable for acquisition computation (depends on the objective:
71 : optimization, UQ, etc.)
72 : */
73 : virtual void setupGeneric();
74 :
75 : /**
76 : * Include additional inputs before evaluating the acquisition function.
77 : * Has trivial function in base, but can be modified in derived if necessary depending
78 : * upon the objective of active learning (i.e., forward UQ, inverse UQ, optimization, etc.)
79 : */
80 : virtual void includeAdditionalInputs();
81 :
82 : /**
83 : * Output the acquisition function values and ordering of the indices
84 : * @param acq_new The computed values of the acquisition function
85 : * @param indices The indices ordered according to the acqusition values to be sent to Sampler
86 : */
87 : virtual void getAcquisition(std::vector<Real> & acq_new, std::vector<unsigned int> & indices);
88 :
89 : /// The base sampler
90 : SamplerType & _al_sampler;
91 :
92 : /// The input dimension for GP, equal to Sampler columns
93 : unsigned int _n_dim;
94 :
95 : /// Storage for the number of parallel proposals
96 : dof_id_type _props;
97 :
98 : /// Storage for all the proposed samples to test the GP model
99 : const std::vector<std::vector<Real>> & _inputs_test;
100 :
101 : /// Model output value from SubApp
102 : const std::vector<Real> & _output_value;
103 :
104 : /// Modified value of model output by this reporter class
105 : std::vector<Real> & _output_comm;
106 :
107 : /// The selected sample indices to evaluate the subApp
108 : std::vector<unsigned int> & _sorted_indices;
109 :
110 : /// The active learning GP trainer that permits re-training
111 : const ActiveLearningGaussianProcess & _al_gp;
112 :
113 : /// The GP evaluator object that permits re-evaluations
114 : const SurrogateModel & _gp_eval;
115 :
116 : /// Storage for the parallel acquisition object to be utilized
117 : ParallelAcquisitionFunctionBase & _acquisition_obj;
118 :
119 : /// The acquistion function values in the current iteration
120 : std::vector<Real> & _acquisition_value;
121 :
122 : /// For monitoring convergence of active learning
123 : Real & _convergence_value;
124 :
125 : /// Storage for all the modified proposed samples to test the GP model
126 : std::vector<std::vector<Real>> _inputs_test_modified;
127 :
128 : /// Transmit the required inputs to the json file
129 : std::vector<std::vector<Real>> & _inputs_required;
130 :
131 : /// Penalize acquisition to prevent clustering when operating in parallel
132 : const bool & _penalize_acquisition;
133 :
134 : /// Ensure that the MCMC algorithm proceeds in a sequential fashion
135 : int _check_step;
136 :
137 : /// Storage for the GP re-training inputs
138 : std::vector<std::vector<Real>> _gp_inputs;
139 :
140 : /// Storage for the GP re-training outputs
141 : std::vector<Real> _gp_outputs;
142 :
143 : /// Outputs of GP model for the test samples
144 : std::vector<Real> _gp_outputs_test;
145 :
146 : /// Outputs of GP model standard deviation for the test samples
147 : std::vector<Real> _gp_std_test;
148 :
149 : /// Storage for the length scales after the GP training
150 : std::vector<Real> _length_scales;
151 :
152 : /// A generic parameter to be passed to the acquisition function
153 : std::vector<Real> _generic;
154 :
155 : /// The GP outputs from the current iteration before re-training (to evaluate convergence)
156 : std::vector<Real> _eval_outputs_current;
157 : };
158 :
159 : template <typename SamplerType>
160 : InputParameters
161 96 : GenericActiveLearnerTempl<SamplerType>::validParams()
162 : {
163 96 : InputParameters params = GeneralReporter::validParams();
164 96 : params += ParallelAcquisitionInterface::validParams();
165 96 : params.addClassDescription("A generic reporter to support parallel active learning: re-trains GP "
166 : "and picks the next best batch.");
167 192 : params.addRequiredParam<ReporterName>("output_value",
168 : "Value of the model output from the SubApp.");
169 192 : params.addParam<ReporterValueName>(
170 : "outputs_required",
171 : "outputs_required",
172 : "Modified value of the model output from this reporter class.");
173 192 : params.addRequiredParam<SamplerName>("sampler", "The sampler object.");
174 192 : params.addRequiredParam<UserObjectName>("al_gp", "Active learning GP trainer.");
175 192 : params.addRequiredParam<UserObjectName>("gp_evaluator", "Evaluator for the trained GP.");
176 192 : params.addParam<ReporterValueName>(
177 : "sorted_indices",
178 : "sorted_indices",
179 : "The sorted sample indices in order of importance to evaluate the subApp.");
180 192 : params.addParam<ReporterValueName>(
181 : "acquisition_function",
182 : "acquisition_function",
183 : "The values of the acquistion function in the current iteration.");
184 192 : params.addParam<ReporterValueName>(
185 : "convergence_value", "convergence_value", "Value to measure convergence of active learning.");
186 192 : params.addParam<ReporterValueName>(
187 : "inputs", "inputs", "Modified value of the model inputs from this reporter class.");
188 192 : params.addRequiredParam<UserObjectName>("acquisition", "Name of the acquisition function.");
189 192 : params.addParam<bool>(
190 : "penalize_acquisition",
191 192 : true,
192 : "Set true to prevent clustering of the best batch inputs when operating in parallel.");
193 96 : return params;
194 0 : }
195 :
196 : template <typename SamplerType>
197 48 : GenericActiveLearnerTempl<SamplerType>::GenericActiveLearnerTempl(
198 : const InputParameters & parameters)
199 : : GeneralReporter(parameters),
200 : ParallelAcquisitionInterface(parameters),
201 : SurrogateModelInterface(this),
202 48 : _al_sampler(getSampler<SamplerType>("sampler")),
203 48 : _n_dim(_al_sampler.getNumberOfCols()),
204 48 : _props(_al_sampler.getNumParallelProposals()),
205 48 : _inputs_test(_al_sampler.getSampleTries()),
206 48 : _output_value(getReporterValue<std::vector<Real>>("output_value", REPORTER_MODE_DISTRIBUTED)),
207 48 : _output_comm(declareValue<std::vector<Real>>("outputs_required")),
208 48 : _sorted_indices(declareValue<std::vector<unsigned int>>("sorted_indices")),
209 48 : _al_gp(getUserObject<ActiveLearningGaussianProcess>("al_gp")),
210 48 : _gp_eval(getSurrogateModel<GaussianProcessSurrogate>("gp_evaluator")),
211 96 : _acquisition_obj(getParallelAcquisitionFunctionByName(getParam<UserObjectName>("acquisition"))),
212 48 : _acquisition_value(declareValue<std::vector<Real>>("acquisition_function")),
213 48 : _convergence_value(declareValue<Real>("convergence_value")),
214 48 : _inputs_required(declareValue<std::vector<std::vector<Real>>>("inputs")),
215 96 : _penalize_acquisition(getParam<bool>("penalize_acquisition")),
216 96 : _check_step(std::numeric_limits<int>::max())
217 : {
218 : // Setting up the variable sizes to facilitate active learning.
219 48 : _gp_outputs_test.resize(_inputs_test.size());
220 48 : _gp_std_test.resize(_inputs_test.size());
221 48 : _acquisition_value.resize(_props);
222 48 : _length_scales.resize(_n_dim);
223 48 : _eval_outputs_current.resize(_props);
224 48 : _generic.resize(1);
225 48 : _inputs_required.resize(_props, std::vector<Real>(_n_dim, 0.0));
226 48 : _sorted_indices.resize(_props, 1u);
227 48 : }
228 :
229 : template <typename SamplerType>
230 : void
231 92 : GenericActiveLearnerTempl<SamplerType>::setupGPData(const std::vector<Real> & data_out,
232 : const DenseMatrix<Real> & data_in)
233 : {
234 552 : for (unsigned int i = 0; i < data_out.size(); ++i)
235 : {
236 1380 : for (unsigned int j = 0; j < _n_dim; ++j)
237 920 : _inputs_required[i][j] = data_in(i, j);
238 460 : _gp_inputs.push_back(_inputs_required[i]);
239 460 : _gp_outputs.push_back(data_out[i]);
240 : }
241 92 : }
242 :
243 : template <typename SamplerType>
244 : void
245 60 : GenericActiveLearnerTempl<SamplerType>::computeGPOutput(std::vector<Real> & eval_outputs)
246 : {
247 360 : for (unsigned int i = 0; i < eval_outputs.size(); ++i)
248 300 : eval_outputs[i] = _gp_eval.evaluate(_gp_inputs[i]);
249 60 : }
250 :
251 : template <typename SamplerType>
252 : void
253 108 : GenericActiveLearnerTempl<SamplerType>::setupGeneric()
254 : {
255 108 : _generic = _gp_outputs;
256 108 : }
257 :
258 : template <typename SamplerType>
259 : void
260 92 : GenericActiveLearnerTempl<SamplerType>::includeAdditionalInputs()
261 : {
262 92 : _inputs_test_modified = _inputs_test;
263 92 : }
264 :
265 : template <typename SamplerType>
266 : void
267 108 : GenericActiveLearnerTempl<SamplerType>::getAcquisition(std::vector<Real> & acq_new,
268 : std::vector<unsigned int> & indices)
269 : {
270 : std::vector<Real> acq;
271 108 : acq.resize(_inputs_test.size());
272 108 : includeAdditionalInputs();
273 108 : _acquisition_obj.computeAcquisition(
274 108 : acq, _gp_outputs_test, _gp_std_test, _inputs_test_modified, _gp_inputs, _generic);
275 108 : acq_new = acq;
276 108 : if (_penalize_acquisition)
277 108 : _acquisition_obj.penalizeAcquisition(
278 108 : acq_new, indices, acq, _length_scales, _inputs_test_modified);
279 108 : }
280 :
281 : template <typename SamplerType>
282 : Real
283 48 : GenericActiveLearnerTempl<SamplerType>::computeConvergenceValue()
284 : {
285 : Real convergence_value = 0.0;
286 288 : for (unsigned int ii = 0; ii < _output_comm.size(); ++ii)
287 240 : convergence_value += Utility::pow<2>(_output_comm[ii] - _eval_outputs_current[ii]);
288 48 : convergence_value = std::sqrt(convergence_value) / _output_comm.size();
289 48 : return convergence_value;
290 : }
291 :
292 : template <typename SamplerType>
293 : void
294 92 : GenericActiveLearnerTempl<SamplerType>::evaluateGPTest()
295 : {
296 92092 : for (unsigned int i = 0; i < _gp_outputs_test.size(); ++i)
297 92000 : _gp_outputs_test[i] = _gp_eval.evaluate(_inputs_test[i], _gp_std_test[i]);
298 92 : }
299 :
300 : template <typename SamplerType>
301 : void
302 156 : GenericActiveLearnerTempl<SamplerType>::execute()
303 : {
304 156 : if (_al_sampler.getNumberOfLocalRows() == 0 || _check_step == _t_step)
305 : {
306 0 : _check_step = _t_step;
307 0 : return;
308 : }
309 :
310 156 : DenseMatrix<Real> data_in(_al_sampler.getNumberOfRows(), _al_sampler.getNumberOfCols());
311 886 : for (dof_id_type ss = _al_sampler.getLocalRowBegin(); ss < _al_sampler.getLocalRowEnd(); ++ss)
312 : {
313 730 : const auto data = _al_sampler.getNextLocalRow();
314 2390 : for (unsigned int j = 0; j < _al_sampler.getNumberOfCols(); ++j)
315 1660 : data_in(ss, j) = data[j];
316 : }
317 156 : _communicator.sum(data_in.get_values());
318 156 : _output_comm = _output_value;
319 156 : _communicator.allgather(_output_comm);
320 :
321 156 : if (_t_step > 1)
322 : {
323 : // Setup the GP training data
324 108 : setupGPData(_output_comm, data_in);
325 :
326 : // Compute the convergence value before re-training the GP
327 108 : if (_t_step > 2)
328 : {
329 60 : computeGPOutput(_eval_outputs_current);
330 60 : _convergence_value = computeConvergenceValue();
331 : }
332 :
333 : // Retrain the GP and get the length scales
334 108 : _al_gp.reTrain(_gp_inputs, _gp_outputs);
335 108 : _length_scales = _al_gp.getLengthScales();
336 :
337 : // Evaluate the GP on all the test samples sent by the Sampler
338 108 : evaluateGPTest();
339 :
340 : // Setup the generic variable for acquisition computation (depends on the objective:
341 : // optimization, UQ, etc.)
342 108 : setupGeneric();
343 :
344 : // Get the acquisition function values and ordering of indices as per the acquisition
345 : std::vector<Real> acq_new;
346 : std::vector<unsigned int> indices;
347 108 : indices.resize(_inputs_test.size());
348 108 : getAcquisition(acq_new, indices);
349 :
350 : // Output the acquisition function values and the best ordering of the indices
351 108 : std::copy_n(indices.begin(), _props, _sorted_indices.begin());
352 108 : std::copy_n(acq_new.begin(), _props, _acquisition_value.begin());
353 108 : }
354 : else
355 48 : std::iota(_sorted_indices.begin(), _sorted_indices.end(), 0);
356 :
357 : // Track the current step
358 156 : _check_step = _t_step;
359 156 : }
|