iCub-main
Loading...
Searching...
No Matches
TrainModule.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007-2010 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 <iostream>
20#include <stdexcept>
21#include <cassert>
22
23#include <yarp/os/Vocab.h>
24
28
29namespace iCub {
30namespace learningmachine {
31
32void TrainProcessor::onRead(yarp::os::PortablePair<yarp::sig::Vector,yarp::sig::Vector>& sample) {
33 if(this->getMachinePortable().hasWrapped() && this->enabled) {
34 try {
35 // Event Code
36 if(EventDispatcher::instance().hasListeners()) {
37 Prediction prediction = this->getMachine().predict(sample.head);
38 TrainEvent te(sample.head, sample.body, prediction);
40 }
41 // Event Code
42
43 this->getMachine().feedSample(sample.head, sample.body);
44
45 } catch(const std::exception& e) {
46 std::cerr << "Error: " << e.what() << std::endl;
47 }
48 }
49
50 return;
51}
52
53
54void TrainModule::printOptions(std::string error) {
55 if(error != "") {
56 std::cout << "Error: " << error << std::endl;
57 }
58 std::cout << "Available options for training module" << std::endl;
59 std::cout << "--help Display this help message" << std::endl;
60 std::cout << "--list Print a list of available algorithms" << std::endl;
61 std::cout << "--load file Load serialized machine from a file" << std::endl;
62 std::cout << "--machine type Desired type of learning machine" << std::endl;
63 std::cout << "--port pfx Prefix for registering the ports" << std::endl;
64 std::cout << "--commands file Load configuration commands from a file" << std::endl;
65}
66
67
68void TrainModule::printMachineList() {
69 std::vector<std::string> keys = FactoryT<std::string, IMachineLearner>::instance().getKeys();
70 std::cout << "Available Machine Learners:" << std::endl;
71 for(unsigned int i = 0; i < keys.size(); i++) {
72 std::cout << " " << keys[i] << std::endl;
73 }
74}
75
76
77void TrainModule::registerAllPorts() {
78 // ports from PredictModule, without model:i
79 //this->registerPort(this->model_in, "/" + this->portPrefix + "/model:i");
80 this->registerPort(this->predict_inout, this->portPrefix + "/predict:io");
81 this->predict_inout.setStrict();
82 this->registerPort(this->cmd_in, this->portPrefix + "/cmd:i");
83
84 this->registerPort(this->model_out, this->portPrefix + "/model:o");
85 this->registerPort(this->train_in, this->portPrefix + "/train:i");
86 this->train_in.setStrict();
87}
88
89void TrainModule::unregisterAllPorts() {
91 this->train_in.close();
92 this->model_out.close();
93}
94
97 train_in.interrupt();
98 return true;
99}
100
101bool TrainModule::configure(yarp::os::ResourceFinder& opt) {
102 /* Implementation note:
103 * Calling open() in the base class (i.e. PredictModule) is cumbersome due
104 * to different ordering and dynamic binding (e.g. it calls
105 * registerAllPorts()) and because we do bother with an incoming model port.
106 */
107
108 // read for the general specifiers:
109 yarp::os::Value* val;
110 std::string machineName;
111
112 // cache resource finder
113 this->setResourceFinder(&opt);
114
115 // check for help request
116 if(opt.check("help")) {
117 this->printOptions();
118 return false;
119 }
120
121 // check for algorithm listing request
122 if(opt.check("list")) {
123 this->printMachineList();
124 return false;
125 }
126
127 // check for port specifier: portSuffix
128 if(opt.check("port", val)) {
129 this->portPrefix = val->asString().c_str();
130 }
131
132 // check for filename to load machine from
133 if(opt.check("load", val)) {
134 this->getMachinePortable().readFromFile(val->asString().c_str());
135 } else{
136 // not loading anything, require machine name
137 if(opt.check("machine", val)) {
138 machineName = val->asString().c_str();
139 } else {
140 this->printOptions("No machine type specified");
141 return false;
142 }
143
144 // construct new machine
145 this->getMachinePortable().setWrapped(machineName);
146
147 // send configuration options to the machine
148 this->getMachine().configure(opt);
149 }
150
151
152 // add replier for incoming data (prediction requests)
153 this->predict_inout.setReplier(this->predictProcessor);
154
155 // add processor for incoming data (training samples)
156 this->train_in.useCallback(trainProcessor);
157
158 // register ports before connecting
159 this->registerAllPorts();
160
161 // and finally load command file
162 if(opt.check("commands", val)) {
163 this->loadCommandFile(val->asString().c_str());
164 }
165
166 // attach to the incoming command port and terminal
167 this->attach(cmd_in);
168 this->attachTerminal();
169
170 return true;
171}
172
173
174bool TrainModule::respond(const yarp::os::Bottle& cmd, yarp::os::Bottle& reply) {
175 // NOTE: the module class spawns a new thread, which implies that exception
176 // handling needs to be done in this thread, so not the 'main' thread.
177 bool success = false;
178
179 try {
180 switch(cmd.get(0).asVocab32()) {
181 case yarp::os::createVocab32('h','e','l','p'): // print help information
182 reply.add(yarp::os::Value::makeVocab32("help"));
183
184 reply.addString("Training module configuration options");
185 reply.addString(" help Displays this message");
186 reply.addString(" train Trains the machine and sends the model");
187 reply.addString(" model Sends the model to the prediction module");
188 reply.addString(" reset Resets the machine to its current state");
189 reply.addString(" info Outputs information about the machine");
190 reply.addString(" pause Disable passing the samples to the machine");
191 reply.addString(" continue Enable passing the samples to the machine");
192 reply.addString(" set key val Sets a configuration option for the machine");
193 reply.addString(" load fname Loads a machine from a file");
194 reply.addString(" save fname Saves the current machine to a file");
195 reply.addString(" event [cmd ...] Sends commands to event dispatcher (see: event help)");
196 reply.addString(" cmd fname Loads commands from a file");
197 reply.addString(this->getMachine().getConfigHelp().c_str());
198 success = true;
199 break;
200
201 case yarp::os::createVocab32('t','r','a','i'): // train the machine, implies sending model
202 this->getMachine().train();
203 reply.addString("Training completed.");
204
205 case yarp::os::createVocab32('m','o','d','e'): // send model
206 this->model_out.write(this->machinePortable);
207 reply.addString("The model has been written to the port.");
208 success = true;
209 break;
210
211 case yarp::os::createVocab32('c','l','e','a'): // clear machine
212 case yarp::os::createVocab32('c','l','r'):
213 case yarp::os::createVocab32('r','e','s','e'): // reset
214 case yarp::os::createVocab32('r','s','t'):
215 this->getMachine().reset();
216 reply.addString("Machine cleared.");
217 success = true;
218 break;
219
220 case yarp::os::createVocab32('p','a','u','s'): // pause sample stream
221 case yarp::os::createVocab32('d','i','s','a'): // disable
222 this->trainProcessor.setEnabled(false);
223 reply.addString("Sample stream to machine disabled.");
224 success = true;
225 break;
226
227 case yarp::os::createVocab32('c','o','n','t'): // continue sample stream
228 case yarp::os::createVocab32('e','n','a','b'): // enable
229 this->trainProcessor.setEnabled(true);
230 reply.addString("Sample stream to machine enabled.");
231 success = true;
232 break;
233
234 case yarp::os::createVocab32('i','n','f','o'): // information
235 case yarp::os::createVocab32('s','t','a','t'): // statistics
236 { // prevent identifier initialization to cross borders of case
237 reply.add(yarp::os::Value::makeVocab32("help"));
238 reply.addString("Machine Information: ");
239 reply.addString(this->getMachine().getInfo().c_str());
240 success = true;
241 break;
242 }
243
244 case yarp::os::createVocab32('l','o','a','d'): // load
245 { // prevent identifier initialization to cross borders of case
246 reply.add(yarp::os::Value::makeVocab32("help"));
247 std::string replymsg = std::string("Loading machine from '") +
248 cmd.get(1).asString().c_str() + "'... " ;
249 if(!cmd.get(1).isString()) {
250 replymsg += "failed";
251 } else {
252 this->getMachinePortable().readFromFile(cmd.get(1).asString().c_str());
253 replymsg += "succeeded";
254 }
255 reply.addString(replymsg.c_str());
256 success = true;
257 break;
258 }
259
260 case yarp::os::createVocab32('s','a','v','e'): // save
261 { // prevent identifier initialization to cross borders of case
262 reply.add(yarp::os::Value::makeVocab32("help"));
263 std::string replymsg = std::string("Saving machine to '") +
264 cmd.get(1).asString().c_str() + "'... " ;
265 if(!cmd.get(1).isString()) {
266 replymsg += "failed";
267 } else {
268 this->getMachinePortable().writeToFile(cmd.get(1).asString().c_str());
269 replymsg += "succeeded";
270 }
271 reply.addString(replymsg.c_str());
272 success = true;
273 break;
274 }
275
276 case yarp::os::createVocab32('s','e','t'): // set a configuration option for the machine
277 { // prevent identifier initialization to cross borders of case
278 yarp::os::Bottle property;
279 /*
280 * This is a simple hack to enable multiple parameters The need
281 * for this hack lies in the fact that a group can only be found
282 * using findGroup if it is a nested list in a Bottle. If the
283 * Bottle itself is the list, then the group will _not_ be found.
284 */
285 property.addList() = cmd.tail();
286 std::string replymsg = "Setting configuration option ";
287 bool ok = this->getMachine().configure(property);
288 replymsg += ok ? "succeeded" :
289 "failed; please check key and value type.";
290 reply.addString(replymsg.c_str());
291 success = true;
292 break;
293 }
294
295 case yarp::os::createVocab32('e','v','e','n'): // event
296 { // prevent identifier initialization to cross borders of case
297 success = this->dmanager.respond(cmd.tail(), reply);
298 break;
299 }
300
301 case yarp::os::createVocab32('c','m','d'): // cmd
302 case yarp::os::createVocab32('c','o','m','m'): // command
303 { // prevent identifier initialization to cross borders of case
304 reply.add(yarp::os::Value::makeVocab32("help"));
305 std::string replymsg;
306 if(!cmd.get(1).isString()) {
307 replymsg = "Please supply a valid filename.";
308 } else {
309 std::string full_fname = this->findFile(cmd.get(1).asString().c_str());
310 replymsg = std::string("Loading commands from '") +
311 full_fname + "'... " ;
312 this->loadCommandFile(full_fname, &reply);
313 replymsg += "succeeded";
314 }
315 reply.addString(replymsg.c_str());
316 success = true;
317 break;
318 }
319
320 default:
321 break;
322
323 }
324 } catch(const std::exception& e) {
325 std::string msg = std::string("Error: ") + e.what();
326 reply.addString(msg.c_str());
327 success = true;
328 }
329
330 return success;
331}
332
333} // learningmachine
334} // iCub
bool respond(const yarp::os::Bottle &cmd, yarp::os::Bottle &reply)
Respond to a command or configuration message.
virtual void raise(IEvent &event)
Raises an IEvent, causing it to be dispatched to each registered IEventListener.
static EventDispatcher & instance()
An instance retrieval method that follows the Singleton pattern.
static FactoryT< K, T > & instance()
An instance retrieval method that follows the Singleton pattern.
Definition FactoryT.h:86
DispatcherManager dmanager
An instance of the DispatchManager to configure event listeners.
std::string portPrefix
A prefix path for the ports that will be registered.
virtual void setResourceFinder(yarp::os::ResourceFinder *rf)
Mutator for the locally stored ResourceFinder.
std::string findFile(std::string fname)
Finds the full path to a specified filename using the ResourceFinder.
void registerPort(yarp::os::Contactable &port, std::string name)
Register a port with a given name.
yarp::os::Port cmd_in
An input port for commands.
virtual void loadCommandFile(std::string fname, yarp::os::Bottle *out=(yarp::os::Bottle *) 0)
Reads bottles from a file and sends these one by one to the respond method.
virtual bool configure(yarp::os::Searchable &config)
Change parameters.
virtual void reset()=0
Forget everything and start over.
virtual void train()
Train the learning machine on the examples that have been supplied so far.
virtual Prediction predict(const yarp::sig::Vector &input)=0
Ask the learning machine to predict the output for a given input.
virtual void feedSample(const yarp::sig::Vector &input, const yarp::sig::Vector &output)=0
Provide the learning machine with an example of the desired mapping.
virtual MachinePortable & getMachinePortable()
Retrieve the machine portable machine wrapper.
virtual IMachineLearner & getMachine()
Convenience function to quickly retrieve the machine that is wrapped in the portable machine wrapper.
void setWrapped(T *w, bool wipe=true)
The mutator for the wrapped object.
Definition PortableT.h:228
bool writeToFile(std::string filename)
Writes a wrapped object to a file.
Definition PortableT.h:161
bool readFromFile(std::string filename)
Reads a wrapped object from a file.
Definition PortableT.h:182
void unregisterAllPorts()
Unregisters all ports used by this module.
yarp::os::BufferedPort< yarp::sig::Vector > predict_inout
Buffered port for the incoming samples and corresponding replies.
MachinePortable machinePortable
A concrete wrapper around a learning machine.
virtual IMachineLearner & getMachine()
Retrieve the machine that is wrapped in the portable machine wrapper.
virtual MachinePortable & getMachinePortable()
Retrieve the machine portable.
PredictProcessor predictProcessor
The processor handling prediction requests.
A class that represents a prediction result.
Definition Prediction.h:44
A TrainEvent is raised when the machine handles a training sample.
Definition TrainEvent.h:44
virtual bool configure(yarp::os::ResourceFinder &opt)
virtual bool respond(const yarp::os::Bottle &cmd, yarp::os::Bottle &reply)
virtual void setEnabled(bool val)
Enables or disables processing of training samples.
Definition TrainModule.h:60
virtual void onRead(yarp::os::PortablePair< yarp::sig::Vector, yarp::sig::Vector > &sample)
cmd
Definition dataTypes.h:30
bool error
This file contains the definition of unique IDs for the body parts and the skin parts of the robot.