MeLOn
Loading...
Searching...
No Matches
ffNet.h
Go to the documentation of this file.
1/**********************************************************************************
2* Copyright (c) 2020 Process Systems Engineering (AVT.SVT), RWTH Aachen University
3*
4* This program and the accompanying materials are made available under the
5* terms of the Eclipse Public License 2.0 which is available at
6* http://www.eclipse.org/legal/epl-2.0.
7*
8* SPDX-License-Identifier: EPL-2.0
9*
10* @file ffNet.h
11*
12* @brief File containing declaration of the FeedForwardNet class.
13*
14**********************************************************************************/
15
16#pragma once
17
18#include <vector> // std::vector a
19#include <cmath> // std::tanh
20#include <algorithm> // std::min, std::max, std::transform
21#include <string> // std::string, std::to_string
22#include <utility> // std::pair, std::make_pair
23#include <memory> // std::shared_ptr, std::make_shared
24
25#include "vectorarithmetics.h"
26#include "exceptions.h"
27#include "MeLOn.h"
28#include "AnnProperties.h"
29#include "AnnParser.h"
30
31namespace melon {
32
44
51 template <typename T>
52 class FeedForwardNet : public MelonModel<T> {
53 private:
54
55 std::shared_ptr<const AnnData> _annData;
56
57 std::unique_ptr<Scaler<T>> _inputScaler;
58 std::unique_ptr<Scaler<T>> _outputScaler;
62 inline static T _tanh(T x) { using std::tanh; return tanh(x); }
63 inline static T _tanh_reformulation_1(T x) { return (exp(x) - exp(-1 * x)) / (exp(x) + exp(-1 * x)); }
64 inline static T _tanh_reformulation_2(T x) { return (exp(2 * x) - 1) / (exp(2 * x) + 1); }
65 inline static T _tanh_reformulation_3(T x) { return 1 - 2 / (1 + exp(2 * x)); }
66 inline static T _tanh_reformulation_4(T x) { return (1 - exp(-2 * x)) / (1 + exp(-2 * x)); }
67
68 inline static T _relu(T x) { using std::max; return max((T)0, x); }
69 inline static T _relu6(T x) { using std::max; using std::min; return min((T)6, max((T)0, x)); }
70
71
81 std::vector<T> _calculate_layer_activation(const std::vector<T>& v, const ACTIVATION_FUNCTION activationFunction);
82
96 std::vector<T> _calculate_prediction(const std::vector<T> input, const std::vector<T> internalVariables, const bool fullSpace, std::vector<T>& constraints);
97
103 void _set_data_object(std::shared_ptr<const ModelData> modelData) override;
104
105 public:
106
110 FeedForwardNet() : MelonModel<T>(std::make_shared<AnnParserFactory>()) {};
111
119 FeedForwardNet(std::string modelName, MODEL_FILE_TYPE fileType) : FeedForwardNet() { this->load_model(modelName, fileType); };
120
130 FeedForwardNet(std::string modelPath, std::string modelName, MODEL_FILE_TYPE fileType) : FeedForwardNet() { this->load_model(modelPath, modelName, fileType); };
131
137 FeedForwardNet(std::shared_ptr<AnnData> modelData) : FeedForwardNet() { this->load_model(modelData); };
138
142 ~FeedForwardNet() = default;
143
151 std::vector<T> calculate_prediction_reduced_space(const std::vector<T> input);
152
164 std::vector<T> calculate_prediction_full_space(const std::vector<T> input, const std::vector<T> internalVariables, std::vector<T>& constraints);
165
171 void set_tanh_formulation(const TANH_REFORMULATION& reformulation);
172
179
189 void get_full_space_variables(unsigned int& variableNumber, std::vector<std::string>& variableNames, std::vector<std::pair<double, double>>& variableBounds);
190
191 };
192
194 // Set data object containing model parameters
195 template<typename T>
196 void FeedForwardNet<T>::_set_data_object(std::shared_ptr<const ModelData> modelData) {
197
198 // Check if you can downcast the ModelData pointer to an AnnData pointer
199 _annData = std::dynamic_pointer_cast<const AnnData>(modelData);
200 if (_annData == nullptr) {
201 throw(MelonException(" Error while loading feed forward network: Incorrect type of passed data object. The data object must be of type AnnData."));
202 }
203
204 _inputScaler = ScalerFactory<T>::create_scaler(_annData->inputScalerData);
205 _outputScaler = ScalerFactory<T>::create_scaler(_annData->outputScalerData);
206 }
207
209 // Calculates the prediction of the feed forward net for a given point in reduced space mode (only values network inputs are given)
210 template <typename T>
211 std::vector<T> FeedForwardNet<T>::calculate_prediction_reduced_space(std::vector<T> input) {
212 std::vector<T> dummyConstraints;
213 std::vector<T> dummyInternalVariables;
214 try {
215 return _calculate_prediction(input, dummyInternalVariables, false, dummyConstraints);
216 }
217 catch (const std::exception& e) {
218 throw(MelonException(" Encountered a fatal error while evaluating feed forward network. Terminating.", e));
219 }
220 catch (...) {
221 throw(MelonException(" Encountered a fatal error while evaluating feed forward network. Terminating."));
222 }
223 }
224
225
227 // Calculates the prediction of the feed forward net for a given point in full space mode (values for all internal variables are given and a set of constraints is returned)
228 template <typename T>
229 std::vector<T> FeedForwardNet<T>::calculate_prediction_full_space(const std::vector<T> input, const std::vector<T> internalVariables, std::vector<T>& constraints) {
230 try {
231 return _calculate_prediction(input, internalVariables, true, constraints);
232 }
233 catch (const std::exception& e) {
234 throw(MelonException(" Encountered a fatal error while evaluating feed forward network. Terminating.", e));
235 }
236 catch (...) {
237 throw(MelonException(" Encountered a fatal error while evaluating feed forward network. Terminating."));
238 }
239 }
240
241
243 // Changes the reformulation to be used for tanh evaluations.
244 template <typename T>
246 switch (reformulation) {
248 this->_tanh_formulation = &_tanh;
249 break;
251 this->_tanh_formulation = &_tanh_reformulation_1;
252 break;
254 this->_tanh_formulation = &_tanh_reformulation_2;
255 break;
257 this->_tanh_formulation = &_tanh_reformulation_3;
258 break;
260 this->_tanh_formulation = &_tanh_reformulation_4;
261 break;
262 default:
263 throw MelonException(" Error while setting tanh formulation: Unknown tanh formulation.");
264 }
265 }
266
267
269 // Get the number of internal network variables
270 template <typename T>
273 throw MelonException(" Error: No network loaded.");
274 }
275
276 unsigned int variableNumber;
277 std::vector<std::string> dummyVariableNames;
278 std::vector<std::pair<double, double>> dummyVariableBounds;
279
280 get_full_space_variables(variableNumber, dummyVariableNames, dummyVariableBounds);
281
282 return variableNumber;
283 }
284
285
287 // Returns the number and the names of the internal variables of the network
288 template <typename T>
289 void FeedForwardNet<T>::get_full_space_variables(unsigned int& variableNumber, std::vector<std::string>& variableNames, std::vector<std::pair<double, double>>& variableBounds) {
291 throw MelonException(" Error: No network loaded.");
292 }
293
294 // Create aliases for data
295 auto& structure = _annData->structure;
296 auto& weights = _annData->weights;
297
298 const double MAX_BOUND = 10e6;
299 variableNumber = 0;
300 variableNames.clear();
301 variableBounds.clear();
302
303 // Normalized input
304 if (structure.scaledInput) {
305 variableNumber += structure.inputSize;
306 for (int i = 0; i < structure.inputSize; i++) {
307 variableNames.push_back("input_normalized_" + std::to_string(i));
308 variableBounds.push_back(std::make_pair(-1., 1.));
309 }
310 }
311
312 for (int iLayer = 0; iLayer < structure.numLayers; iLayer++) {
313
314 // Accumulated layer inputs
315 variableNumber += structure.layerSize.at(iLayer);
316 for (int iNeuron = 0; iNeuron < structure.layerSize.at(iLayer); iNeuron++) {
317 variableNames.push_back("layer_" + std::to_string(iLayer) + "_neuron_" + std::to_string(iNeuron) + "_acummulated_input");
318 variableBounds.push_back(std::make_pair(-MAX_BOUND, MAX_BOUND));
319 }
320
321 // Layer outputs
322 variableNumber += structure.layerSize.at(iLayer);
323 for (int iNeuron = 0; iNeuron < structure.layerSize.at(iLayer); iNeuron++) {
324 variableNames.push_back("layer_" + std::to_string(iLayer) + "_neuron_" + std::to_string(iNeuron) + "_output");
325 variableBounds.push_back(std::make_pair(-MAX_BOUND, MAX_BOUND));
326 }
327 }
328
329 // Denormalized ouput
330 if (structure.normalizedOutput) {
331 variableNumber += structure.layerSize.back();
332 for (int i = 0; i < structure.layerSize.back(); i++) {
333 variableNames.push_back("output_" + std::to_string(i));
334 variableBounds.push_back(std::make_pair(-MAX_BOUND, MAX_BOUND));
335 }
336 }
337 }
338
339
341 // Calculates the prediction of the feed forward net for a given point
342 template <typename T>
343 std::vector<T> FeedForwardNet<T>::_calculate_prediction(const std::vector<T> input, const std::vector<T> internalVariables, const bool fullSpace, std::vector<T>& constraints) {
345 // ---------------------------------------------------------------------------------
346 // 0: Initialization
347 // ---------------------------------------------------------------------------------
348
349 // Create aliases for data
350 auto& structure = _annData->structure;
351 auto& weights = _annData->weights;
352
353 // Check if variables vector has correct size
354 if (input.size() != structure.inputSize) {
355 throw MelonException(" Error while evaluating network: Incorrect number of variables. In reduced space mode evaluation the number of variables must be equal to the number of network inputs.");
356 }
357 if (fullSpace) {
358 unsigned int variablesSize = get_number_of_full_space_variables();
359 if (internalVariables.size() != variablesSize) {
360 throw MelonException(" Error while evaluating network: Incorrect number of variables. In full space mode evaluation the number of variables must be equal to the number of internal network variables.");
361 }
362 }
363
364 std::vector<std::vector<T>> networkValues(structure.numLayers);
365
366 auto variableIterator = internalVariables.begin();
367
368 // ---------------------------------------------------------------------------------
369 // 1: Normalize the input
370 // ---------------------------------------------------------------------------------
371 std::vector<T> normalizedInput = input;
372 if (structure.scaledInput) {
373 normalizedInput = _inputScaler->scale(input);
374 if (fullSpace) {
375 this->_set_constraints(constraints, normalizedInput, variableIterator);
376 }
377 }
378
379
380 // ---------------------------------------------------------------------------------
381 // 2: Evaluate each layer in the network
382 // ---------------------------------------------------------------------------------
383 for (size_t iLayer = 0; iLayer < networkValues.size(); iLayer++) {
384
385 // Create aliases for better code readability
386 auto& layerInputWeights = weights.inputWeight.at(iLayer);
387 auto& layerBiasWeights = weights.biasWeight.at(iLayer);
388 auto& layerIncidentLayerWeights = weights.layerWeight.at(iLayer);
389 auto& layerConnections = structure.layerConnect.at(iLayer);
390 auto& layerSize = structure.layerSize.at(iLayer);
391
392 // 1a Calculate weighted sum
393 std::vector<T> accumulatedLayerInputs(structure.layerSize.at(iLayer), 0);
394
395 // - input variables incident to the current layer
396 if (structure.inputConnect.at(iLayer) == 1) {
397 accumulatedLayerInputs = accumulatedLayerInputs + layerInputWeights * normalizedInput;
398 }
399
400 // - bias for the current layer
401 if (structure.biasConnect.at(iLayer) == 1) {
402 accumulatedLayerInputs = accumulatedLayerInputs + layerBiasWeights;
403 }
404
405 // - values from previous layers that are incident to the current layer
406 for (size_t iIncidentLayer = 0; iIncidentLayer < layerConnections.size(); iIncidentLayer++) {
407 if (layerConnections.at(iIncidentLayer) == 1) {
408 accumulatedLayerInputs = accumulatedLayerInputs + layerIncidentLayerWeights.at(iIncidentLayer)*networkValues.at(iIncidentLayer);
409 }
410 }
411
412 if (fullSpace) {
413 this->_set_constraints(constraints, accumulatedLayerInputs, variableIterator);
414 }
415
416 // 2b Calculate the layer output by evaluating the activation function on the weighted sum
417 std::vector<T> layerOutput = _calculate_layer_activation(accumulatedLayerInputs, structure.activationFunction.at(iLayer));
418
419 if (fullSpace) {
420 this->_set_constraints(constraints, layerOutput, variableIterator);
421 }
422
423 networkValues.at(iLayer) = layerOutput;
424 }
425
426 // ---------------------------------------------------------------------------------
427 // 2: Denormalize network output
428 // ---------------------------------------------------------------------------------
429 std::vector<T> output = networkValues.back();
430 if (structure.normalizedOutput) {
431 output = _outputScaler->descale(networkValues.back());
432 if (fullSpace) {
433 this->_set_constraints(constraints, output, variableIterator);
434 }
435 }
436
437 return output;
438 }
439 else {
440 throw MelonException(" Error while evaluating network: No network loaded.");
441 }
442 };
443
444
446 // Calculates the activations for a layer given its inputs.
447 template <typename T>
448 std::vector<T> FeedForwardNet<T>::_calculate_layer_activation(const std::vector<T> &v, const ACTIVATION_FUNCTION activationFunction) {
449
450 std::vector<T> layerActivation(v);
451
452 // Select correct activation function
453 T(*activation_function) (T);
454 switch (activationFunction) {
456 return layerActivation;
458 activation_function = this->_tanh_formulation;
459 break;
461 activation_function = &_relu;
462 break;
464 activation_function = &_relu6;
465 break;
466 }
467
468 // Apply activation function to all entries in v (layer neurons) and write the results to layerActivation
469 std::transform(v.begin(), v.end(), layerActivation.begin(), activation_function);
470
471 return layerActivation;
472 };
473}
This class defines the exceptions thrown by FeedForwardNet.
Definition exceptions.h:32
This class is a factory class for creating child instances of AnnParser.
Definition AnnParser.h:215
This class represents a feed foward artificial network to be used in the MAiNGO solver.
Definition ffNet.h:52
std::vector< T > calculate_prediction_full_space(const std::vector< T > input, const std::vector< T > internalVariables, std::vector< T > &constraints)
Calculates the prediction of the feed forward net for a given point in full space mode (values for al...
Definition ffNet.h:229
std::unique_ptr< Scaler< T > > _outputScaler
Definition ffNet.h:58
~FeedForwardNet()=default
Default Destructor.
std::shared_ptr< const AnnData > _annData
Definition ffNet.h:55
FeedForwardNet()
Constructor for creating object with no model loaded.
Definition ffNet.h:110
unsigned int get_number_of_full_space_variables()
Get the number of internal network variables.
Definition ffNet.h:271
std::vector< T > _calculate_layer_activation(const std::vector< T > &v, const ACTIVATION_FUNCTION activationFunction)
Calculates the activations for a layer given its inputs.
Definition ffNet.h:448
void set_tanh_formulation(const TANH_REFORMULATION &reformulation)
Changes the reformulation to be used for tanh evaluations. The reformulations are intended to be used...
Definition ffNet.h:245
FeedForwardNet(std::shared_ptr< AnnData > modelData)
Constructor for creating object from existing AnnData object.
Definition ffNet.h:137
static T _relu(T x)
Definition ffNet.h:68
std::vector< T > _calculate_prediction(const std::vector< T > input, const std::vector< T > internalVariables, const bool fullSpace, std::vector< T > &constraints)
Calculates the prediction of the feed forward net for a given point.
Definition ffNet.h:343
std::unique_ptr< Scaler< T > > _inputScaler
Definition ffNet.h:57
void get_full_space_variables(unsigned int &variableNumber, std::vector< std::string > &variableNames, std::vector< std::pair< double, double > > &variableBounds)
Returns the number and the names of the internal variables of the network.
Definition ffNet.h:289
static T _tanh_reformulation_3(T x)
Definition ffNet.h:65
T(* _tanh_formulation)(T)
Definition ffNet.h:61
FeedForwardNet(std::string modelPath, std::string modelName, MODEL_FILE_TYPE fileType)
Constructor for creating object from file with the modelName being relative to modelPath.
Definition ffNet.h:130
static T _tanh_reformulation_1(T x)
Definition ffNet.h:63
static T _relu6(T x)
Definition ffNet.h:69
FeedForwardNet(std::string modelName, MODEL_FILE_TYPE fileType)
Constructor for creating object from file with the modelName relative to the current working director...
Definition ffNet.h:119
static T _tanh_reformulation_4(T x)
Definition ffNet.h:66
static T _tanh(T x)
Definition ffNet.h:62
void _set_data_object(std::shared_ptr< const ModelData > modelData) override
Sets data object containing model parameters.
Definition ffNet.h:196
std::vector< T > calculate_prediction_reduced_space(const std::vector< T > input)
Calculates the prediction of the feed forward net for a given point in reduced space mode (only value...
Definition ffNet.h:211
static T _tanh_reformulation_2(T x)
Definition ffNet.h:64
Definition MeLOn.h:32
void load_model(std::string modelName, MODEL_FILE_TYPE fileType)
Loads new model from file.
Definition MeLOn.h:114
static std::unique_ptr< Scaler< T > > create_scaler(const std::shared_ptr< const ScalerData > scalerData)
Factory function for creating a instance of a scaler object.
Definition scaler.h:208
Definition kernel.h:21
MODEL_FILE_TYPE
Enum for representing the parsable filetypes.
Definition modelParser.h:30
ACTIVATION_FUNCTION
Enum for representing the available types of scaler parameters.
Definition AnnProperties.h:30
@ PURE_LIN
Definition AnnProperties.h:31
@ RELU6
Definition AnnProperties.h:34
@ RELU
Definition AnnProperties.h:33
@ TANH
Definition AnnProperties.h:32
TANH_REFORMULATION
Enum for representing the different reformulations for the tanh activation function.
Definition ffNet.h:37
@ TANH_REF_0
Definition ffNet.h:38
@ TANH_REF4
Definition ffNet.h:42
@ TANH_REF1
Definition ffNet.h:39
@ TANH_REF3
Definition ffNet.h:41
@ TANH_REF2
Definition ffNet.h:40