Point Cloud Library (PCL)  1.12.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;
102  /// The value assigned to the correspondent feature.
103  float value;
104 
105  SVMDataPoint() : idx(-1), value(0) {}
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_; // buffer for line reading
132  int max_line_len_; // max line length in the input file
133  bool labelled_training_set_; // it stores whether the input set of samples is labelled
134 
135  /** Set for output printings during classification. */
136  static void
137  printNull(const char*){};
138 
139  /** To read a line from the input file. Stored in "line_". */
140  char*
141  readline(FILE* input);
142 
143  /** Outputs an error in file reading. */
144  void
145  exitInputError(int line_num)
146  {
147  fprintf(stderr, "Wrong input format at line %d\n", line_num);
148  exit(1);
149  }
150 
151  /** Get a string representation of the name of this class. */
152  inline const std::string&
153  getClassName() const
154  {
155  return (class_name_);
156  }
157 
158  /** Convert the input format (vector of SVMData) into a readable format for libSVM. */
159  void
160  adaptInputToLibSVM(std::vector<SVMData> training_set, svm_problem& prob);
161 
162  /** Convert the libSVM format (svm_problem) into a easier output format. */
163  void
164  adaptLibSVMToInput(std::vector<SVMData>& training_set, svm_problem prob) const;
165 
166  /** Load a problem from an extern file. */
167  bool
168  loadProblem(const char* filename, svm_problem& prob);
169 
170  /** Save the raw problem in an extern file.*/
171  bool
172  saveProblem(const char* filename, bool labelled);
173 
174  /** Save the problem (with normalized values) in an extern file.*/
175  bool
176  saveProblemNorm(const char* filename, svm_problem prob_, bool labelled);
177 
178 public:
179  /** Constructor. */
180  SVM() : prob_(), line_(nullptr), max_line_len_(10000), labelled_training_set_(true) {}
181 
182  /** Destructor. */
184  {
185  svm_destroy_param(&param_); // delete parameters
186 
187  if (scaling_.max > 0)
188  free(scaling_.obj); // delete scaling factors
189 
190  // delete the problem
191  if (prob_.l > 0) {
192  free(prob_.x);
193  free(prob_.y);
194  }
195  }
196 
197  /** Return the labels order from the classifier model. */
198  void
199  getLabel(std::vector<int>& labels)
200  {
201  int nr_class = svm_get_nr_class(&model_);
202  int* labels_ = static_cast<int*>(malloc(nr_class * sizeof(int)));
203  svm_get_labels(&model_, labels_);
204 
205  for (int j = 0; j < nr_class; j++)
206  labels.push_back(labels_[j]);
207 
208  free(labels_);
209  };
210 
211  /** Save the classifier model in an extern file (in svmlight format). */
212  void
213  saveClassifierModel(const char* filename)
214  {
215  // exit if model has no data
216  if (model_.l == 0)
217  return;
218 
219  if (svm_save_model(filename, &model_)) {
220  fprintf(stderr, "can't save model to file %s\n", filename);
221  exit(1);
222  }
223  };
224 };
225 
226 /** SVM (Support Vector Machines) training class for the SVM machine learning.
227  *
228  * It creates a model for the classifier from a labelled input dataset.
229  *
230  * OPTIONAL: pcl::SVMParam has to be given as input to vary the default training method
231  * and parameters.
232  */
233 class SVMTrain : public SVM {
234 protected:
235  using SVM::class_name_;
237  using SVM::line_;
238  using SVM::max_line_len_;
239  using SVM::model_;
240  using SVM::param_;
241  using SVM::prob_;
242  using SVM::scaling_;
243  using SVM::training_set_;
244 
245  /// Set to 1 to see the training output
246  bool debug_;
247  /// Set too 1 for cross validating the classifier
249  /// Number of folds to be used during cross validation. It indicates in how many parts
250  /// is split the input training set.
251  int nr_fold_;
252 
253  /** To cross validate the classifier. It is automatic for probability estimate. */
254  void
256 
257  /** It extracts scaling factors from the input training_set.
258  *
259  * The scaling of the training_set is a mandatory for a good training of the
260  * classifier. */
261  void
262  scaleFactors(std::vector<SVMData> training_set, svm_scaling& scaling);
263 
264 public:
265  /** Constructor. */
267  {
268  class_name_ = "SVMTrain";
269  svm_set_print_string_function(
270  &printNull); // Default to NULL to not print debugging info
271  }
272 
273  /** Destructor. */
275  {
276  if (model_.l > 0)
277  svm_free_model_content(&model_);
278  }
279 
280  /** Change default training parameters (pcl::SVMParam). */
281  void
283  {
284  param_ = param;
285  }
286 
287  /** Return the current training parameters. */
288  SVMParam
290  {
291  return param_;
292  }
293 
294  /** Return the result of the training. */
295  SVMModel
297  {
298  return model_;
299  }
300 
301  /** It adds/store the training set with labelled data. */
302  void
303  setInputTrainingSet(std::vector<SVMData> training_set)
304  {
305  training_set_.insert(training_set_.end(), training_set.begin(), training_set.end());
306  }
307 
308  /** Return the current training set. */
309  std::vector<SVMData>
311  {
312  return training_set_;
313  }
314 
315  /** Reset the training set. */
316  void
318  {
319  training_set_.clear();
320  }
321 
322  /** Start the training of the SVM classifier.
323  *
324  * \return false if fails
325  */
326  bool
328 
329  /** Read in a problem (in svmlight format).
330  *
331  * \return false if fails
332  */
333  bool
334  loadProblem(const char* filename)
335  {
336  return SVM::loadProblem(filename, prob_);
337  };
338 
339  /** Set to 1 for debugging info. */
340  void
341  setDebugMode(bool in)
342  {
343  debug_ = in;
344 
345  if (in)
346  svm_set_print_string_function(nullptr);
347  else
348  svm_set_print_string_function(&printNull);
349  };
350 
351  /** Save the raw training set in a file (in svmlight format).
352  *
353  * \return false if fails
354  */
355  bool
356  saveTrainingSet(const char* filename)
357  {
358  return SVM::saveProblem(filename, true);
359  };
360 
361  /** Save the normalized training set in a file (in svmlight format).
362  *
363  * \return false if fails
364  */
365  bool
366  saveNormTrainingSet(const char* filename)
367  {
368  return SVM::saveProblemNorm(filename, prob_, true);
369  };
370 };
371 
372 /** SVM (Support Vector Machines) classification of a dataset.
373  *
374  * It can be used both for testing a classifier model and for classify of new data.
375  */
376 class SVMClassify : public SVM {
377 protected:
378  using SVM::class_name_;
380  using SVM::line_;
381  using SVM::max_line_len_;
382  using SVM::model_;
383  using SVM::param_;
384  using SVM::prob_;
385  using SVM::scaling_;
386  using SVM::training_set_;
387 
388  bool model_extern_copied_; // Set to 0 if the model is loaded from an extern file.
389  bool predict_probability_; // Set to 1 to predict probabilities.
390  std::vector<std::vector<double>> prediction_; // It stores the resulting prediction.
391 
392  /** It scales the input dataset using the model information. */
393  void
395 
396 public:
397  /** Constructor. */
399  {
400  class_name_ = "SvmClassify";
401  }
402 
403  /** Destructor. */
405  {
406  if (!model_extern_copied_ && model_.l > 0)
407  svm_free_model_content(&model_);
408  }
409 
410  /** It adds/store the training set with labelled data. */
411  void
412  setInputTrainingSet(std::vector<SVMData> training_set)
413  {
414  assert(training_set.size() > 0);
415 
416  if (scaling_.max == 0) {
417  // to be sure to have loaded the scaling
418  PCL_ERROR("[pcl::%s::setInputTrainingSet] Classifier model not loaded!\n",
419  getClassName().c_str());
420  return;
421  }
422 
423  training_set_.insert(training_set_.end(), training_set.begin(), training_set.end());
425  }
426 
427  /** Return the current training set. */
428  std::vector<SVMData>
430  {
431  return training_set_;
432  }
433 
434  /** Reset the training set. */
435  void
437  {
438  training_set_.clear();
439  }
440 
441  /** Read in a classifier model (in svmlight format).
442  *
443  * \return false if fails
444  */
445  bool
446  loadClassifierModel(const char* filename);
447 
448  /** Get the result of the classification. */
449  void
450  getClassificationResult(std::vector<std::vector<double>>& out)
451  {
452  out.clear();
453  out.insert(out.begin(), prediction_.begin(), prediction_.end());
454  }
455 
456  /** Save the classification result in an extern file. */
457  void
458  saveClassificationResult(const char* filename);
459 
460  /** Set the classifier model. */
461  void
463  {
464  // model (inner pointers are references)
465  model_ = model;
466  int i = 0;
467 
468  while (model_.scaling[i].index != -1)
469  i++;
470 
471  scaling_.max = i;
472  scaling_.obj = Malloc(struct svm_node, i + 1);
473  scaling_.obj[i].index = -1;
474 
475  // Performing full scaling copy
476  for (int j = 0; j < i; j++) {
477  scaling_.obj[j] = model_.scaling[j];
478  }
479 
480  model_extern_copied_ = true;
481  };
482 
483  /** Read in a raw classification problem (in svmlight format).
484  *
485  * The values are normalized using the classifier model information.
486  *
487  * \return false if fails
488  */
489  bool
490  loadClassProblem(const char* filename)
491  {
492  assert(model_.l != 0);
493 
494  bool out = SVM::loadProblem(filename, prob_);
497  return out;
498  };
499 
500  /** Read in a normalized classification problem (in svmlight format).
501  *
502  * The data are kept whitout normalizing.
503  *
504  * \return false if fails
505  */
506  bool
507  loadNormClassProblem(const char* filename)
508  {
509  bool out = SVM::loadProblem(filename, prob_);
511  return out;
512  };
513 
514  /** Set whether the classification has to be done with the probability estimate. (The
515  * classifier model has to support it). */
516  void
518  {
519  predict_probability_ = set;
520  };
521 
522  /** Start the classification on labelled input dataset.
523  *
524  * It returns the accuracy percentage. To get the classification result, use
525  * getClassificationResult().
526  *
527  * \return false if fails
528  */
529  bool
531 
532  /** Start the classification on un-labelled input dataset.
533  *
534  * To get the classification result, use getClassificationResult().
535  *
536  * \return false if fails
537  */
538  bool
540 
541  /** Start the classification on a single set. */
542  std::vector<double>
544 
545  /** Save the raw classification problem in a file (in svmlight format).
546  *
547  * \return false if fails
548  */
549  bool
550  saveClassProblem(const char* filename)
551  {
552  return SVM::saveProblem(filename, false);
553  };
554 
555  /** Save the normalized classification problem in a file (in svmlight format).
556  *
557  * \return false if fails
558  */
559  bool
560  saveNormClassProblem(const char* filename)
561  {
562  return SVM::saveProblemNorm(filename, prob_, false);
563  };
564 };
565 
566 } // namespace pcl
SVM (Support Vector Machines) classification of a dataset.
Definition: svm_wrapper.h:376
bool saveClassProblem(const char *filename)
Save the raw classification problem in a file (in svmlight format).
Definition: svm_wrapper.h:550
bool saveNormClassProblem(const char *filename)
Save the normalized classification problem in a file (in svmlight format).
Definition: svm_wrapper.h:560
std::vector< std::vector< double > > prediction_
Definition: svm_wrapper.h:390
bool loadClassProblem(const char *filename)
Read in a raw classification problem (in svmlight format).
Definition: svm_wrapper.h:490
void resetTrainingSet()
Reset the training set.
Definition: svm_wrapper.h:436
bool predict_probability_
Definition: svm_wrapper.h:389
~SVMClassify()
Destructor.
Definition: svm_wrapper.h:404
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
Definition: svm_wrapper.h:429
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:517
void getClassificationResult(std::vector< std::vector< double >> &out)
Get the result of the classification.
Definition: svm_wrapper.h:450
SVMClassify()
Constructor.
Definition: svm_wrapper.h:398
bool model_extern_copied_
Definition: svm_wrapper.h:388
bool classificationTest()
Start the classification on labelled input dataset.
void setClassifierModel(SVMModel model)
Set the classifier model.
Definition: svm_wrapper.h:462
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
Definition: svm_wrapper.h:412
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:507
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:213
const std::string & getClassName() const
Get a string representation of the name of this class.
Definition: svm_wrapper.h:153
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:183
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:199
SVM()
Constructor.
Definition: svm_wrapper.h:180
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:145
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:137
SVM (Support Vector Machines) training class for the SVM machine learning.
Definition: svm_wrapper.h:233
SVMModel model_
Definition: svm_wrapper.h:125
void doCrossValidation()
To cross validate the classifier.
void resetTrainingSet()
Reset the training set.
Definition: svm_wrapper.h:317
~SVMTrain()
Destructor.
Definition: svm_wrapper.h:274
int cross_validation_
Set too 1 for cross validating the classifier.
Definition: svm_wrapper.h:248
SVMModel getClassifierModel()
Return the result of the training.
Definition: svm_wrapper.h:296
bool debug_
Set to 1 to see the training output.
Definition: svm_wrapper.h:246
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
Definition: svm_wrapper.h:303
bool loadProblem(const char *filename)
Read in a problem (in svmlight format).
Definition: svm_wrapper.h:334
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
Definition: svm_wrapper.h:310
bool saveNormTrainingSet(const char *filename)
Save the normalized training set in a file (in svmlight format).
Definition: svm_wrapper.h:366
bool saveTrainingSet(const char *filename)
Save the raw training set in a file (in svmlight format).
Definition: svm_wrapper.h:356
bool trainClassifier()
Start the training of the SVM classifier.
void setDebugMode(bool in)
Set to 1 for debugging info.
Definition: svm_wrapper.h:341
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:282
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:251
SVMParam getParameters()
Return the current training parameters.
Definition: svm_wrapper.h:289
SVMTrain()
Constructor.
Definition: svm_wrapper.h:266
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
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