Point Cloud Library (PCL) 1.12.1
Loading...
Searching...
No Matches
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
52namespace 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 */
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 */
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 */
111struct 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). */
121class SVM {
122protected:
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&
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
178public:
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 */
233class SVMTrain : public SVM {
234protected:
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.
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
264public:
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. */
290 {
291 return param_;
292 }
293
294 /** Return the result of the training. */
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
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 */
376class SVMClassify : public SVM {
377protected:
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
396public:
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
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 {
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
bool saveClassProblem(const char *filename)
Save the raw classification problem in a file (in svmlight format).
bool saveNormClassProblem(const char *filename)
Save the normalized classification problem in a file (in svmlight format).
std::vector< std::vector< double > > prediction_
bool loadClassProblem(const char *filename)
Read in a raw classification problem (in svmlight format).
void resetTrainingSet()
Reset the training set.
~SVMClassify()
Destructor.
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.
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
SVMClassify()
Constructor.
std::vector< double > classification(SVMData in)
Start the classification on a single set.
bool classificationTest()
Start the classification on labelled input dataset.
void setClassifierModel(SVMModel model)
Set the classifier model.
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
bool loadClassifierModel(const char *filename)
Read in a classifier model (in svmlight format).
std::string class_name_
svm_scaling scaling_
svm_problem prob_
void scaleProblem(svm_problem &input, svm_scaling scaling)
It scales the input dataset using the model information.
std::vector< SVMData > training_set_
bool loadNormClassProblem(const char *filename)
Read in a normalized classification problem (in svmlight format).
void getClassificationResult(std::vector< std::vector< double > > &out)
Get the result of the classification.
SVMModel model_
bool loadProblem(const char *filename, svm_problem &prob)
Load a problem from an extern file.
void saveClassifierModel(const char *filename)
Save the classifier model in an extern file (in svmlight format).
int max_line_len_
char * line_
char * readline(FILE *input)
To read a line from the input file.
bool labelled_training_set_
void adaptLibSVMToInput(std::vector< SVMData > &training_set, svm_problem prob) const
Convert the libSVM format (svm_problem) into a easier output format.
const std::string & getClassName() const
Get a string representation of the name of this class.
~SVM()
Destructor.
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_
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.
SVM()
Constructor.
svm_scaling scaling_
SVMParam param_
svm_problem prob_
void exitInputError(int line_num)
Outputs an error in file reading.
std::vector< SVMData > training_set_
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.
SVMModel model_
void doCrossValidation()
To cross validate the classifier.
void resetTrainingSet()
Reset the training set.
~SVMTrain()
Destructor.
int cross_validation_
Set too 1 for cross validating the classifier.
SVMModel getClassifierModel()
Return the result of the training.
bool debug_
Set to 1 to see the training output.
void setInputTrainingSet(std::vector< SVMData > training_set)
It adds/store the training set with labelled data.
bool loadProblem(const char *filename)
Read in a problem (in svmlight format).
bool saveNormTrainingSet(const char *filename)
Save the normalized training set in a file (in svmlight format).
bool saveTrainingSet(const char *filename)
Save the raw training set in a file (in svmlight format).
bool trainClassifier()
Start the training of the SVM classifier.
void setDebugMode(bool in)
Set to 1 for debugging info.
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).
std::string class_name_
SVMParam param_
svm_problem prob_
std::vector< SVMData > training_set_
int nr_fold_
Number of folds to be used during cross validation.
std::vector< SVMData > getInputTrainingSet()
Return the current training set.
SVMParam getParameters()
Return the current training parameters.
SVMTrain()
Constructor.
The structure stores the features and the label of a single sample which has to be used for the train...
std::vector< pcl::SVMDataPoint > SV
Vector of features for the specific sample.
double label
Pointer to the label value. It is a mandatory to train the classifier.
int idx
It's the feature index. It has to be an integer number greater or equal to zero.
float value
The value assigned to the correspondent feature.
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
double * probB
Definition svm.h:109
int l
Definition svm.h:103
double * probA
Definition svm.h:108
Definition svm.h:49
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