2009-03-23 05:31:27 +08:00
|
|
|
// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt
|
|
|
|
/*
|
|
|
|
|
2010-03-01 12:38:42 +08:00
|
|
|
This is an example showing how to use sparse feature vectors with
|
|
|
|
the dlib C++ library's machine learning tools.
|
2009-03-23 05:31:27 +08:00
|
|
|
|
|
|
|
This example creates a simple binary classification problem and shows
|
|
|
|
you how to train a support vector machine on that data.
|
|
|
|
|
|
|
|
The data used in this example will be 100 dimensional data and will
|
|
|
|
come from a simple linearly separable distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <ctime>
|
|
|
|
#include <vector>
|
|
|
|
#include "dlib/svm.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace dlib;
|
|
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
// In this example program we will be dealing with feature vectors that are sparse (i.e. most
|
|
|
|
// of the values in each vector are zero). So rather than using a dlib::matrix we can use
|
|
|
|
// one of the containers from the STL to represent our sample vectors. In particular, we
|
|
|
|
// can use the std::map to represent sparse vectors. (Note that you don't have to use std::map.
|
|
|
|
// Any STL container of std::pair objects that is sorted can be used. So for example, you could
|
2010-03-01 12:38:42 +08:00
|
|
|
// use a std::vector<std::pair<unsigned long,double> > here so long as you took care to sort every vector)
|
|
|
|
typedef std::map<unsigned long,double> sample_type;
|
2009-03-23 05:31:27 +08:00
|
|
|
|
|
|
|
|
|
|
|
// This is a typedef for the type of kernel we are going to use in this example.
|
|
|
|
// Since our data is linearly separable I picked the linear kernel. Note that if you
|
|
|
|
// are using a sparse vector representation like std::map then you have to use a kernel
|
|
|
|
// meant to be used with that kind of data type.
|
|
|
|
typedef sparse_linear_kernel<sample_type> kernel_type;
|
|
|
|
|
|
|
|
|
|
|
|
// Here we create an instance of the pegasos svm trainer object we will be using.
|
|
|
|
svm_pegasos<kernel_type> trainer;
|
|
|
|
// Here we setup a parameter to this object. See the dlib documentation for a
|
|
|
|
// description of what this parameter does.
|
|
|
|
trainer.set_lambda(0.00001);
|
|
|
|
|
2010-03-01 12:38:42 +08:00
|
|
|
// Lets also use the svm trainer specially optimized for the linear_kernel and
|
|
|
|
// sparse_linear_kernel.
|
|
|
|
svm_c_linear_trainer<kernel_type> linear_trainer;
|
2010-03-03 11:36:26 +08:00
|
|
|
// This trainer solves the "C" formulation of the SVM. See the documentation for
|
|
|
|
// details.
|
|
|
|
linear_trainer.set_c(10);
|
2010-03-01 12:38:42 +08:00
|
|
|
|
2009-03-23 05:31:27 +08:00
|
|
|
std::vector<sample_type> samples;
|
|
|
|
std::vector<double> labels;
|
|
|
|
|
|
|
|
// make an instance of a sample vector so we can use it below
|
|
|
|
sample_type sample;
|
|
|
|
|
|
|
|
|
|
|
|
// Now lets go into a loop and randomly generate 10000 samples.
|
|
|
|
srand(time(0));
|
|
|
|
double label = +1;
|
|
|
|
for (int i = 0; i < 10000; ++i)
|
|
|
|
{
|
|
|
|
// flip this flag
|
|
|
|
label *= -1;
|
|
|
|
|
|
|
|
sample.clear();
|
|
|
|
|
|
|
|
// now make a random sparse sample with at most 10 non-zero elements
|
|
|
|
for (int j = 0; j < 10; ++j)
|
|
|
|
{
|
|
|
|
int idx = std::rand()%100;
|
|
|
|
double value = static_cast<double>(std::rand())/RAND_MAX;
|
|
|
|
|
|
|
|
sample[idx] = label*value;
|
|
|
|
}
|
|
|
|
|
2010-03-01 12:38:42 +08:00
|
|
|
// let the svm_pegasos learn about this sample.
|
2009-03-23 05:31:27 +08:00
|
|
|
trainer.train(sample,label);
|
2010-03-01 12:38:42 +08:00
|
|
|
|
|
|
|
// Also save the samples we are generating so we can let the svm_c_linear_trainer
|
|
|
|
// learn from them below.
|
|
|
|
samples.push_back(sample);
|
|
|
|
labels.push_back(label);
|
2009-03-23 05:31:27 +08:00
|
|
|
}
|
|
|
|
|
2010-03-01 12:38:42 +08:00
|
|
|
// In addition to the rule we learned with the pegasos trainer lets also use our linear_trainer
|
|
|
|
// to learn a decision rule.
|
|
|
|
decision_function<kernel_type> df = linear_trainer.train(samples, labels);
|
|
|
|
|
|
|
|
// Now we have trained our SVMs. Lets test them out a bit.
|
|
|
|
// Each of these statements prints the output of the SVMs given a particular sample.
|
|
|
|
// Each SVM outputs a number > 0 if a sample is predicted to be in the +1 class and < 0
|
2009-03-23 05:31:27 +08:00
|
|
|
// if a sample is predicted to be in the -1 class.
|
|
|
|
|
2010-03-01 12:38:42 +08:00
|
|
|
|
2009-03-23 05:31:27 +08:00
|
|
|
sample.clear();
|
|
|
|
sample[4] = 0.3;
|
|
|
|
sample[10] = 0.9;
|
|
|
|
cout << "This is a +1 example, its SVM output is: " << trainer(sample) << endl;
|
2010-03-01 12:38:42 +08:00
|
|
|
cout << "df: " << df(sample) << endl;
|
2009-03-23 05:31:27 +08:00
|
|
|
|
|
|
|
sample.clear();
|
|
|
|
sample[83] = -0.3;
|
|
|
|
sample[26] = -0.9;
|
|
|
|
sample[58] = -0.7;
|
|
|
|
cout << "This is a -1 example, its SVM output is: " << trainer(sample) << endl;
|
2010-03-01 12:38:42 +08:00
|
|
|
cout << "df: " << df(sample) << endl;
|
2009-03-23 05:31:27 +08:00
|
|
|
|
|
|
|
sample.clear();
|
|
|
|
sample[0] = -0.2;
|
|
|
|
sample[9] = -0.8;
|
|
|
|
cout << "This is a -1 example, its SVM output is: " << trainer(sample) << endl;
|
2010-03-01 12:38:42 +08:00
|
|
|
cout << "df: " << df(sample) << endl;
|
|
|
|
|
2009-03-23 05:31:27 +08:00
|
|
|
}
|
|
|
|
|