29 #include <yarp/os/Network.h>
30 #include <yarp/os/ResourceFinder.h>
31 #include <yarp/os/RFModule.h>
32 #include <yarp/os/PortablePair.h>
33 #include <yarp/sig/Vector.h>
34 #include <yarp/os/Port.h>
35 #include <yarp/os/BufferedPort.h>
36 #include <yarp/os/Time.h>
37 #include <yarp/os/Vocab.h>
39 #define TWOPI 6.283185307179586
41 using namespace yarp::os;
42 using namespace yarp::sig;
45 namespace learningmachine {
56 std::ostringstream output;
62 std::ostringstream output;
68 std::ostringstream output;
70 for(
unsigned int i = 0; i < v.size(); i++) {
71 if(i > 0) output <<
", ";
79 std::ostringstream output;
81 for(
size_t i = 0; i < v.size(); i++) {
82 if(i > 0) output <<
",";
90 std::ostringstream output;
93 for(
size_t i = 0; i < v.size(); i++) {
94 if(i > 0) output <<
",";
100 for(
size_t i = 0; i < v.size(); i++) {
101 if(i > 0) output <<
",";
114 std::string filename;
115 std::vector<int> inputCols;
116 std::vector<int> outputCols;
121 this->inputCols.resize(1);
122 this->outputCols.resize(1);
124 this->inputCols.clear();
125 this->outputCols.clear();
130 this->inputCols.push_back(col);
134 this->outputCols.push_back(col);
138 return this->inputCols;
142 return this->outputCols;
147 return this->filename;
152 this->filename = filename;
157 this->open(this->filename);
161 void open(std::string filename) {
163 if(this->file.is_open()) {
167 this->file.open(filename.c_str());
168 if(!
file.is_open() ||
file.fail()) {
169 std::string msg(
"could not open file '" + filename +
"'");
170 this->setFilename(
"");
171 throw std::runtime_error(msg);
174 this->setFilename(filename);
179 return !this->file.eof() && this->file.good();
183 this->samplesRead = 0;
185 this->file.seekg(0, std::ios::beg);
196 std::string lineString;
198 if(!this->hasNextSample()) {
199 throw std::runtime_error(
"at end of dataset");
204 getline(
file, lineString);
205 }
while(lineString[0] ==
'#' && !
file.eof());
207 if(!this->hasNextSample()) {
208 throw std::runtime_error(
"at end of dataset");
212 std::istringstream lineStream(lineString);
213 while(!lineStream.eof()) {
217 std::vector<int>::iterator inputFind = std::find(this->inputCols.begin(), this->inputCols.end(), currentCol);
218 if(inputFind != this->inputCols.end()) {
219 input.push_back(val);
223 std::vector<int>::iterator outputFind = std::find(this->outputCols.begin(), this->outputCols.end(), currentCol);
224 if(outputFind != this->outputCols.end()) {
225 output.push_back(val);
230 std::pair<Vector,Vector> sample(input, output);
246 BufferedPort<PortablePair<Vector,Vector> > train_out;
249 std::string portPrefix;
255 void registerPort(Contactable& port, std::string name) {
256 if(port.open(name.c_str()) !=
true) {
257 std::string msg(
"could not register port ");
259 throw std::runtime_error(msg);
263 void registerAllPorts() {
264 this->registerPort(this->train_out, this->portPrefix +
"/train:o");
265 this->train_out.setStrict();
266 this->registerPort(this->predict_inout, this->portPrefix +
"/predict:io");
269 void unregisterAllPorts() {
270 this->train_out.close();
271 this->predict_inout.close();
281 std::cout <<
"Error: " << error << std::endl;
283 std::cout <<
"Available options" << std::endl;
284 std::cout <<
"--help Display this help message" << std::endl;
285 std::cout <<
"--trainport port Data port for the training samples" << std::endl;
286 std::cout <<
"--predictport port Data port for the prediction samples" << std::endl;
287 std::cout <<
"--datafile file Filename containing the dataset" << std::endl;
288 std::cout <<
"--inputs (idx1, ..) List of indices to use as inputs" << std::endl;
289 std::cout <<
"--outputs (idx1, ..) List of indices to use as outputs" << std::endl;
290 std::cout <<
"--port pfx Prefix for registering the ports" << std::endl;
291 std::cout <<
"--frequency f Sampling frequency in Hz" << std::endl;
295 std::cout <<
"* - Configuration -" << std::endl;
296 std::cout <<
"* Datafile: " << this->dataset.
getFilename() << std::endl;
307 if(opt.check(
"help")) {
308 this->printOptions();
313 if(opt.check(
"port", val)) {
314 this->portPrefix = val->asString().c_str();
317 std::cout <<
"* Registering ports...";
318 this->registerAllPorts();
319 std::cout <<
"Done!" << std::endl;
322 if(opt.check(
"trainport", val)) {
323 Network::connect(this->train_out.where().getName().c_str(), val->asString().c_str());
329 if(opt.check(
"predictport", val)) {
330 Network::connect(this->predict_inout.where().getName().c_str(), val->asString().c_str());
336 if(opt.check(
"datafile", val)) {
338 this->dataset.
open(val->asString().c_str());
342 if(opt.check(
"inputs", val)) {
345 Bottle* inputs = val->asList();
346 for(
int i = 0; i < inputs->size(); i++) {
347 if(inputs->get(i).isInt32()) {
351 }
else if(val->isInt32()) {
359 if(opt.check(
"outputs", val)) {
362 Bottle* outputs = val->asList();
363 for(
int i = 0; i < outputs->size(); i++) {
364 if(outputs->get(i).isInt32()) {
368 }
else if(val->isInt32()) {
376 if(opt.check(
"frequency", val)) {
377 this->frequency = val->asInt32();
384 this->attachTerminal();
390 PortablePair<Vector,Vector>& sample = this->train_out.prepare();
392 sample.body = output;
393 this->train_out.writeStrict();
398 this->predict_inout.write(input, prediction);
408 bool success =
false;
411 switch(
cmd.get(0).asVocab32()) {
412 case yarp::os::createVocab32(
'h',
'e',
'l',
'p'):
414 reply.add(Value::makeVocab32(
"help"));
416 reply.addString(
"Testing module configuration options");
417 reply.addString(
" help Displays this message");
418 reply.addString(
" conf Print configuration");
419 reply.addString(
" train [n] Send training samples");
420 reply.addString(
" predict [n] Send testing samples");
421 reply.addString(
" skip [n] Skip samples");
422 reply.addString(
" reset Reset dataset");
423 reply.addString(
" shoot v1 ... vn Shoot a single prediction sample");
424 reply.addString(
" open fname Opens a datafile");
425 reply.addString(
" freq f Sampling frequency in Hertz (0 for disabled)");
427 case yarp::os::createVocab32(
'c',
'o',
'n',
'f'):
434 case yarp::os::createVocab32(
's',
'k',
'i',
'p'):
438 if(
cmd.get(1).isInt32()) {
439 noSamples =
cmd.get(1).asInt32();
442 for(
int i = 0; i < noSamples; i++) {
443 std::pair<Vector,Vector> sample = this->dataset.
getNextSample();
446 reply.addString(
"Done!");
451 case yarp::os::createVocab32(
't',
'r',
'a',
'i'):
453 reply.add(Value::makeVocab32(
"help"));
456 if(
cmd.get(1).isInt32()) {
457 noSamples =
cmd.get(1).asInt32();
461 for(
int i = 0; i < noSamples; i++) {
462 std::pair<Vector,Vector> sample = this->dataset.
getNextSample();
463 this->sendTrainSample(sample.first, sample.second);
466 if(this->frequency > 0)
467 yarp::os::Time::delay(1. / this->frequency);
473 reply.addString(
"Done!");
478 case yarp::os::createVocab32(
'p',
'r',
'e',
'd'):
480 reply.add(Value::makeVocab32(
"help"));
483 if(
cmd.get(1).isInt32()) {
484 noSamples =
cmd.get(1).asInt32();
494 double start = yarp::os::Time::now();
495 for(
int i = 0; i < noSamples; i++) {
496 std::pair<Vector,Vector> sample = this->dataset.
getNextSample();
497 Prediction prediction = this->sendPredictSample(sample.first);
502 Vector expected = prediction.head;
503 if(expected.size() != sample.second.size()) {
504 std::string msg(
"incoming prediction has incorrect dimension");
505 throw std::runtime_error(msg);
507 for(
size_t j = 0; j < error.size(); j++) {
508 double dist = sample.second[j] - expected[j];
509 error[j] += (dist * dist);
512 Vector variance = prediction.body;
513 if(variance.size() > 0 && variance.size() != sample.second.size()) {
514 std::string msg(
"incoming predictive variance has invalid dimension");
515 throw std::runtime_error(msg);
517 for(
size_t j = 0; j < nmlp.size(); j++) {
518 double normdist = (sample.second[j] - expected[j]) / variance[j];
519 nmlp[j] += 0.5 * ((normdist * normdist) + log(
TWOPI) + 2 * log(variance[j]));
523 if(this->frequency > 0)
524 yarp::os::Time::delay(1. / this->frequency);
526 double end = yarp::os::Time::now();
527 std::string reply_str =
"Timing: " +
doubletostring(noSamples / (end - start)) +
" samples per second";
528 reply.addString(reply_str.c_str());
531 for(
size_t i = 0; i < error.size(); i++) {
532 error[i] = error[i] / double(noSamples);
534 for(
size_t i = 0; i < error.size(); i++) {
535 nmlp[i] = nmlp[i] / double(noSamples);
539 reply.addString(reply_str.c_str());
542 reply.addString(reply_str.c_str());
547 case yarp::os::createVocab32(
's',
'h',
'o',
'o'):
551 for(
int i = 1; i <=
cmd.size(); i++) {
552 if(
cmd.get(i).isFloat64() ||
cmd.get(i).isInt32()) {
553 input.push_back(
cmd.get(i).asFloat64());
556 Prediction prediction = this->sendPredictSample(input);
558 reply.addString(reply_str.c_str());
563 case yarp::os::createVocab32(
'o',
'p',
'e',
'n'):
565 if(
cmd.get(1).isString()) {
566 std::cout <<
"Open..." << std::endl;
567 this->dataset.
open(
cmd.get(1).asString().c_str());
569 reply.addString((std::string(
"Opened dataset: ") +
cmd.get(1).asString().c_str()).c_str());
572 case yarp::os::createVocab32(
'r',
'e',
's',
'e'):
573 case yarp::os::createVocab32(
'r',
's',
't'):
575 this->dataset.
reset();
576 reply.addString(
"Dataset reset to beginning");
579 case yarp::os::createVocab32(
'f',
'r',
'e',
'q'):
581 if(
cmd.size() > 1 &&
cmd.get(1).isInt32()) {
583 this->frequency =
cmd.get(1).asInt32();
584 reply.addString((std::string(
"Current frequency: ") +
inttostring(this->frequency)).c_str());
589 case yarp::os::createVocab32(
's',
'e',
't'):
596 }
catch(
const std::exception&
e) {
598 std::string msg = std::string(
"Error: ") +
e.what();
599 reply.addString(msg.c_str());
602 std::string msg = std::string(
"Error. (something bad happened, but I wouldn't know what!)");
603 reply.addString(msg.c_str());
610 this->unregisterAllPorts();
627 rf.setDefaultContext(
"learningMachine");
628 rf.configure(
argc, argv);
632 ret = module.runModule(rf);
634 }
catch(
const std::exception&
e) {
635 std::cerr <<
"Error: " <<
e.what() << std::endl;
639 std::cerr <<
"Error: " << msg << std::endl;
void open(std::string filename)
std::vector< int > getInputColumns()
std::pair< Vector, Vector > getNextSample()
std::vector< int > getOutputColumns()
void addInputColumn(int col)
std::string getFilename()
void addOutputColumn(int col)
void setFilename(std::string filename)
The MachineLearnerTestModule is used to feed datasets loaded from a file to the learning machines and...
void printOptions(std::string error="")
virtual bool configure(ResourceFinder &opt)
Prediction sendPredictSample(Vector input)
void sendTrainSample(Vector input, Vector output)
bool respond(const Bottle &cmd, Bottle &reply)
MachineLearnerTestModule(std::string pp="/lm/test")
std::string printPrediction(Prediction &p)
PortablePair< Vector, Vector > Prediction
std::string doubletostring(double d)
std::string printVector(const Vector &v)
std::string inttostring(int i)
This file contains the definition of unique IDs for the body parts and the skin parts of the robot.
Copyright (C) 2008 RobotCub Consortium.
int main(int argc, char *argv[])