| Prev: Creating a new experiment | Up: Creating a new experiment | Next: Customizing the environment |
|---|---|---|
Table of contents
The Creating a new experiment page explain how to quickly setup a new robotic experiment by using the EvoRobotExperiment class. Here we show other ways to create new experiments that are more flexible (e.g. enable you to instantiate only the components that are needed) but that require more programming effort. This can be done by using the BaseExperiment or the Component classes instead of EvoRobotExperiment. You might decide to use these methods, for example, if you want to design an experiment that use a neural network but does not require the utilization of any robot, as in the case of the BackPropagationExperiment illustrated below.
Please notice that when you create a new experiment using the instructions in this page, you should specify the type of your component in the type parameter of the Component group, as in the example below.
:::INI
[TOTAL99]
...
# The name of the group specifying the main component of the experiment
mainComponent = Component
pluginFile = Backpropagation
...
[Component]
type = Backpropagation
....
While FARSA was created with evolutionary robotic experiments in mind, and provides a lot of ready-to-use code for that, the component and plugin architecture is general enough to allow any kind of experiment to be run. For example you may want to write a plugin to work with a neural network learning algorithm (without any robot involved) or to have a physical simulation without a robot controller or even without any robot at all. While you can still use the EvoRobotExperiment class, that means being constrained to the flow imposed by that class (i.e. trials and steps). Moreover, at runtime, a lot of objects that you do not use will be created, wasting memory and computational resources. A better approach is to start from the BaseExperiment class, that allows to easily define actions that can be executed both in batch or through the GUI, in a separate thread or in the GUI thread, with support for pause and resume or not, and to add new windows.
A further possibility is to inherit from the Component class (that, despite the name, is simply a particular kind of component, see the section at the end of this page). This approach will be briefly described at the end of this page, but it is highly discouraged because it is too low-level and because it is scheduled to be removed in the next major FARSA release.
The BaseExperiment class enables you to define actions that can be run in batch or via the Actions menu of the total99 graphic interface. For each action you can specify whether it will run in the GUI thread or in a separate thread and, in this case, whether it is possible to pause the action and run it step-by-step or not. Moreover it enables you to declare additional windows required by the experiment (see this page). The API documentation of BaseExperiment contains a detailed description of the class methods. In this page we use the Backpropagation experimental plugin to illustrate how it can be used.
Below we include the configuration file of the experiment. As you can see, in this case only the main experimental component and the neural network sub-component are configured and istantiated.
:::INI
[TOTAL99]
name = Backpropagation experiment
author = Tomassino Ferrauto
date = 20/10/14 22:20
description = A simple experiement to train neural networks using backpropagation
mainComponent = Component
pluginFile = Backpropagation
pluginPath = .
logLevel = LogAll
[Component]
type = Backpropagation
[Component/NET]
type = Evonet
nSensors = 2
nMotors = 1
Below we include the header file and the definition of the class constructor. For the sake of clarity we only show the portions that we want to review. In this example the experiment is called Backpropagation and, as you can see, the Backpropagation class is declared as a sub-class of BaseExperiment component. The configure(), describe(), save(), and postConfigurateInitialization() methods are standard method of all components.
The getViewers() function is used to create a custom windows. It is similar to the function with the same name of the ParameterSettableUI class described in the page about components. However within the BaseExperiment class, there is no need to create a separate class inheriting from ParameterSettableUI.
The public slots indicate the actions of the experiment that can be executed through the total99 graphic interface or through batch commands. There are different macros that can be used to declare the characteristics of actions (for a detailed documentation refer to the API documentation:
The first argument of each macro is the class name, the second one is the name of the function implementing the operation. The communication between actions running in a dedicated thread and the GUI should be treated with care (for more information see the Threading issues note in this page).
:::C++
#include "baseexperiment.h"
#include "farsaplugin.h"
#include "evonet.h"
class FARSA_PLUGIN_API Backpropagation : public farsa::BaseExperiment
{
Q_OBJECT
FARSA_REGISTER_CLASS(BaseExperiment)
[...]
public:
Backpropagation();
virtual ~Backpropagation();
virtual void configure(farsa::ConfigurationParameters& params, QString prefix);
virtual void save(farsa::ConfigurationParameters& params, QString prefix);
static void describe(QString type);
virtual void postConfigureInitialization();
virtual QList<farsa::ParameterSettableUIViewer> getViewers(QWidget* parent, Qt::WindowFlags flags);
public slots:
virtual void trainAllSeeds();
virtual void trainCurrentNetwork();
virtual void testAllSeeds();
virtual void testCurrentNetwork();
virtual void resetNetwork();
virtual void saveNetwork();
virtual void loadNetwork();
private:
[...]
};
[...]
Backpropagation::Backpropagation()
: farsa::BaseExperiment()
, [...]
{
DECLARE_STEPPABLE_THREAD_OPERATION(Backpropagation, trainAllSeeds)
DECLARE_STEPPABLE_THREAD_OPERATION(Backpropagation, trainCurrentNetwork)
DECLARE_STEPPABLE_THREAD_OPERATION(Backpropagation, testAllSeeds)
DECLARE_STEPPABLE_THREAD_OPERATION(Backpropagation, testCurrentNetwork)
DECLARE_THREAD_OPERATION(Backpropagation, resetNetwork)
DECLARE_IMMEDIATE_OPERATION(Backpropagation, saveNetwork)
DECLARE_IMMEDIATE_OPERATION(Backpropagation, loadNetwork)
}
Below we include the critical portions of the .cpp file containing the implementation of the Backpropagation class.
The resetNetwork() is the implementation of an action that replaces the connection weights of the network with randomly generated values by calling a specific function. Since this operation action is defined as an operation that run in its own thread, it will not slow down or freeze the operation of the tota99 graphic interface.
The testCurrentNetwork() action operates by setting state of the input neurons of the network, by allowing the activation to spread over the network, and by printing the state of the internal and output neurons of the network, for each defined input pattern. Being declared as a steppable thread operation it enables to user to pause/resume/terminate its execution, to operate in a step-by-step mode, and to vary its execution speed. For making this possible, you need to use the: pauseFlow() and stopFlow() functions. The former pauses the execution flow or adds a delay depending on the user requestes. The way in which the action operates basically depends on the code included between two subsequent calls of the pauseFlow() functions. The stopFlow() function, instead, checks whether the action should be terminated as soon as possible and returns true in this case. For a more detailed information please refer to the API documentation.
The saveNetwork() action enables the user to save the current parameters of the network in an user specified file name. Since it requires to open a window to allow the user to indicate the file name and the directory in which the file should be save, it needs to operate within the same thread of the GUI. As a consequence, as explained above, it is declared as an immediate operation.
Finally the getViewers() function creates a window that is used to disply the backpropagation error. Its implementation is the same that you may find in the function with the same name of a ParameterSettableUI subclass. For more information see this page.
NOTE The BaseExperiment class does not include support for resources. If you want to use the resource mechanism in your component, remember to inherit from both BaseExperiment and ConcurrentResourcesUser.
:::C++
void Backpropagation::resetNetwork()
{
internalResetNetwork();
farsa::Logger::info("Neural network weights have been randomized");
}
void Backpropagation::testCurrentNetwork()
{
if (!m_validNetwork) {
farsa::Logger::error("The neural network is invalid, please load a valid network, first");
return;
}
// Initialization
[...]
for (int i = 0; i < m_testingSet.size(); i++) {
pauseFlow();
if (stopFlow()) {
farsa::Logger::info("Testing interrupted");
return;
}
// Computing the neural network output and the error
[...]
}
[...]
farsa::Logger::info("Testing done");
}
void Backpropagation::saveNetwork()
{
const QString filename = QFileDialog::getSaveFileName(NULL, "Save neural network", QString(), "Phenotypes (*.phe)");
if (!filename.isEmpty()) {
m_net->save_net_blocks(filename.toLatin1().data(), 1);
farsa::Logger::info("Neural network saved");
}
}
QList<farsa::ParameterSettableUIViewer> Backpropagation::getViewers(QWidget* parent, Qt::WindowFlags flags)
{
QList<farsa::ParameterSettableUIViewer> viewers = BaseExperiment::getViewers(parent, flags);
ErrorStatViewer* statViewer = new ErrorStatViewer(parent, flags);
viewers.append(farsa::ParameterSettableUIViewer(statViewer, "Learning Error Statistics"));
return viewers;
}
Alternatively you can use the Component class, which is the parent of components that are instantiated directly by total99 (i.e. that can be specified as the type of the Component group in the example configuration files above). It is basically a standard component, so you can refer to the Configuring components page for detailed information. The only method that must necessarily be implemented to use this class is stopCurrentOperation that is used by total99 to terminate all running operation when the application is closed. The usage of this class however is discoraged since it lack several of the important features (e.g. thread management, automatic filling of action menu) which are provided by the BaseExperiment class.
Manual: APIDoc
Manual: ComponentsConfig
Manual: CreatingNewExperiment
Manual: CustomizeEnvironment
Manual: Home
Anonymous