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