iCub-main
LSSVMLearner.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2011 RobotCub Consortium, European Commission FP6 Project IST-004370
3  * author: Arjan Gijsberts
4  * email: arjan.gijsberts@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17  */
18 
19 #include <cassert>
20 #include <sstream>
21 #include <cmath>
22 
23 #include <yarp/math/Math.h>
24 #include <yarp/math/SVD.h>
25 
28 
29 using namespace yarp::math;
31 
32 namespace iCub {
33 namespace learningmachine {
34 
35 double RBFKernel::evaluate(const yarp::sig::Vector& v1, const yarp::sig::Vector& v2) {
36  assert(v1.size() == v2.size());
37  double result = 0.0;
38  double diff;
39 
40  for(size_t i = 0; i < v1.size(); i++) {
41  diff = v1(i) - v2(i);
42  result += diff * diff;
43  }
44  result *= -1 * this->gamma;
45  return std::exp(result);
46 }
47 
48 
49 LSSVMLearner::LSSVMLearner(unsigned int dom, unsigned int cod, double c) {
50  this->setName("LSSVM");
51  this->kernel = new RBFKernel();
52  // make sure to not use initialization list to constructor of base for
53  // domain and codomain size, as it will not use overloaded mutators
54  this->setDomainSize(dom);
55  this->setCoDomainSize(cod);
56  this->setC(c);
57 }
58 
59 LSSVMLearner::LSSVMLearner(const LSSVMLearner& other)
60  : IFixedSizeLearner(other), inputs(other.inputs), outputs(other.outputs),
61  alphas(other.alphas), bias(other.bias), LOO(other.LOO), C(other.C),
62  kernel(new RBFKernel(*other.kernel)) {
63 
64 }
65 
67  delete this->kernel;
68 }
69 
71  if(this == &other) return *this; // handle self initialization
72 
73  this->IFixedSizeLearner::operator=(other);
74  this->inputs = other.inputs;
75  this->outputs = other.outputs;
76  this->alphas = other.alphas;
77  this->bias = other.bias;
78  this->LOO = other.LOO;
79  this->C = other.C;
80  delete this->kernel;
81  this->kernel = new RBFKernel(*other.kernel);
82 
83  return *this;
84 }
85 
86 void LSSVMLearner::feedSample(const yarp::sig::Vector& input, const yarp::sig::Vector& output) {
87  // call parent method to let it do some validation for us
88  this->IFixedSizeLearner::feedSample(input, output);
89 
90  this->inputs.push_back(input);
91  this->outputs.push_back(output);
92 }
93 
95  assert(this->inputs.size() == this->outputs.size());
96 
97  // save wasting some time
98  if(inputs.size() == 0) {
99  return;
100  }
101 
102  // create kernel matrix
103  yarp::sig::Matrix K(inputs.size() + 1, inputs.size() + 1);
104  for(int r = 0; r < K.rows() - 1; r++) {
105  // symmetric matrix
106  for(int c = 0; c <= r; c++) {
107  K(r, c) = K(c, r) = this->kernel->evaluate(this->inputs[r], this->inputs[c]);
108  if(r == c) K(r, c) += (1.0 / this->C);
109  }
110  }
111  for(int i = 0; i < K.rows() - 1; i++) {
112  K(i, K.cols() - 1) = K(K.rows() - 1, i) = 1.;
113  }
114  K(K.rows() - 1, K.cols() - 1) = 0.;
115 
116  // invert kernel matrix
117  yarp::sig::Matrix Kinv = luinv(K);
118 
119  // compute solution
120  yarp::sig::Matrix Y = zeros(this->outputs.size() + 1, this->getCoDomainSize());
121  for(int r = 0; r < Y.rows() - 1; r++) {
122  for(int c = 0; c < Y.cols(); c++) {
123  Y(r, c) = this->outputs[r](c);
124  }
125  }
126 
127  yarp::sig::Matrix result = Kinv * Y;
128  this->alphas = result.submatrix(0, result.rows() - 2, 0, result.cols() - 1);
129  this->bias = result.getRow(result.rows() - 1);
130 
131  // compute LOO
132  this->LOO = zeros(this->getCoDomainSize());
133 
134  for(unsigned int i = 0; i < this->getCoDomainSize(); i++) {
135  yarp::sig::Vector alphas_i = this->alphas.getCol(i);
136  for(size_t j = 0; j < alphas_i.size(); j++) {
137  double err = alphas_i(j) / Kinv(j, j);
138  this->LOO(i) += err * err;
139  }
140  this->LOO(i) /= alphas_i.size();
141  }
142 
143 }
144 
145 Prediction LSSVMLearner::predict(const yarp::sig::Vector& input) {
146  this->checkDomainSize(input);
147 
148  if(this->inputs.size() == 0) {
149  return zeros(this->getCoDomainSize());
150  }
151 
152  // compute kernel expansion
153  yarp::sig::Vector k(this->inputs.size());
154  for(size_t i = 0; i < k.size(); i++) {
155  k(i) = this->kernel->evaluate(this->inputs[i], input);
156  }
157 
158  return Prediction((this->alphas.transposed() * k) + this->bias);
159 }
160 
162  this->inputs.clear();
163  this->outputs.clear();
164  this->alphas = yarp::sig::Matrix();
165  this->LOO.clear();
166  this->bias.clear();
167 }
168 
170  return new LSSVMLearner(*this);
171 }
172 
173 std::string LSSVMLearner::getInfo() {
174  std::ostringstream buffer;
175  buffer << this->IFixedSizeLearner::getInfo();
176  buffer << "C: " << this->getC() << " | ";
177  buffer << "Collected Samples: " << this->inputs.size() << " | ";
178  buffer << "Training Samples: " << this->alphas.rows() << " | ";
179  buffer << "Kernel: " << this->kernel->getInfo() << std::endl;
180  buffer << "LOO: " << this->LOO.toString() << std::endl;
181  return buffer.str();
182 }
183 
185  std::ostringstream buffer;
186  buffer << this->IFixedSizeLearner::getConfigHelp();
187  //buffer << " kernel idx|all cfg Kernel configuration" << std::endl;
188  buffer << " c val Tradeoff parameter C" << std::endl;
189  buffer << this->kernel->getConfigHelp() << std::endl;
190  return buffer.str();
191 }
192 
193 void LSSVMLearner::writeBottle(yarp::os::Bottle& bot) {
194  // write kernel gamma
195  bot << this->kernel->getGamma() << this->getC() << this->bias
196  << this->alphas;
197 
198  // write inputs
199  for(unsigned int i = 0; i < this->inputs.size(); i++) {
200  for(unsigned int d = 0; d < this->getDomainSize(); d++) {
201  bot.addFloat64(this->inputs[i](d));
202  }
203  }
204  bot.addInt32(this->inputs.size());
205 
206  // write outputs
207  for(unsigned int i = 0; i < this->outputs.size(); i++) {
208  for(unsigned int d = 0; d < this->getCoDomainSize(); d++) {
209  bot.addFloat64(this->outputs[i](d));
210  }
211  }
212  bot.addInt32(this->outputs.size());
213 
214  // make sure to call the superclass's method
216 }
217 
218 void LSSVMLearner::readBottle(yarp::os::Bottle& bot) {
219  // make sure to call the superclass's method
221 
222  // read outputs
223  this->outputs.resize(bot.pop().asInt32());
224  for(int i = this->outputs.size() - 1; i >= 0; i--) {
225  this->outputs[i].resize(this->getCoDomainSize());
226  for(int d = this->getCoDomainSize() - 1; d >= 0; d--) {
227  this->outputs[i](d) = bot.pop().asFloat64();
228  }
229  }
230 
231  // read inputs
232  this->inputs.resize(bot.pop().asInt32());
233  for(int i = this->inputs.size() - 1; i >= 0; i--) {
234  this->inputs[i].resize(this->getDomainSize());
235  for(int d = this->getDomainSize() - 1; d >= 0; d--) {
236  this->inputs[i](d) = bot.pop().asFloat64();
237  }
238  }
239 
240  double c;
241  double gamma;
242  bot >> this->alphas >> this->bias >> c >> gamma;
243  this->setC(c);
244  this->kernel->setGamma(gamma);
245 }
246 
247 void LSSVMLearner::setDomainSize(unsigned int size) {
249 }
250 
251 void LSSVMLearner::setCoDomainSize(unsigned int size) {
253  //this->initAll(this->getCoDomainSize());
254 }
255 
256 bool LSSVMLearner::configure(yarp::os::Searchable& config) {
257  bool success = this->IFixedSizeLearner::configure(config);
258 
259  // format: set c dbl
260  if(config.find("c").isFloat64() || config.find("c").isInt32()) {
261  double val = config.find("c").asFloat64();
262  if(val > 0) {
263  this->setC(config.find("c").asFloat64());
264  success = true;
265  }
266  }
267 
268  success |= this->kernel->configure(config);
269 
270  return success;
271 }
272 
273 } // learningmachine
274 } // iCub
275 
276 
An generalized interface for a learning machine with a fixed domain and codomain size.
virtual void writeBottle(yarp::os::Bottle &bot) const
Writes a serialization of the machine into a bottle.
virtual void feedSample(const yarp::sig::Vector &input, const yarp::sig::Vector &output)
Provide the learning machine with an example of the desired mapping.
virtual void readBottle(yarp::os::Bottle &bot)
Unserializes a machine from a bottle.
virtual bool checkDomainSize(const yarp::sig::Vector &input)
Checks whether the input is of the desired dimensionality.
unsigned int getCoDomainSize() const
Returns the size (dimensionality) of the output domain (codomain).
virtual std::string getInfo()
Asks the learning machine to return a string containing information on its operation so far.
virtual void setCoDomainSize(unsigned int size)
Mutator for the codomain size.
virtual bool configure(yarp::os::Searchable &config)
Change parameters.
virtual void setDomainSize(unsigned int size)
Mutator for the domain size.
virtual std::string getConfigHelp()
Asks the learning machine to return a string containing the list of configuration options that it sup...
unsigned int getDomainSize() const
Returns the size (dimensionality) of the input domain.
This is basic implementation of the LSSVM algorithms.
Definition: LSSVMLearner.h:120
virtual void feedSample(const yarp::sig::Vector &input, const yarp::sig::Vector &output)
Provide the learning machine with an example of the desired mapping.
virtual void writeBottle(yarp::os::Bottle &bot)
virtual double getC()
Accessor for the regularization parameter C.
Definition: LSSVMLearner.h:257
void setCoDomainSize(unsigned int size)
Mutator for the codomain size.
void reset()
Forget everything and start over.
virtual ~LSSVMLearner()
Destructor.
void setDomainSize(unsigned int size)
Mutator for the domain size.
virtual void setC(double C)
Mutator for the regularization parameter C.
Definition: LSSVMLearner.h:248
LSSVMLearner * clone()
Asks the learning machine to return a clone of its type.
Prediction predict(const yarp::sig::Vector &input)
Ask the learning machine to predict the output for a given input.
virtual void train()
Train the learning machine on the examples that have been supplied so far.
virtual void readBottle(yarp::os::Bottle &bot)
Unserializes a machine from a bottle.
LSSVMLearner(unsigned int dom=1, unsigned int cod=1, double c=1.0)
Constructor.
virtual std::string getInfo()
Asks the learning machine to return a string containing information on its operation so far.
virtual LSSVMLearner & operator=(const LSSVMLearner &other)
Assignment operator.
virtual std::string getConfigHelp()
Asks the learning machine to return a string containing the list of configuration options that it sup...
virtual bool configure(yarp::os::Searchable &config)
Change parameters.
A class that represents a prediction result.
Definition: Prediction.h:44
virtual std::string getConfigHelp()
Definition: LSSVMLearner.h:91
virtual std::string getInfo()
Definition: LSSVMLearner.h:98
virtual void setGamma(double g)
Definition: LSSVMLearner.h:70
virtual double evaluate(const yarp::sig::Vector &v1, const yarp::sig::Vector &v2)
virtual bool configure(yarp::os::Searchable &config)
Definition: LSSVMLearner.h:81
zeros(2, 2) eye(2
exp(-x3 *T)]
PortablePair< Vector, Vector > Prediction
Definition: test.cpp:52
This file contains the definition of unique IDs for the body parts and the skin parts of the robot.