Point Cloud Library (PCL)  1.13.1-dev
svm_wrapper.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  * Copyright (c) 2000-2012 Chih-Chung Chang and Chih-Jen Lin
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of copyright holders nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  */
38 
39 #pragma once
40 
41 #include <pcl/console/print.h> // for PCL_ERROR
42 #include <pcl/ml/svm.h>
43 
44 #include <cassert> // for assert
45 #include <cstdio>
46 #include <cstdlib>
47 #include <limits> // for numeric_limits
48 #include <string> // for string
49 #include <vector>
50 #define Malloc(type, n) static_cast<type*>(malloc((n) * sizeof(type)))
51 
52 namespace pcl {
53 
54 /** The structure stores the parameters for the classificationa nd must be initialized
55  * and passed to the training method pcl::SVMTrain.
56  *
57  * \param svm_type {C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR}
58  * \param kernel_type {LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED}
59  * \param probability sets the probability estimates
60  */
63  {
64  svm_type = C_SVC; // C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR
65  kernel_type = RBF; // LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED
66  degree = 3; // for poly
67  gamma = 0; // 1/num_features {for poly/rbf/sigmoid}
68  coef0 = 0; // for poly/sigmoid
69 
70  nu = 0.5; // for NU_SVC, ONE_CLASS, and NU_SVR
71  cache_size = 100; // in MB
72  C = 1; // for C_SVC, EPSILON_SVR and NU_SVR
73  eps = 1e-3; // stopping criteria
74  p = 0.1; // for EPSILON_SVR
75  shrinking = 0; // use the shrinking heuristics
76  probability = 0; // do probability estimates
77 
78  nr_weight = 0; // for C_SVC
79  weight_label = nullptr; // for C_SVC
80  weight = nullptr; // for C_SVC
81  }
82 };
83 
84 /** The structure initialize a model created by the SVM (Support Vector Machines)
85  * classifier (pcl::SVMTrain).
86  */
87 struct SVMModel : svm_model {
89  {
90  l = 0;
91  probA = nullptr;
92  probB = nullptr;
93  }
94 };
95 
96 /** The structure initialize a single feature value for the classification using
97  * SVM (Support Vector Machines).
98  */
99 struct SVMDataPoint {
100  /// It's the feature index. It has to be an integer number greater or equal to zero
101  int idx{-1};
102  /// The value assigned to the correspondent feature.
103  float value{0};
104 
105  SVMDataPoint() = default;
106 };
107 
108 /** The structure stores the features and the label of a single sample which has to be
109  * used for the training or the classification of the SVM (Support Vector Machines).
110  */
111 struct SVMData {
112  /// Pointer to the label value. It is a mandatory to train the classifier
113  double label;
114  /// Vector of features for the specific sample.
115  std::vector<pcl::SVMDataPoint> SV;
116 
117  SVMData() : label(std::numeric_limits<double>::signaling_NaN()) {}
118 };
119 
120 /** Base class for SVM SVM (Support Vector Machines). */
121 class SVM {
122 protected:
123  std::vector<SVMData> training_set_; // Basic training set
124  svm_problem prob_; // contains the problem (vector of samples with their features)
125  SVMModel model_; // model of the classifier
126  svm_scaling scaling_; // for the best model training, the input dataset is scaled and
127  // the scaling factors are stored here
128  SVMParam param_; // it stores the training parameters
129  std::string class_name_; // The SVM class name.
130 
131  char* line_{nullptr}; // buffer for line reading
132  int max_line_len_{10000}; // max line length in the input file
134  true}; // it stores whether the input set of samples is labelled
135 
136  /** Set for output printings during classification. */
137  static void
138  printNull(const char*){};
139 
140  /** To read a line from the input file. Stored in "line_". */
141  char*
142  readline(FILE* input);
143 
144  /** Outputs an error in file reading. */
145  void
146  exitInputError(int line_num)
147  {
148  fprintf(stderr, "Wrong input format at line %d\n", line_num);
149  exit(1);
150  }
151 
152  /** Get a string representation of the name of this class. */
153  inline const std::string&
154  getClassName() const
155  {
156  return (class_name_);
157  }
158 
159  /** Convert the input format (vector of SVMData) into a readable format for libSVM. */
160  void
161  adaptInputToLibSVM(std::vector<SVMData> training_set, svm_problem& prob);
162 
163  /** Convert the libSVM format (svm_problem) into a easier output format. */
164  void
165  adaptLibSVMToInput(std::vector<SVMData>& training_set, svm_problem prob) const;
166 
167  /** Load a problem from an extern file. */
168  bool
169  loadProblem(const char* filename, svm_problem& prob);
170 
171  /** Save the raw problem in an extern file.*/
172  bool
173  saveProblem(const char* filename, bool labelled);
174 
175  /** Save the problem (with normalized values) in an extern file.*/
176  bool
177  saveProblemNorm(const char* filename, svm_problem prob_, bool labelled);
178 
179 public:
180  /** Constructor. */
181  SVM() : prob_() {}
182 
183  /** Destructor. */
185  {
186  svm_destroy_param(&param_); // delete parameters
187 
188  if (scaling_.max > 0)
189  free(scaling_.obj); // delete scaling factors
190 
191  // delete the problem
192  if (prob_.l > 0) {
193  free(prob_.x);
194  free(prob_.y);
195  }
196  }
197 
198  /** Return the labels order from the classifier model. */
199  void
200  getLabel(std::vector<int>& labels)
201  {
202  int nr_class = svm_get_nr_class(&model_);
203  int* labels_ = static_cast<int*>(malloc(nr_class * sizeof(int)));
204  svm_get_labels(&model_, labels_);
205 
206  for (int j = 0; j < nr_class; j++)
207  labels.push_back(labels_[j]);
208 
209  free(labels_);
210  };
211 
212  /** Save the classifier model in an extern file (in svmlight format). */
213  void
214  saveClassifierModel(const char* filename)
215  {
216  // exit if model has no data
217  if (model_.l == 0)
218  return;
219 
220  if (svm_save_model(filename, &model_)) {
221  fprintf(stderr, "can't save model to file %s\n", filename);
222  exit(1);
223  }
224  };
225 };
226 
227 /** SVM (Support Vector Machines) training class for the SVM machine learning.
228  *
229  * It creates a model for the classifier from a labelled input dataset.
230  *
231  * OPTIONAL: pcl::SVMParam has to be given as input to vary the default training method
232  * and parameters.
233  */
234 class SVMTrain : public SVM {
235 protected:
236  using SVM::class_name_;
238  using SVM::line_;
239  using SVM::max_line_len_;
240  using SVM::model_;
241  using SVM::param_;
242  using SVM::prob_;
243  using SVM::scaling_;
244  using SVM::training_set_;
245 
246  /// Set to 1 to see the training output
247  bool debug_{false};
248  /// Set too 1 for cross validating the classifier
250  /// Number of folds to be used during cross validation. It indicates in how many parts
251  /// is split the input training set.
252  int nr_fold_{0};
253 
254  /** To cross validate the classifier. It is automatic for probability estimate. */
255  void
257 
258  /** It extracts scaling factors from the input training_set.
259  *
260  * The scaling of the training_set is a mandatory for a good training of the
261  * classifier. */
262  void
263  scaleFactors(std::vector<SVMData> training_set, svm_scaling& scaling);
264 
265 public:
266  /** Constructor. */
268  {
269  class_name_ = "SVMTrain";
270  svm_set_print_string_function(
271  &printNull); // Default to NULL to not print debugging info
272  }
273 
274  /** Destructor. */
276  {
277  if (model_.l > 0)
278  svm_free_model_content(&model_);
279  }
280 
281  /** Change default training parameters (pcl::SVMParam). */
282  void
284  {
285  param_ = param;
286  }
287 
288  /** Return the current training parameters. */
289  SVMParam
291  {
292  return param_;
293  }
294 
295  /** Return the result of the training. */
296  SVMModel
298  {
299  return model_;
300  }
301 
302  /** It adds/store the training set with labelled data. */
303  void
304  setInputTrainingSet(std::vector<SVMData> training_set)
305  {
306  training_set_.insert(training_set_.end(), training_set.begin(), training_set.end());
307  }
308 
309  /** Return the current training set. */
310  std::vector<SVMData>
312  {
313  return training_set_;
314  }
315 
316  /** Reset the training set. */
317  void
319  {
320  training_set_.clear();
321  }
322 
323  /** Start the training of the SVM classifier.
324  *
325  * \return false if fails
326  */
327  bool
329 
330  /** Read in a problem (in svmlight format).
331  *
332  * \return false if fails
333  */
334  bool
335  loadProblem(const char* filename)
336  {
337  return SVM::loadProblem(filename, prob_);
338  };
339 
340  /** Set to 1 for debugging info. */
341  void
342  setDebugMode(bool in)
343  {
344  debug_ = in;
345 
346  if (in)
347  svm_set_print_string_function(nullptr);
348  else
349  svm_set_print_string_function(&printNull);
350  };
351 
352  /** Save the raw training set in a file (in svmlight format).
353  *
354  * \return false if fails
355  */
356  bool
357  saveTrainingSet(const char* filename)
358  {
359  return SVM::saveProblem(filename, true);
360  };
361 
362  /** Save the normalized training set in a file (in svmlight format).
363  *
364  * \return false if fails
365  */
366  bool
367  saveNormTrainingSet(const char* filename)
368  {
369  return SVM::saveProblemNorm(filename, prob_, true);
370  };
371 };
372 
373 /** SVM (Support Vector Machines) classification of a dataset.
374  *
375  * It can be used both for testing a classifier model and for classify of new data.
376  */
377 class SVMClassify : public SVM {
378 protected:
379  using SVM::class_name_;
381  using SVM::line_;
382  using SVM::max_line_len_;
383  using SVM::model_;
384  using SVM::param_;
385  using SVM::prob_;
386  using SVM::scaling_;
387  using SVM::training_set_;
388 
390  false}; // Set to 0 if the model is loaded from an extern file.
391  bool predict_probability_{false}; // Set to 1 to predict probabilities.
392  std::vector<std::vector<double>> prediction_; // It stores the resulting prediction.
393 
394  /** It scales the input dataset using the model information. */
395  void
397 
398 public:
399  /** Constructor. */
400  SVMClassify() { class_name_ = "SvmClassify"; }
401 
402  /** Destructor. */
404  {
405  if (!model_extern_copied_ && model_.l > 0)
406  svm_free_model_content(&model_);
407  }
408 
409  /** It adds/store the training set with labelled data. */
410  void
411  setInputTrainingSet(std::vector<SVMData> training_set)
412  {
413  assert(training_set.size() > 0);
414 
415  if (scaling_.max == 0) {
416  // to be sure to have loaded the scaling
417  PCL_ERROR("[pcl::%s::setInputTrainingSet] Classifier model not loaded!\n",
418  getClassName().c_str());
419  return;
420  }
421 
422  training_set_.insert(training_set_.end(), training_set.begin(), training_set.end());
424  }
425 
426  /** Return the current training set. */
427  std::vector<SVMData>
429  {
430  return training_set_;
431  }
432 
433  /** Reset the training set. */
434  void
436  {
437  training_set_.clear();
438  }
439 
440  /** Read in a classifier model (in svmlight format).
441  *
442  * \return false if fails
443  */
444  bool
445  loadClassifierModel(const char* filename);
446 
447  /** Get the result of the classification. */
448  void
449  getClassificationResult(std::vector<std::vector<double>>& out)
450  {
451  out.clear();
452  out.insert(out.begin(), prediction_.begin(), prediction_.end());
453  }
454 
455  /** Save the classification result in an extern file. */
456  void
457  saveClassificationResult(const char* filename);
458 
459  /** Set the classifier model. */
460  void
462  {
463  // model (inner pointers are references)
464  model_ = model;
465  int i = 0;
466 
467  while (model_.scaling[i].index != -1)
468  i++;
469 
470  scaling_.max = i;
471  scaling_.obj = Malloc(struct svm_node, i + 1);
472  scaling_.obj[i].index = -1;
473 
474  // Performing full scaling copy
475  for (int j = 0; j < i; j++) {
476  scaling_.obj[j] = model_.scaling[j];
477  }
478 
479  model_extern_copied_ = true;
480  };
481 
482  /** Read in a raw classification problem (in svmlight format).
483  *
484  * The values are normalized using the classifier model information.
485  *
486  * \return false if fails
487  */
488  bool
489  loadClassProblem(const char* filename)
490  {
491  assert(model_.l != 0);
492 
493  bool out = SVM::loadProblem(filename, prob_);
496  return out;
497  };
498 
499  /** Read in a normalized classification problem (in svmlight format).
500  *
501  * The data is kept without normalizing.
502  *
503  * \return false if fails
504  */
505  bool
506  loadNormClassProblem(const char* filename)
507  {
508  bool out = SVM::loadProblem(filename, prob_);
510  return out;
511  };
512 
513  /** Set whether the classification has to be done with the probability estimate. (The
514  * classifier model has to support it). */
515  void
517  {
518  predict_probability_ = set;
519  };
520 
521  /** Start the classification on labelled input dataset.
522  *
523  * It returns the accuracy percentage. To get the classification result, use
524  * getClassificationResult().
525  *
526  * \return false if fails
527  */
528  bool
530 
531  /** Start the classification on un-labelled input dataset.
532  *
533  * To get the classification result, use getClassificationResult().
534  *
535  * \return false if fails
536  */
537  bool
539 
540  /** Start the classification on a single set. */
541  std::vector<double>
543 
544  /** Save the raw classification problem in a file (in svmlight format).
545  *
546  * \return false if fails
547  */
548  bool
549  saveClassProblem(const char* filename)
550  {
551  return SVM::saveProblem(filename, false);
552  };
553 
554  /** Save the normalized classification problem in a file (in svmlight format).
555  *
556  * \return false if fails
557  */
558  bool
559  saveNormClassProblem(const char* filename)
560  {
561  return SVM::saveProblemNorm(filename, prob_, false);
562  };
563 };
564 
565 } // namespace pcl
SVM (Support Vector Machines) classification of a dataset.
Definition: svm_wrapper.h:377
bool saveClassProblem(const char *filename)
Save the raw classification problem in a file (in svmlight format).
Definition: svm_wrapper.h:549
bool saveNormClassProblem(const char *filename)
Save the normalized classification problem in a file (in svmlight format).
Definition: svm_wrapper.h:559
std::vector< std::vector< double > > prediction_
Definition: svm_wrapper.h:392
bool loadClassProblem(const char *filename)
Read in a raw classification problem (in svmlight format).
Definition: svm_wrapper.h:489
void resetTrainingSet()
Reset the training set.
Definition: svm_wrapper.h:435
bool predict_probability_
Definition: svm_wrapper.h:391
~SVMClassify()
Destructor.
Definition: svm_wrapper.h:403
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
Definition: svm_wrapper.h:428
std::vector< double > classification(SVMData in)
Start the classification on a single set.
bool classification()
Start the classification on un-labelled input dataset.
void saveClassificationResult(const char *filename)
Save the classification result in an extern file.
void setProbabilityEstimates(bool set)
Set whether the classification has to be done with the probability estimate.
Definition: svm_wrapper.h:516
void getClassificationResult(std::vector< std::vector< double >> &out)
Get the result of the classification.
Definition: svm_wrapper.h:449
SVMClassify()
Constructor.
Definition: svm_wrapper.h:400
bool model_extern_copied_
Definition: svm_wrapper.h:389
bool classificationTest()
Start the classification on labelled input dataset.
void setClassifierModel(SVMModel model)
Set the classifier model.
Definition: svm_wrapper.h:461
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
Definition: svm_wrapper.h:411
bool loadClassifierModel(const char *filename)
Read in a classifier model (in svmlight format).
std::string class_name_
Definition: svm_wrapper.h:129
svm_scaling scaling_
Definition: svm_wrapper.h:126
svm_problem prob_
Definition: svm_wrapper.h:124
void scaleProblem(svm_problem &input, svm_scaling scaling)
It scales the input dataset using the model information.
std::vector< SVMData > training_set_
Definition: svm_wrapper.h:123
bool loadNormClassProblem(const char *filename)
Read in a normalized classification problem (in svmlight format).
Definition: svm_wrapper.h:506
Base class for SVM SVM (Support Vector Machines).
Definition: svm_wrapper.h:121
SVMModel model_
Definition: svm_wrapper.h:125
bool loadProblem(const char *filename, svm_problem &prob)
Load a problem from an extern file.
char * readline(FILE *input)
To read a line from the input file.
void saveClassifierModel(const char *filename)
Save the classifier model in an extern file (in svmlight format).
Definition: svm_wrapper.h:214
const std::string & getClassName() const
Get a string representation of the name of this class.
Definition: svm_wrapper.h:154
int max_line_len_
Definition: svm_wrapper.h:132
char * line_
Definition: svm_wrapper.h:131
bool labelled_training_set_
Definition: svm_wrapper.h:133
void adaptLibSVMToInput(std::vector< SVMData > &training_set, svm_problem prob) const
Convert the libSVM format (svm_problem) into a easier output format.
~SVM()
Destructor.
Definition: svm_wrapper.h:184
void adaptInputToLibSVM(std::vector< SVMData > training_set, svm_problem &prob)
Convert the input format (vector of SVMData) into a readable format for libSVM.
std::string class_name_
Definition: svm_wrapper.h:129
bool saveProblem(const char *filename, bool labelled)
Save the raw problem in an extern file.
void getLabel(std::vector< int > &labels)
Return the labels order from the classifier model.
Definition: svm_wrapper.h:200
SVM()
Constructor.
Definition: svm_wrapper.h:181
svm_scaling scaling_
Definition: svm_wrapper.h:126
SVMParam param_
Definition: svm_wrapper.h:128
svm_problem prob_
Definition: svm_wrapper.h:124
void exitInputError(int line_num)
Outputs an error in file reading.
Definition: svm_wrapper.h:146
std::vector< SVMData > training_set_
Definition: svm_wrapper.h:123
bool saveProblemNorm(const char *filename, svm_problem prob_, bool labelled)
Save the problem (with normalized values) in an extern file.
static void printNull(const char *)
Set for output printings during classification.
Definition: svm_wrapper.h:138
SVM (Support Vector Machines) training class for the SVM machine learning.
Definition: svm_wrapper.h:234
SVMModel model_
Definition: svm_wrapper.h:125
void doCrossValidation()
To cross validate the classifier.
void resetTrainingSet()
Reset the training set.
Definition: svm_wrapper.h:318
~SVMTrain()
Destructor.
Definition: svm_wrapper.h:275
int cross_validation_
Set too 1 for cross validating the classifier.
Definition: svm_wrapper.h:249
SVMModel getClassifierModel()
Return the result of the training.
Definition: svm_wrapper.h:297
bool debug_
Set to 1 to see the training output.
Definition: svm_wrapper.h:247
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
Definition: svm_wrapper.h:304
bool loadProblem(const char *filename)
Read in a problem (in svmlight format).
Definition: svm_wrapper.h:335
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
Definition: svm_wrapper.h:311
bool saveNormTrainingSet(const char *filename)
Save the normalized training set in a file (in svmlight format).
Definition: svm_wrapper.h:367
bool saveTrainingSet(const char *filename)
Save the raw training set in a file (in svmlight format).
Definition: svm_wrapper.h:357
bool trainClassifier()
Start the training of the SVM classifier.
void setDebugMode(bool in)
Set to 1 for debugging info.
Definition: svm_wrapper.h:342
void scaleFactors(std::vector< SVMData > training_set, svm_scaling &scaling)
It extracts scaling factors from the input training_set.
void setParameters(SVMParam param)
Change default training parameters (pcl::SVMParam).
Definition: svm_wrapper.h:283
std::string class_name_
Definition: svm_wrapper.h:129
SVMParam param_
Definition: svm_wrapper.h:128
svm_problem prob_
Definition: svm_wrapper.h:124
std::vector< SVMData > training_set_
Definition: svm_wrapper.h:123
int nr_fold_
Number of folds to be used during cross validation.
Definition: svm_wrapper.h:252
SVMParam getParameters()
Return the current training parameters.
Definition: svm_wrapper.h:290
SVMTrain()
Constructor.
Definition: svm_wrapper.h:267
The structure stores the features and the label of a single sample which has to be used for the train...
Definition: svm_wrapper.h:111
std::vector< pcl::SVMDataPoint > SV
Vector of features for the specific sample.
Definition: svm_wrapper.h:115
double label
Pointer to the label value. It is a mandatory to train the classifier.
Definition: svm_wrapper.h:113
The structure initialize a single feature value for the classification using SVM (Support Vector Mach...
Definition: svm_wrapper.h:99
int idx
It's the feature index. It has to be an integer number greater or equal to zero.
Definition: svm_wrapper.h:101
float value
The value assigned to the correspondent feature.
Definition: svm_wrapper.h:103
SVMDataPoint()=default
The structure initialize a model created by the SVM (Support Vector Machines) classifier (pcl::SVMTra...
Definition: svm_wrapper.h:87
The structure stores the parameters for the classificationa nd must be initialized and passed to the ...
Definition: svm_wrapper.h:61
Definition: svm.h:99
struct svm_node * scaling
Definition: svm.h:122
double * probB
Definition: svm.h:109
int l
Definition: svm.h:103
double * probA
Definition: svm.h:108
Definition: svm.h:49
int index
Definition: svm.h:50
double cache_size
Definition: svm.h:83
int * weight_label
Definition: svm.h:87
double eps
Definition: svm.h:84
double coef0
Definition: svm.h:80
int svm_type
Definition: svm.h:76
double p
Definition: svm.h:90
int kernel_type
Definition: svm.h:77
int nr_weight
Definition: svm.h:86
double nu
Definition: svm.h:89
double gamma
Definition: svm.h:79
double C
Definition: svm.h:85
int probability
Definition: svm.h:92
int shrinking
Definition: svm.h:91
int degree
Definition: svm.h:78
double * weight
Definition: svm.h:88
int l
Definition: svm.h:55
double * y
Definition: svm.h:56
struct svm_node ** x
Definition: svm.h:58
struct svm_node * obj
Definition: svm.h:64
int max
Definition: svm.h:67