MeLOn
svm.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 svm.h
11 *
12 * @brief File containing declaration of the support vector machine class.
13 *
14 **********************************************************************************/
15 
16 #include <vector>
17 #include <string>
18 #include <cmath>
19 #include <memory>
20 
21 #include "MeLOn.h"
22 #include "exceptions.h"
23 #include "kernel.h"
24 #include "scaler.h"
25 #include "vectorarithmetics.h"
26 #include "svmData.h"
27 #include "svmParser.h"
28 
29 namespace melon {
30 
35  template<typename T>
36  class SupportVectorMachine : public MelonModel<T> {
37  protected:
38  std::shared_ptr<const SvmData> _data;
39  std::unique_ptr<kernel::StationaryKernel<double, T>> _kernel;
41  std::unique_ptr<Scaler<T>> _inputScaler;
42  std::unique_ptr<Scaler<T>> _outputScaler;
49  void _set_data_object(std::shared_ptr<const ModelData> modelData) override;
50 
64  T _calculate_prediction(std::vector<T> input, std::vector<T> internalVariables, const bool fullSpace, std::vector<T>& constraints);
65 
69  void _update_kernel();
70 
78  virtual T _decision_function(std::vector<T> kernelValues) = 0;
79 
80  public:
81 
85  SupportVectorMachine() : MelonModel<T>(std::make_shared<SvmParserFactory>()) {};
86 
92  SupportVectorMachine(std::string modelName) : SupportVectorMachine() { this->load_model(modelName, MODEL_FILE_TYPE::JSON); };
93 
101  SupportVectorMachine(std::string modelPath, std::string modelName) : SupportVectorMachine() { this->load_model(modelPath, modelName, MODEL_FILE_TYPE::JSON); };
102 
108  SupportVectorMachine(std::shared_ptr<const SvmData> modelData) : SupportVectorMachine() { this->load_model(modelData); };
109 
119  void get_fullspace_variables(size_t& variableNumber, std::vector<std::string>& variableNames, std::vector<std::pair<double, double>>& variableBounds);
120 
132  T calculate_prediction_full_space(std::vector<T> input, std::vector<T> internalVariables, std::vector<T>& constraints);
133 
141  T calculate_prediction_reduced_space(std::vector<T> input);
142 
149  };
150 
155  template<typename T>
156  class SupportVectorRegression : public SupportVectorMachine<T> {
157  private:
158 
166  T _decision_function(std::vector<T> input) override;
167  public:
168  // Inherit SupportVectorMachine constructors
170  };
171 
176  template<typename T>
178  private:
179 
187  T _decision_function(std::vector<T> input) override;
188  public:
189  // Inherit SupportVectorMachine constructors
191 
193  // Sets data object containing model parameters.
194  template<typename T>
195  void SupportVectorMachine<T>::_set_data_object(std::shared_ptr<const ModelData> modelData) {
196  // Downcast the ModelData pointer to a SvmData pointer
197  _data = std::dynamic_pointer_cast<const SvmData>(modelData);
198  if (_data == nullptr) {
199  throw(MelonException(" Error while loading support vector machine: Incorrect type of passed data object. The data object must be of type SvmData."));
200  }
201 
202  _inputScaler = ScalerFactory<T>::create_scaler(_data->inputScalerData);
203  _outputScaler = ScalerFactory<T>::create_scaler(_data->outputScalerData);
204  _update_kernel();
205  }
206 
207 
209  // Loads kernel according to loaded internal parameters
210  template<typename T>
212  switch (_data->kernelFunction) {
214  _kernel = std::unique_ptr<kernel::KernelRBF<double, T>>(new kernel::KernelRBF<double, T>(_data->kernelParameters.front()));
215  }
216  }
217 
218 
220  // Calculates prediction based on inputs and set constraints for fullspace formulation
221  template<typename T>
222  T SupportVectorMachine<T>::calculate_prediction_full_space(std::vector<T> input, std::vector<T> internalVariables, std::vector<T>& constraints) {
223  try{
224  return _calculate_prediction(input, internalVariables, true, constraints);
225  }
226  catch (const std::exception& e) {
227  throw(MelonException(" Encountered a fatal error while evaluating support vector machine. Terminating.", e));
228  }
229  catch (...) {
230  throw(MelonException(" Encountered a fatal error while evaluating support vector machine. Terminating."));
231  }
232 
233  }
234 
235 
237  // Calculates prediction based on inputs in reduced space
238  template<typename T>
240  std::vector<T> dummyInternalVariables;
241  std::vector<T> dummyConstraints;
242  try{
243  return _calculate_prediction(input, dummyInternalVariables, false, dummyConstraints);
244  }
245  catch (const std::exception& e) {
246  throw(MelonException(" Encountered a fatal error while evaluating support vector machine. Terminating.", e));
247  }
248  catch (...) {
249  throw(MelonException(" Encountered a fatal error while evaluating support vector machine. Terminating."));
250  }
251  }
252 
253 
255  // Calculates prediction
256  template<typename T>
257  T SupportVectorMachine<T>::_calculate_prediction(std::vector<T> input, std::vector<T> internalVariables, const bool fullSpace, std::vector<T>& constraints) {
258 
259  // ---------------------------------------------------------------------------------
260  // 0: Check input dimensions
261  // ---------------------------------------------------------------------------------
262 
263  if (input.size() != _data->supportVectors.at(0).size()) {
264  throw MelonException(" Error while calculating svm prediction: Incorrect input dimension. In reduced space mode evaluation the size of the variables vector must be equal to the input dimension of the svm.");
265  }
266  if (fullSpace) {
267  size_t variablesSize = get_number_of_full_space_variables();
268  if (internalVariables.size() != variablesSize) {
269  throw MelonException(" Error while calculating svm prediction: Incorrect input dimension. In full space mode evaluation the size of the variables vector be equal to the number of internal variables.");
270  }
271  }
272 
273  auto variableIterator = internalVariables.begin();
274  if (this->_modelLoaded) {
275 
276  // ---------------------------------------------------------------------------------
277  // 1: Scale inputs
278  // ---------------------------------------------------------------------------------
279 
280  std::vector<T> scaledInput = _inputScaler->scale(input);
281  if (fullSpace) {
282  this->_set_constraints(constraints, scaledInput, variableIterator);
283  }
284 
285  // ---------------------------------------------------------------------------------
286  // 2: Evaluate kernel for support vectors and input
287  // ---------------------------------------------------------------------------------
288 
289  std::vector<T> kernelValues;
290  kernelValues.reserve(_data->supportVectors.size());
291  for (auto& iSupportVector: _data->supportVectors) {
292  T distance = _kernel->calculate_distance(iSupportVector, scaledInput);
293  if (fullSpace) {
294  this->_set_constraints(constraints, distance, variableIterator);
295  }
296 
297  T kernelValue = _kernel->evaluate_kernel(distance);
298  if (fullSpace) {
299  this->_set_constraints(constraints, kernelValue, variableIterator);
300  }
301 
302  kernelValues.push_back(kernelValue);
303  }
304 
305  // ---------------------------------------------------------------------------------
306  // 3: Evaluate decision function
307  // ---------------------------------------------------------------------------------
308 
309  T result = _decision_function(kernelValues);
310  if (fullSpace) {
311  this->_set_constraints(constraints, result, variableIterator);
312  }
313 
314  // ---------------------------------------------------------------------------------
315  // 4: Descale ouput
316  // ---------------------------------------------------------------------------------
317 
318  T output = _outputScaler->descale({ result }).front();
319  if (fullSpace) {
320  this->_set_constraints(constraints, output, variableIterator);
321  }
322 
323  return output;
324  }
325  else {
326  throw MelonException{ " Error while calculating support vector machine prediction: No model was loaded yet." };
327  }
328  }
329 
330 
332  // Decision function for support vector regression.
333  template<typename T>
334  T SupportVectorRegression<T>::_decision_function(std::vector<T> input) {
335  return dot_product(this->_data->dualCoefficients, input) + this->_data->rho;
336  }
337 
338 
340  // Decision function for one class support vector machine.
341  template<typename T>
343  return dot_product(this->_data->dualCoefficients, input) + this->_data->rho;
344  }
345 
346 
348  // Calculates the number of full space variables.
349  template<typename T>
351  size_t variableNumber;
352  std::vector<std::string> variableNames;
353  std::vector<std::pair<double, double>> variableBounds;
354  get_fullspace_variables(variableNumber, variableNames, variableBounds);
355  return variableNumber;
356  }
357 
358 
360  // Creates variables for the full space formulation in MAiNGO.
361  template<typename T>
362  void SupportVectorMachine<T>::get_fullspace_variables(size_t& variableNumber, std::vector<std::string>& variableNames, std::vector<std::pair<double, double>>& variableBounds) {
363 
364  variableNumber = 0;
365  variableNames.clear();
366  variableBounds.clear();
367 
368 
369  // get max squared distance between support vectors
370  auto n = this->_data->supportVectors.at(0).size();
371  auto lbs = std::vector<double>(n, 1e6);
372  auto ubs = std::vector<double>(n, -1e6);
373  for (auto iSupportVector : this->_data->supportVectors) {
374  for (int i = 0; i < iSupportVector.size(); i++) {
375  auto xi = iSupportVector[i];
376  if (xi < lbs[i]) lbs[i] = xi;
377  if (xi > ubs[i]) ubs[i] = xi;
378  }
379  }
380  double maxSquaredDistance = 0;
381  for (size_t i = 0; i < lbs.size(); i++) {
382  maxSquaredDistance = maxSquaredDistance + (ubs[i] - lbs[i])*(ubs[i] - lbs[i]);
383  }
384 
385  //std::cout << "Hint: Using max squared distance = " << maxSquaredDistance << "\n\n\n";
386 
387  variableNumber += 2 * _data->dualCoefficients.size();
388  for (int i = 0; i < _data->dualCoefficients.size(); i++) {
389  variableNames.push_back("squared_distance_" + std::to_string(i));
390  variableNames.push_back("kernel_value_" + std::to_string(i));
391  variableBounds.push_back(std::make_pair(0., maxSquaredDistance));
392  variableBounds.push_back(std::make_pair(0., 1.0));
393  }
394 
395  double sum_alpha = 0;
396  for (auto alpha : this->_data->dualCoefficients) {
397  sum_alpha = sum_alpha + alpha;
398  }
399 
400  variableNames.push_back("prediction");
401  if (this->_data->kernelFunction == RBF) {
402  variableBounds.push_back(std::make_pair(0, (sum_alpha - this->_data->rho)));
403  }
404  else {
405  variableBounds.push_back(std::make_pair(-1e6, 1e6));
406 
407  }
408  variableNumber++;
409  }
410 }
kernel.h
melon::SupportVectorMachine::_calculate_prediction
T _calculate_prediction(std::vector< T > input, std::vector< T > internalVariables, const bool fullSpace, std::vector< T > &constraints)
Calculates prediction.
Definition: svm.h:270
exceptions.h
melon::SupportVectorMachine::calculate_prediction_full_space
T calculate_prediction_full_space(std::vector< T > input, std::vector< T > internalVariables, std::vector< T > &constraints)
Calculates prediction based on inputs and set constraints for fullspace formulation.
Definition: svm.h:235
melon::SupportVectorMachine::calculate_prediction_reduced_space
T calculate_prediction_reduced_space(std::vector< T > input)
Calculates prediction based on inputs in reduced space.
Definition: svm.h:252
melon::SupportVectorMachine::_kernel
std::unique_ptr< kernel::StationaryKernel< double, T > > _kernel
Definition: svm.h:52
melon::MelonModel
Definition: MeLOn.h:45
melon::RBF
@ RBF
Definition: svmData.h:45
melon::SupportVectorMachine::get_fullspace_variables
void get_fullspace_variables(size_t &variableNumber, std::vector< std::string > &variableNames, std::vector< std::pair< double, double >> &variableBounds)
Creates variables for the full space formulation in MAiNGO.
Definition: svm.h:375
vectorarithmetics.h
melon::dot_product
auto dot_product(const std::vector< T > &v1, const std::vector< U > &v2)
Overloaded operator for vector class allowing the calulation of dot product of two vectors.
Definition: vectorarithmetics.h:168
MeLOn.h
svmParser.h
scaler.h
melon::SupportVectorMachineOneClass::_decision_function
T _decision_function(std::vector< T > input) override
Decision function for one class support vector machine.
Definition: svm.h:355
melon::SupportVectorMachineOneClass
Class defining support vector machine for one class classification to be used in the MAiNGO solver.
Definition: svm.h:190
melon::SupportVectorMachine::_update_kernel
void _update_kernel()
Loads kernel according to loaded internal parameters.
Definition: svm.h:224
melon::SupportVectorMachine::SupportVectorMachine
SupportVectorMachine()
Default Constructor.
Definition: svm.h:98
melon::SvmParserFactory
This class is a factory class for creating child instances of SvmParser.
Definition: svmParser.h:74
melon::MelonModel::load_model
void load_model(std::string modelName, MODEL_FILE_TYPE fileType)
Loads new model from file.
Definition: MeLOn.h:127
melon::SupportVectorMachine::_set_data_object
void _set_data_object(std::shared_ptr< const ModelData > modelData) override
Sets data object containing model parameters.
Definition: svm.h:208
svmData.h
melon::SupportVectorMachine::_data
std::shared_ptr< const SvmData > _data
Definition: svm.h:51
melon::SupportVectorMachine::_inputScaler
std::unique_ptr< Scaler< T > > _inputScaler
Definition: svm.h:54
melon::SupportVectorMachine::_decision_function
virtual T _decision_function(std::vector< T > kernelValues)=0
Decision function used by the different types of svms.
melon::SupportVectorMachine::_outputScaler
std::unique_ptr< Scaler< T > > _outputScaler
Definition: svm.h:55
MelonException
This class defines the exceptions thrown by FeedForwardNet.
Definition: exceptions.h:32
melon::JSON
@ JSON
Definition: modelParser.h:46
melon::SupportVectorMachine::get_number_of_full_space_variables
size_t get_number_of_full_space_variables()
Calculates the number of full space variables.
Definition: svm.h:363
melon
Definition: kernel.h:21
melon::SupportVectorMachine
Class defining support vector machine to be used in the MAiNGO solver.
Definition: svm.h:49
melon::ScalerFactory::create_scaler
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:221
melon::SupportVectorRegression::_decision_function
T _decision_function(std::vector< T > input) override
Decision function for support vector regression.
Definition: svm.h:347