LCOV - code coverage report
Current view: top level - include/reporters - GenericActiveLearner.h (source / functions) Hit Total Coverage
Test: idaholab/moose stochastic_tools: #33416 (b10b36) with base 9fbd27 Lines: 107 110 97.3 %
Date: 2026-07-23 16:21:17 Functions: 19 23 82.6 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14