iCub-main
Loading...
Searching...
No Matches
neuralNetworks.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 iCub Facility - Istituto Italiano di Tecnologia
3 * Author: Ugo Pattacini
4 * email: ugo.pattacini@iit.it
5 * Permission is granted to copy, distribute, and/or modify this program
6 * under the terms of the GNU General Public License, version 2 or any
7 * later version published by the Free Software Foundation.
8 *
9 * A copy of the license can be found at
10 * http://www.robotcub.org/icub/license/gpl.txt
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details
16*/
17
18#include <algorithm>
19#include <string>
20
21#include <yarp/math/Math.h>
22#include <yarp/math/Rand.h>
23#include <iCub/ctrl/math.h>
25
26#include <IpTNLP.hpp>
27#include <IpIpoptApplication.hpp>
28
29#define CAST_IPOPTAPP(x) (static_cast<Ipopt::IpoptApplication*>(x))
30
31using namespace std;
32using namespace yarp::os;
33using namespace yarp::sig;
34using namespace yarp::math;
35using namespace iCub::ctrl;
36using namespace iCub::optimization;
37
38
39namespace iCub
40{
41
42namespace optimization
43{
44
45/****************************************************************/
46class ff2LayNNTrainNLP : public Ipopt::TNLP
47{
48protected:
49 Property bounds;
51
53 deque<Vector> &IW;
54 deque<Vector> &LW;
55 Vector &b1;
56 Vector &b2;
57
58 const deque<Vector> &in;
59 const deque<Vector> &out;
60 deque<Vector> &pred;
61 double error;
62
63 /****************************************************************/
64 bool getBounds(const string &tag, double &min, double &max)
65 {
66 min=-1.0; max=1.0;
67 if (Bottle *b=bounds.find(tag).asList())
68 {
69 if (b->size()>=2)
70 {
71 min=b->get(0).asFloat64();
72 max=b->get(1).asFloat64();
73 return true;
74 }
75 }
76
77 return false;
78 }
79
80 /****************************************************************/
81 void fillNet(const Ipopt::Number *x)
82 {
83 Ipopt::Index k=0;
84 for (size_t i=0; i<IW.size(); i++)
85 for (size_t j=0; j<IW.front().length(); j++, k++)
86 IW[i][j]=x[k];
87
88 for (size_t i=0; i<LW.size(); i++)
89 for (size_t j=0; j<LW.front().length(); j++, k++)
90 LW[i][j]=x[k];
91
92 for (size_t i=0; i<b1.length(); i++, k++)
93 b1[i]=x[k];
94
95 for (size_t i=0; i<b2.length(); i++, k++)
96 b2[i]=x[k];
97 }
98
99 /****************************************************************/
100 void fillVar(Ipopt::Number *x, const Ipopt::Number *x_l, const Ipopt::Number *x_u)
101 {
102 Ipopt::Index k=0;
103 for (size_t i=0; i<IW.size(); i++)
104 for (size_t j=0; j<IW.front().length(); j++, k++)
105 x[k]=std::min(x_u[k],std::max(IW[i][j],x_l[k]));
106
107 for (size_t i=0; i<LW.size(); i++)
108 for (size_t j=0; j<LW.front().length(); j++, k++)
109 x[k]=std::min(x_u[k],std::max(LW[i][j],x_l[k]));
110
111 for (size_t i=0; i<b1.length(); i++, k++)
112 x[k]=std::min(x_u[k],std::max(b1[i],x_l[k]));
113
114 for (size_t i=0; i<b2.length(); i++, k++)
115 x[k]=std::min(x_u[k],std::max(b2[i],x_l[k]));
116 }
117
118public:
119 /****************************************************************/
120 ff2LayNNTrainNLP(ff2LayNNTrain &_net, const Property &_bounds,
121 const bool _randomInit, const deque<Vector> &_in,
122 const deque<Vector> &_out, deque<Vector> &_pred) :
123 net(_net), bounds(_bounds), randomInit(_randomInit),
124 in(_in), out(_out), pred(_pred),
125 IW(_net.get_IW()), LW(_net.get_LW()),
126 b1(_net.get_b1()), b2(_net.get_b2())
127 {
128 pred.clear();
129 error=0.0;
130 }
131
132 /****************************************************************/
133 virtual double get_error() const
134 {
135 return error;
136 }
137
138 /****************************************************************/
139 bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g,
140 Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style)
141 {
142 n=IW.size()*IW.front().length()+LW.size()*LW.front().length()+b1.length()+b2.length();
143 m=nnz_jac_g=nnz_h_lag=0;
144 index_style=TNLP::C_STYLE;
145
146 return true;
147 }
148
149 /****************************************************************/
150 bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u,
151 Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
152 {
153 double min_IW,max_IW; getBounds("IW",min_IW,max_IW);
154 double min_LW,max_LW; getBounds("LW",min_LW,max_LW);
155 double min_b1,max_b1; getBounds("b1",min_b1,max_b1);
156 double min_b2,max_b2; getBounds("b2",min_b2,max_b2);
157
158 Ipopt::Index k=0;
159 for (size_t i=0; i<IW.size(); i++)
160 {
161 for (size_t j=0; j<IW.front().length(); j++, k++)
162 {
163 x_l[k]=min_IW;
164 x_u[k]=max_IW;
165 }
166 }
167
168 for (size_t i=0; i<LW.size(); i++)
169 {
170 for (size_t j=0; j<LW.front().length(); j++, k++)
171 {
172 x_l[k]=min_LW;
173 x_u[k]=max_LW;
174 }
175 }
176
177 for (size_t i=0; i<b1.size(); i++, k++)
178 {
179 x_l[k]=min_b1;
180 x_u[k]=max_b1;
181 }
182
183 for (size_t i=0; i<b2.size(); i++, k++)
184 {
185 x_l[k]=min_b2;
186 x_u[k]=max_b2;
187 }
188
189 return true;
190 }
191
192 /****************************************************************/
193 bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x,
194 bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U,
195 Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
196 {
197 Ipopt::Number *x_l=new Ipopt::Number[n];
198 Ipopt::Number *x_u=new Ipopt::Number[n];
199 Ipopt::Number *g_l=new Ipopt::Number[n];
200 Ipopt::Number *g_u=new Ipopt::Number[n];
201
202 get_bounds_info(n,x_l,x_u,m,g_l,g_u);
203 if (randomInit)
204 {
205 Rand::init();
206 for (Ipopt::Index i=0; i<n; i++)
207 x[i]=Rand::scalar(x_l[i],x_u[i]);
208 }
209 else
210 fillVar(x,x_l,x_u);
211
212 delete[] x_l;
213 delete[] x_u;
214 delete[] g_l;
215 delete[] g_u;
216
217 return true;
218 }
219
220 /****************************************************************/
221 bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
222 Ipopt::Number &obj_value)
223 {
224 fillNet(x);
225
226 obj_value=0.0;
227 for (size_t i=0; i<in.size(); i++)
228 {
229 Vector pred=net.predict(in[i]);
230 obj_value+=norm2(out[i]-pred);
231 }
232
233 obj_value/=in.size();
234 return true;
235 }
236
237 /****************************************************************/
238 bool eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
239 Ipopt::Number *grad_f)
240 {
241 return true;
242 }
243
244 /****************************************************************/
245 bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
246 Ipopt::Index m, Ipopt::Number *g)
247 {
248 return true;
249 }
250
251 /****************************************************************/
252 bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
253 Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow,
254 Ipopt::Index *jCol, Ipopt::Number *values)
255 {
256 return true;
257 }
258
259 /****************************************************************/
260 bool eval_h(Ipopt::Index n, const Ipopt::Number *x, bool new_x,
261 Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number *lambda,
262 bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index *iRow,
263 Ipopt::Index *jCol, Ipopt::Number *values)
264 {
265 return true;
266 }
267
268 /****************************************************************/
269 void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n,
270 const Ipopt::Number *x, const Ipopt::Number *z_L,
271 const Ipopt::Number *z_U, Ipopt::Index m,
272 const Ipopt::Number *g, const Ipopt::Number *lambda,
273 Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data,
274 Ipopt::IpoptCalculatedQuantities *ip_cq)
275 {
276 error=0.0;
277 pred.clear();
278 for (size_t i=0; i<in.size(); i++)
279 {
280 Vector pred=net.predict(in[i]);
281 error+=norm2(out[i]-pred);
282 this->pred.push_back(pred);
283 }
284 error/=in.size();
285 }
286};
287
288}
289
290}
291
292
293/****************************************************************/
295{
296 App=new Ipopt::IpoptApplication();
297 CAST_IPOPTAPP(App)->Options()->SetNumericValue("tol",1e-8);
298 CAST_IPOPTAPP(App)->Options()->SetIntegerValue("acceptable_iter",0);
299 CAST_IPOPTAPP(App)->Options()->SetStringValue("mu_strategy","adaptive");
300 CAST_IPOPTAPP(App)->Options()->SetIntegerValue("max_iter",300);
301 CAST_IPOPTAPP(App)->Options()->SetStringValue("nlp_scaling_method","gradient-based");
302 CAST_IPOPTAPP(App)->Options()->SetStringValue("hessian_approximation","limited-memory");
303 CAST_IPOPTAPP(App)->Options()->SetStringValue("jacobian_approximation","finite-difference-values");
304 CAST_IPOPTAPP(App)->Options()->SetIntegerValue("print_level",0);
305 CAST_IPOPTAPP(App)->Options()->SetStringValue("derivative_test","none");
306 CAST_IPOPTAPP(App)->Initialize();
307}
308
309
310/****************************************************************/
311void ff2LayNNTrain::setBounds(const Property &bounds)
312{
313 this->bounds=bounds;
314}
315
316
317/****************************************************************/
318bool ff2LayNNTrain::train(const unsigned int numHiddenNodes,
319 const deque<Vector> &in, const deque<Vector> &out,
320 deque<Vector> &pred, double &error)
321{
322 if ((in.size()==0) || (in.size()!=out.size()))
323 return false;
324
325 IW.clear();
326 IW.assign(numHiddenNodes,Vector(in.front().length(),0.0));
327 b1.resize(numHiddenNodes,0.0);
328
329 LW.clear();
330 LW.assign(out.front().length(),Vector(numHiddenNodes,0.0));
331 b2.resize(out.front().length(),0.0);
332
333 inMinMaxX.clear();
334 inMinMaxY.clear();
335
336 outMinMaxX.clear();
337 outMinMaxY.clear();
338
339 // seek for min-max of input and scale it in [-1,1]
340 const Vector &in_front=in.front();
341 for (size_t i=0; i<in_front.length(); i++)
342 {
343 minmax range;
344 range.min=range.max=in_front[i];
345 inMinMaxX.push_back(range);
346 range.min=-1.0; range.max=1.0;
347 inMinMaxY.push_back(range);
348 }
349 for (size_t i=1; i<in.size(); i++)
350 {
351 for (size_t j=0; j<in_front.length(); j++)
352 {
353 inMinMaxX[j].min=std::min(inMinMaxX[j].min,in[i][j]);
354 inMinMaxX[j].max=std::max(inMinMaxX[j].max,in[i][j]);
355 }
356 }
357
358 // enlarge of 10%
359 for (size_t i=0; i<inMinMaxX.size(); i++)
360 {
361 inMinMaxX[i].min-=0.1*fabs(inMinMaxX[i].min);
362 inMinMaxX[i].max+=0.1*fabs(inMinMaxX[i].max);
363 }
364
365 // seek for min-max of output and scale it in [-1,1]
366 const Vector &out_front=out.front();
367 for (size_t i=0; i<out_front.length(); i++)
368 {
369 minmax range;
370 range.min=range.max=out_front[i];
371 outMinMaxX.push_back(range);
372 range.min=-1.0; range.max=1.0;
373 outMinMaxY.push_back(range);
374 }
375 for (size_t i=1; i<out.size(); i++)
376 {
377 for (size_t j=0; j<out_front.length(); j++)
378 {
379 outMinMaxX[j].min=std::min(outMinMaxX[j].min,out[i][j]);
380 outMinMaxX[j].max=std::max(outMinMaxX[j].max,out[i][j]);
381 }
382 }
383
384 // enlarge of 10%
385 for (size_t i=0; i<outMinMaxX.size(); i++)
386 {
387 outMinMaxX[i].min-=0.1*fabs(outMinMaxX[i].min);
388 outMinMaxX[i].max+=0.1*fabs(outMinMaxX[i].max);
389 }
390
391 prepare();
392 configured=true;
393
394 Ipopt::SmartPtr<ff2LayNNTrainNLP> nlp=new ff2LayNNTrainNLP(*this,bounds,true,in,out,pred);
395 Ipopt::ApplicationReturnStatus status=CAST_IPOPTAPP(App)->OptimizeTNLP(GetRawPtr(nlp));
396
397 error=nlp->get_error();
398 return (status==Ipopt::Solve_Succeeded);
399}
400
401
402/****************************************************************/
403bool ff2LayNNTrain::retrain(const deque<Vector> &in, const deque<Vector> &out,
404 deque<Vector> &pred, double &error)
405{
406 if ((in.size()==0) || (in.size()!=out.size()) || !configured)
407 return false;
408
409 Ipopt::SmartPtr<ff2LayNNTrainNLP> nlp=new ff2LayNNTrainNLP(*this,bounds,false,in,out,pred);
410 Ipopt::ApplicationReturnStatus status=CAST_IPOPTAPP(App)->OptimizeTNLP(GetRawPtr(nlp));
411
412 error=nlp->get_error();
413 return (status==Ipopt::Solve_Succeeded);
414}
415
416
417/****************************************************************/
422
423
yarp::sig::Vector b2
yarp::sig::Vector b1
std::deque< minmax > inMinMaxX
std::deque< minmax > inMinMaxY
std::deque< yarp::sig::Vector > IW
std::deque< minmax > outMinMaxX
virtual yarp::sig::Vector predict(const yarp::sig::Vector &x) const
Predict the output given a certain input to the network.
std::deque< minmax > outMinMaxY
std::deque< yarp::sig::Vector > LW
bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Number *g)
bool getBounds(const string &tag, double &min, double &max)
bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g, Ipopt::Index &nnz_h_lag, IndexStyleEnum &index_style)
bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u, Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
ff2LayNNTrainNLP(ff2LayNNTrain &_net, const Property &_bounds, const bool _randomInit, const deque< Vector > &_in, const deque< Vector > &_out, deque< Vector > &_pred)
void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, const Ipopt::Number *x, const Ipopt::Number *z_L, const Ipopt::Number *z_U, Ipopt::Index m, const Ipopt::Number *g, const Ipopt::Number *lambda, Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq)
bool eval_h(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number *lambda, bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
void fillVar(Ipopt::Number *x, const Ipopt::Number *x_l, const Ipopt::Number *x_u)
bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number &obj_value)
bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x, bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U, Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number *grad_f)
void fillNet(const Ipopt::Number *x)
Class to deal with training of Feed-Forward 2 layers Neural Network using IpOpt.
void setBounds(const yarp::os::Property &bounds)
Allow specifying the bounds for training network's parameters.
virtual bool train(const unsigned int numHiddenNodes, const std::deque< yarp::sig::Vector > &in, const std::deque< yarp::sig::Vector > &out, std::deque< yarp::sig::Vector > &pred, double &error)
Train the network through optimization.
virtual bool retrain(const std::deque< yarp::sig::Vector > &in, const std::deque< yarp::sig::Vector > &out, std::deque< yarp::sig::Vector > &pred, double &error)
Retrain the network through optimization.
virtual ~ff2LayNNTrain()
Default destructor.
int n
bool error
double norm2(const yarp::sig::Matrix &M, int col)
Returns the squared norm of the vector given in the form: matrix(:,col).
Definition math.h:91
#define CAST_IPOPTAPP(x)
Definition iKinIpOpt.cpp:20
This file contains the definition of unique IDs for the body parts and the skin parts of the robot.
out
Definition sine.m:8