Point Cloud Library (PCL)  1.9.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 <cctype>
42 #include <cerrno>
43 #include <cstdio>
44 #include <cstdlib>
45 #include <cstring>
46 #include <fstream>
47 #include <iostream>
48 #include <pcl/common/eigen.h>
49 #include <vector>
50 
51 #include <pcl/ml/svm.h>
52 #define Malloc(type, n) static_cast<type*>(malloc((n) * sizeof(type)))
53 
54 namespace pcl {
55 
56 /** The structure stores the parameters for the classificationa nd must be initialized
57  * and passed to the training method pcl::SVMTrain.
58  *
59  * \param svm_type {C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR}
60  * \param kernel_type {LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED}
61  * \param probability sets the probability estimates
62  */
65  {
66  svm_type = C_SVC; // C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR
67  kernel_type = RBF; // LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED
68  degree = 3; // for poly
69  gamma = 0; // 1/num_features {for poly/rbf/sigmoid}
70  coef0 = 0; // for poly/sigmoid
71 
72  nu = 0.5; // for NU_SVC, ONE_CLASS, and NU_SVR
73  cache_size = 100; // in MB
74  C = 1; // for C_SVC, EPSILON_SVR and NU_SVR
75  eps = 1e-3; // stopping criteria
76  p = 0.1; // for EPSILON_SVR
77  shrinking = 0; // use the shrinking heuristics
78  probability = 0; // do probability estimates
79 
80  nr_weight = 0; // for C_SVC
81  weight_label = nullptr; // for C_SVC
82  weight = nullptr; // for C_SVC
83  }
84 };
85 
86 /** The structure initialize a model created by the SVM (Support Vector Machines)
87  * classifier (pcl::SVMTrain).
88  */
89 struct SVMModel : svm_model {
91  {
92  l = 0;
93  probA = nullptr;
94  probB = nullptr;
95  }
96 };
97 
98 /** The structure initialize a single feature value for the classification using
99  * SVM (Support Vector Machines).
100  */
101 struct SVMDataPoint {
102  /// It's the feature index. It has to be an integer number greater or equal to zero
103  int idx;
104  /// The value assigned to the correspondent feature.
105  float value;
106 
107  SVMDataPoint() : idx(-1), value(0) {}
108 };
109 
110 /** The structure stores the features and the label of a single sample which has to be
111  * used for the training or the classification of the SVM (Support Vector Machines).
112  */
113 struct SVMData {
114  /// Pointer to the label value. It is a mandatory to train the classifier
115  double label;
116  /// Vector of features for the specific sample.
117  std::vector<pcl::SVMDataPoint> SV;
118 
119  SVMData() : label(std::numeric_limits<double>::signaling_NaN()) {}
120 };
121 
122 /** Base class for SVM SVM (Support Vector Machines). */
123 class SVM {
124 protected:
125  std::vector<SVMData> training_set_; // Basic training set
126  svm_problem prob_; // contains the problem (vector of samples with their features)
127  SVMModel model_; // model of the classifier
128  svm_scaling scaling_; // for the best model training, the input dataset is scaled and
129  // the scaling factors are stored here
130  SVMParam param_; // it stores the training parameters
131  std::string class_name_; // The SVM class name.
132 
133  char* line_; // buffer for line reading
134  int max_line_len_; // max line length in the input file
135  bool labelled_training_set_; // it stores whether the input set of samples is labelled
136 
137  /** Set for output printings during classification. */
138  static void
139  printNull(const char*){};
140 
141  /** To read a line from the input file. Stored in "line_". */
142  char*
143  readline(FILE* input);
144 
145  /** Outputs an error in file reading. */
146  void
147  exitInputError(int line_num)
148  {
149  fprintf(stderr, "Wrong input format at line %d\n", line_num);
150  exit(1);
151  }
152 
153  /** Get a string representation of the name of this class. */
154  inline const std::string&
155  getClassName() const
156  {
157  return (class_name_);
158  }
159 
160  /** Convert the input format (vector of SVMData) into a readable format for libSVM. */
161  void
162  adaptInputToLibSVM(std::vector<SVMData> training_set, svm_problem& prob);
163 
164  /** Convert the libSVM format (svm_problem) into a easier output format. */
165  void
166  adaptLibSVMToInput(std::vector<SVMData>& training_set, svm_problem prob);
167 
168  /** Load a problem from an extern file. */
169  bool
170  loadProblem(const char* filename, svm_problem& prob);
171 
172  /** Save the raw problem in an extern file.*/
173  bool
174  saveProblem(const char* filename, bool labelled);
175 
176  /** Save the problem (with normalized values) in an extern file.*/
177  bool
178  saveProblemNorm(const char* filename, svm_problem prob_, bool labelled);
179 
180 public:
181  /** Constructor. */
182  SVM() : prob_(), line_(nullptr), max_line_len_(10000), labelled_training_set_(true) {}
183 
184  /** Destructor. */
186  {
187  svm_destroy_param(&param_); // delete parameters
188 
189  if (scaling_.max > 0)
190  free(scaling_.obj); // delete scaling factors
191 
192  // delete the problem
193  if (prob_.l > 0) {
194  free(prob_.x);
195  free(prob_.y);
196  }
197  }
198 
199  /** Return the labels order from the classifier model. */
200  void
201  getLabel(std::vector<int>& labels)
202  {
203  int nr_class = svm_get_nr_class(&model_);
204  int* labels_ = static_cast<int*>(malloc(nr_class * sizeof(int)));
205  svm_get_labels(&model_, labels_);
206 
207  for (int j = 0; j < nr_class; j++)
208  labels.push_back(labels_[j]);
209 
210  free(labels_);
211  };
212 
213  /** Save the classifier model in an extern file (in svmlight format). */
214  void
215  saveClassifierModel(const char* filename)
216  {
217  // exit if model has no data
218  if (model_.l == 0)
219  return;
220 
221  if (svm_save_model(filename, &model_)) {
222  fprintf(stderr, "can't save model to file %s\n", filename);
223  exit(1);
224  }
225  };
226 };
227 
228 /** SVM (Support Vector Machines) training class for the SVM machine learning.
229  *
230  * It creates a model for the classifier from a labelled input dataset.
231  *
232  * OPTIONAL: pcl::SVMParam has to be given as input to vary the default training method
233  * and parameters.
234  */
235 class SVMTrain : public SVM {
236 protected:
237  using SVM::class_name_;
239  using SVM::line_;
240  using SVM::max_line_len_;
241  using SVM::model_;
242  using SVM::param_;
243  using SVM::prob_;
244  using SVM::scaling_;
245  using SVM::training_set_;
246 
247  /// Set to 1 to see the training output
248  bool debug_;
249  /// Set too 1 for cross validating the classifier
251  /// Number of folds to be used during cross validation. It indicates in how many parts
252  /// is split the input training set.
253  int nr_fold_;
254 
255  /** To cross validate the classifier. It is automatic for probability estimate. */
256  void
257  doCrossValidation();
258 
259  /** It extracts scaling factors from the input training_set.
260  *
261  * The scaling of the training_set is a mandatory for a good training of the
262  * classifier. */
263  void
264  scaleFactors(std::vector<SVMData> training_set, svm_scaling& scaling);
265 
266 public:
267  /** Constructor. */
268  SVMTrain() : debug_(false), cross_validation_(0), nr_fold_(0)
269  {
270  class_name_ = "SVMTrain";
271  svm_set_print_string_function(
272  &printNull); // Default to NULL to not print debugging info
273  }
274 
275  /** Destructor. */
277  {
278  if (model_.l > 0)
279  svm_free_model_content(&model_);
280  }
281 
282  /** Change default training parameters (pcl::SVMParam). */
283  void
285  {
286  param_ = param;
287  }
288 
289  /** Return the current training parameters. */
290  SVMParam
292  {
293  return param_;
294  }
295 
296  /** Return the result of the training. */
297  SVMModel
299  {
300  return model_;
301  }
302 
303  /** It adds/store the training set with labelled data. */
304  void
305  setInputTrainingSet(std::vector<SVMData> training_set)
306  {
307  training_set_.insert(training_set_.end(), training_set.begin(), training_set.end());
308  }
309 
310  /** Return the current training set. */
311  std::vector<SVMData>
313  {
314  return training_set_;
315  }
316 
317  /** Reset the training set. */
318  void
320  {
321  training_set_.clear();
322  }
323 
324  /** Start the training of the SVM classifier.
325  *
326  * \return false if fails
327  */
328  bool
329  trainClassifier();
330 
331  /** Read in a problem (in svmlight format).
332  *
333  * \return false if fails
334  */
335  bool
336  loadProblem(const char* filename)
337  {
338  return SVM::loadProblem(filename, prob_);
339  };
340 
341  /** Set to 1 for debugging info. */
342  void
343  setDebugMode(bool in)
344  {
345  debug_ = in;
346 
347  if (in)
348  svm_set_print_string_function(nullptr);
349  else
350  svm_set_print_string_function(&printNull);
351  };
352 
353  /** Save the raw training set in a file (in svmlight format).
354  *
355  * \return false if fails
356  */
357  bool
358  saveTrainingSet(const char* filename)
359  {
360  return SVM::saveProblem(filename, true);
361  };
362 
363  /** Save the normalized training set in a file (in svmlight format).
364  *
365  * \return false if fails
366  */
367  bool
368  saveNormTrainingSet(const char* filename)
369  {
370  return SVM::saveProblemNorm(filename, prob_, true);
371  };
372 };
373 
374 /** SVM (Support Vector Machines) classification of a dataset.
375  *
376  * It can be used both for testing a classifier model and for classify of new data.
377  */
378 class SVMClassify : public SVM {
379 protected:
380  using SVM::class_name_;
382  using SVM::line_;
383  using SVM::max_line_len_;
384  using SVM::model_;
385  using SVM::param_;
386  using SVM::prob_;
387  using SVM::scaling_;
388  using SVM::training_set_;
389 
390  bool model_extern_copied_; // Set to 0 if the model is loaded from an extern file.
391  bool predict_probability_; // 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
396  scaleProblem(svm_problem& input, svm_scaling scaling);
397 
398 public:
399  /** Constructor. */
400  SVMClassify() : model_extern_copied_(false), predict_probability_(false)
401  {
402  class_name_ = "SvmClassify";
403  }
404 
405  /** Destructor. */
407  {
408  if (!model_extern_copied_ && model_.l > 0)
409  svm_free_model_content(&model_);
410  }
411 
412  /** It adds/store the training set with labelled data. */
413  void
414  setInputTrainingSet(std::vector<SVMData> training_set)
415  {
416  assert(training_set.size() > 0);
417 
418  if (scaling_.max == 0) {
419  // to be sure to have loaded the scaling
420  PCL_ERROR("[pcl::%s::setInputTrainingSet] Classifier model not loaded!\n",
421  getClassName().c_str());
422  return;
423  }
424 
425  training_set_.insert(training_set_.end(), training_set.begin(), training_set.end());
426  SVM::adaptInputToLibSVM(training_set_, prob_);
427  }
428 
429  /** Return the current training set. */
430  std::vector<SVMData>
432  {
433  return training_set_;
434  }
435 
436  /** Reset the training set. */
437  void
439  {
440  training_set_.clear();
441  }
442 
443  /** Read in a classifier model (in svmlight format).
444  *
445  * \return false if fails
446  */
447  bool
448  loadClassifierModel(const char* filename);
449 
450  /** Get the result of the classification. */
451  void
452  getClassificationResult(std::vector<std::vector<double>>& out)
453  {
454  out.clear();
455  out.insert(out.begin(), prediction_.begin(), prediction_.end());
456  }
457 
458  /** Save the classification result in an extern file. */
459  void
460  saveClassificationResult(const char* filename);
461 
462  /** Set the classifier model. */
463  void
465  {
466  // model (inner pointers are references)
467  model_ = model;
468  int i = 0;
469 
470  while (model_.scaling[i].index != -1)
471  i++;
472 
473  scaling_.max = i;
474  scaling_.obj = Malloc(struct svm_node, i + 1);
475  scaling_.obj[i].index = -1;
476 
477  // Performing full scaling copy
478  for (int j = 0; j < i; j++) {
479  scaling_.obj[j] = model_.scaling[j];
480  }
481 
482  model_extern_copied_ = true;
483  };
484 
485  /** Read in a raw classification problem (in svmlight format).
486  *
487  * The values are normalized using the classifier model information.
488  *
489  * \return false if fails
490  */
491  bool
492  loadClassProblem(const char* filename)
493  {
494  assert(model_.l != 0);
495 
496  bool out = SVM::loadProblem(filename, prob_);
497  SVM::adaptLibSVMToInput(training_set_, prob_);
498  scaleProblem(prob_, scaling_);
499  return out;
500  };
501 
502  /** Read in a normalized classification problem (in svmlight format).
503  *
504  * The data are kept whitout normalizing.
505  *
506  * \return false if fails
507  */
508  bool
509  loadNormClassProblem(const char* filename)
510  {
511  bool out = SVM::loadProblem(filename, prob_);
512  SVM::adaptLibSVMToInput(training_set_, prob_);
513  return out;
514  };
515 
516  /** Set whether the classification has to be done with the probability estimate. (The
517  * classifier model has to support it). */
518  void
520  {
521  predict_probability_ = set;
522  };
523 
524  /** Start the classification on labelled input dataset.
525  *
526  * It returns the accuracy percentage. To get the classification result, use
527  * getClassificationResult().
528  *
529  * \return false if fails
530  */
531  bool
532  classificationTest();
533 
534  /** Start the classification on un-labelled input dataset.
535  *
536  * To get the classification result, use getClassificationResult().
537  *
538  * \return false if fails
539  */
540  bool
541  classification();
542 
543  /** Start the classification on a single set. */
544  std::vector<double>
545  classification(SVMData in);
546 
547  /** Save the raw classification problem in a file (in svmlight format).
548  *
549  * \return false if fails
550  */
551  bool
552  saveClassProblem(const char* filename)
553  {
554  return SVM::saveProblem(filename, false);
555  };
556 
557  /** Save the normalized classification problem in a file (in svmlight format).
558  *
559  * \return false if fails
560  */
561  bool
562  saveNormClassProblem(const char* filename)
563  {
564  return SVM::saveProblemNorm(filename, prob_, false);
565  };
566 };
567 
568 } // namespace pcl
struct svm_node * obj
Definition: svm.h:64
float value
The value assigned to the correspondent feature.
Definition: svm_wrapper.h:105
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
Definition: svm_wrapper.h:312
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
Definition: svm_wrapper.h:305
~SVMTrain()
Destructor.
Definition: svm_wrapper.h:276
svm_problem prob_
Definition: svm_wrapper.h:126
bool saveNormClassProblem(const char *filename)
Save the normalized classification problem in a file (in svmlight format).
Definition: svm_wrapper.h:562
void getClassificationResult(std::vector< std::vector< double >> &out)
Get the result of the classification.
Definition: svm_wrapper.h:452
bool saveProblemNorm(const char *filename, svm_problem prob_, bool labelled)
Save the problem (with normalized values) in an extern file.
bool loadNormClassProblem(const char *filename)
Read in a normalized classification problem (in svmlight format).
Definition: svm_wrapper.h:509
This file defines compatibility wrappers for low level I/O functions.
Definition: convolution.h:45
The structure initialize a single feature value for the classification using SVM (Support Vector Mach...
Definition: svm_wrapper.h:101
const std::string & getClassName() const
Get a string representation of the name of this class.
Definition: svm_wrapper.h:155
std::vector< pcl::SVMDataPoint > SV
Vector of features for the specific sample.
Definition: svm_wrapper.h:117
int idx
It&#39;s the feature index. It has to be an integer number greater or equal to zero.
Definition: svm_wrapper.h:103
The structure stores the features and the label of a single sample which has to be used for the train...
Definition: svm_wrapper.h:113
SVMClassify()
Constructor.
Definition: svm_wrapper.h:400
Base class for SVM SVM (Support Vector Machines).
Definition: svm_wrapper.h:123
bool model_extern_copied_
Definition: svm_wrapper.h:390
int l
Definition: svm.h:103
void exitInputError(int line_num)
Outputs an error in file reading.
Definition: svm_wrapper.h:147
int nr_weight
Definition: svm.h:86
void setDebugMode(bool in)
Set to 1 for debugging info.
Definition: svm_wrapper.h:343
std::vector< std::vector< double > > prediction_
Definition: svm_wrapper.h:392
std::string class_name_
Definition: svm_wrapper.h:131
SVMParam getParameters()
Return the current training parameters.
Definition: svm_wrapper.h:291
bool loadClassProblem(const char *filename)
Read in a raw classification problem (in svmlight format).
Definition: svm_wrapper.h:492
SVMModel model_
Definition: svm_wrapper.h:127
int nr_fold_
Number of folds to be used during cross validation.
Definition: svm_wrapper.h:253
int * weight_label
Definition: svm.h:87
bool saveTrainingSet(const char *filename)
Save the raw training set in a file (in svmlight format).
Definition: svm_wrapper.h:358
void resetTrainingSet()
Reset the training set.
Definition: svm_wrapper.h:319
~SVM()
Destructor.
Definition: svm_wrapper.h:185
bool saveProblem(const char *filename, bool labelled)
Save the raw problem in an extern file.
double label
Pointer to the label value. It is a mandatory to train the classifier.
Definition: svm_wrapper.h:115
bool predict_probability_
Definition: svm_wrapper.h:391
SVM (Support Vector Machines) classification of a dataset.
Definition: svm_wrapper.h:378
The structure initialize a model created by the SVM (Support Vector Machines) classifier (pcl::SVMTra...
Definition: svm_wrapper.h:89
SVM()
Constructor.
Definition: svm_wrapper.h:182
Definition: svm.h:99
double p
Definition: svm.h:90
bool saveNormTrainingSet(const char *filename)
Save the normalized training set in a file (in svmlight format).
Definition: svm_wrapper.h:368
bool loadProblem(const char *filename)
Read in a problem (in svmlight format).
Definition: svm_wrapper.h:336
char * line_
Definition: svm_wrapper.h:133
SVM (Support Vector Machines) training class for the SVM machine learning.
Definition: svm_wrapper.h:235
double cache_size
Definition: svm.h:83
bool saveClassProblem(const char *filename)
Save the raw classification problem in a file (in svmlight format).
Definition: svm_wrapper.h:552
int cross_validation_
Set too 1 for cross validating the classifier.
Definition: svm_wrapper.h:250
void saveClassifierModel(const char *filename)
Save the classifier model in an extern file (in svmlight format).
Definition: svm_wrapper.h:215
void setParameters(SVMParam param)
Change default training parameters (pcl::SVMParam).
Definition: svm_wrapper.h:284
SVMTrain()
Constructor.
Definition: svm_wrapper.h:268
~SVMClassify()
Destructor.
Definition: svm_wrapper.h:406
double eps
Definition: svm.h:84
void adaptInputToLibSVM(std::vector< SVMData > training_set, svm_problem &prob)
Convert the input format (vector of SVMData) into a readable format for libSVM.
bool labelled_training_set_
Definition: svm_wrapper.h:135
int shrinking
Definition: svm.h:91
void resetTrainingSet()
Reset the training set.
Definition: svm_wrapper.h:438
static void printNull(const char *)
Set for output printings during classification.
Definition: svm_wrapper.h:139
struct svm_node ** x
Definition: svm.h:58
bool loadProblem(const char *filename, svm_problem &prob)
Load a problem from an extern file.
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
Definition: svm_wrapper.h:414
void setClassifierModel(SVMModel model)
Set the classifier model.
Definition: svm_wrapper.h:464
void adaptLibSVMToInput(std::vector< SVMData > &training_set, svm_problem prob)
Convert the libSVM format (svm_problem) into a easier output format.
void getLabel(std::vector< int > &labels)
Return the labels order from the classifier model.
Definition: svm_wrapper.h:201
std::vector< SVMData > training_set_
Definition: svm_wrapper.h:125
int max
Definition: svm.h:67
svm_scaling scaling_
Definition: svm_wrapper.h:128
int probability
Definition: svm.h:92
int degree
Definition: svm.h:78
int max_line_len_
Definition: svm_wrapper.h:134
The structure stores the parameters for the classificationa nd must be initialized and passed to the ...
Definition: svm_wrapper.h:63
bool debug_
Set to 1 to see the training output.
Definition: svm_wrapper.h:248
Definition: svm.h:49
double * y
Definition: svm.h:56
void setProbabilityEstimates(bool set)
Set whether the classification has to be done with the probability estimate.
Definition: svm_wrapper.h:519
double gamma
Definition: svm.h:79
int l
Definition: svm.h:55
double * weight
Definition: svm.h:88
double C
Definition: svm.h:85
int svm_type
Definition: svm.h:76
double nu
Definition: svm.h:89
double coef0
Definition: svm.h:80
int kernel_type
Definition: svm.h:77
SVMModel getClassifierModel()
Return the result of the training.
Definition: svm_wrapper.h:298
SVMParam param_
Definition: svm_wrapper.h:130
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
Definition: svm_wrapper.h:431