init
@@ -0,0 +1,3 @@
|
||||
|
||||
# Add all the subdirs as projects of the named branch
|
||||
OV_ADD_PROJECTS("CONTRIB_APPLICATIONS_DEVELOPER-TOOLS")
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
compilation.log
|
||||
|
||||
|
||||
# Created by https://www.gitignore.io/api/python
|
||||
# Edit at https://www.gitignore.io/?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# End of https://www.gitignore.io/api/python
|
||||
@@ -0,0 +1,98 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file NewBoxPattern.h
|
||||
/// \brief Class NewBoxPattern
|
||||
/// \author Thibaut Monseigne (Inria) & Jimmy Leblanc (Polymont) & Yannis Bendi-Ouis (Polymont)
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/%22%3EGNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "CPolyBox.hpp"
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
namespace OpenViBE { namespace Plugins
|
||||
{
|
||||
namespace PyBox
|
||||
{
|
||||
class CBoxAlgorithmNewBoxPattern final : public CPolyBox
|
||||
{
|
||||
public:
|
||||
CBoxAlgorithmNewBoxPattern() { m_script = "NewScript.py";}
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm < IBoxAlgorithm >, OVP_ClassId_BoxAlgorithm_NewBoxPattern)
|
||||
};
|
||||
|
||||
class CBoxAlgorithmNewBoxPatternListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setInputType(index, OV_TypeId_StreamedMatrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onOutputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setOutputType(index, OV_TypeId_StreamedMatrix);
|
||||
return true;
|
||||
}
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener < IBoxListener >, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmNewBoxPatternDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("NewBoxPattern"); }
|
||||
CString getAuthorName() const override { return CString("NewAuthor"); }
|
||||
CString getAuthorCompanyName() const override { return CString("NewCompany"); }
|
||||
CString getShortDescription() const override { return CString("Default Python Description"); }
|
||||
CString getDetailedDescription() const override { return CString(""); }
|
||||
CString getCategory() const override { return CString("Scripting/Pybox/"); }
|
||||
CString getVersion() const override { return CString("0.1"); }
|
||||
CString getStockItemName() const override { return CString("gtk-convert"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_NewBoxPattern; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmNewBoxPattern; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmNewBoxPatternListener; }
|
||||
void releaseBoxListener(IBoxListener* pBoxListener) const override{ delete pBoxListener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addSetting("Clock frequency (Hz)", OV_TypeId_Integer, "64");
|
||||
// <tag> settings
|
||||
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddOutput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddSetting);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifySetting);
|
||||
|
||||
prototype.addInputSupport(OV_TypeId_Signal);
|
||||
prototype.addInputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
prototype.addOutputSupport(OV_TypeId_Signal);
|
||||
prototype.addOutputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
// <tag> input & output
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_NewBoxPatternDesc)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 127 KiB |
@@ -0,0 +1,57 @@
|
||||
PROJECT(openvibe-plugins-contrib-pybox)
|
||||
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION ${OV_GLOBAL_VERSION_STRING})
|
||||
|
||||
FILE(GLOB_RECURSE source_files src/*.cpp src/*.hpp src/*.h src/*.inl)
|
||||
ADD_LIBRARY(${PROJECT_NAME} SHARED ${source_files})
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${PLUGINS_FOLDER}
|
||||
COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared")
|
||||
|
||||
INCLUDE_DIRECTORIES("src")
|
||||
|
||||
# ---------------------------------
|
||||
# OpenVibe Modules (uncomment usefull package)
|
||||
# ---------------------------------
|
||||
# OpenViBE Base
|
||||
INCLUDE("FindOpenViBE")
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
INCLUDE("FindOpenViBEToolkit")
|
||||
|
||||
# OpenViBE Module
|
||||
INCLUDE("FindOpenViBEModuleEBML")
|
||||
INCLUDE("FindOpenViBEModuleSystem")
|
||||
|
||||
# OpenViBE Third Party
|
||||
INCLUDE("FindThirdPartyBoost")
|
||||
INCLUDE("FindThirdPartyPython3")
|
||||
|
||||
# ---------------------------------
|
||||
# Target macros
|
||||
# Defines target operating system
|
||||
# Defines target architecture
|
||||
# Defines target compiler
|
||||
# ---------------------------------
|
||||
SET_BUILD_PLATFORM()
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
|
||||
INSTALL(DIRECTORY box-tutorials DESTINATION ${DIST_DATADIR}/openvibe/scenarios/)
|
||||
INSTALL(DIRECTORY share/ DESTINATION ${DIST_DATADIR}/openvibe/plugins/python3)
|
||||
|
||||
# ---------------------------------
|
||||
# Test applications (uncomment to enable your test directory)
|
||||
# ---------------------------------
|
||||
#IF(OV_COMPILE_TESTS)
|
||||
# ADD_SUBDIRECTORY(test)
|
||||
#ENDIF(OV_COMPILE_TESTS)
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
# OpenViBE Python
|
||||
|
||||
This Project aims to bring modifications to OpenVibe and to widen its data-oriented functionnalities. OpenVibe is a signal processing software allowing the use of machine learning algorithms, however their number is reduced. Thus, we woud like to benefit from the Openvibe Python scripting box (which allows the use of python scripts in OV) in order to allow users to use Scikit-learn Machine Learning algorithms.
|
||||
|
||||
## Dependancies
|
||||
|
||||
`pip install pyqt5 pandas numpy natsort pygame sklearn matplotlib pyriemann`
|
||||
|
||||
## What OpenViBE Python allows
|
||||
|
||||
- The use of components already implemented in OpenVibe that will allow you to :
|
||||
- The use of ML algorithms from Scikit-learn and Pyriemann (Library centered on the use of Riemannian geometry) that will allow you to train and store models.
|
||||
- Visualization of your data in 2D/3D via a PCA or LDA.
|
||||
- Easily create datasets compatible with OpenVibe's operation
|
||||
- The use of a manager that allows you to simply :
|
||||
- Create new boxes in OpenVibe
|
||||
- Create new types of openvibe settings that can be used in your new boxes.
|
||||
- The reuse of our scripts in order to simply implement your own python data management
|
||||
|
||||
1. The new boxes
|
||||
TrainerML / ML Class Boxes
|
||||
Box ProcessML
|
||||
Box DataViz
|
||||
DatasetCreator Box
|
||||
2. The Pybox Manager
|
||||
Box Manager
|
||||
Stimulations / Labels Manager
|
||||
Custom Settings Manager
|
||||
3. Internal functioning and details
|
||||
Our box model: PolyBox
|
||||
Input management with PolyBox, two modes possible
|
||||
Duplicating the Python Scripting Box
|
||||
PolyBox: Automatic data storage
|
||||
Managing Custom Settings
|
||||
|
||||
Translated with www.DeepL.com/Translator (free version)
|
||||
|
||||
## Table des matières
|
||||
|
||||
- [OpenViBE Python](#openvibe-python)
|
||||
- [Dependancies](#dependancies)
|
||||
- [What OpenViBE Python allows](#what-openvibe-python-allows)
|
||||
- [Table des matières](#table-des-mati%c3%a8res)
|
||||
- [1. The new boxes](#1-the-new-boxes)
|
||||
- [TrainerML Class / ML Boxes](#trainerml-class--ml-boxes)
|
||||
- [Scikit-learn](#scikit-learn)
|
||||
- [Pyriemann](#pyriemann)
|
||||
- [Box ProcessML](#box-processml)
|
||||
- [Box DataViz](#box-dataviz)
|
||||
- [Box DatasetCreator](#box-datasetcreator)
|
||||
- [2. The Pybox Manager](#2-the-pybox-manager)
|
||||
- [Box Manager](#box-manager)
|
||||
- [Stimulations / Labels Manager](#stimulations--labels-manager)
|
||||
- [Custom Settings Manager](#custom-settings-manager)
|
||||
- [3. Internal Functioning and Details](#3-internal-functioning-and-details)
|
||||
- [Our Box model : PolyBox](#our-box-model--polybox)
|
||||
- [Input management with PolyBox, two possible modes](#input-management-with-polybox-two-possible-modes)
|
||||
- [Duplicating the Python Scripting Box](#duplicating-the-python-scripting-box)
|
||||
- [Automatic data storage](#automatic-data-storage)
|
||||
- [Managing Custom Settings](#managing-custom-settings)
|
||||
|
||||
## 1. The new boxes
|
||||
|
||||
### TrainerML Class / ML Boxes
|
||||
|
||||
The TrainerML class defined in TrainerML.py is a class that inherits from [PolyBox](#our-box-model-polybox), its purpose is to be used in boxes that will be configured to allow the use of certain learning machine algorithms. The following parameters can be passed to it:
|
||||
|
||||
- **Filename to save model to** : Path to the file in which to save the model. If no file is indicated, then the model will not be saved.
|
||||
- **Filename to load model from** : Path to the file in which the model to be loaded is saved. If a file is specified and exists, no model will be created and the model contained in the file will be loaded and used for the current session.
|
||||
- **classifier** : Algorithm you wish to use. The various Algorithms are from Scikit-learn or Pyriemann.
|
||||
- **discriminator** : In case the chosen classifier is `TangentSpace`, it is necessary to provide a second algorithm which will be used to classify after the projection on the tangent space. All the previous algorithms can be used except `TangentSpace` and `MDM`. If no algorithm is specified, `LinearDiscriminantAnalysis` will be used by default.
|
||||
Similarly for `MDM`, a second algorithm may be used, but is not mandatory.
|
||||
- **labels**: If the read mode is Poly-Mode, you must specify the list of labels as `my label1, my label2, my label3`, otherwise, the labels will be as follows `1, 2, 3, 4, ...`. If the read mode is ov-mode, you can leave the field blank, the labels will be extracted from the stimuli.
|
||||
- **Test set share**: float between 0 and 1 (1 not included) which represents the proportion of the input dataset transformed into a test set, allowing us to evaluate our model once the training on the set train is done. If 0 is filled in, then all the data will constitute the train set and no metrics will be displayed.
|
||||
|
||||
Here are the new algorithms / boxes implemented in OV :
|
||||
|
||||
#### Scikit-learn
|
||||
|
||||
<https://scikit-learn.org/stable/>
|
||||
|
||||
> | Box Name | Algorithm |
|
||||
> | :-: | :-: |
|
||||
> | Nearest Centroid | NearestCentroid |
|
||||
> | Nearest Neighbors Classifier | KNeighborsClassifier |
|
||||
> | Gaussian Naive Bayes | GaussianNB |
|
||||
> | Stochastic Gradient Descent | SGDClassifier |
|
||||
> | Logistic Regression | LogisticRegression |
|
||||
> | Decision Tree Classifier | DecisionTreeClassifier |
|
||||
> | Extra Trees | ExtraTreesClassifier |
|
||||
> | Bagging | BaggingClassifier |
|
||||
> | Random Forest | RandomForestClassifier |
|
||||
> | Support Vector Machine | LinearSVC |
|
||||
> | Linear Discriminant Analysis | LinearDiscriminantAnalysis |
|
||||
> | AdaBoost | AdaBoostClassifier |
|
||||
> | Multi Layer Perceptron | MLPClassifier |
|
||||
> | Linear SVC | LinearSVC |
|
||||
|
||||
#### Pyriemann
|
||||
|
||||
<https://pyriemann.readthedocs.io/en/latest/index.html>
|
||||
|
||||
> | String | Algorithm |
|
||||
> | :-: | :-: |
|
||||
> | Riemann Minimum Distance to Mean | MDM |
|
||||
> | Riemann Tangent Space | TangentSpace |
|
||||
|
||||
You can easily find information on each of these methods in the docs of their library.
|
||||
|
||||
For each of these classifiers, an Openvibe box using TrainerML with the appropriate parameters has been created. So, if you want to train with the Random Forest algorithm of Scikit-learn for example, you just have to look for the associated box in Openvibe and you will be able to use it directly, and modify the parameters related to the algorithm. You will find the information concerning all these parameters on the respective pages of the algorithms, ex: <https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html.>
|
||||
|
||||
> 
|
||||
>
|
||||
> Example of parameterization of a box implementing Random Forest
|
||||
|
||||
### Box ProcessML
|
||||
|
||||
This box allows you to make classification predictions on new data using a previously trained model (via TrainerML or the boxes that inherit it, e.g. SVM, LDA, RandomForest ...).
|
||||
|
||||
- **Model Filename**: Path where the model you want to use is stored.
|
||||
- **Filename to save predictions** : Path to the file where to save the predictions. If no file is specified, then the predictions will not be saved. The predictions are saved as a string where each prediction is separated from the others by a comma: `pred1,pred2,pred3 ...`.
|
||||
|
||||
Once the model is loaded, the predictions will be made on each chunk of data received, they can be used in real time, and if a path is given, they can be saved for later use.
|
||||
|
||||
### Box DataViz
|
||||
|
||||
The DataViz Box allows the visualization of our data. To do this, it applies a dimension reduction via an LDA or PCA and then displays our data using the matplotlib library. It inherits from PolyBox. It requires the following parameters:
|
||||
|
||||
- **Path to save the model**: Path to the file in which to save the model. If no file is specified, then the model will not be saved.
|
||||
- **Path to load the model** : Path to the file in which is saved the model you want to load. If a file is specified and exists, then no model will be created and the model contained in the file will be loaded and used for the current session.
|
||||
- **Algorithm (PCA or LDA)** : Name of the algorithm to be used to reduce dimensions. Accepted values are `PCA` or `LDA`. The default algorithm used is LDA.
|
||||
- **Dimension reduction**: Number of dimensions to display. The different possible values are 2 and 3. By default, if no number is given or if the field is filled incorrectly, the number of dimension is 2.
|
||||
- **labels** : List of labels to indicate as `my label1, my label2, my label3` if the read mode is poly-mode. Otherwise, the labels will be in the form `1, 2, 3, 4, ...`.
|
||||
|
||||
### Box DatasetCreator
|
||||
|
||||
To facilitate data acquisition during our experiments, we created the python box `DatasetCreator`. This box takes a signal as an input and outputs a `OVTK_StimulationId_ExperimentStop' stimulation when it has finished creating the dataset.
|
||||
|
||||
It works in the following way: the user first chooses some labels, then the box will randomly determine an order between them. It will then record the user's brain activity while verbally indicating the current action. In this way, we will be able to create a labeled dataset that can be used for learning.
|
||||
|
||||
The recording of an action takes place in the following way:
|
||||
|
||||
1. Audible warning of the beginning of the action.
|
||||
2. 2 second wait.
|
||||
3. Recording for 10 seconds.
|
||||
4. Audible warning of the end of the action.
|
||||
5. Wait for 3 seconds.
|
||||
|
||||
It can be configured by indicating :
|
||||
|
||||
- The path to the directory that will contain the data.
|
||||
- The number of folds you wish to obtain.
|
||||
- The number of actions you wish to record. That is to say 30 if you wish to obtain 30 recordings of 10 seconds distributed among the different labels.
|
||||
- The names of the labels you want to record (/!\ Attention, these names must have a corresponding mp3 file in `pybox-manager/Assets/Sounds/`, you can create new labels with the manager).
|
||||
- A boolean indicating whether you want several CSVs or only one CSV. If you enter "true", then the data will be split into as many CSVs as there are actions, one CSV per action. If you enter "false", then the data will all be recorded in a single CSV, in which the start of a new recording for a label will be indicated in the stimuli.
|
||||
|
||||
## 2. The Pybox Manager
|
||||
|
||||
The Pybox Manager allows you to simply create and incorporate new boxes running a Python script of your choice, new labels/stimulations and new Custom Settings for your python boxes into OpenVibe.
|
||||
|
||||
To run it: `python pybox_manager.py`.
|
||||
|
||||
(Python 2.7 and python 3.X compatible.)
|
||||
|
||||
An option is available to enable the so-called "developer settings" i.e. the ones you created.
|
||||
To do this, run the manager with the `-mode=developer` option.
|
||||
|
||||
### Box Manager
|
||||
|
||||
The Box Manager looks like this:
|
||||
|
||||
> 
|
||||
>
|
||||
> PyBox Manager.
|
||||
|
||||
- New: Create a new box
|
||||
- Duplicate: duplicates the currently selected box.
|
||||
- Reset Box: resets the selected box, cancels all changes made since the last compilation.
|
||||
- Category : category in which the box will be stored in OV.
|
||||
- Author : add the author's name in the box's references.
|
||||
- Settings: Allows you to manage all the settings necessary to use the box. These can be types from Openvibe (String, Float etc.) or types created by yourself with the [Custom settings Manager](#custom-settings-manager)
|
||||
- Inputs: Used to fill in the different inputs that your box will receive.
|
||||
- Outputs : Used to fill in the different outputs that your box will send.
|
||||
- Enable settings / inputs / outputs modifications : Allows you to prevent the users of your box from modifying these elements later on.
|
||||
- Mode : allows you to quickly configure the inputs of your box according to the mode you want to use. [Inputs Polybox](#input-management-with-polybox-two-possible-modes)
|
||||
|
||||
Once your modifications are finished you can press Build to have the modifications taken into account, and the compilation is done (mandatory to have your modifications and new boxes). The compilation.log file contains information from the last compilation.
|
||||
|
||||
Delete Box deletes the currently selected box (a compilation is necessary to take the deletion into account).
|
||||
|
||||
### Stimulations / Labels Manager
|
||||
|
||||
When reading and processing our signals, OpenViBE can handle stimulations. These can be used to label our data during a classification/training procedure.
|
||||
All these stimulations are indicated in the file `pybox-manager/share/PolyStimulations.py`.
|
||||
|
||||
The DatasetCreator box we have created allows you to monitor the creation of a labeled dataset for the user. To do this, the box plays a sound during each action, indicating the action the user should think about. Basically, the user will have at his disposal about ten different labels.
|
||||
|
||||
We allow the user to add labels (stimulations) via the `Stimulations/Labels Manager` interface present in the manager.
|
||||
To do this, the manager must provide the name of the label, and a corresponding `.mp3` file, which will be played by the DatasetCreator.
|
||||
|
||||
> 
|
||||
>
|
||||
> Add a label/stimulation to OpenViBE.
|
||||
|
||||
### Custom Settings Manager
|
||||
|
||||
The `Custom Settings Manager` allows you to create or delete special types of settings, as well as possible values for these settings, according to your needs.
|
||||
|
||||
This is especially useful to allow easy use on OpenVibe using a drop-down list. For example, if you want to be able to choose one algorithm among several, directly in your OpenVibe box configuration, you just have to create this new type as well as the associated values via the manager as shown in the following illustration.
|
||||
|
||||
To be able to use them with the manager when defining the parameters of a box, you have to launch the manager with the option `mode=developer`.
|
||||
|
||||
> 
|
||||
>
|
||||
> Add/Remove/Manage Custom Settings.
|
||||
|
||||
Result in OpenVibe :
|
||||
|
||||
> 
|
||||
>
|
||||
> Example with a new type 'classifier'.
|
||||
|
||||
## 3. Internal Functioning and Details
|
||||
|
||||
### Our Box model : PolyBox
|
||||
|
||||
To facilitate our development phases, we have added in `pybox-manager/share/PolyBox.py` a class called `PolyBox`. This class inherits from the OVBox class. It automates the reception and storage of an input signal and allows the development of simple methods called at key moments:
|
||||
|
||||
- **on_initialize(self) :** called at initialization, this method aims at allowing the user to define a particular behavior during initialization.
|
||||
- **on_header_received(self, header) :** called at each reception of a header, this method aims to allow the user to define a particular behavior when receiving a header.
|
||||
- **on_chunk_received(self, chunk, label, shape) :** called at each reception of a chunk, this method aims to allow the user to define a particular behavior when receiving a chunk.
|
||||
- **on_end_box(self) :** called just before the box finishes its work, this method aims to allow the user to define a particular behavior when the box finishes.
|
||||
|
||||
We have created this box in order to be able to attribute behaviors adapted to our use cases, in particular to easily create boxes proposing Machine Learning algorithms based on its architecture.
|
||||
|
||||
#### Input management with PolyBox, two possible modes
|
||||
|
||||
Any box inheriting the PolyBox automatically has two possible read modes to retrieve input data.
|
||||
|
||||
The first mode (`ov-mode`) corresponds to the classic OpenViBE reading mode: the different classes are all included in the same .csv file, and we use input stimuli to separate our data into different classes. To use this mode, you just have to give the box only two inputs: 1 StreamedMatrix and 1 Stimulation.
|
||||
|
||||
For example:
|
||||
|
||||
> 
|
||||
>
|
||||
> **Figure 1** - ov-mode
|
||||
|
||||
The second mode (`poly-mode`) consists in considering as many files as there are classes, i.e. one .csv file per class. To read all these files, the box then needs to have at least as many StreamedMatrix inputs as there are different classes. To use this mode, you just have to create only StreamedMatrix inputs.
|
||||
(Often, this mode requires a `label` parameter in which to fill in the labels of our different classes in the form: `my label1, my label2, my label3`).
|
||||
|
||||
For example:
|
||||
|
||||
> 
|
||||
> **Figure 2** - poly-mode
|
||||
|
||||
Thus, these two reading modes are transparent for the user and allow him to operate the `PolyBoxes` either with a single file containing all the actions, or with several files: one per action.
|
||||
The user doesn't need to indicate anything for the box to choose the right behavior to adopt, the box chooses its behavior according to its inputs.
|
||||
|
||||
### Duplicating the Python Scripting Box
|
||||
|
||||
Toutes les modifications ont été faite, on peut maintenant compiler. Toutes ces étapes sont implémentées dans `pybox-manager/ov-manager.py`.
|
||||
|
||||
All the modifications we have made to the software are based on the duplication of the Python Scripting box. Since the latter allows the use of a python script, we decided to create a manager that allows us to automatically make changes in the OV code to duplicate the C++ files needed to duplicate the Python Scripting Box. This way, we can definitively associate a script to a box, and let the user configure it and integrate it into OpenViBE.
|
||||
|
||||
Each time a python box is created, the manager performs the following tasks:
|
||||
|
||||
1. Go to the root directory of the python boxes: `pybox-manager/src/`.
|
||||
2. We duplicate `pybox-manager/Assets/BoxManager/NewBoxPattern-skeletton.h` into `ovpBoxName.h`
|
||||
3. Insert the CIdentifier declaration into `src/defines.hpp`.
|
||||
4. Add to `src/main.cpp` the imports of the newly created files for the box creation as well as the declarations.
|
||||
5. In `src/box-algorithms/ovpBoxName.h`, replace the box name and includes/declarations.
|
||||
6. Change the box name and description in `src/box-algorithms/ovpBoxName.h`.
|
||||
7. Set the path of the script to be executed in `src/box-algorithms/ovpBoxName.h`.
|
||||
8. Remove the possibility to change the path.
|
||||
9. Add the parameters of our box to `src/box-algorithms/ovpBoxName.h`.
|
||||
10. Add the box's inputs and outputs to `src/box-algorithms/ovpBoxName.h`.
|
||||
|
||||
All changes have been made, we can now compile. All these steps are implemented in `pybox-manager/ov-manager.py`.
|
||||
|
||||
### Automatic data storage
|
||||
|
||||
Automatically, the box stores all received chunk in `self.data`. This can be handy if the user wants to use all the data at the end of the box (to train a learning machine model for example).
|
||||
However, it is possible to prevent this behavior voluntarily. To do this, simply give as a parameter when creating the PolyBox `record=False`. By default, record is set to True.
|
||||
|
||||
### Managing Custom Settings
|
||||
|
||||
We add to `meta/sdk/toolkit/include/toolkit/ovtk_defines.hpp` the declaration of our new Custom Settings and to `meta/sdk/toolkit/src/ovtk_main.cpp` the creation of the custom setting and the declaration of its different values.
|
||||
@@ -0,0 +1,266 @@
|
||||
# OpenViBE Python
|
||||
|
||||
Ce projet a pour but d'apporter des modifications à OpenViBE et d'ouvrir ses possibilités d'un point de vue Data Science. OpenViBE est un logiciel de traitement du signal permettant l'utilisation d'algorithmes de machine learning, cependant ces algorithmes sont limités en choix. Ainsi, nous souhaitons utiliser l'ouverture laissée par la Python scripting box d'OpenViBE (qui permet d'utiliser des scripts python dans OV) pour permettre aux utilisateurs d'utiliser les algorithmes implémentés par des librairies tierces.
|
||||
|
||||
## Dépendances
|
||||
|
||||
`pip install pyqt5 pandas numpy natsort pygame sklearn matplotlib pyriemann`
|
||||
|
||||
## Ce que permet OpenViBE Python
|
||||
|
||||
- L'utilisation de composants déjà implémentés dans OpenVibe qui vous permettront :
|
||||
- l'utilisation d'algorithmes de ML issus de Scikit-learn ainsi que Pyriemann (Librarie centrée sur l'utilisation de la géométrie Riemannienne) qui vous permettront d'entrainer et de stocker des modèles.
|
||||
- La visualisation de vos données en 2D/3D via une PCA ou une LDA.
|
||||
- Créer facilement des datasets compatibles avec le fonctionnement d'OpenVibe
|
||||
- L'utilisation d'un manager qui permet de simplement :
|
||||
- Créer des nouvelles boites dans OpenVibe
|
||||
- Créer des nouveaux types de "settings" openvibe qui pourront être utilisés dans vos nouvelles boites
|
||||
- La réutilisation de nos scripts afin d'implenter simplement votre propre gestion de la donnée en python
|
||||
|
||||
## Table des matières
|
||||
|
||||
- [OpenViBE Python](#openvibe-python)
|
||||
- [Dépendances](#d%c3%a9pendances)
|
||||
- [Ce que permet OpenViBE Python](#ce-que-permet-openvibe-python)
|
||||
- [Table des matières](#table-des-mati%c3%a8res)
|
||||
- [1. Les nouvelles boites](#1-les-nouvelles-boites)
|
||||
- [Classe TrainerML / ML Boxes](#classe-trainerml--ml-boxes)
|
||||
- [Scikit-learn](#scikit-learn)
|
||||
- [Pyriemann](#pyriemann)
|
||||
- [Box ProcessML](#box-processml)
|
||||
- [Box DataViz](#box-dataviz)
|
||||
- [Box DatasetCreator](#box-datasetcreator)
|
||||
- [2. Le Pybox Manager](#2-le-pybox-manager)
|
||||
- [Box Manager](#box-manager)
|
||||
- [Stimulations / Labels Manager](#stimulations--labels-manager)
|
||||
- [Custom Settings Manager](#custom-settings-manager)
|
||||
- [3. Fonctionnement interne et détails](#3-fonctionnement-interne-et-d%c3%a9tails)
|
||||
- [Notre modèle de boite : PolyBox](#notre-mod%c3%a8le-de-boite--polybox)
|
||||
- [Gestion des inputs avec PolyBox, deux modes possibles](#gestion-des-inputs-avec-polybox-deux-modes-possibles)
|
||||
- [Duplication de la Python Scripting Box](#duplication-de-la-python-scripting-box)
|
||||
- [PolyBox : Stockage automatique des données](#polybox--stockage-automatique-des-donn%c3%a9es)
|
||||
- [Gestion des Custom Settings](#gestion-des-custom-settings)
|
||||
|
||||
## 1. Les nouvelles boites
|
||||
|
||||
### Classe TrainerML / ML Boxes
|
||||
|
||||
La classe TrainerML définie dans TrainerML.py est une classe qui hérite de [PolyBox](#notre-modèle-de-boite-polybox), son but est d'être utilisée dans des boîtes qui vont être paramétrées afin de permettre l'utilisation de certains algorithmes de machine learning. On peut lui passer les paramètres suivants :
|
||||
|
||||
- **Filename to save model to** : Chemin vers le fichier dans lequel sauvegarder le modèle. Si aucun fichier n'est indiqué, alors le modèle ne sera pas enregistré.
|
||||
- **Filename to load model from** : Chemin vers le fichier dans lequel est sauvegardé le modèle que l'on souhaite charger. Si un fichier est renseigné et qu'il existe, aucun modèle ne sera créé et le modèle contenu dans le fichier sera chargé et utilisé pour la session en cours.
|
||||
- **classifier** : Algorithme que l'on souhaite utiliser. Les différents Algorithmes sont issus de Scikit-learn ou bien de Pyriemann.
|
||||
- **discriminator** : Dans le cas où le classifier choisi est `TangentSpace`, il est nécessaire de fournir un second algorithme qui servira de classifier après la projection sur l'espace tangent. Tous les algorithmes précédents peuvent être utilisés sauf `TangentSpace` et `MDM`. Si aucun algorithme n'est indiqué, `LinearDiscriminantAnalysis` sera utilisé par défault.
|
||||
De même pour `MDM`, un second algorithme peut être utilisé, mais n'est pas obligatoire.
|
||||
- **labels** : Si le mode de lecture est Poly-Mode, vous devez indiquer la liste de labels sous la forme `mon label1, mon label2, mon label3`, sinon, les labels seront de la forme `1, 2, 3, 4, ...`. Si le mode de lecture est ov-mode, vous pouvez laissez le champs vide, les labels seront extraits des stimulations.
|
||||
- **Test set share** : float compris entre 0 et 1 (1 non inclus) qui représente la proportion du dataset d'entrée transformée en test set, nous permettant d'évaluer notre modèle une fois l'entrainement sur le train set effectué. Si 0 est renseigné, alors toutes les données constitueront le train set et aucune métrique ne sera affichée.
|
||||
|
||||
Voici les nouveaux algorithmes / boites implémentés dans OV :
|
||||
|
||||
#### Scikit-learn
|
||||
|
||||
<https://scikit-learn.org/stable/>
|
||||
|
||||
| Nom de la Box | Algorithme |
|
||||
| :-: | :-: |
|
||||
| Nearest Centroid | NearestCentroid |
|
||||
| Nearest Neighbors Classifier | KNeighborsClassifier |
|
||||
| Gaussian Naive Bayes | GaussianNB |
|
||||
| Stochastic Gradient Descent | SGDClassifier |
|
||||
| Logistic Regression | LogisticRegression |
|
||||
| Decision Tree Classifier | DecisionTreeClassifier |
|
||||
| Extra Trees | ExtraTreesClassifier |
|
||||
| Bagging | BaggingClassifier |
|
||||
| Random Forest | RandomForestClassifier |
|
||||
| Support Vector Machine | LinearSVC |
|
||||
| Linear Discriminant Analysis | LinearDiscriminantAnalysis |
|
||||
| AdaBoost | AdaBoostClassifier |
|
||||
| Multi Layer Perceptron | MLPClassifier |
|
||||
| Linear SVC | LinearSVC |
|
||||
|
||||
#### Pyriemann
|
||||
|
||||
<https://pyriemann.readthedocs.io/en/latest/index.html>
|
||||
|
||||
| String | Algorithme |
|
||||
| :-: | :-: |
|
||||
| Riemann Minimum Distance to Mean | MDM |
|
||||
| Riemann Tangent Space | TangentSpace |
|
||||
|
||||
Vous trouverez facilement des informations sur chacune de ces méthodes dans la doc de leur librairies.
|
||||
|
||||
Pour chacun de ces classifiers, une boite Openvibe utilisant TrainerML avec les paramètres adéquats a été créé. Ainsi, si vous souhaitez réaliser un entrainement avec l'algorithme Random Forest de Scikit-learn par exemple, il vous suffit de chercher la boite associée dans Openvibe et vous pourrez directement l'utiliser, et modifier les paramètres relatifs à l'algorithme. Vous trouverez les informations concernant tous ces paramètres sur les pages respectives des algorithmes, ex : <https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html>
|
||||
|
||||
> 
|
||||
>
|
||||
> Exemple de paramétrisation d'une boite implémentant Random Forest
|
||||
|
||||
### Box ProcessML
|
||||
|
||||
Cette box permet de réaliser des prédictions de classification sur des nouvelles données en utilisant un modèle préalablement entraîné (via TrainerML ou les boites qui en héritent, e.g. SVM, LDA, RandomForest ... )
|
||||
|
||||
- **Model Filename** : Chemin où le modèle que l'on souhaite utiliser est stocké.
|
||||
- **Filename to save predictions** : Chemin vers le fichier dans lequel sauvegarder les prédictions. Si aucun fichier n'est indiqué, alors les prédictions ne seront pas sauvegardées. Les prédictions sont enregistrées sous la forme d'une chaîne de caractère où chaque prédiction est séparée des autres par une virgule : `pred1,pred2,pred3 ...`
|
||||
|
||||
Une fois le modèle chargé, les prédictions seront réalisées sur chaque chunk de donnée reçu, elles pourront être utilisées en temps réel, et si un chemin est indiqué, elles pourront être sauvegardées pour un usage ultérieur.
|
||||
|
||||
### Box DataViz
|
||||
|
||||
La Box DataViz permet la visualisation de nos données. Pour ce faire, elle applique une réduction de dimension via une LDA ou une PCA, puis affiche nos données en utilisant la bibliothèque matplotlib. Elle hérite de PolyBox.
|
||||
Elle nécessite les paramètres suivants :
|
||||
|
||||
- **Path to save the model** : Chemin vers le fichier dans lequel sauvegarder le modèle. Si aucun fichier n'est indiqué, alors le modèle ne sera pas enregistré.
|
||||
- **Path to load the model** : Chemin vers le fichier dans lequel est sauvegardé le modèle que l'on souhaite charger. Si un fichier est renseigné et qu'il existe, aucun modèle ne sera créé et le modèle contenu dans le fichier sera chargé et utilisé pour la session en cours.
|
||||
- **Algorithm (PCA or LDA)** : Nom de l'algorithme à utiliser pour réduire les dimensions. Les valeurs acceptées sont `PCA` ou `LDA`. L'algorithme utilisé par défaut est LDA.
|
||||
- **Dimension reduction** : Nombre de dimension à afficher. Les différentes valeurs possibles sont 2 et 3. Par défaut, si aucun nombre n'est indiqué ou si le champs est mal rempli, le nombre de dimension est 2.
|
||||
- **labels** : Si le mode de lecture est Poly-Mode, vous devez indiquer la liste de labels sous la forme `mon label1, mon label2, mon label3`, sinon, les labels seront de la forme `1, 2, 3, 4, ...`. Si le mode de lecture est ov-mode, vous pouvez laissez le champs vide, les labels seront extraits des stimulations.
|
||||
|
||||
### Box DatasetCreator
|
||||
|
||||
Pour faciliter l'acquisition de données lors de nos expériences, nous avons créé la box python `DatasetCreator`. Cette dernière prend en entrée un signal et émet en sortie une stimulation de type `OVTK_StimulationId_ExperimentStop` lorsqu'elle a fini de créer le dataset.
|
||||
|
||||
Elle fonctionne de la manière suivante : l'utilisateur choisit au préalable certains labels, puis la box va aléatoirement déterminer un ordre entre ceux-ci. Elle va ensuite monitorer l'utilisateur sur les actions à penser en indiquant oralement l'action courante. De cette manière, nous allons pouvoir créer un jeu de données labelisées qui pourra être utilisé pour de l'apprentissage.
|
||||
|
||||
L'enregistrement d'une action se déroule de la manière suivante :
|
||||
|
||||
1. Avertissement sonore du début de l'action.
|
||||
2. Attente de 2 secondes.
|
||||
3. Enregistrement pendant 10 secondes.
|
||||
4. Avertissement sonore de la fin de l'action.
|
||||
5. Attente de 3 secondes.
|
||||
|
||||
On peut la configurer en indiquant :
|
||||
|
||||
- Le path jusqu'au répertoire devant contenir les données.
|
||||
- Le nombre de folds que l'on souhaite obtenir.
|
||||
- Le nombre d'action que l'on souhaite enregistrer. C'est à dire 30 si vous souhaitez obtenir 30 enregistrement de 10 secondes répartis parmi les différents labels.
|
||||
- Le nom des labels que vous souhaitez enregistrer. (/!\ Attention, ces noms doivent avoir un fichier mp3 correspondant dans `pybox-manager/Assets/Sounds/`, vous pouvez créer de nouveaux labels avec le manager.)
|
||||
- Un boolean indiquant si vous souhaitez plusieurs CSV ou un seul CSV. Si vous renseignez "true", alors les données seront réparties en autant de CSV qu'il y a d'action, un CSV par action. Si vous renseignez "false", alors les données seront toutes enregistrées en un seul CSV, dans lequel le début d'un nouvel enregistrement pour un label sera indiqué dans les stimulations.
|
||||
|
||||
## 2. Le Pybox Manager
|
||||
|
||||
Le Pybox Manager permet de simplement créer et incorporer à OpenVibe de nouvelles boites éxécutant un script Python de votre choix, de nouveaux labels/stimulations et de nouveau Custom Settings pour vos box python.
|
||||
|
||||
Pour l'éxécuter : `python pybox_manager.py`
|
||||
|
||||
(Compatible python 2.7 et python 3.X.)
|
||||
|
||||
Une option est disponible pour activer les settings dit "développeurs" c-à-d ceux que vous avez créés.
|
||||
Pour ceci lancer le manager avec l'option `mode=developer`
|
||||
|
||||
### Box Manager
|
||||
|
||||
Le Box Manager se présente comme ceci :
|
||||
|
||||
> 
|
||||
>
|
||||
> Visualisation du PyBox Manager.
|
||||
|
||||
- New : Créer une nouvelle boite
|
||||
- Duplicate : duplique la boite actuellement séléctionnée.
|
||||
- Reset Box : réinitialise la box séléctionnée, annule toutes les modifications effectuées depuis la dernière compilation.
|
||||
- Category : catégorie dans laquelle la boîte sera rangée dans OV.
|
||||
- Author : ajoute le nom des auteurs dans les références de la boite.
|
||||
- Settings : Permet d'administrer tous les settings nécessaires afin d'utiliser la box. Ceux-ci peuvent être des types issus d'Openvibe (String, Float etc.) ou bien des types créés par vous même grâce au [Custom settings Manager](#custom-settings-manager)
|
||||
- Inputs : Sert à renseigner les différents inputs que va recevoir votre boite
|
||||
- Outputs : : Sert à renseigner les différents outputs que va envoyer votre boite.
|
||||
- Enable settings / inputs / outputs modifications : permet d'empêcher les utilisateurs de votre boite de modifier ultérieurement ces éléments.
|
||||
- Mode : permet de configurer rapidement les inputs de votre box selon le mode que vous souhaitez utiliser. [Inputs Polybox](#gestion-des-inputs-avec-polybox-deux-modes-possibles)
|
||||
|
||||
Une fois que vos modifications sont terminées vous pouvez appuyer sur Build pour que les modifications soient prises en compte, et que la compilation s'effectue (obligatoire pour avoir vos modifications et nouvelles boites). Le fichier compilation.log contient les informations issus de la dernière compilation.
|
||||
|
||||
Delete Box supprime la boite actuellement séléctionnée (une compilation est nécéssaire pour prendre la suppression en compte)
|
||||
|
||||
### Stimulations / Labels Manager
|
||||
|
||||
Lors de la lecture et du traitement de nos signaux, OpenViBE peut gérer des stimulations. Ces dernières peuvent servir à indiquer le label de nos données lors d'une procédure de classification/entraînement.
|
||||
L'ensemble de ces stimulations sont indiquées dans le fichier `pybox-manager/share/PolyStimulations.py`.
|
||||
|
||||
La box DatasetCreator que nous avons créée permet de monitorer la création d'un dataset labelisé pour l'utilisateur. Pour ce faire, la box joue un son lors de chaque action, indiquant l'action auquel l'utilisateur doit penser. De base, l'utilisateur aura a disposition une dizaine de labels différents.
|
||||
|
||||
Nous permettons à l'utilisateur d'ajouter des labels (stimulations) via l'interface `Stimulations/Labels Manager` présent dans le manager.
|
||||
Pour ce faire, ce dernier doit fournir le nom du label, et un fichier `.mp3` correspondant, qui sera joué par le DatasetCreator.
|
||||
|
||||
> 
|
||||
>
|
||||
> Add a label/stimulation to OpenViBE.
|
||||
|
||||
### Custom Settings Manager
|
||||
|
||||
Le `Custom Settings Manager` permet de créer ou de supprimer des types de paramètres spéciaux, ainsi que des valeurs possibles pour ces paramètres, selon vos besoins.
|
||||
C'est notamment utile pour permettre une utilisation facile sur OpenVibe à l'aide d'une liste déroulante. Par exemple, vous voulez pouvoir choisir un algorithme parmis plusieurs, directement dans la configuration de votre boite sur openvibe, il vous suffit de créer ce nouveau type ainsi que les valeurs associées via le manager comme dans l'illustration suivante.
|
||||
|
||||
Pour pouvoir les utiliser avec le manager lors de la définition des paramètres d'une box, il faut lancer le manager avec l'option `mode=developer`.
|
||||
|
||||
> 
|
||||
>
|
||||
> Add/Remove/Manage Custom Settings.
|
||||
|
||||
Résultat dans OpenVibe :
|
||||
|
||||
> 
|
||||
>
|
||||
> Exemple avec un nouveau type 'classifier'.
|
||||
|
||||
## 3. Fonctionnement interne et détails
|
||||
|
||||
### Notre modèle de boite : PolyBox
|
||||
|
||||
Pour faciliter nos phases de développement, nous avons ajouté dans `pybox-manager/share/PolyBox.py` une classe appelée `PolyBox`. Cette dernière hérite de la classe OVBox. Elle automatise la réception et le stockage d'un signal en entrée et permet le développement de méthodes simples appelées à des moments clés :
|
||||
|
||||
- **on_initialize(self) :** appelée à l'initialisation, cette méthode a pour but de permettre à l'utilisateur de définir un comportement particulier lors de l'initialisation.
|
||||
- **on_header_received(self, header) :** appelée à chaque réception d'un header, cette méthode a pour but de permettre à l'utilisateur de définir un comportement particulier lors de la réception d'un header.
|
||||
- **on_chunk_received(self, chunk, label, shape) :** appelée à chaque réception d'un chunk, cette méthode a pour but de permettre à l'utilisateur de définir un comportement particulier lors de la réception d'un chunk.
|
||||
- **on_end_box(self) :** appelée juste avant que la box finisse son travail, cette méthode a pour but de permettre à l'utilisateur de définir un comportement particulier lors de la fin de la box.
|
||||
|
||||
Nous avons créée cette box afin de pouvoir lui attribuer des comportements adaptés à nos cas d'utilisations, en particulier pour facilement créer des boites proposant des algorithmes de Machine Learning en se basant sur son architecture.
|
||||
|
||||
### Gestion des inputs avec PolyBox, deux modes possibles
|
||||
|
||||
Toute box héritant de la PolyBox possède automatiquement deux modes de lectures possibles pour récupérer des données en entrée.
|
||||
|
||||
Le premier mode (`ov-mode`) correspond au mode de lecture classique de OpenViBE : les différentes classes sont toutes comprises dans un même fichier .csv, et on utilise des stimulations reçues en entré pour séparer nos données en différentes classes. Pour utiliser ce mode, il suffit de n'accorder à la box que deux inputs : 1 StreamedMatrix et 1 Stimulation.
|
||||
|
||||
Exemple :
|
||||
|
||||
> 
|
||||
>
|
||||
> ov-mode
|
||||
|
||||
Le second mode (`poly-mode`) consiste à considérer autant de fichiers qu'il y a de classes, soit un fichier .csv par classe. Pour lire tous ces fichiers, la box a alors besoin d'avoir au moins autant d'input StreamedMatrix qu'il existe de classes différentes. Pour utiliser ce mode, il suffit donc de ne créer que des entrées StreamedMatrix.
|
||||
(Souvent, ce mode nécessite un paramètre `label` dans lequel renseigner les labels de nos différentes classes sous la forme : `mon label1, mon label2, mon label3`.)
|
||||
|
||||
Exemple :
|
||||
|
||||
> 
|
||||
>
|
||||
> poly-mode
|
||||
|
||||
Ainsi, ces deux modes de lectures sont transparents pour l'utilisateur et lui permettent d'exploiter les box `PolyBox` soit avec un seul fichier contenant l'ensemble des actions, soit avec plusieurs fichiers : un par action.
|
||||
L'utilisateur n'a donc rien besoin d'indiquer pour que la box choisisse le bon comportement à adopter, celle-ci choisit son comportement en fonction de ses inputs.
|
||||
|
||||
### Duplication de la Python Scripting Box
|
||||
|
||||
L'ensemble des modifications que nous avons apportées au logiciel repose sur la duplication de la box Python Scripting. Cette dernière permettant l'utilisation d'un script python, nous avons décidé de créer un manager permettant d'effectuer automatiquement des modifications dans le code d'OV pour dupliquer les fichiers C++ nécessaires à la duplication de la Python Scripting Box. De cette manière, nous pouvons associer définitivement un script à une box, et laisser l'utilisateur la configurer et l'intégrer à OpenViBE.
|
||||
|
||||
Lors de chaque création de box python, le manager effectue les tâches suivantes :
|
||||
|
||||
1. On se place à dans le dossier racine des box python : `pybox-manager/src/`.
|
||||
2. On duplique `pybox-manager/Assets/BoxManager/NewBoxPattern-skeletton.h` en `box-algorithms/ovpBoxName.h`
|
||||
3. On insère dans `src/defines.hpp` la déclaration des CIdentifier.
|
||||
4. On ajoute dans `src/main.cpp` les imports des fichiers récemment créés pour la création de la box ainsi que les déclarations.
|
||||
5. On remplace dans `src/box-algorithms/ovpBoxName.h` le nom de la boite et celui des includes/déclarations.
|
||||
6. On change le nom, la description, les auteurs et la catégorie de la boite dans `src/box-algorithms/ovpBoxName.h`.
|
||||
7. On définit le path du script à éxécuter dans `src/box-algorithms/ovpBoxName.h`.
|
||||
8. On efface la possibilité de modifier le path.
|
||||
9. On ajoute les paramètres de notre boite dans `src/box-algorithms/ovpBoxName.h`
|
||||
10. On ajoute dans `src/box-algorithms/ovpBoxName.h` les inputs et outputs de la boite.
|
||||
|
||||
### PolyBox : Stockage automatique des données
|
||||
|
||||
Automatiquement, les box héritant de PolyBox stockent tous les chunk reçus dans `self.data`. Cela peut s'avérer pratique si l'utilisateur souhaite utiliser l'ensemble des données à la fin de la boite (pour entraîner un modèle de machine learning par exemple).
|
||||
Il est cependant possible d'empêcher ce comportement. Pour ce faire, il suffit de donner comme paramètre lors de la création de la PolyBox `record=False`. Par défaut, record est à True.
|
||||
|
||||
### Gestion des Custom Settings
|
||||
|
||||
On ajoute à `meta/sdk/toolkit/include/toolkit/ovtk_defines.hpp` la déclaration de nos nouveaux Custom Settings et à `meta/sdk/toolkit/src/ovtk_main.cpp` la création du custom setting ainsi que la déclaration de ses différentes valeurs.
|
||||
@@ -0,0 +1,263 @@
|
||||
<OpenViBE-Scenario>
|
||||
<FormatVersion>2</FormatVersion>
|
||||
<Creator>OpenViBE Designer</Creator>
|
||||
<CreatorVersion>2.2.0</CreatorVersion>
|
||||
<Settings></Settings>
|
||||
<Inputs></Inputs>
|
||||
<Outputs></Outputs>
|
||||
<Boxes>
|
||||
<Box>
|
||||
<Identifier>(0x00001a44, 0x00001322)</Identifier>
|
||||
<Name>CSV File Reader</Name>
|
||||
<AlgorithmClassIdentifier>(0x336a3d9a, 0x753f1ba4)</AlgorithmClassIdentifier>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
|
||||
<Name>Output stream</Name>
|
||||
</Output>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Output stimulation</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Filename</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value>${Player_ScenarioDirectory}/datas/data-tutorial.csv</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>32</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>496</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0xa9cdc629, 0xb153eb33)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00001ddb, 0x0000547b)</Identifier>
|
||||
<Name>DataViz</Name>
|
||||
<AlgorithmClassIdentifier>(0x057b49ad, 0x040868cf)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
|
||||
<Name>input_StreamMatrix</Name>
|
||||
</Input>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>input_Stimulations</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>stim_out</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Clock frequency (Hz)</Name>
|
||||
<DefaultValue>64</DefaultValue>
|
||||
<Value>64</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Path to save the model</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value></Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Path to load the model</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value></Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Algorithm (PCA or LDA)</Name>
|
||||
<DefaultValue>PCA</DefaultValue>
|
||||
<Value>PCA</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Dimension reduction</Name>
|
||||
<DefaultValue>2</DefaultValue>
|
||||
<Value>2</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Labels</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value></Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>96</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>496</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0x434a6f9c, 0xa4ed45b3)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>6</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00002a38, 0x00000aed)</Identifier>
|
||||
<Name>Player Controller</Name>
|
||||
<AlgorithmClassIdentifier>(0x5f426dce, 0x08456e13)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Stimulations</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
|
||||
<Name>Stimulation name</Name>
|
||||
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
|
||||
<Value>OVTK_StimulationId_ExperimentStop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0xcc14d8d6, 0xf27ecb73)</TypeIdentifier>
|
||||
<Name>Action to perform</Name>
|
||||
<DefaultValue>Pause</DefaultValue>
|
||||
<Value>Stop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>160</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>496</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0x568d148e, 0x650792b3)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
</Boxes>
|
||||
<Links>
|
||||
<Link>
|
||||
<Identifier>(0x00006692, 0x000071be)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00001ddb, 0x0000547b)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00002a38, 0x00000aed)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
<Link>
|
||||
<Identifier>(0x00007e63, 0x00007a47)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00001a44, 0x00001322)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00001ddb, 0x0000547b)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
</Links>
|
||||
<Comments>
|
||||
<Comment>
|
||||
<Identifier>(0x00007426, 0x0000717e)</Identifier>
|
||||
<Text>You must wait the end of reading file to have display</Text>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x473d9a43, 0x97fc0a97)</Identifier>
|
||||
<Value>720</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x7234b86b, 0x2b8651a5)</Identifier>
|
||||
<Value>32</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Comment>
|
||||
</Comments>
|
||||
<Metadata>
|
||||
<Entry>
|
||||
<Identifier>(0x000070c2, 0x000055b1)</Identifier>
|
||||
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
|
||||
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":1,"identifier":"(0x00005a2c, 0x00002f6b)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":1},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x000042d2, 0x00004a25)","index":0,"name":"Default tab","parentIdentifier":"(0x00005a2c, 0x00002f6b)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x00003ebf, 0x000013aa)","index":0,"name":"Empty","parentIdentifier":"(0x000042d2, 0x00004a25)","type":0}]</Data>
|
||||
</Entry>
|
||||
</Metadata>
|
||||
</OpenViBE-Scenario>
|
||||
@@ -0,0 +1,271 @@
|
||||
<OpenViBE-Scenario>
|
||||
<FormatVersion>2</FormatVersion>
|
||||
<Creator>OpenViBE Designer</Creator>
|
||||
<CreatorVersion>2.2.0</CreatorVersion>
|
||||
<Settings></Settings>
|
||||
<Inputs></Inputs>
|
||||
<Outputs></Outputs>
|
||||
<Boxes>
|
||||
<Box>
|
||||
<Identifier>(0x00002553, 0x00001145)</Identifier>
|
||||
<Name>DatasetCreator</Name>
|
||||
<AlgorithmClassIdentifier>(0x7b6738c4, 0x2c5156ed)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
|
||||
<Name>input_StreamMatrix</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>stim_out</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Clock frequency (Hz)</Name>
|
||||
<DefaultValue>64</DefaultValue>
|
||||
<Value>64</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Path directory</Name>
|
||||
<DefaultValue>${Player_ScenarioDirectory}/datas/</DefaultValue>
|
||||
<Value>${Player_ScenarioDirectory}/datas/</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Label_1</Name>
|
||||
<DefaultValue>right</DefaultValue>
|
||||
<Value>right</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Label_2</Name>
|
||||
<DefaultValue>left</DefaultValue>
|
||||
<Value>left</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Label_3</Name>
|
||||
<DefaultValue>up</DefaultValue>
|
||||
<Value>up</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Label_4</Name>
|
||||
<DefaultValue>down</DefaultValue>
|
||||
<Value>down</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x2cdb2f0b, 0x12f231ea)</TypeIdentifier>
|
||||
<Name>Several CSV</Name>
|
||||
<DefaultValue>false</DefaultValue>
|
||||
<Value>false</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Number of folds</Name>
|
||||
<DefaultValue>1</DefaultValue>
|
||||
<Value>1</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Number of actions</Name>
|
||||
<DefaultValue>4</DefaultValue>
|
||||
<Value>4</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>176</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>496</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0xd79a853e, 0x3396ae60)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>9</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00002a38, 0x00000aed)</Identifier>
|
||||
<Name>Player Controller</Name>
|
||||
<AlgorithmClassIdentifier>(0x5f426dce, 0x08456e13)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Stimulations</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
|
||||
<Name>Stimulation name</Name>
|
||||
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
|
||||
<Value>OVTK_StimulationId_ExperimentStop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0xcc14d8d6, 0xf27ecb73)</TypeIdentifier>
|
||||
<Name>Action to perform</Name>
|
||||
<DefaultValue>Pause</DefaultValue>
|
||||
<Value>Stop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>240</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>496</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0x568d148e, 0x650792b3)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00003615, 0x000063b8)</Identifier>
|
||||
<Name>Sinus oscillator</Name>
|
||||
<AlgorithmClassIdentifier>(0x7e33bdb8, 0x68194a4a)</AlgorithmClassIdentifier>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
|
||||
<Name>Generated signal</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Channel count</Name>
|
||||
<DefaultValue>4</DefaultValue>
|
||||
<Value>4</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Sampling frequency</Name>
|
||||
<DefaultValue>512</DefaultValue>
|
||||
<Value>512</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Generated epoch sample count</Name>
|
||||
<DefaultValue>32</DefaultValue>
|
||||
<Value>32</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>112</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>496</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0x0b214ed8, 0x1f9ad83a)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>3</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
</Boxes>
|
||||
<Links>
|
||||
<Link>
|
||||
<Identifier>(0x00004d38, 0x00007bd2)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00002553, 0x00001145)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00002a38, 0x00000aed)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
<Link>
|
||||
<Identifier>(0x00007380, 0x00007709)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00003615, 0x000063b8)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00002553, 0x00001145)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
</Links>
|
||||
<Comments></Comments>
|
||||
<Metadata>
|
||||
<Entry>
|
||||
<Identifier>(0x0000716e, 0x00000d37)</Identifier>
|
||||
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
|
||||
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x0000227a, 0x00001a2b)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00005d03, 0x00003bf1)","index":0,"name":"Default tab","parentIdentifier":"(0x0000227a, 0x00001a2b)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x0000792d, 0x0000021b)","index":0,"name":"Empty","parentIdentifier":"(0x00005d03, 0x00003bf1)","type":0}]</Data>
|
||||
</Entry>
|
||||
</Metadata>
|
||||
</OpenViBE-Scenario>
|
||||
@@ -0,0 +1,223 @@
|
||||
<OpenViBE-Scenario>
|
||||
<FormatVersion>2</FormatVersion>
|
||||
<Creator>OpenViBE Designer</Creator>
|
||||
<CreatorVersion>2.2.0</CreatorVersion>
|
||||
<Settings></Settings>
|
||||
<Inputs></Inputs>
|
||||
<Outputs></Outputs>
|
||||
<Boxes>
|
||||
<Box>
|
||||
<Identifier>(0x00001a44, 0x00001322)</Identifier>
|
||||
<Name>CSV File Reader</Name>
|
||||
<AlgorithmClassIdentifier>(0x336a3d9a, 0x753f1ba4)</AlgorithmClassIdentifier>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
|
||||
<Name>Output stream</Name>
|
||||
</Output>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Output stimulation</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Filename</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value>${Player_ScenarioDirectory}/datas/data-tutorial.csv</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>64</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>480</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0xa9cdc629, 0xb153eb33)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00002a38, 0x00000aed)</Identifier>
|
||||
<Name>Player Controller</Name>
|
||||
<AlgorithmClassIdentifier>(0x5f426dce, 0x08456e13)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Stimulations</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
|
||||
<Name>Stimulation name</Name>
|
||||
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
|
||||
<Value>OVTK_StimulationId_ExperimentStop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0xcc14d8d6, 0xf27ecb73)</TypeIdentifier>
|
||||
<Name>Action to perform</Name>
|
||||
<DefaultValue>Pause</DefaultValue>
|
||||
<Value>Stop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>208</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>480</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0x568d148e, 0x650792b3)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00004501, 0x000079b6)</Identifier>
|
||||
<Name>Process Sklearn</Name>
|
||||
<AlgorithmClassIdentifier>(0x681d3dfe, 0x060e2afb)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
|
||||
<Name>input_StreamMatrix</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>stim_out</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Clock frequency (Hz)</Name>
|
||||
<DefaultValue>64</DefaultValue>
|
||||
<Value>64</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Model filename</Name>
|
||||
<DefaultValue>${Player_ScenarioDirectory}/model.clf</DefaultValue>
|
||||
<Value>${Player_ScenarioDirectory}/model.clf</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Predictions filename</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value></Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>144</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>480</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0xb942ac8a, 0x83cd7760)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x527ad68d, 0x16d746a0)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x61d11811, 0x71e65362)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>3</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xf191c1c8, 0xa0123976)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xfba64161, 0x65304e21)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
</Boxes>
|
||||
<Links>
|
||||
<Link>
|
||||
<Identifier>(0x00002056, 0x00007dc0)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00004501, 0x000079b6)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00002a38, 0x00000aed)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
<Link>
|
||||
<Identifier>(0x00002361, 0x0000065a)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00001a44, 0x00001322)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00004501, 0x000079b6)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
</Links>
|
||||
<Comments></Comments>
|
||||
<Metadata>
|
||||
<Entry>
|
||||
<Identifier>(0x00005f34, 0x0000794a)</Identifier>
|
||||
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
|
||||
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":320,"identifier":"(0x00005a92, 0x00001b40)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":480},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x000023fa, 0x00007573)","index":0,"name":"Default tab","parentIdentifier":"(0x00005a92, 0x00001b40)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x00001a40, 0x00000ba9)","index":0,"name":"Empty","parentIdentifier":"(0x000023fa, 0x00007573)","type":0}]</Data>
|
||||
</Entry>
|
||||
</Metadata>
|
||||
</OpenViBE-Scenario>
|
||||
@@ -0,0 +1,271 @@
|
||||
<OpenViBE-Scenario>
|
||||
<FormatVersion>2</FormatVersion>
|
||||
<Creator>OpenViBE Designer</Creator>
|
||||
<CreatorVersion>2.2.0</CreatorVersion>
|
||||
<Settings></Settings>
|
||||
<Inputs></Inputs>
|
||||
<Outputs></Outputs>
|
||||
<Boxes>
|
||||
<Box>
|
||||
<Identifier>(0x00000206, 0x00006ab1)</Identifier>
|
||||
<Name>Trainer Sklearn</Name>
|
||||
<AlgorithmClassIdentifier>(0x44b85a3a, 0xabfc390a)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x544a003e, 0x6dcba5f6)</TypeIdentifier>
|
||||
<Name>input_StreamMatrix</Name>
|
||||
</Input>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>input_Stimulations</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>stim_out</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>Clock frequency (Hz)</Name>
|
||||
<DefaultValue>64</DefaultValue>
|
||||
<Value>64</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Filename to save model to</Name>
|
||||
<DefaultValue>${Player_ScenarioDirectory}/model.clf</DefaultValue>
|
||||
<Value>${Player_ScenarioDirectory}/model.clf</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Filename to load model from</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value></Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x73ae164d, 0xea21ab0a)</TypeIdentifier>
|
||||
<Name>Classifier</Name>
|
||||
<DefaultValue>None</DefaultValue>
|
||||
<Value>AdaBoost</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
|
||||
<Name>Test set share</Name>
|
||||
<DefaultValue>0.2</DefaultValue>
|
||||
<Value>0.2</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>Labels</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value></Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x007deef9, 0x2f3e95c6)</TypeIdentifier>
|
||||
<Name>n_estimators</Name>
|
||||
<DefaultValue>50</DefaultValue>
|
||||
<Value>50</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x512a166f, 0x5c3ef83f)</TypeIdentifier>
|
||||
<Name>learning_rate</Name>
|
||||
<DefaultValue>1.0</DefaultValue>
|
||||
<Value>1.0</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x27025481, 0x09bedc31)</TypeIdentifier>
|
||||
<Name>algorithm</Name>
|
||||
<DefaultValue>SAMME.R</DefaultValue>
|
||||
<Value>SAMME.R</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x79a9edeb, 0x245d83fc)</TypeIdentifier>
|
||||
<Name>random_state</Name>
|
||||
<DefaultValue>None</DefaultValue>
|
||||
<Value>None</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>128</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>480</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0xbe66982a, 0x597f92cf)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>4</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00001a44, 0x00001322)</Identifier>
|
||||
<Name>CSV File Reader</Name>
|
||||
<AlgorithmClassIdentifier>(0x336a3d9a, 0x753f1ba4)</AlgorithmClassIdentifier>
|
||||
<Outputs>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x5ba36127, 0x195feae1)</TypeIdentifier>
|
||||
<Name>Output stream</Name>
|
||||
</Output>
|
||||
<Output>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Output stimulation</Name>
|
||||
</Output>
|
||||
</Outputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x330306dd, 0x74a95f98)</TypeIdentifier>
|
||||
<Name>Filename</Name>
|
||||
<DefaultValue></DefaultValue>
|
||||
<Value>${Player_ScenarioDirectory}/datas/data-tutorial.csv</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>48</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>480</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x30a4e5c9, 0x83502953)</Identifier>
|
||||
<Value></Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0xa9cdc629, 0xb153eb33)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xc80ce8af, 0xf699f813)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
<Box>
|
||||
<Identifier>(0x00002a38, 0x00000aed)</Identifier>
|
||||
<Name>Player Controller</Name>
|
||||
<AlgorithmClassIdentifier>(0x5f426dce, 0x08456e13)</AlgorithmClassIdentifier>
|
||||
<Inputs>
|
||||
<Input>
|
||||
<TypeIdentifier>(0x6f752dd0, 0x082a321e)</TypeIdentifier>
|
||||
<Name>Stimulations</Name>
|
||||
</Input>
|
||||
</Inputs>
|
||||
<Settings>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0x2c132d6e, 0x44ab0d97)</TypeIdentifier>
|
||||
<Name>Stimulation name</Name>
|
||||
<DefaultValue>OVTK_StimulationId_Label_00</DefaultValue>
|
||||
<Value>OVTK_StimulationId_ExperimentStop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
<Setting>
|
||||
<TypeIdentifier>(0xcc14d8d6, 0xf27ecb73)</TypeIdentifier>
|
||||
<Name>Action to perform</Name>
|
||||
<DefaultValue>Pause</DefaultValue>
|
||||
<Value>Stop</Value>
|
||||
<Modifiability>false</Modifiability>
|
||||
</Setting>
|
||||
</Settings>
|
||||
<Attributes>
|
||||
<Attribute>
|
||||
<Identifier>(0x1fa7a38f, 0x54edbe0b)</Identifier>
|
||||
<Value>192</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x207c9054, 0x3c841b63)</Identifier>
|
||||
<Value>480</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0x4e7b798a, 0x183beafb)</Identifier>
|
||||
<Value>(0x568d148e, 0x650792b3)</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xce18836a, 0x9c0eb403)</Identifier>
|
||||
<Value>2</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Identifier>(0xcfad85b0, 0x7c6d841c)</Identifier>
|
||||
<Value>1</Value>
|
||||
</Attribute>
|
||||
</Attributes>
|
||||
</Box>
|
||||
</Boxes>
|
||||
<Links>
|
||||
<Link>
|
||||
<Identifier>(0x00003f8b, 0x00002044)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00001a44, 0x00001322)</BoxIdentifier>
|
||||
<BoxOutputIndex>1</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00000206, 0x00006ab1)</BoxIdentifier>
|
||||
<BoxInputIndex>1</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
<Link>
|
||||
<Identifier>(0x00005663, 0x000061f4)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00000206, 0x00006ab1)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00002a38, 0x00000aed)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
<Link>
|
||||
<Identifier>(0x00006e58, 0x000045c5)</Identifier>
|
||||
<Source>
|
||||
<BoxIdentifier>(0x00001a44, 0x00001322)</BoxIdentifier>
|
||||
<BoxOutputIndex>0</BoxOutputIndex>
|
||||
</Source>
|
||||
<Target>
|
||||
<BoxIdentifier>(0x00000206, 0x00006ab1)</BoxIdentifier>
|
||||
<BoxInputIndex>0</BoxInputIndex>
|
||||
</Target>
|
||||
</Link>
|
||||
</Links>
|
||||
<Comments></Comments>
|
||||
<Metadata>
|
||||
<Entry>
|
||||
<Identifier>(0x00004b79, 0x00004f0d)</Identifier>
|
||||
<Type>(0x3bcce5d2, 0x43f2d968)</Type>
|
||||
<Data>[{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"height":1,"identifier":"(0x000033dc, 0x0000473a)","name":"Default window","parentIdentifier":"(0xffffffff, 0xffffffff)","type":1,"width":1},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":1,"identifier":"(0x00006ab8, 0x00002aa8)","index":0,"name":"Default tab","parentIdentifier":"(0x000033dc, 0x0000473a)","type":2},{"boxIdentifier":"(0xffffffff, 0xffffffff)","childCount":0,"identifier":"(0x00006208, 0x00003307)","index":0,"name":"Empty","parentIdentifier":"(0x00006ab8, 0x00002aa8)","type":0}]</Data>
|
||||
</Entry>
|
||||
</Metadata>
|
||||
</OpenViBE-Scenario>
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* \page BoxAlgorithmDataViz DataViz
|
||||
__________________________________________________________________
|
||||
|
||||
Detailed description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Description|
|
||||
This box aims to transform the data with a LDA or a PCA and plot the data in 2D or 3D.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Description|
|
||||
__________________________________________________________________
|
||||
|
||||
Settings description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Settings|
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Settings|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Setting1|
|
||||
The box clock frequency. The Python process function is called at
|
||||
each tick.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Setting1|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Setting2|
|
||||
If specified, path to save the model which transform the data.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Setting2|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Setting3|
|
||||
If specified, path to load the model which transform the data.
|
||||
If empty, a new model will be created depending on the input's data.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Setting3|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Setting4|
|
||||
Algorithm to use to reduce the data's dimensions. Two options are available :
|
||||
PCA or LDA. By default, the box will use PCA.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Setting4|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Setting5|
|
||||
Number of dimensions to plot the data. The user can only choose between 2 or 3.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Setting5|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Setting6|
|
||||
Labels of the data, if not specified then labels will be "1, 2, 3, etc".
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Setting6|
|
||||
|
||||
__________________________________________________________________
|
||||
|
||||
Examples description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Examples|
|
||||
See <a href="http://openvibe.inria.fr/tutorial-using-python-with-openvibe">this page</a> for commented examples.
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Examples|
|
||||
__________________________________________________________________
|
||||
|
||||
Miscellaneous description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDataViz_Miscellaneous|
|
||||
* |OVP_DocEnd_BoxAlgorithmDataViz_Miscellaneous|
|
||||
*/
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* \page BoxAlgorithmDatasetCreator DatasetCreator
|
||||
__________________________________________________________________
|
||||
|
||||
Detailed description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Description|
|
||||
|
||||
This box aims to monitor the user to create a dataset.
|
||||
The user first configure the box and chooses some labels, then
|
||||
the box will randomly determine an order between them. It will
|
||||
then record the user's brain activity while verbally indicating
|
||||
the current action. In this way, we will be able to create a
|
||||
labeled dataset that can be used for learning.
|
||||
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Description|
|
||||
__________________________________________________________________
|
||||
|
||||
Settings description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Settings|
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Settings|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting1|
|
||||
The box clock frequency. The Python process function is called at
|
||||
each tick.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting1|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting2|
|
||||
The path to the dir where the user want to save the data.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting2|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting3|
|
||||
Name of the first label. That label has to be configured with the
|
||||
manager to associate a sound.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting3|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting4|
|
||||
Name of the second label. That label has to be configured with the
|
||||
manager to associate a sound.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting4|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting5|
|
||||
Name of the third label. That label has to be configured with the
|
||||
manager to associate a sound.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting5|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting6|
|
||||
Name of the fourth label. That label has to be configured with the
|
||||
manager to associate a sound.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting6|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting7|
|
||||
True if you want one csv per label, false if you want one csv
|
||||
containing all the labels.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting7|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting3|
|
||||
Number of folds you want to create.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting3|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Setting3|
|
||||
Number of action to record. For exemple, if you want two record for
|
||||
4 labels, then number of actions if 8.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Setting3|
|
||||
|
||||
__________________________________________________________________
|
||||
|
||||
Examples description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Examples|
|
||||
See <a href="http://openvibe.inria.fr/tutorial-using-python-with-openvibe">this page</a> for commented examples.
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Examples|
|
||||
__________________________________________________________________
|
||||
|
||||
Miscellaneous description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmDatasetCreator_Miscellaneous|
|
||||
* |OVP_DocEnd_BoxAlgorithmDatasetCreator_Miscellaneous|
|
||||
*/
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* \page BoxAlgorithmProcessML Process Sklearn
|
||||
__________________________________________________________________
|
||||
|
||||
Detailed description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Description|
|
||||
This box aims to load a machine learning model from scikit-learn
|
||||
or pyriemann already trained and to use it to predict its input's data.
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Description|
|
||||
__________________________________________________________________
|
||||
|
||||
Settings description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Settings|
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Settings|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Setting1|
|
||||
The box clock frequency. The Python process function is called at
|
||||
each tick.
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Setting1|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Setting2|
|
||||
The path to the model the user want to load.
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Setting2|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Setting3|
|
||||
If not empty, the path where the user want to save the predictions
|
||||
results.
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Setting3|
|
||||
|
||||
__________________________________________________________________
|
||||
|
||||
Examples description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Examples|
|
||||
See <a href="http://openvibe.inria.fr/tutorial-using-python-with-openvibe">this page</a> for commented examples.
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Examples|
|
||||
__________________________________________________________________
|
||||
|
||||
Miscellaneous description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmProcessML_Miscellaneous|
|
||||
* |OVP_DocEnd_BoxAlgorithmProcessML_Miscellaneous|
|
||||
*/
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* \page BoxAlgorithmTrainerML Trainer Sklearn
|
||||
__________________________________________________________________
|
||||
|
||||
Detailed description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Description|
|
||||
This box aims to create a machine learning model based on algorithm implemented in scikit-learn.
|
||||
The user can modify nearly all the settings from scikit-learn.
|
||||
It is possible for the user to test his model with a test set.
|
||||
He can also save the model in a file which he can use with the ProcessML box.
|
||||
|
||||
An AdaBoost classifier is a meta-estimator that begins by fitting
|
||||
a classifier on the original dataset and then fits additional
|
||||
copies of the classifier on the same dataset but where the weights
|
||||
of incorrectly classified instances are adjusted such that
|
||||
subsequent classifiers focus more on difficult cases.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Description|
|
||||
__________________________________________________________________
|
||||
|
||||
Settings description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Settings|
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Settings|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Setting1|
|
||||
The box clock frequency. The Python process function is called at
|
||||
each tick.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Setting1|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Setting2|
|
||||
The path to the file where the user want to save the model.
|
||||
If empty, the model is not saved.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Setting2|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Setting3|
|
||||
The path to the file where the user want to load a model.
|
||||
If empty, a new model will be created.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Setting3|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Setting4|
|
||||
The name of the scikit-learn algorithm. The user should not try
|
||||
to modify this setting.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Setting4|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Setting5|
|
||||
Float between 0 and 1 (1 not included) which represents the proportion
|
||||
of the input dataset transformed into a test set, allowing us to
|
||||
evaluate our model once the training on the set train is done. If 0
|
||||
is filled in, then all the data will constitute the train set and no
|
||||
metrics will be displayed.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Setting5|
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Setting6|
|
||||
Names of the labels of input's data. This parameter is only usefull
|
||||
when the PolyMode is used (several streamed matrix in input, one for
|
||||
each label). Then the labels as to be described as follows :
|
||||
"my_label_1, mylabel_2, my_label_3, etc"
|
||||
Otherwise the labels will be "1, 2, 3, etc".
|
||||
If the input mode is ov-mode (one input streamed matrix and one
|
||||
stimulation), the labels will be read by the stimulations.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Setting6|
|
||||
|
||||
The rest of the settings are from scikit-learn. You can find
|
||||
their purpose here :
|
||||
https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.AdaBoostClassifier.html
|
||||
|
||||
__________________________________________________________________
|
||||
|
||||
Examples description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Examples|
|
||||
See <a href="http://openvibe.inria.fr/tutorial-using-python-with-openvibe">this page</a> for commented examples.
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Examples|
|
||||
__________________________________________________________________
|
||||
|
||||
Miscellaneous description
|
||||
__________________________________________________________________
|
||||
|
||||
* |OVP_DocBegin_BoxAlgorithmTrainerML_Miscellaneous|
|
||||
* |OVP_DocEnd_BoxAlgorithmTrainerML_Miscellaneous|
|
||||
*/
|
||||
@@ -0,0 +1,725 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import platform
|
||||
import subprocess
|
||||
import time
|
||||
import inspect
|
||||
import ast
|
||||
import copy
|
||||
from pathlib import Path
|
||||
from collections import namedtuple
|
||||
from shutil import copyfile
|
||||
from filecmp import cmp as compare_file
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
|
||||
|
||||
system = platform.system()
|
||||
if system != 'Linux' and system != 'Windows':
|
||||
raise Exception("OS {} is not handled with that script.".format(system))
|
||||
|
||||
def find_folders() :
|
||||
"""Find openvibe and the manager folders."""
|
||||
|
||||
current_file = inspect.getfile(lambda : None)
|
||||
current_file = Path(current_file)
|
||||
manager_folder = str(current_file.parent) + '/'
|
||||
openvibe_folder = str(current_file.parent.parent.parent.parent.parent.parent) + '/'
|
||||
return manager_folder, openvibe_folder
|
||||
|
||||
def find_all_stims():
|
||||
"""Retrieve all stimulation from Poly_Stimulation"""
|
||||
|
||||
prefixe_stim = 'OVPoly_'
|
||||
stims = [k for k in Poly_stimulation.keys() if prefixe_stim in k]
|
||||
stims = [k[len(prefixe_stim):] for k in stims]
|
||||
return stims
|
||||
|
||||
def find_all_custom_settings(manager_folder) :
|
||||
""" Generate a list containing all custom settings and their values"""
|
||||
|
||||
def get_custom_settings(path_header, prefixe) :
|
||||
with open(path_header, 'r') as f :
|
||||
text = f.read()
|
||||
matchs = re.findall(r"{}[a-zA-Z0-9_]+".format(prefixe), text)
|
||||
return matchs
|
||||
|
||||
def get_custom_settings_confirmed(path_cpp, custom_settings) :
|
||||
with open(path_cpp, 'r') as f :
|
||||
text = f.read()
|
||||
custom_settings_confirmed = []
|
||||
|
||||
for ct in custom_settings :
|
||||
match = re.search(r"rPluginModuleContext\.getTypeManager\(\)\.registerEnumerationType\({}, \"[a-zA-Z0-9_ \.]+\"\);".format(ct), text)
|
||||
if match is not None :
|
||||
custom_settings_confirmed += [ct]
|
||||
return custom_settings_confirmed
|
||||
|
||||
def get_custom_values(path_cpp, custom_settings, prefixe) :
|
||||
custom_values = {}
|
||||
|
||||
with open(path_cpp, 'r') as f :
|
||||
text = f.read()
|
||||
|
||||
for ct in custom_settings :
|
||||
matchs = re.findall(r'rPluginModuleContext\.getTypeManager\(\)\.registerEnumerationEntry\({}, "[0-9a-zA-Z_ \.]+", [0-9]+\);'.format(ct), text)
|
||||
values = []
|
||||
|
||||
for match in matchs :
|
||||
m_text = match.split('"')[1]
|
||||
m_id = int(match.split(',')[-1][1:-2])
|
||||
values += [Value(text=m_text, id=m_id)]
|
||||
|
||||
cs_name = ct[len(prefixe):]
|
||||
custom_values[cs_name] = Custom_Setting(ct, values)
|
||||
|
||||
return custom_values
|
||||
|
||||
prefixe = 'OVPoly_ClassId_'
|
||||
path_header = "{}/src/defines.hpp".format(manager_folder)
|
||||
path_cpp = "{}/src/main.cpp".format(manager_folder)
|
||||
|
||||
custom_settings = get_custom_settings(path_header, prefixe)
|
||||
custom_settings = get_custom_settings_confirmed(path_cpp, custom_settings)
|
||||
custom_values = get_custom_values(path_cpp, custom_settings, prefixe)
|
||||
|
||||
return custom_values
|
||||
|
||||
def find_all_boxes(manager_folder, io_dic_type, settings_dic_type):
|
||||
"""Generate a list containing all the existing box inside"""
|
||||
|
||||
path_all_boxes = "{}/src/box-algorithms/".format(manager_folder)
|
||||
list_all_files = os.listdir(path_all_boxes)
|
||||
|
||||
directories = {}
|
||||
for elem in list_all_files:
|
||||
if elem[:3] == 'ovp' :
|
||||
|
||||
with open(path_all_boxes + elem, 'r') as f:
|
||||
file_h = f.read()
|
||||
|
||||
# Path Script
|
||||
script = re.findall(
|
||||
r"m_script = \"(.*.py)\";", file_h)[0]
|
||||
|
||||
# Description
|
||||
desc = re.findall(r"virtual CString getShortDescription\(void\) const "
|
||||
r"{ return CString\(\"(.*?)\"\); }", file_h, flags=re.DOTALL)[0]
|
||||
desc = desc.replace("\"", "\\\"")
|
||||
|
||||
author = re.search(r'virtual CString getAuthorName\(void\) const { return CString\(\"[a-zA-Z 0-9\-&]*\"\); }', file_h).group()
|
||||
author = author[89:-5]
|
||||
|
||||
category = re.search(r'virtual CString getCategory\(void\) const { return CString\(\"[/a-zA-Z ]+\"\); }', file_h).group()
|
||||
category = category[89:-5]
|
||||
category = category[16:]
|
||||
|
||||
# Creation of the object
|
||||
|
||||
# workaround to allow creation of box with spaces
|
||||
boxname = elem[3:-2]
|
||||
name = boxname.replace('_',' ')
|
||||
|
||||
box = BoxPython(name=name, filename= boxname, desc=desc, path_script=script)
|
||||
box.author = author
|
||||
box.category = category
|
||||
|
||||
# Settings
|
||||
setts = re.findall(r"(?<!//)prototype.addSetting\(\"(.*)\", "
|
||||
r"((OV_TypeId|OVPoly)_[a-z_A-Z]*), \"(.*)\"\);", file_h)
|
||||
# r"(OV_TypeId_[a-z_A-Z]*), \"(.*)\"\);", file_h)
|
||||
|
||||
# Same value as the one in counters in the display part
|
||||
settings_compt = 2
|
||||
for sett in setts:
|
||||
if sett[0] != 'Clock frequency (Hz)':
|
||||
keys = list(settings_dic_type.keys())
|
||||
values = list(settings_dic_type.values())
|
||||
|
||||
|
||||
box.settings[settings_compt] = [
|
||||
sett[0], keys[values.index(sett[1])], sett[3]]
|
||||
settings_compt += 1
|
||||
|
||||
# inputs
|
||||
inputs = re.findall(
|
||||
r"(?<!\/\/)prototype\.addInput\(\"(.*)\", (OV_TypeId_[a-zA-Z]*)\);", file_h)
|
||||
|
||||
# Same value as the one in counters in the display part
|
||||
inputs_compt = 2
|
||||
keys = list(io_dic_type.keys())
|
||||
values = list(io_dic_type.values())
|
||||
for inp in inputs:
|
||||
box.inputs[inputs_compt] = [
|
||||
inp[0], keys[values.index(inp[1])]]
|
||||
inputs_compt += 1
|
||||
|
||||
# outputs
|
||||
outputs = re.findall(
|
||||
r"(?<!\/\/)prototype\.addOutput\(\"(.*)\", (OV_TypeId_[a-zA-Z]*)\);", file_h)
|
||||
# Same value as the one in counters in the display part
|
||||
outputs_compt = 2
|
||||
for out in outputs:
|
||||
box.outputs[outputs_compt] = [
|
||||
out[0], keys[values.index(out[1])]]
|
||||
outputs_compt += 1
|
||||
|
||||
# modify permission
|
||||
permission_input = re.search(r"(\/\/)?prototype\.addFlag\(Kernel::BoxFlag_CanModifyInput\);", file_h)
|
||||
permission_output = re.search(r"(\/\/)?prototype\.addFlag\(Kernel::BoxFlag_CanModifyOutput\);", file_h)
|
||||
permission_setting = re.search(r"(\/\/)?prototype\.addFlag\(Kernel::BoxFlag_CanModifySetting\);", file_h)
|
||||
|
||||
if permission_input.group()[:2] == '//' :
|
||||
box.modify_inputs = False
|
||||
if permission_output.group()[:2] == '//' :
|
||||
box.modify_outputs = False
|
||||
if permission_setting.group()[:2] == '//' :
|
||||
box.modify_settings = False
|
||||
|
||||
directories[box.name] = box
|
||||
|
||||
return directories
|
||||
|
||||
def warning_msg(msg) :
|
||||
"""Show a warning message : msg in the manager to the user."""
|
||||
box = QMessageBox()
|
||||
box.setIcon(QMessageBox.Warning)
|
||||
box.setText(msg)
|
||||
box.setWindowTitle('Warning')
|
||||
box.exec_()
|
||||
|
||||
def info_msg(msg) :
|
||||
"""Show an information msg in the manager to the user."""
|
||||
box = QMessageBox()
|
||||
box.setIcon(QMessageBox.Information)
|
||||
box.setText(msg)
|
||||
box.setWindowTitle('Information')
|
||||
box.exec_()
|
||||
|
||||
def insert_line_in_file(filename, string, tag):
|
||||
"""Insert the line string in the file filename just after the first
|
||||
line containing tag."""
|
||||
with open(filename, 'r+') as f:
|
||||
text = f.read()
|
||||
i = text.index(tag) + len(tag)
|
||||
f.seek(0)
|
||||
f.write(text[:i] + '\n' + string + text[i:])
|
||||
|
||||
|
||||
def replace_in_file(filename, old, new):
|
||||
"""Replace in filename old by new."""
|
||||
with open(filename, 'r') as f:
|
||||
text = f.read()
|
||||
text = text.replace(old, new)
|
||||
with open(filename, 'w') as f:
|
||||
f.write(text)
|
||||
|
||||
|
||||
def remove_line_from_file(filename, tag):
|
||||
"""Delete the first line in the file with the tag inside."""
|
||||
flag = False
|
||||
with open(filename, 'r') as f:
|
||||
text = f.read()
|
||||
tab = text.split('\n')
|
||||
for i, line in enumerate(tab):
|
||||
if tag in line:
|
||||
flag = True
|
||||
break
|
||||
if flag:
|
||||
tab = tab[:i] + tab[i + 1:]
|
||||
text = '\n'.join(tab)
|
||||
if flag:
|
||||
with open(filename, 'w') as f:
|
||||
f.write(text)
|
||||
|
||||
|
||||
def generate_new_id(openvibe_folder):
|
||||
"""Generate a set of 4 different random ids for openvibe"""
|
||||
|
||||
def get_folder_sdk_releae(openvibe_folder) :
|
||||
path = '{}/build/'.format(openvibe_folder)
|
||||
dirs = os.listdir(path)
|
||||
path_to_return = path + [f for f in dirs if 'sdk-Release' in f][0]
|
||||
return path_to_return
|
||||
|
||||
def get_path_ov_id_generator(openvibe_folder) :
|
||||
path_sdk = get_folder_sdk_releae(openvibe_folder)
|
||||
path_to_return = '{}/applications/developer-tools/id-generator/openvibe-id-generator'.format(path_sdk)
|
||||
if system == 'Windows' :
|
||||
path_to_return += '.exe'
|
||||
return path_to_return
|
||||
|
||||
path_generator = get_path_ov_id_generator(openvibe_folder)
|
||||
filename_tmp = 'tmp_result'
|
||||
os.system('{} > {}'.format(path_generator, filename_tmp))
|
||||
with open(filename_tmp, 'r') as f:
|
||||
text = f.read()
|
||||
text = text.split('\n')
|
||||
line = text[0]
|
||||
tab = line.split(',')
|
||||
val1 = tab[0][-10:]
|
||||
val2 = tab[1][1:11]
|
||||
line = text[1]
|
||||
tab = line.split(',')
|
||||
val3 = tab[0][-10:]
|
||||
val4 = tab[1][1:11]
|
||||
if system == 'Linux' :
|
||||
os.system('rm {}'.format(filename_tmp))
|
||||
elif system == 'Windows' :
|
||||
os.system('del {}'.format(filename_tmp))
|
||||
return val1, val2, val3, val4
|
||||
|
||||
def create_box(openvibe_folder, manager_folder, setting_type, io_type, box_name, desc, path_script, category, author, settings, inputs, outputs, modify_settings, modify_inputs, modify_outputs):
|
||||
"""Create and modify the files to create/modify a new box in openvibe."""
|
||||
|
||||
global system
|
||||
|
||||
# preventing the use of spaces which would cause problems for c++ filenames
|
||||
box_name = box_name.replace(' ','_')
|
||||
|
||||
# force category to be in scripting
|
||||
category = 'Scripting/PyBox/' + category
|
||||
|
||||
# 1/ We place ourselves at the root of the python boxe
|
||||
old_location = os.getcwd()
|
||||
os.chdir("{}/src/".format(manager_folder))
|
||||
|
||||
# 2/ We create the corresponding directory
|
||||
path_dir_box = 'box-algorithms/'
|
||||
full_path_dir_box = os.getcwd() + '/' + path_dir_box
|
||||
|
||||
# We duplicate files from the original box
|
||||
path_file_header = path_dir_box + 'ovp{}.h'.format(box_name)
|
||||
path_pattern_header = '{}Assets/BoxManager/NewBoxPattern-skeletton.h'.format(
|
||||
manager_folder)
|
||||
copyfile(path_pattern_header, path_file_header)
|
||||
|
||||
|
||||
# 3/ We insert in defines.hpp the declaration of CIdentifiers
|
||||
filename = 'defines.hpp'
|
||||
tag = '// <tag> Tag Box Declaration'
|
||||
time.sleep(1)
|
||||
new_id1, new_id2, new_id3, new_id4 = generate_new_id(openvibe_folder)
|
||||
new_line = "#define OVP_ClassId_BoxAlgorithm_{} OpenViBE::CIdentifier({}, {})"\
|
||||
.format(box_name, new_id1, new_id2)
|
||||
insert_line_in_file(filename, new_line, tag)
|
||||
new_line = "#define OVP_ClassId_BoxAlgorithm_{}Desc OpenViBE::CIdentifier({}, {})"\
|
||||
.format(box_name, new_id3, new_id4)
|
||||
insert_line_in_file(filename, new_line, tag)
|
||||
|
||||
# 4/ We add our lines in main.cpp
|
||||
filename = 'main.cpp'
|
||||
tag = '#include "box-algorithms/CPolyBox.hpp"'
|
||||
new_line = '#include "{}"'.format(path_file_header)
|
||||
insert_line_in_file(filename, new_line, tag)
|
||||
|
||||
tag = '// <tag> OVP_Declare_New'
|
||||
new_line = '\t\tOVP_Declare_New(Python::CBoxAlgorithm{}Desc);'.format(
|
||||
box_name)
|
||||
insert_line_in_file(filename, new_line, tag)
|
||||
|
||||
# 5/ We replace in ovpmyBox.h
|
||||
replace_in_file(path_file_header, 'CBoxAlgorithmNewBoxPattern',
|
||||
'CBoxAlgorithm{}'.format(box_name))
|
||||
replace_in_file(path_file_header, 'OVP_ClassId_BoxAlgorithm_NewBoxPattern',
|
||||
'OVP_ClassId_BoxAlgorithm_{}'.format(box_name))
|
||||
replace_in_file(path_file_header, 'OVP_ClassId_BoxAlgorithm_NewBoxPatternDesc',
|
||||
'OVP_ClassId_BoxAlgorithm_{}Desc'.format(box_name))
|
||||
|
||||
|
||||
# 6/ We change the name, the description, the author name and the category
|
||||
desc = desc.replace("\"", "\\\"")
|
||||
|
||||
# we reset the spaces for the name of the box
|
||||
box_name = box_name.replace('_',' ')
|
||||
|
||||
replace_in_file(path_file_header,
|
||||
'CString getName() const override { return CString("NewBoxPattern"); }',
|
||||
'CString getName() const override { return CString("' + box_name + '"); }')
|
||||
replace_in_file(path_file_header,
|
||||
'CString getShortDescription() const override { return CString("Default Python Description"); }',
|
||||
'CString getShortDescription() const override { return CString("' + desc + '"); }')
|
||||
replace_in_file(path_file_header,
|
||||
'CString getAuthorName() const override { return CString("NewAuthor"); }',
|
||||
'CString getAuthorName() const override { return CString("' + author + '"); }')
|
||||
replace_in_file(path_file_header,
|
||||
'CString getCategory() const override { return CString("Scripting/Pybox/"); }',
|
||||
'CString getCategory() const override { return CString("' + category + '"); }')
|
||||
|
||||
# 7/ We set the python script to execute
|
||||
# On set le script python a executer
|
||||
replace_in_file(path_file_header,
|
||||
'm_script = "NewScript.py";',
|
||||
'm_script = "{}";'.format(path_script.replace('\\', '/')))
|
||||
|
||||
|
||||
# 8/ We can then add our params
|
||||
tag = '// <tag> settings'
|
||||
for number, (key, kind, value) in reversed(list(settings.items())):
|
||||
if key:
|
||||
new_line = ' prototype.addSetting("{}", {}, "{}");'.format(
|
||||
key, all_settings_type[kind], value)
|
||||
insert_line_in_file(path_file_header, new_line, tag)
|
||||
|
||||
# 9/ We can then add our inputs and our outputs
|
||||
tag_inoutset = '// <tag> input & output'
|
||||
for number, (name, kind) in reversed(list(inputs.items())):
|
||||
if name:
|
||||
new_line = ' prototype.addInput("{}", {});'.format(
|
||||
name, io_type[kind])
|
||||
insert_line_in_file(path_file_header, new_line, tag_inoutset)
|
||||
|
||||
for number, (name, kind) in reversed(list(outputs.items())):
|
||||
new_line = ' prototype.addOutput("{}", {});'.format(
|
||||
name, io_type[kind])
|
||||
insert_line_in_file(path_file_header, new_line, tag_inoutset)
|
||||
|
||||
|
||||
# 10/ Permissions to modify boxes in OV
|
||||
if not modify_settings :
|
||||
replace_in_file(path_file_header,
|
||||
"prototype.addFlag(Kernel::BoxFlag_CanModifySetting);",
|
||||
"//prototype.addFlag(Kernel::BoxFlag_CanModifySetting);")
|
||||
if not modify_inputs :
|
||||
replace_in_file(path_file_header,
|
||||
"prototype.addFlag(Kernel::BoxFlag_CanModifyInput);",
|
||||
"//prototype.addFlag(Kernel::BoxFlag_CanModifyInput);")
|
||||
if not modify_outputs :
|
||||
replace_in_file(path_file_header,
|
||||
"prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);",
|
||||
"//prototype.addFlag(Kernel::BoxFlag_CanModifyOutput);")
|
||||
|
||||
os.chdir(old_location)
|
||||
|
||||
|
||||
def delete_box(manager_folder, box_name):
|
||||
"""Delete and modify files to delete an existing box."""
|
||||
|
||||
global system
|
||||
|
||||
box_name = box_name.replace(' ', '_')
|
||||
|
||||
# 1/ Change directory to src/
|
||||
old_location = os.getcwd()
|
||||
os.chdir("{}src/".format(manager_folder))
|
||||
|
||||
# 2/ Remove directory with the box algorithms
|
||||
path_box = 'box-algorithms/ovp{}.h'.format(box_name)
|
||||
os.remove(path_box)
|
||||
|
||||
# 3/ Remove lines from defines.hpp
|
||||
path = 'defines.hpp'
|
||||
tag = 'OVP_ClassId_BoxAlgorithm_{}Desc'.format(box_name)
|
||||
remove_line_from_file(path, tag)
|
||||
tag = 'OVP_ClassId_BoxAlgorithm_{}'.format(box_name)
|
||||
remove_line_from_file(path, tag)
|
||||
|
||||
# 4/ Remove lines from main.cpp
|
||||
path = 'main.cpp'
|
||||
tag = 'OVP_Declare_New(Python::CBoxAlgorithm{}Desc);'.format(box_name)
|
||||
remove_line_from_file(path, tag)
|
||||
tag = '#include "box-algorithms/ovp{}.h"'.format(box_name)
|
||||
remove_line_from_file(path, tag)
|
||||
|
||||
os.chdir(old_location)
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
def create_custom_setting(manager_folder, openvibe_folder, cs) :
|
||||
""" Make all modification to openvibe to create a custom setting."""
|
||||
|
||||
prefixe = 'OVPoly_ClassId_'
|
||||
path_cpp = '{}/src/main.cpp'.format(manager_folder)
|
||||
path_header = '{}/src/defines.hpp'.format(manager_folder)
|
||||
|
||||
tag = '// <tag> Custom Type Settings'
|
||||
cs_define = "{}{}".format(prefixe, cs.name)
|
||||
|
||||
# header
|
||||
id_1, id_2, _, _ = generate_new_id(openvibe_folder)
|
||||
line_header = '#define {} OpenViBE::CIdentifier({}, {})'.format(cs_define, id_1, id_2)
|
||||
insert_line_in_file(path_header, line_header, tag)
|
||||
|
||||
# cpp
|
||||
for value in reversed(cs.values) :
|
||||
line_entry = '\trKernelContext.getTypeManager().registerEnumerationEntry({}, "{}", {});'.format(cs_define, value.text, value.id)
|
||||
insert_line_in_file(path_cpp, line_entry, tag)
|
||||
|
||||
line_type = '\trKernelContext.getTypeManager().registerEnumerationType({}, "{}");'.format(cs_define, cs.name)
|
||||
insert_line_in_file(path_cpp, line_type, tag)
|
||||
|
||||
def delete_custom_setting(manager_folder, cs) :
|
||||
"""Make all the modification to openvibe to delete a custom setting."""
|
||||
|
||||
def remove_lines_with_tag_in_file(file, tag) :
|
||||
with open(file, 'r') as f :
|
||||
text = f.read()
|
||||
new_text = []
|
||||
for line in text.split('\n') :
|
||||
if not (tag in line) :
|
||||
new_text += [line]
|
||||
new_text = '\n'.join(new_text)
|
||||
with open(file, 'w') as f :
|
||||
f.write(new_text)
|
||||
|
||||
prefixe = 'OVPoly_ClassId_'
|
||||
path_cpp = '{}/src/main.cpp'.format(manager_folder)
|
||||
path_header = '{}/src/defines.hpp'.format(manager_folder)
|
||||
|
||||
tag = '{}{}'.format(prefixe, cs.name)
|
||||
remove_lines_with_tag_in_file(path_header, tag)
|
||||
remove_lines_with_tag_in_file(path_cpp, tag)
|
||||
|
||||
def compile(manager_folder, openvibe_folder):
|
||||
"""Compile OpenVibe."""
|
||||
|
||||
# Go to openvibe folder directory
|
||||
old_location = os.getcwd()
|
||||
os.chdir(openvibe_folder)
|
||||
|
||||
path_log = manager_folder + 'compilation.log'
|
||||
|
||||
if system == 'Linux':
|
||||
os.system('./build.sh | tee {}'.format(path_log))
|
||||
elif system == 'Windows':
|
||||
os.system('build.cmd > {}'.format(path_log))
|
||||
|
||||
# Set back to normal
|
||||
os.chdir(old_location)
|
||||
|
||||
|
||||
|
||||
def add_stimulation(manager_folder, label, file_sound) :
|
||||
"""Make all the modifications to add a stimulation to openvibe."""
|
||||
|
||||
def find_next_id(path_file_stim) :
|
||||
# We open the PolyStimulations.py to find the next id
|
||||
with open(path_file_stim, 'r') as f :
|
||||
text = f.read()
|
||||
# On charge de dictionnaire de stimulation
|
||||
dico_string = ''
|
||||
flag = False
|
||||
for c in text :
|
||||
if c == '{' :
|
||||
flag = True
|
||||
elif c == '}' :
|
||||
dico_string += c
|
||||
break
|
||||
|
||||
if flag :
|
||||
dico_string += c
|
||||
dico = ast.literal_eval(dico_string)
|
||||
|
||||
ids = [int(value) for key, value in Poly_stimulation.items() if 'OVPoly' in key]
|
||||
ids.sort()
|
||||
try :
|
||||
current_id = ids[0]
|
||||
except IndexError :
|
||||
return 0x10001
|
||||
while True :
|
||||
if not current_id in ids :
|
||||
return hex(current_id)
|
||||
current_id += 1
|
||||
|
||||
def get_line_to_add(label, path_file_stim) :
|
||||
key = '\'OVPoly_' + label[0].upper() + label[1:].lower() + '\''+ ' '*(29-len(label))
|
||||
value = find_next_id(path_file_stim)
|
||||
line = '{}: {},'.format(key, value)
|
||||
return line
|
||||
|
||||
|
||||
path_file_stim = '{}/share/PolyStimulations.py'.format(manager_folder)
|
||||
tag = '# <Flag> New Stims'
|
||||
|
||||
line = get_line_to_add(label, path_file_stim)
|
||||
insert_line_in_file(path_file_stim, line, tag)
|
||||
|
||||
copyfile(file_sound, '{}/Assets/Sounds/{}.mp3'.format(manager_folder, label))
|
||||
|
||||
|
||||
def get_name_duplicate(dict, name) :
|
||||
"""Find the name for a duplicated box."""
|
||||
|
||||
def regex_handling(regex, name):
|
||||
res = re.search(regex, name)
|
||||
|
||||
try:
|
||||
prefix_1 = res.group(1)
|
||||
idx_1 = res.group(2) # useless ?
|
||||
max_idx = 1
|
||||
|
||||
# Does we already have a duplicate ?
|
||||
# we do so we find the max index and increment it
|
||||
for bn in dict.keys() :
|
||||
|
||||
regex = '(' + prefix_1 + ')(\d+)'
|
||||
res_2 = re.search(regex,bn)
|
||||
try:
|
||||
idx = int(res_2.group(2))
|
||||
|
||||
if idx >= max_idx:
|
||||
max_idx = idx + 1
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
current_name = prefix_1 + str(max_idx)
|
||||
|
||||
except AttributeError:
|
||||
# current_name = 'rr'
|
||||
|
||||
for bn in dict.keys() :
|
||||
if bn == name :
|
||||
current_name = '{}_{}'.format(name, 1)
|
||||
finally:
|
||||
return current_name
|
||||
|
||||
|
||||
current_name = name
|
||||
|
||||
regex = '(.+?_)(\d+)'
|
||||
res = re.search(regex, current_name) # useless ?
|
||||
|
||||
|
||||
# We already have doublon
|
||||
for bn in dict.keys():
|
||||
|
||||
# if we have the "original" name
|
||||
if current_name in bn:
|
||||
current_name = regex_handling(regex, bn)
|
||||
break
|
||||
else:
|
||||
current_name = regex_handling(regex, current_name)
|
||||
|
||||
|
||||
return current_name
|
||||
|
||||
|
||||
def delete_stimulation(manager_folder, label) :
|
||||
"""Make the modification to remove a stimulation from openvibe."""
|
||||
|
||||
path_file_stim = '{}/share/PolyStimulations.py'.format(manager_folder)
|
||||
remove_line_from_file(path_file_stim, label)
|
||||
path_sound = '{}/Assets/Sounds/{}.mp3'.format(manager_folder, label.lower())
|
||||
os.remove(path_sound)
|
||||
|
||||
|
||||
def retrieve_settings_type(custom_settings, all_settings=False) :
|
||||
"""If 'mode=developer' in args : load all default and custom settings,
|
||||
else load only default settings"""
|
||||
|
||||
settings = {
|
||||
'Integer': 'OV_TypeId_Integer',
|
||||
'Float': 'OV_TypeId_Float',
|
||||
'String': 'OV_TypeId_String',
|
||||
'Boolean': 'OV_TypeId_Boolean',
|
||||
'Filename': 'OV_TypeId_Filename',
|
||||
'Stimulation': 'OV_TypeId_Stimulation',
|
||||
}
|
||||
|
||||
flag = False
|
||||
for arg in sys.argv[1:] :
|
||||
if 'mode=developer' in arg :
|
||||
flag = True
|
||||
|
||||
if flag or all_settings :
|
||||
for k,v in custom_settings.items() :
|
||||
settings[k] = v.name
|
||||
|
||||
return settings
|
||||
|
||||
Setting = namedtuple('Setting', ['name', 'type', 'value', 'button_delete'])
|
||||
Input = namedtuple('Input', ['name', 'type', 'button_delete'])
|
||||
Output = namedtuple('Output', ['name', 'type', 'button_delete'])
|
||||
|
||||
Custom_Setting_Line = namedtuple('CSV', ['name', 'value', 'button_delete'])
|
||||
Custom_Setting = namedtuple("Custom_Setting", ['name', 'values'])
|
||||
Value = namedtuple("Value", ["text", "id"])
|
||||
|
||||
|
||||
class BoxPython:
|
||||
"""This class aim to contain all the data needed to create a box in openvibe."""
|
||||
|
||||
def __init__(self, name='Default Box', filename='Default filename', desc='Default Python Description', path_script='/home/', old_name=None,):
|
||||
self.name = name
|
||||
self.filename = filename
|
||||
self.description = desc
|
||||
self.py_script = path_script
|
||||
self.category = ''
|
||||
self.author = ''
|
||||
self.settings = {}
|
||||
self.inputs = {}
|
||||
self.outputs = {}
|
||||
self.modify_settings = True
|
||||
self.modify_inputs = True
|
||||
self.modify_outputs = True
|
||||
self.to_be_updated = False
|
||||
|
||||
if old_name is None :
|
||||
self.old_name = name
|
||||
else :
|
||||
self.old_name = old_name
|
||||
|
||||
|
||||
|
||||
def __eq__(self, obj):
|
||||
equals = False
|
||||
if isinstance(obj, BoxPython):
|
||||
equals = self.name == obj.name and \
|
||||
self.description == obj.description and \
|
||||
self.py_script == obj.py_script and \
|
||||
cmp(self.settings, obj.settings) == 0 and \
|
||||
cmp(self.inputs, obj.inputs) == 0 and \
|
||||
cmp(self.outputs, obj.outputs) == 0
|
||||
return equals
|
||||
|
||||
def __ne__(self, obj):
|
||||
return not self == obj
|
||||
|
||||
|
||||
# Load all the data necessary to make the manager work.
|
||||
|
||||
manager_folder, openvibe_folder = find_folders()
|
||||
|
||||
io_type = {
|
||||
'Signal': 'OV_TypeId_Signal',
|
||||
'Stimulations': 'OV_TypeId_Stimulations',
|
||||
'Streamed Matrix': 'OV_TypeId_StreamedMatrix'
|
||||
}
|
||||
|
||||
|
||||
modes = ['ov-mode', 'poly-mode']
|
||||
|
||||
category = ['Acquisition and network IO',
|
||||
'Advanced Visualization',
|
||||
'Classification',
|
||||
'Data generation',
|
||||
'Evaluation',
|
||||
'Examples',
|
||||
'Feature extraction',
|
||||
'File reading and writing',
|
||||
'Signal processing',
|
||||
'Stimulation',
|
||||
'Streaming',
|
||||
'Tests',
|
||||
'Tools',
|
||||
'Visualization'
|
||||
]
|
||||
|
||||
|
||||
sys.path.append('{}/share/'.format(manager_folder))
|
||||
from PolyStimulations import Poly_stimulation
|
||||
|
||||
custom_settings = find_all_custom_settings(manager_folder)
|
||||
all_settings_type = retrieve_settings_type(custom_settings, all_settings=True)
|
||||
settings_type = retrieve_settings_type(custom_settings)
|
||||
|
||||
boxes = find_all_boxes(manager_folder, io_type, all_settings_type)
|
||||
stims = find_all_stims()
|
||||
@@ -0,0 +1,203 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# File Name : PolyBox.py
|
||||
# Created By : Yannis Bendi-Ouis
|
||||
|
||||
from StimulationsCodes import *
|
||||
from PolyStimulations import *
|
||||
from openvibe import *
|
||||
import sys, traceback, collections
|
||||
from io import StringIO
|
||||
import re
|
||||
|
||||
|
||||
def get_label_from_stim(stim):
|
||||
stims_1 = list(OpenViBE_stimulation.items())
|
||||
stims_2 = list(Poly_stimulation.items())
|
||||
inv_dictstim = {v: k for k, v in stims_1 + stims_2}
|
||||
label = inv_dictstim[stim.identifier][7:].lower()
|
||||
label = ' '.join(label.split('_'))
|
||||
return label
|
||||
|
||||
|
||||
class PolyBox(OVBox):
|
||||
|
||||
def __init__(self, record=True):
|
||||
OVBox.__init__(self)
|
||||
self.acquiring_channel = []
|
||||
self.signalHeader = []
|
||||
self.data = {}
|
||||
self.record = record
|
||||
|
||||
self.mode = ''
|
||||
self.current_stimulation = None
|
||||
self.labels = []
|
||||
|
||||
def initialize(self):
|
||||
|
||||
def verify_entry(self):
|
||||
# Verify that the inputs corresponds to ov-mode or poly-mode
|
||||
# ov-mode : 1 stimulations and 1 streamed matrix
|
||||
# poly-mode : several streamed-matrix
|
||||
# others : others -> warning
|
||||
list_entry_type = [entry.type() for entry in self.input]
|
||||
nb_matrix = list_entry_type.count('StreamedMatrix')
|
||||
nb_stim = list_entry_type.count('Stimulations')
|
||||
nb_signal = list_entry_type.count('Signal')
|
||||
|
||||
if nb_stim == 1 and nb_matrix == 1 and nb_signal == 0:
|
||||
# ov-mode
|
||||
self.mode = 'ov-mode'
|
||||
elif nb_stim == 0 and nb_matrix >= 1 and nb_signal == 0:
|
||||
# poly-mode
|
||||
self.mode = 'poly-mode'
|
||||
else:
|
||||
raise Exception("ERROR : Entry of the box does not corresponds to any mode. \
|
||||
You can use 1 stimulations and 1 streamed matrix, or several streamed matrix. \
|
||||
But you can not use {} StreamedMatrix, {} Stimulations and {} Signal entry.".format(nb_matrix, nb_stim, nb_signal))
|
||||
|
||||
def verify_stim_output(self):
|
||||
# Verify that an output stim exist, otherwise prevent the user that the program won't stop
|
||||
flag = False
|
||||
for out in self.output:
|
||||
if out.type() == 'Stimulations':
|
||||
flag = True
|
||||
break
|
||||
|
||||
if not flag:
|
||||
print('WARNING : The DatasetCreator does not have any output Stimulation. The program may never stop.')
|
||||
|
||||
def get_labels(self):
|
||||
# retrieve labels in form : label1, label2, label3, mon label4
|
||||
# Useless if you are in OV-MODE
|
||||
if 'Labels' in self.setting.keys():
|
||||
string = self.setting['Labels']
|
||||
if len(string) > 0:
|
||||
labels_cut = string.lower().split(',')
|
||||
for label in labels_cut:
|
||||
self.labels += ['_'.join([w for w in label.split(' ') if w != ''])]
|
||||
|
||||
def init_acquiring_channel(self):
|
||||
# We get data for every input channel
|
||||
for _ in range(len(self.input)):
|
||||
self.acquiring_channel += [False]
|
||||
self.signalHeader += [None]
|
||||
|
||||
verify_entry(self)
|
||||
verify_stim_output(self)
|
||||
get_labels(self)
|
||||
init_acquiring_channel(self)
|
||||
self.on_initialize()
|
||||
|
||||
def process(self):
|
||||
# we go through every input
|
||||
for inputIndex in range(len(self.input)):
|
||||
for chunkIndex in range(len(self.input[inputIndex])):
|
||||
|
||||
# Signal init
|
||||
if type(self.input[inputIndex][chunkIndex]) == OVStreamedMatrixHeader:
|
||||
self.header_received(inputIndex, chunkIndex)
|
||||
|
||||
# Process every chunk received
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStreamedMatrixBuffer:
|
||||
self.chunk_received(inputIndex, chunkIndex)
|
||||
|
||||
# End of signal
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStreamedMatrixEnd:
|
||||
self.end_received(inputIndex, chunkIndex)
|
||||
|
||||
# Stimulations init
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStimulationHeader:
|
||||
self.header_received(inputIndex, chunkIndex)
|
||||
|
||||
# Process every stimulation
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStimulationSet:
|
||||
self.stimulation_received(inputIndex, chunkIndex)
|
||||
|
||||
# End of stim
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStimulationEnd:
|
||||
self.end_received(inputIndex, chunkIndex)
|
||||
|
||||
def uninitialize(self):
|
||||
pass
|
||||
|
||||
# ------- * -------- * ---------
|
||||
|
||||
def header_received(self, inputIndex, chunkIndex):
|
||||
header = self.input[inputIndex].pop()
|
||||
self.signalHeader[inputIndex] = header
|
||||
self.acquiring_channel[inputIndex] = True
|
||||
self.on_header_received(header)
|
||||
|
||||
def chunk_received(self, inputIndex, chunkIndex):
|
||||
chunk = list(self.input[inputIndex].pop())
|
||||
if self.acquiring_channel[inputIndex]:
|
||||
|
||||
# We look for the best key to use in function of mode and settings labels.
|
||||
key = None
|
||||
if self.mode == 'poly-mode':
|
||||
if len(self.labels) > 0:
|
||||
key = self.labels[inputIndex]
|
||||
else:
|
||||
key = inputIndex
|
||||
|
||||
elif self.mode == 'ov-mode':
|
||||
key = get_label_from_stim(self.current_stimulation)
|
||||
|
||||
if self.record:
|
||||
try:
|
||||
self.data[key].append(chunk)
|
||||
except KeyError:
|
||||
self.data[key] = [chunk]
|
||||
|
||||
shape = tuple(self.signalHeader[inputIndex].dimensionSizes)
|
||||
self.on_chunk_received(chunk, key, shape)
|
||||
|
||||
def stimulation_received(self, inputIndex, chunkIndex):
|
||||
stim_list = self.input[inputIndex].pop()
|
||||
if len(stim_list) > 0:
|
||||
self.current_stimulation = stim_list[0]
|
||||
|
||||
def end_received(self, inputIndex, chunkIndex):
|
||||
self.acquiring_channel[inputIndex] = False
|
||||
self.input[inputIndex].pop()
|
||||
if not self.is_acquiring():
|
||||
print("Fin de l'acquisition des données...")
|
||||
self.on_end_box()
|
||||
self.send_end_stim()
|
||||
|
||||
def is_acquiring(self):
|
||||
# Return false when all inputs of type StreamedMatrix received End flag.
|
||||
nb_inputs = len(self.input)
|
||||
for i in range(nb_inputs):
|
||||
acquiring = self.acquiring_channel[i]
|
||||
kind = self.input[i].type()
|
||||
if kind == 'StreamedMatrix' and acquiring:
|
||||
return True
|
||||
return False
|
||||
|
||||
def send_end_stim(self):
|
||||
indice = -1
|
||||
for i, out in enumerate(self.output):
|
||||
if out.type() == 'Stimulations':
|
||||
indice = i
|
||||
|
||||
if indice != -1:
|
||||
stimLabel = 'OVTK_StimulationId_ExperimentStop'
|
||||
stimCode = OpenViBE_stimulation[stimLabel]
|
||||
stimSet = OVStimulationSet(0, self.getCurrentTime())
|
||||
stimSet.append(OVStimulation(stimCode, self.getCurrentTime(), 0.))
|
||||
self.output[indice].append(stimSet)
|
||||
|
||||
# ---------- * -------------- * ---------------
|
||||
|
||||
def on_initialize(self):
|
||||
pass
|
||||
|
||||
def on_header_received(self, header):
|
||||
pass
|
||||
|
||||
def on_chunk_received(self, chunk, label, shape):
|
||||
pass
|
||||
|
||||
def on_end_box(self):
|
||||
pass
|
||||
@@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#File Name : StimulationsCodes.py
|
||||
#Created By :
|
||||
|
||||
## Stimulation codes
|
||||
# Avoid the declaration of new stimulation (added in new tab here). Only Stimulation contains gdf in original list is really standard...
|
||||
Poly_stimulation = {
|
||||
'OVPoly_Down' : 0x10001, #Useless use 'OVTK_GDF_Down'
|
||||
'OVPoly_Up' : 0x10002, #Useless use 'OVTK_GDF_Up'
|
||||
'OVPoly_Right' : 0x10003, #Useless use 'OVTK_GDF_Right'
|
||||
'OVPoly_Left' : 0x10004, #Useless use 'OVTK_GDF_Left'
|
||||
'OVPoly_Neutral' : 0x10005,
|
||||
'OVPoly_Push' : 0x10006,
|
||||
'OVPoly_Pull' : 0x10007,
|
||||
'OVPoly_Left_Wink' : 0x10008,
|
||||
'OVPoly_Right_Wink' : 0x10009,
|
||||
# <Flag> New Stims
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from matplotlib import pyplot as plt
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
|
||||
from sklearn.decomposition import PCA
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pickle
|
||||
from PolyBox import PolyBox
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
flag_3D = True
|
||||
try:
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
except:
|
||||
print('Unable to import Axes3D from mpl_toolkits.mplot3d, 3D visualization disabled.')
|
||||
flag_3D = False
|
||||
|
||||
|
||||
class DataViz(PolyBox):
|
||||
|
||||
def __init__(self):
|
||||
PolyBox.__init__(self)
|
||||
|
||||
self.x_data = []
|
||||
self.y_data = []
|
||||
self.model = None
|
||||
|
||||
self.path_load_model = ''
|
||||
self.path_save_model = ''
|
||||
self.algo = ''
|
||||
self.dimension_reduction = -1
|
||||
|
||||
def on_initialize(self):
|
||||
# We retrieve the setting from OpenViBE
|
||||
|
||||
def retrieve_path_save_model(self):
|
||||
try:
|
||||
self.path_save_model = self.setting["Path to save the model"]
|
||||
except KeyError:
|
||||
pass
|
||||
if self.path_save_model == '':
|
||||
print('No path has been given to save the model, thus it won\'t be saved.')
|
||||
|
||||
def retrieve_path_load_model(self):
|
||||
try:
|
||||
self.path_load_model = self.setting["Path to load the model"]
|
||||
except KeyError:
|
||||
pass
|
||||
if self.path_load_model == '':
|
||||
print('No path has been given to load the model, thus a new model will be created.')
|
||||
|
||||
def retrieve_algo(self):
|
||||
try:
|
||||
self.algo = self.setting['Algorithm (PCA or LDA)'].upper()
|
||||
except KeyError:
|
||||
pass
|
||||
if self.algo == '':
|
||||
print('No algo has been given to the model, default algo is PCA.')
|
||||
self.algo = 'PCA'
|
||||
|
||||
def retrieve_dimension_reduction(self):
|
||||
try:
|
||||
self.dimension_reduction = int(self.setting['Dimension reduction'])
|
||||
except KeyError:
|
||||
pass
|
||||
except ValueError:
|
||||
print('{} is not a number. Please use 2 or 3 dimensions only.'.format(self.setting['Dimension reduction']))
|
||||
|
||||
if self.dimension_reduction == -1:
|
||||
print('No dimension reduction has been given, default value is 2.')
|
||||
self.dimension_reduction = 2
|
||||
|
||||
elif self.dimension_reduction == 3 and not flag_3D:
|
||||
print('3D disabled, cannot show data in 3 dimensions. Default dimension is 2.')
|
||||
self.dimension_reduction = 3
|
||||
|
||||
retrieve_path_save_model(self)
|
||||
retrieve_path_load_model(self)
|
||||
retrieve_algo(self)
|
||||
retrieve_dimension_reduction(self)
|
||||
def on_end_box(self):
|
||||
self.prepare_data()
|
||||
self.make_model_and_transform()
|
||||
self.make_plot()
|
||||
|
||||
# ---------
|
||||
|
||||
def prepare_data(self):
|
||||
for label in self.data.keys():
|
||||
self.x_data += self.data[label]
|
||||
self.y_data += [label for _ in range(len(self.data[label]))]
|
||||
|
||||
def make_model_and_transform(self):
|
||||
# load the model if it exists, else create a new one
|
||||
# then transform the data
|
||||
|
||||
def load_model(self):
|
||||
model = pickle.load(open(self.path_load_model, 'rb'))
|
||||
print('Model load from {}.'.format(self.path_load_model))
|
||||
return model
|
||||
|
||||
def save_model(self):
|
||||
pickle.dump(self.model, open(self.path_save_model, 'wb'))
|
||||
print('Dataviz model saved in {}'.format(self.path_save_model))
|
||||
|
||||
def map_algo(self):
|
||||
switcher = { 'LDA': LDA, 'PCA': PCA }
|
||||
clf = switcher.get(self.algo)
|
||||
return clf, switcher
|
||||
|
||||
def create_fit_model(self):
|
||||
clf, _ = map_algo(self)
|
||||
clf = clf(n_components=self.dimension_reduction)
|
||||
if self.algo == 'PCA':
|
||||
clf.fit(self.x_data)
|
||||
elif self.algo == 'LDA':
|
||||
clf.fit(self.x_data, self.y_data)
|
||||
else:
|
||||
raise Exception('{} is not known as an Algorithm. Please use PCA or LDA.'.format(self.algo))
|
||||
return clf
|
||||
|
||||
# Load or create the model
|
||||
if len(self.path_load_model) > 0:
|
||||
self.model = load_model(self)
|
||||
else:
|
||||
self.model = create_fit_model(self)
|
||||
|
||||
# Save the model
|
||||
if self.path_save_model != '':
|
||||
save_model(self)
|
||||
|
||||
# Transform data
|
||||
self.x_data = self.model.transform(self.x_data)
|
||||
self.y_data = np.array(self.y_data)
|
||||
|
||||
def make_plot(self):
|
||||
|
||||
fig = plt.figure(figsize=(12, 12))
|
||||
|
||||
all_labels = list(self.data.keys())
|
||||
colors = np.array([all_labels.index(label) for label in self.y_data])
|
||||
|
||||
if self.dimension_reduction == 2:
|
||||
|
||||
ax = plt.axes()
|
||||
|
||||
for label in all_labels:
|
||||
ax.text(self.x_data[self.y_data == label, 0].mean(), self.x_data[self.y_data == label, 1].mean(),
|
||||
label, horizontalalignment='center', bbox=dict(alpha=0.5, edgecolor='w', facecolor='w'))
|
||||
|
||||
ax.scatter(self.x_data[:, 0], self.x_data[:, 1], alpha=0.5, c=colors, cmap='Spectral', edgecolor='g')
|
||||
|
||||
plt.show()
|
||||
elif self.dimension_reduction == 3:
|
||||
|
||||
ax = Axes3D(fig)
|
||||
|
||||
for label in all_labels:
|
||||
ax.text3D(self.x_data[self.y_data == label, 0].mean(),
|
||||
self.x_data[self.y_data == label, 1].mean(),
|
||||
self.x_data[self.y_data == label, 2].mean(),
|
||||
label, horizontalalignment='center', bbox=dict(alpha=0.5, edgecolor='w', facecolor='w'))
|
||||
|
||||
ax.scatter(self.x_data[:, 0], self.x_data[:, 1], self.x_data[:, 2],
|
||||
alpha=0.5, c=colors, cmap='Spectral', edgecolor='g')
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
box = DataViz()
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
* Software License Agreement (AGPL-3 License)
|
||||
*
|
||||
* OpenViBE
|
||||
* Copyright (C) Inria, 2006-2019
|
||||
*
|
||||
* Authors
|
||||
*
|
||||
* 2019, Yannis Bendi-Ouis <yannis.bendiouis@gmail.com>
|
||||
* 2019, Jimmy Leblanc <jimmy.leblanc01@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
'''
|
||||
|
||||
from pandas import Series, DataFrame, read_csv
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from natsort import natsorted
|
||||
from PolyStimulations import Poly_stimulation
|
||||
import os
|
||||
import pickle
|
||||
import random
|
||||
import inspect
|
||||
|
||||
# Dans les settings :
|
||||
# - "Path directory" : path qui mène au directory de sauvegarde des données. Donc finir par un '/'.
|
||||
# - "Label_X" : Nom des labels, où X est un nombre. Il en faut autant qu'il y a de labels.
|
||||
# - "Several CSV" : Boolean ou string qui return "true" ou "false".
|
||||
# - "Number of folds" : Integer qui indique en combien de différents folds les data doivent être séparées.
|
||||
# - "Number of actions" : Integer qui indique le nombre d'actions à enregistrer lors d'une session.
|
||||
|
||||
#------------------------------------------------------------
|
||||
ACTION_DURATION = 12 # in seconds
|
||||
TAMPON_DURATION = 3 # in seconds
|
||||
BEGIN_RECORD = 2 # in seconds
|
||||
END_RECORD = ACTION_DURATION
|
||||
FREQ = 128
|
||||
NB_POINTS_ONE_RECORD = ACTION_DURATION * FREQ
|
||||
NB_POINTS_ONE_TAMPON = TAMPON_DURATION * FREQ
|
||||
|
||||
CHANNELS_NAME = ['AF3', 'F7', 'F3', 'FC5', 'T7', 'P7', 'O1', 'O2', 'P8', 'T8', 'FC6', 'F4', 'F8', 'AF4'] # 14
|
||||
CHANNELS_STIMULATION = ['Event Id', 'Event Date', 'Event Duration']
|
||||
|
||||
PREFIXE_STIM = 'OVPoly_'
|
||||
|
||||
#------------------------------------------------------------
|
||||
def ovdf(df, rewrite_stim=True):
|
||||
shape = df.shape
|
||||
timer = Series([float(i)/FREQ for i in range(shape[0])])
|
||||
epochs = Series([int(i/64) for i in range(shape[0])])
|
||||
|
||||
df.insert(0, 'Time:{}Hz'.format(FREQ), timer)
|
||||
df.insert(1, 'Epoch', epochs)
|
||||
|
||||
if rewrite_stim:
|
||||
df['Event Id'] = Series([None for i in range(shape[0])])
|
||||
df['Event Date'] = Series([None for i in range(shape[0])])
|
||||
df['Event Duration'] = Series([None for i in range(shape[0])])
|
||||
|
||||
else:
|
||||
# re-compute the time informations for stimulations
|
||||
stim = df['Event Id'].values.tolist()
|
||||
date = []
|
||||
duration = []
|
||||
for i, event_id in enumerate(stim):
|
||||
if not pd.isnull(event_id):
|
||||
date += [timer[i]]
|
||||
duration += [0]
|
||||
else:
|
||||
date += [None]
|
||||
duration += [None]
|
||||
df['Event Date'] = Series(date)
|
||||
df['Event Duration'] = Series(duration)
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
def get_stim_code_from_label(label):
|
||||
key = label.split('_')
|
||||
key = "_".join([w[0].upper() + w[1:] for w in key])
|
||||
key = PREFIXE_STIM + key
|
||||
return Poly_stimulation[key]
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
class DatasetCreator(OVBox):
|
||||
|
||||
#----------------------------------------
|
||||
def __init__(self):
|
||||
OVBox.__init__(self)
|
||||
self.dir_name = None
|
||||
self.url = None
|
||||
self.signalHeader = None
|
||||
self.labels_queue = None
|
||||
self.current_label = None
|
||||
|
||||
self.is_tampon = False
|
||||
self.several_csv = False
|
||||
|
||||
self.nb_fold = 0
|
||||
self.nb_action_per_session = 0
|
||||
|
||||
self.labels = []
|
||||
self.data_recorded = []
|
||||
self.labels_order = []
|
||||
self.dic_fold = {}
|
||||
self.dic_dicount = {}
|
||||
|
||||
#----------------------------------------
|
||||
def initialize(self):
|
||||
|
||||
def verify_labels_correct(self):
|
||||
for label in self.labels:
|
||||
try:
|
||||
get_stim_code_from_label(label)
|
||||
except KeyError:
|
||||
raise Exception('Label {} not defined in PolyStimulations. You may want to add it with the manager.'.format(label))
|
||||
|
||||
def get_labels(self):
|
||||
param_names = self.setting.keys()
|
||||
param_names = natsorted(param_names)
|
||||
for n in param_names:
|
||||
if 'Label_' in n:
|
||||
label = self.setting[n]
|
||||
label = label.replace(' ', '_')
|
||||
if len(label) > 0:
|
||||
self.labels += [label.lower()]
|
||||
|
||||
def init_dict(self):
|
||||
self.dic_fold = {'fold_{}'.format(i): None for i in range(1, self.nb_fold+1)}
|
||||
self.dic_dicount = {'fold_{}'.format(i): None for i in range(1, self.nb_fold+1)}
|
||||
|
||||
def retrieve_settings(self):
|
||||
|
||||
# On récupère la booleen indiquant si l'on souhaite plusieurs ou un seul csv par fold
|
||||
self.several_csv = self.setting['Several CSV']
|
||||
if self.several_csv == 'true':
|
||||
self.several_csv = True
|
||||
elif self.several_csv == 'false':
|
||||
self.several_csv = False
|
||||
# On récupère le path du directory où l'on créé les fold
|
||||
self.dir_name = self.setting['Path directory']
|
||||
if self.dir_name[-1] != '/':
|
||||
self.dir_name += '/'
|
||||
|
||||
# On récupère le nombre de fold
|
||||
self.nb_fold = int(self.setting['Number of folds'])
|
||||
# On récupère le nombre d'action à record par session
|
||||
self.nb_action_per_session = int(self.setting['Number of actions'])
|
||||
# On récupère les labels
|
||||
get_labels(self)
|
||||
|
||||
def verify_stim_output(self):
|
||||
# Verify that an output stim exist, otherwise prevent the user that the program won't stop
|
||||
flag = False
|
||||
for out in self.output:
|
||||
if out.type() == 'Stimulations':
|
||||
flag = True
|
||||
break
|
||||
|
||||
if not flag:
|
||||
print('WARNING : The DatasetCreator does not have any output Stimulation. The program may never stop.')
|
||||
|
||||
retrieve_settings(self)
|
||||
verify_stim_output(self)
|
||||
verify_labels_correct(self)
|
||||
init_dict(self)
|
||||
|
||||
self.verify_arborescence()
|
||||
self.prepare_session()
|
||||
self.new_record()
|
||||
|
||||
#----------------------------------------
|
||||
def process(self):
|
||||
# On parcours tous les inputs
|
||||
for inputIndex in range(len(self.input)):
|
||||
for chunkIndex in range(len(self.input[inputIndex])):
|
||||
|
||||
# Initialisation pour le signal
|
||||
if type(self.input[inputIndex][chunkIndex]) == OVStreamedMatrixHeader:
|
||||
self.header_received(inputIndex, chunkIndex)
|
||||
|
||||
# Traitement à effectuer pour chaque chunk reçu
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStreamedMatrixBuffer:
|
||||
self.chunk_received(inputIndex, chunkIndex)
|
||||
|
||||
# Fin du signal
|
||||
elif type(self.input[inputIndex][chunkIndex]) == OVStreamedMatrixEnd:
|
||||
self.end_received(inputIndex, chunkIndex)
|
||||
|
||||
#----------------------------------------
|
||||
def uninitialize(self):
|
||||
pass
|
||||
|
||||
# -------------- * ------------- * -------------
|
||||
|
||||
#----------------------------------------
|
||||
def header_received(self, inputIndex, chunkIndex):
|
||||
self.signalHeader = self.input[inputIndex].pop()
|
||||
|
||||
#----------------------------------------
|
||||
def chunk_received(self, inputIndex, chunkIndex):
|
||||
chunk = self.input[inputIndex].pop()
|
||||
|
||||
# Plusieurs lignes sont envoyées en même temps, il faut les séparer
|
||||
indices = [(len(CHANNELS_NAME)*i, len(CHANNELS_NAME)*(i+1)) for i in range(int(len(chunk)/len(CHANNELS_NAME)))]
|
||||
for begin, end in indices:
|
||||
self.data_recorded += [chunk[begin:end]]
|
||||
|
||||
# Fin d'un tampon
|
||||
if self.is_tampon and len(self.data_recorded) >= NB_POINTS_ONE_TAMPON:
|
||||
self.empty_tampon()
|
||||
self.new_record()
|
||||
|
||||
# Fin d'un record
|
||||
if not self.is_tampon and len(self.data_recorded) >= NB_POINTS_ONE_RECORD:
|
||||
if not self.end_record():
|
||||
self.end_of_session()
|
||||
self.end_of_box()
|
||||
|
||||
#----------------------------------------
|
||||
def end_received(self, inputIndex, chunkIndex):
|
||||
self.input[inputIndex].pop()
|
||||
print("Error : entry signal stoped.")
|
||||
self.end_of_box()
|
||||
|
||||
#----------------------------------------
|
||||
def end_of_box(self):
|
||||
indice = -1
|
||||
for i, out in enumerate(self.output):
|
||||
if out.type() == 'Stimulations':
|
||||
indice = i
|
||||
|
||||
if indice != -1:
|
||||
stimLabel = 'OVTK_StimulationId_ExperimentStop'
|
||||
stimCode = OpenViBE_stimulation[stimLabel]
|
||||
stimSet = OVStimulationSet(0, self.getCurrentTime())
|
||||
stimSet.append(OVStimulation(stimCode, self.getCurrentTime(), 0.))
|
||||
self.output[0].append(stimSet)
|
||||
|
||||
# -------------- * ------------- * -------------
|
||||
|
||||
#----------------------------------------
|
||||
def verify_arborescence(self):
|
||||
# On vérifie que chaque dossier du path existe, sinon on les créé
|
||||
# et on vérifie les dicount
|
||||
|
||||
def verify_dir(self):
|
||||
# On vérifie que le dossier existe et ses sous-dossiers, sinon on les créé
|
||||
if not os.path.exists(self.dir_name):
|
||||
os.mkdir(self.dir_name, 0o775)
|
||||
|
||||
def verify_folds(self):
|
||||
# On vérifie que les dossiers des différents folds existent, sinon on les créés
|
||||
for i in range(1, self.nb_fold+1):
|
||||
name = self.dir_name + 'fold_{}/'.format(i)
|
||||
if not os.path.exists(name):
|
||||
os.mkdir(name, 0o775)
|
||||
|
||||
def verify_and_load_dicount(self):
|
||||
# On vérifie que les fichiers contenant les compteurs par label existent, sinon on les créé
|
||||
for i in range(1, self.nb_fold+1):
|
||||
fold = 'fold_{}'.format(i)
|
||||
filename = self.dir_name + fold + '/dicount.pick'
|
||||
|
||||
if not os.path.isfile(filename):
|
||||
dicount = {l: 0 for l in self.labels}
|
||||
self.dic_dicount[fold] = dicount
|
||||
pickle.dump(dicount, open(filename, 'wb'))
|
||||
else:
|
||||
self.dic_dicount[fold] = pickle.load(open(filename, 'rb'))
|
||||
|
||||
verify_dir(self)
|
||||
verify_folds(self)
|
||||
verify_and_load_dicount(self)
|
||||
|
||||
#----------------------------------------
|
||||
def prepare_session(self):
|
||||
|
||||
def create_labels_queue(self):
|
||||
nb_label = len(self.labels)
|
||||
nb_total = int(self.nb_action_per_session / nb_label) # in Python 3 / create float automatically and range hate that
|
||||
nb_reste = self.nb_action_per_session - nb_total*nb_label
|
||||
|
||||
choice_label = []
|
||||
tmp = [l for l in self.labels]
|
||||
for _ in range(nb_reste):
|
||||
l = random.choice(tmp)
|
||||
tmp.remove(l)
|
||||
choice_label += [l]
|
||||
|
||||
tmp = [l for l in self.labels]
|
||||
self.labels_queue = tmp*nb_total + choice_label
|
||||
random.shuffle(self.labels_queue)
|
||||
|
||||
# Prepare la suite aléatoire d'action a exectuer
|
||||
create_labels_queue(self)
|
||||
|
||||
# Initialise self.dic_fold
|
||||
for key in self.dic_fold.keys():
|
||||
self.dic_fold[key] = {l: [] for l in self.labels}
|
||||
|
||||
#----------------------------------------
|
||||
def empty_tampon(self):
|
||||
# Supprime les données tampons entre deux records
|
||||
self.is_tampon = False
|
||||
end = TAMPON_DURATION * FREQ
|
||||
self.data_recorded = self.data_recorded[end:]
|
||||
|
||||
#----------------------------------------
|
||||
def new_record(self):
|
||||
# Prevent the user a new record begin
|
||||
if len(self.labels_queue) > 0:
|
||||
self.current_label = self.labels_queue.pop(0)
|
||||
print('Current label : {}'.format(self.current_label))
|
||||
|
||||
#----------------------------------------
|
||||
def end_record(self):
|
||||
# Démarre un nouvel enregistrement de 10 sec. Si le dernier est fini, l'enregistre.
|
||||
# Return True s'il y a encore d'autres label à étudié pour la session, False sinon.
|
||||
|
||||
def retrieve_record(self):
|
||||
|
||||
def add_to_fold(self, data, label):
|
||||
# Ajoute les éléments dans la liste data au dic_fold label et mets à jour dic_dicount
|
||||
print('hello', self.dic_dicount)
|
||||
tmp = [(key, value[label]) for key, value in self.dic_dicount.items()]
|
||||
fold = min(tmp, key=lambda x: x[1])[0]
|
||||
self.dic_fold[fold][label] += [data]
|
||||
self.dic_dicount[fold][label] += len(data)
|
||||
self.labels_order += [label]
|
||||
|
||||
# Extract the 10s recorded
|
||||
record = self.data_recorded[:NB_POINTS_ONE_RECORD]
|
||||
self.data_recorded = self.data_recorded[NB_POINTS_ONE_RECORD:]
|
||||
|
||||
# Extract data between begin and end
|
||||
begin = FREQ*BEGIN_RECORD
|
||||
end = FREQ*END_RECORD
|
||||
data = record[begin:end]
|
||||
add_to_fold(self, data, self.current_label)
|
||||
|
||||
# End record
|
||||
print('Stop.')
|
||||
|
||||
retrieve_record(self)
|
||||
self.is_tampon = True
|
||||
|
||||
return len(self.labels_queue) > 0
|
||||
|
||||
#----------------------------------------
|
||||
def end_of_session(self):
|
||||
|
||||
def maj_dicount(self, fold):
|
||||
filename = self.dir_name + fold + '/dicount.pick'
|
||||
dicount = self.dic_dicount[fold]
|
||||
pickle.dump(dicount, open(filename, 'wb'))
|
||||
|
||||
def add_label_stimulation(self, data, label):
|
||||
# Add the stimulations indicating the begginning of a label
|
||||
length = len(data)
|
||||
event_id = [None for _ in range(length)]
|
||||
event_date = [None for _ in range(length)]
|
||||
event_duration = [None for _ in range(length)]
|
||||
event_id[0] = get_stim_code_from_label(label)
|
||||
|
||||
dict_event = {"Event Id": event_id, "Event Date": event_date, "Event Duration": event_duration}
|
||||
dict_data = {c: np.array(data)[:, i].tolist() for i, c in enumerate(CHANNELS_NAME)}
|
||||
dict_data.update(dict_event)
|
||||
|
||||
return dict_data
|
||||
|
||||
def append_data_to_csv(self, data, fold, label, several_csv=False):
|
||||
# Create all csv, either you can us one CSV with stimulations, either one CSV per label
|
||||
if several_csv:
|
||||
filename = self.dir_name + fold + '/' + label + '.csv'
|
||||
columns = CHANNELS_NAME
|
||||
else:
|
||||
filename = self.dir_name + fold + '/' + fold + '.csv'
|
||||
columns = CHANNELS_NAME + CHANNELS_STIMULATION
|
||||
data = add_label_stimulation(self, data, label)
|
||||
|
||||
old_df = DataFrame()
|
||||
if os.path.isfile(filename):
|
||||
old_df = read_csv(filename).filter(columns)
|
||||
|
||||
add_df = DataFrame(data, columns=columns)
|
||||
new_df = old_df.append(add_df, ignore_index=True)
|
||||
|
||||
ovdf(new_df, rewrite_stim=several_csv)
|
||||
new_df.to_csv(filename, index=False)
|
||||
labels_count = {label: 0 for label in self.labels}
|
||||
|
||||
self.labels_order = {'fold_{}'.format(n): self.labels_order[self.nb_action_per_session*i: self.nb_action_per_session*(i+1)]
|
||||
for i in range(self.nb_fold) for n in range(1, self.nb_fold+1)}
|
||||
|
||||
for i in range(1, self.nb_fold+1):
|
||||
fold = 'fold_{}'.format(i)
|
||||
|
||||
for label in self.labels_order[fold]:
|
||||
count = labels_count[label]
|
||||
data = self.dic_fold[fold][label][count]
|
||||
labels_count[label] += 1
|
||||
append_data_to_csv(self, data, fold, label, several_csv=self.several_csv)
|
||||
|
||||
maj_dicount(self, fold)
|
||||
|
||||
|
||||
box = DatasetCreator()
|
||||
@@ -0,0 +1,107 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pyriemann.classification import MDM
|
||||
from pyriemann.tangentspace import TangentSpace
|
||||
from pyriemann.estimation import Covariances
|
||||
from sklearn.pipeline import make_pipeline
|
||||
from sklearn.tree import DecisionTreeClassifier
|
||||
from sklearn.linear_model import LogisticRegression, SGDClassifier
|
||||
from sklearn.neural_network import MLPClassifier
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
|
||||
from sklearn.naive_bayes import GaussianNB
|
||||
from sklearn.svm import SVC
|
||||
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, ExtraTreesClassifier, BaggingClassifier
|
||||
from sklearn.neighbors import KNeighborsClassifier, NearestCentroid
|
||||
from sklearn.metrics import confusion_matrix, classification_report
|
||||
from collections import defaultdict
|
||||
import numpy as np
|
||||
import pickle
|
||||
import os
|
||||
from PolyBox import PolyBox
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
class ProcessML(PolyBox):
|
||||
|
||||
#----------------------------------------
|
||||
def __init__(self):
|
||||
PolyBox.__init__(self, record=False)
|
||||
self.model_path = None
|
||||
self.pred_saving_path = None
|
||||
self.model = None
|
||||
self.predictions = []
|
||||
self.shape = None
|
||||
|
||||
#----------------------------------------
|
||||
def on_initialize(self):
|
||||
# we get the model file
|
||||
self.model_path = self.setting['Model filename']
|
||||
|
||||
# we load the model
|
||||
try:
|
||||
self.model = pickle.load(open(self.model_path, 'rb'))
|
||||
except IOError as err:
|
||||
print(err)
|
||||
print('Please indicate an existing model.')
|
||||
self.send_end_stim()
|
||||
|
||||
try:
|
||||
self.pred_saving_path = self.setting['Predictions filename']
|
||||
if len(self.pred_saving_path.replace(' ', '')) > 0:
|
||||
self.pred_saving_path = os.path.abspath(self.pred_saving_path)
|
||||
except IOError:
|
||||
print('No filename to save predictions has been given, they will not be saved')
|
||||
|
||||
#----------------------------------------
|
||||
def on_end_box(self):
|
||||
self.save_preds()
|
||||
self.make_stats()
|
||||
|
||||
#----------------------------------------
|
||||
def list_to_str(self, preds):
|
||||
string = ''
|
||||
for x in preds:
|
||||
string += str(x) + ','
|
||||
return string
|
||||
|
||||
#----------------------------------------
|
||||
def save_preds(self):
|
||||
|
||||
if self.pred_saving_path is not None and self.pred_saving_path != "":
|
||||
|
||||
preds_str = self.list_to_str(self.predictions)
|
||||
|
||||
with open(self.pred_saving_path, 'wb') as file:
|
||||
file.write(preds_str)
|
||||
print('Predictions saved in {}\n'.format(self.pred_saving_path))
|
||||
|
||||
#----------------------------------------
|
||||
def on_chunk_received(self, chunk, label, shape):
|
||||
|
||||
chunk = np.array(chunk)
|
||||
|
||||
if self.shape is None:
|
||||
# Riemanian Geometry
|
||||
if self.model.custom_classifier == 'Riemann Minimum Distance to Mean' or self.model.custom_classifier == 'Riemann Tangent Space':
|
||||
self.shape = (1, shape[0], shape[1])
|
||||
else:
|
||||
self.shape = (1, chunk.shape[0])
|
||||
|
||||
chunk = chunk.reshape(self.shape)
|
||||
pred = self.model.predict(chunk)
|
||||
|
||||
self.predictions += list(pred)
|
||||
|
||||
#----------------------------------------
|
||||
def make_stats(self):
|
||||
|
||||
length = len(self.predictions)
|
||||
dictpred = defaultdict(int)
|
||||
|
||||
for elem in self.predictions:
|
||||
dictpred[elem] += 1
|
||||
print("Metrics : \n")
|
||||
print('\n'.join(['{} : {}'.format(l, float(v)/length) for l, v in dictpred.items()]))
|
||||
|
||||
|
||||
box = ProcessML()
|
||||
@@ -0,0 +1,247 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pyriemann.classification import MDM
|
||||
from pyriemann.tangentspace import TangentSpace
|
||||
from pyriemann.estimation import Covariances
|
||||
import time
|
||||
from sklearn.pipeline import make_pipeline
|
||||
from sklearn.tree import DecisionTreeClassifier
|
||||
from sklearn.linear_model import LogisticRegression, SGDClassifier
|
||||
from sklearn.neural_network import MLPClassifier
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
|
||||
from sklearn.naive_bayes import GaussianNB
|
||||
from sklearn.svm import LinearSVC
|
||||
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier, ExtraTreesClassifier, BaggingClassifier
|
||||
from sklearn.neighbors import KNeighborsClassifier, NearestCentroid
|
||||
from sklearn.metrics import confusion_matrix, classification_report
|
||||
from natsort import natsorted
|
||||
import random
|
||||
import pickle
|
||||
import numpy as np
|
||||
from collections import defaultdict
|
||||
from PolyBox import PolyBox
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
|
||||
#----------------------------------------
|
||||
def train_test_split(data_dict, test_size=0.2):
|
||||
def create_xy(data_dict):
|
||||
# used to shuffle data in a way that prevent any training data to be in the test set
|
||||
y = np.array([])
|
||||
for label in data_dict:
|
||||
y_tmp = np.array([label for _ in data_dict[label]])
|
||||
y = np.concatenate((y, y_tmp))
|
||||
|
||||
array = []
|
||||
for label in data_dict:
|
||||
array.append(data_dict[label])
|
||||
|
||||
x = np.concatenate(array, axis=0)
|
||||
# shuffling
|
||||
permutation = np.random.permutation(x.shape[0])
|
||||
|
||||
permut = True
|
||||
if permut:
|
||||
x = x[permutation]
|
||||
y = y[permutation]
|
||||
|
||||
return x, y
|
||||
|
||||
dict_train = {}
|
||||
dict_test = {}
|
||||
|
||||
for key, data in data_dict.items():
|
||||
icut = int(len(data)*test_size)
|
||||
dict_test[key] = data[:icut]
|
||||
dict_train[key] = data[icut:]
|
||||
|
||||
x_train, y_train = create_xy(dict_train)
|
||||
x_test, y_test = create_xy(dict_test)
|
||||
|
||||
return np.array(x_train), np.array(y_train), np.array(x_test), np.array(y_test)
|
||||
|
||||
|
||||
#----------------------------------------
|
||||
class TrainerML(PolyBox):
|
||||
|
||||
#----------------------------------------
|
||||
# is exec first
|
||||
def __init__(self):
|
||||
PolyBox.__init__(self)
|
||||
self.model_path = None
|
||||
self.config_path = None
|
||||
self.save_path = None
|
||||
self.model = None
|
||||
self.clf = None
|
||||
self.config = None
|
||||
self.std_settings = []
|
||||
self.clf_dependant_settings = None
|
||||
|
||||
#----------------------------------------
|
||||
def on_initialize(self):
|
||||
|
||||
try:
|
||||
self.model_path = self.setting['Filename to save model to']
|
||||
except KeyError:
|
||||
self.model_path = ''
|
||||
if self.model_path == '':
|
||||
print('No correct file location has been given for saving the model, thus it won\'t be saved')
|
||||
|
||||
try:
|
||||
self.test_set_share = float(self.setting['Test set share'])
|
||||
|
||||
# wrong value
|
||||
diff = (1 - self.test_set_share)
|
||||
if diff <= 0 or diff > 1:
|
||||
self.test_set_share = 0
|
||||
print('The value of the test set share must be between 0 and 1 (1 not included), no prediction will be performed')
|
||||
|
||||
except KeyError:
|
||||
self.test_set_share = 0
|
||||
print('The value of the test set share must be between 0 and 1 (1 not included), no prediction will be performed')
|
||||
|
||||
try:
|
||||
self.save_path = self.setting['Filename to load model from']
|
||||
self.model = pickle.load(open(self.save_path, 'rb'))
|
||||
except KeyError:
|
||||
self.save_path = ''
|
||||
print('No correct location has been given to load the model from, thus a new model will be created.')
|
||||
|
||||
# if model doesn't exist we will init a new one with params from the box
|
||||
# FileNotFoundError doesn't exist in Python 2.7
|
||||
except IOError:
|
||||
print('No correct location has been given to load the model from, thus a new model will be created.')
|
||||
|
||||
# special case for Riemannian Geometry because it needs a pipeline
|
||||
clf = self.setting['Classifier']
|
||||
|
||||
try:
|
||||
discriminator, _ = self.map_clf(self.setting['Discriminator'])
|
||||
except KeyError:
|
||||
discriminator = None
|
||||
|
||||
if clf == 'Riemann Tangent Space':
|
||||
|
||||
if discriminator is not None:
|
||||
self.clf = make_pipeline(Covariances(), TangentSpace(metric='riemann'), discriminator())
|
||||
else:
|
||||
self.clf = make_pipeline(Covariances(), TangentSpace(metric='riemann'), LinearDiscriminantAnalysis())
|
||||
|
||||
elif clf == 'Riemann Minimum Distance to Mean':
|
||||
if discriminator is not None:
|
||||
self.clf = make_pipeline(Covariances(), MDM(metric=dict(mean='riemann', distance='riemann')), discriminator())
|
||||
else:
|
||||
self.clf = make_pipeline(Covariances(), MDM(metric=dict(mean='riemann', distance='riemann')))
|
||||
|
||||
else:
|
||||
self.clf, _ = self.map_clf(clf)
|
||||
self.init_params()
|
||||
|
||||
try:
|
||||
self.clf = self.clf(**self.clf_dependant_settings)
|
||||
except TypeError:
|
||||
self.clf = self.clf()
|
||||
|
||||
#----------------------------------------
|
||||
def init_params(self):
|
||||
|
||||
# default settings
|
||||
self.std_settings = ['Classifier', 'Discriminator', 'Filename to load model from', 'Test set share',
|
||||
'Filename to save configuration to', 'Filename to save model to', 'Clock frequency (Hz)', 'Labels']
|
||||
settings = [key for key in self.setting.keys()]
|
||||
|
||||
# we get only settings that are clf relevant
|
||||
clf_dependant_settings = list(set(settings) - set(self.std_settings))
|
||||
clf_dependant_settings = dict((k, v) for k, v in self.setting.items() if (k in clf_dependant_settings and len(v) > 0))
|
||||
|
||||
# we convert values that need to be
|
||||
for k, v in clf_dependant_settings.items():
|
||||
|
||||
try:
|
||||
expr = eval(v)
|
||||
clf_dependant_settings[k] = expr
|
||||
except:
|
||||
if v.lower() == 'true':
|
||||
clf_dependant_settings[k] = True
|
||||
elif v.lower() == 'false':
|
||||
clf_dependant_settings[k] = False
|
||||
elif v.lower() == 'none':
|
||||
clf_dependant_settings[k] = None
|
||||
else:
|
||||
pass
|
||||
|
||||
self.clf_dependant_settings = clf_dependant_settings
|
||||
|
||||
#----------------------------------------
|
||||
def map_clf(self, classifier):
|
||||
"""
|
||||
Returns the correct algorithm according to the classifier string
|
||||
"""
|
||||
|
||||
switcher = {
|
||||
'': None,
|
||||
'None': None,
|
||||
'Nearest Centroid': NearestCentroid,
|
||||
'Nearest Neighbors Classifier': KNeighborsClassifier,
|
||||
'Gaussian Naive Bayes': GaussianNB,
|
||||
'Stochastic Gradient Descent': SGDClassifier,
|
||||
'Logistic Regression': LogisticRegression,
|
||||
'Decision Tree Classifier': DecisionTreeClassifier,
|
||||
'Extra Trees': ExtraTreesClassifier,
|
||||
'Bagging': BaggingClassifier,
|
||||
'Random Forest': RandomForestClassifier,
|
||||
'Support Vector Machine': LinearSVC,
|
||||
'Linear Discriminant Analysis': LinearDiscriminantAnalysis,
|
||||
'AdaBoost': AdaBoostClassifier,
|
||||
'Multi Layer Perceptron': MLPClassifier,
|
||||
'Linear SVC': LinearSVC,
|
||||
}
|
||||
clf = switcher.get(classifier, lambda: 'unknown classifier')
|
||||
return clf, switcher
|
||||
|
||||
#----------------------------------------
|
||||
def on_chunk_received(self, chunk, label, shape):
|
||||
|
||||
# special case for riemannian geometry
|
||||
if self.setting['Classifier'] == 'Riemann Minimum Distance to Mean' or self.setting['Classifier'] == 'Riemann Tangent Space':
|
||||
numpyBuffer = np.array(chunk).reshape(shape)
|
||||
self.data[label][-1] = numpyBuffer
|
||||
|
||||
#----------------------------------------
|
||||
def on_end_box(self):
|
||||
try:
|
||||
self.train()
|
||||
self.save()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.send_end_stim()
|
||||
|
||||
#----------------------------------------
|
||||
def train(self):
|
||||
x_train, y_train, x_test, y_test = train_test_split(self.data, self.test_set_share)
|
||||
|
||||
if self.model != None:
|
||||
self.clf = self.model
|
||||
|
||||
self.clf.fit(x_train, y_train)
|
||||
|
||||
# to be used in ProcessML
|
||||
self.clf.custom_classifier = self.setting['Classifier']
|
||||
|
||||
if x_test.shape[0] > 0:
|
||||
predictions = self.clf.predict(x_test)
|
||||
report = classification_report(y_test, predictions, labels=list(self.data.keys()))
|
||||
matrix = confusion_matrix(y_test, predictions)
|
||||
|
||||
print("Report :\n{}\n".format(report))
|
||||
print("Confusion Matrix : \n{}\n".format(matrix))
|
||||
print("Fin de l'entrainement...")
|
||||
|
||||
#----------------------------------------
|
||||
def save(self):
|
||||
if self.model_path != "":
|
||||
pickle.dump(self.clf, open(self.model_path, 'wb'))
|
||||
print('Model saved in {}\n'.format(self.model_path))
|
||||
|
||||
|
||||
box = TrainerML()
|
||||
@@ -0,0 +1,120 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file ovpADA.h
|
||||
/// \brief Class NewBoxPattern
|
||||
/// \author Thibaut Monseigne (Inria) & Jimmy Leblanc (Polymont) & Yannis Bendi-Ouis (Polymont)
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/%22%3EGNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
// Windows debug build doesn't typically link as most people don't have the python debug library.
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#include "defines.hpp"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
/// <summary> Enumeration of Adaptation Methods for classifier. </summary>
|
||||
enum class EClassifier
|
||||
{
|
||||
NearestCentroid, NearestNeighbors, GaussianNaiveBayes, StochasticGradientDescent, LogisticRegression, DecisionTree, ExtraTrees,
|
||||
Bagging, RandomForest, SVM, LDA, AdaBoost, MultiLayerPerceptron, MDM, TangentSpace, None
|
||||
};
|
||||
|
||||
/// <summary> Convert classifier to string.</summary>
|
||||
/// <param name="type"> The type of classifier.</param>
|
||||
/// <returns> std::string </returns>
|
||||
inline std::string toString(const EClassifier type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case EClassifier::None: return "None";
|
||||
case EClassifier::NearestCentroid: return "Nearest Centroid";
|
||||
case EClassifier::NearestNeighbors: return "Nearest Neighbors";
|
||||
case EClassifier::GaussianNaiveBayes: return "Gaussian Naive Bayes";
|
||||
case EClassifier::StochasticGradientDescent: return "Stochastic Gradient Descent";
|
||||
case EClassifier::LogisticRegression: return "Logistic Regression";
|
||||
case EClassifier::DecisionTree: return "Decision Tree";
|
||||
case EClassifier::ExtraTrees: return "Extra Trees";
|
||||
case EClassifier::Bagging: return "Bagging";
|
||||
case EClassifier::RandomForest: return "Random Forest";
|
||||
case EClassifier::SVM: return "Support Vector Machine";
|
||||
case EClassifier::LDA: return "Linear Discriminant Analysis";
|
||||
case EClassifier::AdaBoost: return "AdaBoost";
|
||||
case EClassifier::MultiLayerPerceptron: return "Multi Layer Perceptron";
|
||||
case EClassifier::MDM: return "Riemann Minimum Distance to Mean";
|
||||
case EClassifier::TangentSpace: return "Riemann Tangent Space";
|
||||
default: return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
class CPolyBox : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
void release() override { delete this; }
|
||||
|
||||
uint64_t getClockFrequency() override { return m_clockFrequency << 32; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool processInput(size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
protected:
|
||||
|
||||
uint64_t m_clockFrequency = 0;
|
||||
CString m_script;
|
||||
|
||||
std::vector<Toolkit::TDecoder<CPolyBox>*> m_decoders;
|
||||
std::vector<Toolkit::TEncoder<CPolyBox>*> m_encoders;
|
||||
|
||||
// These are all borrowed references in python v2.7. Do not free them.
|
||||
static bool m_isInitialized;
|
||||
|
||||
static PyObject *m_mainModule, *m_mainDictionnary;
|
||||
static PyObject *m_matrixHeader, *m_matrixBuffer, *m_matrixEnd;
|
||||
static PyObject *m_signalHeader, *m_signalBuffer, *m_signalEnd;
|
||||
static PyObject *m_stimulationHeader, *m_stimulation, *m_stimulationSet, *m_stimulationEnd;
|
||||
static PyObject* m_buffer;
|
||||
static PyObject* m_execFileFunction;
|
||||
static PyObject *m_stdout, *m_stderr;
|
||||
|
||||
|
||||
//std::map<char,PyObject *> m_PyObjectMap;
|
||||
PyObject *m_box = nullptr, *m_boxInput = nullptr, *m_boxOutput = nullptr, *m_boxSetting = nullptr, *m_boxTime = nullptr;
|
||||
PyObject *m_boxInitialize = nullptr, *m_boxProcess = nullptr, *m_boxUninitialize = nullptr;
|
||||
bool m_initializeSucceeded = false;
|
||||
|
||||
|
||||
bool logSysStd(const bool out);
|
||||
bool logSysStdout() { return logSysStd(true); }
|
||||
bool logSysStderr() { return logSysStd(false); }
|
||||
void buildPythonSettings();
|
||||
|
||||
bool initializePythonSafely();
|
||||
bool transferStreamedMatrixInputChunksToPython(const size_t index);
|
||||
bool transferStreamedMatrixOutputChunksFromPython(const size_t index);
|
||||
bool transferSignalInputChunksToPython(const size_t index);
|
||||
bool transferSignalOutputChunksFromPython(const size_t index);
|
||||
bool transferStimulationInputChunksToPython(const size_t index);
|
||||
bool transferStimulationOutputChunksFromPython(const size_t index);
|
||||
};
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
@@ -0,0 +1,99 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file DataViz.hpp
|
||||
/// \brief Class NewBoxPattern
|
||||
/// \author Thibaut Monseigne (Inria) & Jimmy Leblanc (Polymont) & Yannis Bendi-Ouis (Polymont)
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/%22%3EGNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "CPolyBox.hpp"
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
class CBoxAlgorithmDataViz final : public CPolyBox
|
||||
{
|
||||
public:
|
||||
CBoxAlgorithmDataViz() { m_script = Directories::getDataDir() + "/plugins/python3/pybox/DataViz.py"; }
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxAlgorithm < OpenViBE::Plugins::IBoxAlgorithm >, OVP_ClassId_BoxAlgorithm_DataViz)
|
||||
};
|
||||
|
||||
class CBoxAlgorithmDataVizListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setInputType(index, OV_TypeId_StreamedMatrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxListener < OpenViBE::Plugins::IBoxListener >, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmDataVizDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("DataViz"); }
|
||||
CString getAuthorName() const override { return CString("Yannis Bendi-Ouis & Jimmy Leblanc"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Polymont IT Services"); }
|
||||
CString getShortDescription() const override { return CString("Transform the data with a LDA or a PCA and plot the data in 2D or 3D."); }
|
||||
CString getDetailedDescription() const override { return CString(""); }
|
||||
CString getCategory() const override { return CString("Scripting/PyBox"); }
|
||||
CString getVersion() const override { return CString("0.1"); }
|
||||
CString getStockItemName() const override { return CString("gtk-convert"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_DataViz; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmDataViz; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmDataVizListener; }
|
||||
void releaseBoxListener(IBoxListener* pBoxListener) const override { delete pBoxListener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addSetting("Clock frequency (Hz)", OV_TypeId_Integer, "64");
|
||||
// <tag> settings
|
||||
prototype.addSetting("Path to save the model", OV_TypeId_Filename, "");
|
||||
prototype.addSetting("Path to load the model", OV_TypeId_Filename, "");
|
||||
prototype.addSetting("Algorithm (PCA or LDA)", OV_TypeId_String, "PCA");
|
||||
prototype.addSetting("Dimension reduction", OV_TypeId_Integer, "2");
|
||||
prototype.addSetting("Labels", OV_TypeId_String, "");
|
||||
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddSetting);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifySetting);
|
||||
|
||||
prototype.addInputSupport(OV_TypeId_Signal);
|
||||
prototype.addInputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
prototype.addOutputSupport(OV_TypeId_Signal);
|
||||
prototype.addOutputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
// <tag> input & output
|
||||
prototype.addOutput("stim_out", OV_TypeId_Stimulations);
|
||||
prototype.addInput("input_StreamMatrix", OV_TypeId_StreamedMatrix);
|
||||
prototype.addInput("input_Stimulations", OV_TypeId_Stimulations);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_DataVizDesc)
|
||||
};
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
@@ -0,0 +1,101 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file DatasetCreator.hpp
|
||||
/// \brief Class NewBoxPattern
|
||||
/// \author Thibaut Monseigne (Inria) & Jimmy Leblanc (Polymont) & Yannis Bendi-Ouis (Polymont)
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/%22%3EGNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "CPolyBox.hpp"
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
class CBoxAlgorithmDatasetCreator final : public CPolyBox
|
||||
{
|
||||
public:
|
||||
CBoxAlgorithmDatasetCreator() { m_script = Directories::getDataDir() + "/plugins/python3/pybox/DatasetCreator.py"; }
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxAlgorithm < OpenViBE::Plugins::IBoxAlgorithm >, OVP_ClassId_BoxAlgorithm_DatasetCreator)
|
||||
};
|
||||
|
||||
class CBoxAlgorithmDatasetCreatorListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setInputType(index, OV_TypeId_StreamedMatrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxListener < OpenViBE::Plugins::IBoxListener >, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmDatasetCreatorDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("DatasetCreator"); }
|
||||
CString getAuthorName() const override { return CString("Yannis Bendi-Ouis & Jimmy LeBlanc"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Polymont IT Services"); }
|
||||
CString getShortDescription() const override { return CString("Monitor the user to create a dataset."); }
|
||||
CString getDetailedDescription() const override { return CString(""); }
|
||||
CString getCategory() const override { return CString("Scripting/PyBox"); }
|
||||
CString getVersion() const override { return CString("0.1"); }
|
||||
CString getStockItemName() const override { return CString("gtk-convert"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_DatasetCreator; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmDatasetCreator; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmDatasetCreatorListener; }
|
||||
void releaseBoxListener(IBoxListener* pBoxListener) const override { delete pBoxListener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addSetting("Clock frequency (Hz)", OV_TypeId_Integer, "64");
|
||||
// <tag> settings
|
||||
prototype.addSetting("Path directory", OV_TypeId_Filename, "${Player_ScenarioDirectory}/datas/");
|
||||
prototype.addSetting("Label_1", OV_TypeId_String, "right");
|
||||
prototype.addSetting("Label_2", OV_TypeId_String, "left");
|
||||
prototype.addSetting("Label_3", OV_TypeId_String, "up");
|
||||
prototype.addSetting("Label_4", OV_TypeId_String, "down");
|
||||
prototype.addSetting("Several CSV", OV_TypeId_Boolean, "false");
|
||||
prototype.addSetting("Number of folds", OV_TypeId_Integer, "1");
|
||||
prototype.addSetting("Number of actions", OV_TypeId_Integer, "4");
|
||||
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddSetting);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifySetting);
|
||||
|
||||
prototype.addInputSupport(OV_TypeId_Signal);
|
||||
prototype.addInputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
prototype.addOutputSupport(OV_TypeId_Signal);
|
||||
prototype.addOutputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
// <tag> input & output
|
||||
prototype.addOutput("stim_out", OV_TypeId_Stimulations);
|
||||
prototype.addInput("input_StreamMatrix", OV_TypeId_StreamedMatrix);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_DatasetCreatorDesc)
|
||||
};
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
@@ -0,0 +1,98 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file ProcessML.hpp
|
||||
/// \brief Class NewBoxPattern
|
||||
/// \author Thibaut Monseigne (Inria) & Jimmy Leblanc (Polymont) & Yannis Bendi-Ouis (Polymont)
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/%22%3EGNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "CPolyBox.hpp"
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
class CBoxAlgorithmProcessML final : public CPolyBox
|
||||
{
|
||||
public:
|
||||
CBoxAlgorithmProcessML() { m_script = Directories::getDataDir() + "/plugins/python3/pybox/ProcessML.py"; }
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxAlgorithm < OpenViBE::Plugins::IBoxAlgorithm >, OVP_ClassId_BoxAlgorithm_ProcessML)
|
||||
};
|
||||
|
||||
class CBoxAlgorithmProcessMLListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setInputType(index, OV_TypeId_StreamedMatrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Toolkit::TBoxListener < OpenViBE::Plugins::IBoxListener >, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmProcessMLDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("Process Sklearn"); }
|
||||
CString getAuthorName() const override { return CString("Jimmy Leblanc & Yannis Bendi-Ouis"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Polymont IT Services"); }
|
||||
CString getShortDescription() const override
|
||||
{
|
||||
return CString("This box aim to use a machine learning model previously trained to predict labels of input's data.");
|
||||
}
|
||||
CString getDetailedDescription() const override { return CString(""); }
|
||||
CString getCategory() const override { return CString("Scripting/PyBox"); }
|
||||
CString getVersion() const override { return CString("0.1"); }
|
||||
CString getStockItemName() const override { return CString("gtk-convert"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_ProcessML; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmProcessML; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmProcessMLListener; }
|
||||
void releaseBoxListener(IBoxListener* pBoxListener) const override { delete pBoxListener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addSetting("Clock frequency (Hz)", OV_TypeId_Integer, "64");
|
||||
// <tag> settings
|
||||
prototype.addSetting("Model filename", OV_TypeId_Filename, "${Player_ScenarioDirectory}/model.clf");
|
||||
prototype.addSetting("Predictions filename", OV_TypeId_Filename, "");
|
||||
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifyInput);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddSetting);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanModifySetting);
|
||||
|
||||
prototype.addInputSupport(OV_TypeId_Signal);
|
||||
prototype.addInputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
prototype.addOutputSupport(OV_TypeId_Signal);
|
||||
prototype.addOutputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
// <tag> input & output
|
||||
prototype.addOutput("stim_out", OV_TypeId_Stimulations);
|
||||
prototype.addInput("input_StreamMatrix", OV_TypeId_StreamedMatrix);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_ProcessMLDesc)
|
||||
};
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
@@ -0,0 +1,257 @@
|
||||
#include "TrainerML.hpp"
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> ADA_BOOST_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("n_estimators", OV_TypeId_Integer, "50"),
|
||||
std::make_tuple("learning_rate", OV_TypeId_Float, "1.0"),
|
||||
std::make_tuple("algorithm", OVPoly_ClassId_ADA_algorithm, "SAMME.R"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> BAGGING_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("max_features", OV_TypeId_Float, "1.0"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None"),
|
||||
std::make_tuple("n_estimators", OV_TypeId_Integer, "10"),
|
||||
std::make_tuple("bootstrap", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("bootstrap_features", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("oob_score", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("warm_start", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("n_jobs", OV_TypeId_String, "None"),
|
||||
std::make_tuple("verbose", OV_TypeId_Integer, "0")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> TREE_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("criterion", OVPoly_ClassId_Criterion, "gini"),
|
||||
std::make_tuple("splitter", OVPoly_ClassId_DecisionTree_splitter, "best"),
|
||||
std::make_tuple("max_depth", OV_TypeId_String, "None"),
|
||||
std::make_tuple("min_samples_split", OV_TypeId_Float, "2"),
|
||||
std::make_tuple("min_samples_leaf", OV_TypeId_Float, "1"),
|
||||
std::make_tuple("min_weight_fraction_leaf", OV_TypeId_Float, "0"),
|
||||
std::make_tuple("max_features", OV_TypeId_String, "None"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None"),
|
||||
std::make_tuple("max_leaf_nodes", OV_TypeId_String, "None"),
|
||||
std::make_tuple("min_impurity_decrease", OV_TypeId_Float, "0"),
|
||||
std::make_tuple("min_impurity_split", OV_TypeId_Float, "1e-7")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> XTREE_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("criterion", OVPoly_ClassId_Criterion, "gini"),
|
||||
std::make_tuple("max_depth", OV_TypeId_String, "None"),
|
||||
std::make_tuple("min_samples_split", OV_TypeId_Float, "2"),
|
||||
std::make_tuple("min_samples_leaf", OV_TypeId_Float, "1"),
|
||||
std::make_tuple("min_weight_fraction_leaf", OV_TypeId_Float, "0"),
|
||||
std::make_tuple("max_features", OV_TypeId_String, "auto"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None"),
|
||||
std::make_tuple("max_leaf_nodes", OV_TypeId_String, "None"),
|
||||
std::make_tuple("min_impurity_decrease", OV_TypeId_Float, "0"),
|
||||
std::make_tuple("min_impurity_split", OV_TypeId_Float, "1e-7"),
|
||||
std::make_tuple("bootstrap", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("oob_score", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("verbose", OV_TypeId_Integer, "0"),
|
||||
std::make_tuple("warm_start", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("max_samples", OV_TypeId_String, "None"),
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> GAUSSIAN_SETTING = {
|
||||
std::make_tuple("Discriminator", OV_TypeId_String, ""),
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("var_smoothing", OV_TypeId_Float, "0.000000001"),
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> KNN_SETTING = {
|
||||
std::make_tuple("Discriminator", OV_TypeId_String, ""),
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("n_neighbors", OV_TypeId_Integer, "5"),
|
||||
std::make_tuple("weights", OVPoly_ClassId_Knn_Weights, "uniform"),
|
||||
std::make_tuple("algorithm", OVPoly_ClassId_Knn_Algorithm, "auto"),
|
||||
std::make_tuple("leaf_size", OV_TypeId_Integer, "30"),
|
||||
std::make_tuple("p", OV_TypeId_Integer, "2"),
|
||||
std::make_tuple("metric", OVPoly_ClassId_Metric, "minkowski"),
|
||||
};
|
||||
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> LDA_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("solver", OVPoly_ClassId_LDA_solver, "svd"),
|
||||
std::make_tuple("n_components", OV_TypeId_String, ""),
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> LR_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("penalty", OVPoly_ClassId_Penalty, "l2"),
|
||||
std::make_tuple("dual", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("tol", OV_TypeId_Float, "1e-4"),
|
||||
std::make_tuple("fit_intercept", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("intercept_scaling", OV_TypeId_Float, "1"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None"),
|
||||
std::make_tuple("solver", OVPoly_ClassId_Log_reg_solver, "lbfgs"),
|
||||
std::make_tuple("max_iter", OV_TypeId_Integer, "100"),
|
||||
std::make_tuple("verbose", OV_TypeId_Integer, "0"),
|
||||
std::make_tuple("warm_start", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("n_jobs", OV_TypeId_String, "None"),
|
||||
std::make_tuple("multi_class", OVPoly_ClassId_Log_reg_multi_class, "auto"),
|
||||
std::make_tuple("C", OV_TypeId_Float, "1.0")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> MLP_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("hidden_layer_sizes", OV_TypeId_String, "(100,)"),
|
||||
std::make_tuple("activation", OVPoly_ClassId_MLP_activation, "relu"),
|
||||
std::make_tuple("learning_rate", OVPoly_ClassId_MLP_learning_rate, "constant"),
|
||||
std::make_tuple("solver", OVPoly_ClassId_MLP_solver, "adam"),
|
||||
std::make_tuple("alpha", OV_TypeId_Float, "0.0001"),
|
||||
std::make_tuple("batch_size", OV_TypeId_String, "auto"),
|
||||
std::make_tuple("learning_rate_init", OV_TypeId_Float, "0.001"),
|
||||
std::make_tuple("power_t", OV_TypeId_Float, "0.5"),
|
||||
std::make_tuple("max_iter", OV_TypeId_Integer, "200"),
|
||||
std::make_tuple("shuffle", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None"),
|
||||
std::make_tuple("tol", OV_TypeId_Float, "1e-4"),
|
||||
std::make_tuple("verbose", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("warm_start", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("momentum", OV_TypeId_Float, "0.9"),
|
||||
std::make_tuple("nesterovs_momentum", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("early_stopping", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("validation_fraction", OV_TypeId_Float, "0.1"),
|
||||
std::make_tuple("beta_1", OV_TypeId_Float, "0.9"),
|
||||
std::make_tuple("beta_2", OV_TypeId_Float, "0.999"),
|
||||
std::make_tuple("epsilon", OV_TypeId_Float, "1e-8"),
|
||||
std::make_tuple("n_iter_no_change", OV_TypeId_Integer, "10")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> NC_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("metric", OVPoly_ClassId_Metric, "euclidean"),
|
||||
std::make_tuple("shrink_threshold", OV_TypeId_String, "")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> RF_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("criterion", OVPoly_ClassId_Criterion, "gini"),
|
||||
std::make_tuple("max_depth", OV_TypeId_String, "None"),
|
||||
std::make_tuple("min_samples_split", OV_TypeId_Float, "2"),
|
||||
std::make_tuple("min_samples_leaf", OV_TypeId_Float, "1"),
|
||||
std::make_tuple("min_weight_fraction_leaf", OV_TypeId_Float, "0"),
|
||||
std::make_tuple("max_features", OV_TypeId_String, "auto"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, "None"),
|
||||
std::make_tuple("max_leaf_nodes", OV_TypeId_String, "None"),
|
||||
std::make_tuple("min_impurity_decrease", OV_TypeId_Float, "0"),
|
||||
std::make_tuple("min_impurity_split", OV_TypeId_Float, "1e-7"),
|
||||
std::make_tuple("bootstrap", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("oob_score", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("verbose", OV_TypeId_Integer, "0"),
|
||||
std::make_tuple("warm_start", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("max_samples", OV_TypeId_String, "None"),
|
||||
std::make_tuple("n_estimators", OV_TypeId_Integer, "100")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> RTS_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("Discriminator", OVPoly_ClassId_Classifier_Algorithm, "Linear Discriminant Analysis")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> RMDM_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("Discriminator", OVPoly_ClassId_Classifier_Algorithm, "None")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> SGD_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("loss", OVPoly_ClassId_SGD_loss, "hinge"),
|
||||
std::make_tuple("penalty", OVPoly_ClassId_Penalty, "l2"),
|
||||
std::make_tuple("alpha", OV_TypeId_Float, "0.0001"),
|
||||
std::make_tuple("l1_ratio", OV_TypeId_Float, "0.15"),
|
||||
std::make_tuple("fit_intercept", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("max_iter", OV_TypeId_Integer, "1000"),
|
||||
std::make_tuple("tol", OV_TypeId_Float, "0.001"),
|
||||
std::make_tuple("shuffle", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("verbose", OV_TypeId_Integer, "0"),
|
||||
std::make_tuple("epsilon", OV_TypeId_Float, "0.1"),
|
||||
std::make_tuple("random_state", OV_TypeId_String, ""),
|
||||
std::make_tuple("learning_rate", OVPoly_ClassId_SGD_learning_rate, "optimal"),
|
||||
std::make_tuple("early_stopping", OV_TypeId_Boolean, "false"),
|
||||
std::make_tuple("n_iter_no_change", OV_TypeId_Integer, "5")
|
||||
};
|
||||
|
||||
static const std::vector<std::tuple<std::string, CIdentifier, std::string>> SVM_SETTING = {
|
||||
std::make_tuple("Test set share", OV_TypeId_Float, "0.2"),
|
||||
std::make_tuple("Labels", OV_TypeId_String, ""),
|
||||
std::make_tuple("penalty", OVPoly_ClassId_Penalty, "l2"),
|
||||
std::make_tuple("loss", OVPoly_ClassId_SVM_Loss, "squared_hinge"),
|
||||
std::make_tuple("dual", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("tol", OV_TypeId_Float, "0.0001"),
|
||||
std::make_tuple("C", OV_TypeId_Float, "1.0"),
|
||||
std::make_tuple("multi_class", OVPoly_ClassId_SVM_MultiClass, "ovr"),
|
||||
std::make_tuple("fit_intercept", OV_TypeId_Boolean, "true"),
|
||||
std::make_tuple("intercept_scaling", OV_TypeId_Float, "1"),
|
||||
std::make_tuple("verbose", OV_TypeId_Integer, "0"),
|
||||
std::make_tuple("max_iter", OV_TypeId_Integer, "1000")
|
||||
};
|
||||
|
||||
|
||||
static void ClearSetting(Kernel::IBox& box) { while (box.getSettingCount() > 4) { box.removeSetting(4); } }
|
||||
|
||||
static bool SetSetting(Kernel::IBox& box, const std::vector<std::tuple<std::string, CIdentifier, std::string>>& settings)
|
||||
{
|
||||
for (const auto& t : settings) { box.addSetting(std::get<0>(t).c_str(), std::get<1>(t), std::get<2>(t).c_str()); }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmTrainerMLListener::onSettingValueChanged(Kernel::IBox& box, const size_t index)
|
||||
{
|
||||
if (index == 3)
|
||||
{
|
||||
CString value;
|
||||
box.getSettingValue(index, value);
|
||||
ClearSetting(box);
|
||||
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::NearestCentroid)) { return SetSetting(box, NC_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::NearestNeighbors)) { return SetSetting(box, KNN_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::GaussianNaiveBayes)) { return SetSetting(box, GAUSSIAN_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::StochasticGradientDescent)) { return SetSetting(box, SGD_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::LogisticRegression)) { return SetSetting(box, LR_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::DecisionTree)) { return SetSetting(box, TREE_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::ExtraTrees)) { return SetSetting(box, XTREE_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::Bagging)) { return SetSetting(box, BAGGING_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::RandomForest)) { return SetSetting(box, RF_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::SVM)) { return SetSetting(box, SVM_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::LDA)) { return SetSetting(box, LDA_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::AdaBoost)) { return SetSetting(box, ADA_BOOST_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::MultiLayerPerceptron)) { return SetSetting(box, MLP_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::MDM)) { return SetSetting(box, RMDM_SETTING); }
|
||||
if (std::string(value.toASCIIString()) == toString(EClassifier::TangentSpace)) { return SetSetting(box, RTS_SETTING); }
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
@@ -0,0 +1,94 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file TrainerML.hpp
|
||||
/// \brief Class TrainerML
|
||||
/// \author Thibaut Monseigne (Inria) & Jimmy Leblanc (Polymont) & Yannis Bendi-Ouis (Polymont)
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/%22%3EGNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#include "CPolyBox.hpp"
|
||||
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
class CBoxAlgorithmTrainerML final : public CPolyBox
|
||||
{
|
||||
public:
|
||||
CBoxAlgorithmTrainerML() { m_script = Directories::getDataDir() + "/plugins/python3/pybox/TrainerML.py"; }
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_TrainerML)
|
||||
};
|
||||
|
||||
class CBoxAlgorithmTrainerMLListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t index) override
|
||||
{
|
||||
box.setInputType(index, OV_TypeId_StreamedMatrix);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onSettingValueChanged(Kernel::IBox& box, const size_t index) override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmTrainerMLDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("Trainer Sklearn"); }
|
||||
CString getAuthorName() const override { return CString("Jimmy Leblanc & Yannis Bendi-Ouis"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Polymont IT Services"); }
|
||||
CString getShortDescription() const override { return CString("Train an TrainerML Classifier from Sklearn."); }
|
||||
CString getDetailedDescription() const override { return CString(""); }
|
||||
CString getCategory() const override { return CString("Scripting/PyBox"); }
|
||||
CString getVersion() const override { return CString("0.1"); }
|
||||
CString getStockItemName() const override { return CString("gtk-convert"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_TrainerML; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmTrainerML; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmTrainerMLListener; }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addSetting("Clock frequency (Hz)", OV_TypeId_Integer, "64");
|
||||
// <tag> settings
|
||||
prototype.addSetting("Filename to save model to", OV_TypeId_Filename, "${Player_ScenarioDirectory}/model.clf");
|
||||
prototype.addSetting("Filename to load model from", OV_TypeId_Filename, "");
|
||||
prototype.addSetting("Classifier", OVPoly_ClassId_Classifier_Algorithm, "None");
|
||||
|
||||
prototype.addInputSupport(OV_TypeId_Signal);
|
||||
prototype.addInputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addInputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
prototype.addOutputSupport(OV_TypeId_Signal);
|
||||
prototype.addOutputSupport(OV_TypeId_Stimulations);
|
||||
prototype.addOutputSupport(OV_TypeId_StreamedMatrix);
|
||||
|
||||
// <tag> input & output
|
||||
prototype.addOutput("stim_out", OV_TypeId_Stimulations);
|
||||
prototype.addInput("input_StreamMatrix", OV_TypeId_StreamedMatrix);
|
||||
prototype.addInput("input_Stimulations", OV_TypeId_Stimulations);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_TrainerMLDesc)
|
||||
};
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
//__________________________________________________________________//
|
||||
// //
|
||||
// Box //
|
||||
//__________________________________________________________________//
|
||||
// //
|
||||
|
||||
// <tag> Tag Box Declaration
|
||||
#define OVP_ClassId_BoxAlgorithm_DatasetCreatorDesc OpenViBE::CIdentifier(0x6EBF2A07, 0x52EA5F3E)
|
||||
#define OVP_ClassId_BoxAlgorithm_DatasetCreator OpenViBE::CIdentifier(0x7B6738C4, 0x2C5156ED)
|
||||
#define OVP_ClassId_BoxAlgorithm_DataVizDesc OpenViBE::CIdentifier(0x44E07FAC, 0x57BE15DB)
|
||||
#define OVP_ClassId_BoxAlgorithm_DataViz OpenViBE::CIdentifier(0x057B49AD, 0x040868CF)
|
||||
#define OVP_ClassId_BoxAlgorithm_ProcessMLDesc OpenViBE::CIdentifier(0x764A11C8, 0x04006876)
|
||||
#define OVP_ClassId_BoxAlgorithm_ProcessML OpenViBE::CIdentifier(0x681D3DFE, 0x060E2AFB)
|
||||
#define OVP_ClassId_BoxAlgorithm_TrainerMLDesc OpenViBE::CIdentifier(0x6b14815c, 0x41da26d4)
|
||||
#define OVP_ClassId_BoxAlgorithm_TrainerML OpenViBE::CIdentifier(0x44b85a3a, 0xabfc390a)
|
||||
|
||||
|
||||
//__________________________________________________________________//
|
||||
// //
|
||||
// Custom Settings //
|
||||
//__________________________________________________________________//
|
||||
// //
|
||||
|
||||
// <tag> Custom Type Settings
|
||||
|
||||
#define OVPoly_ClassId_Classifier_Algorithm OpenViBE::CIdentifier(0x73AE164D, 0xEA21AB0A)
|
||||
#define OVPoly_ClassId_Knn_Algorithm OpenViBE::CIdentifier(0xBF763F3B, 0x303EC694)
|
||||
#define OVPoly_ClassId_Knn_Weights OpenViBE::CIdentifier(0x178AF88A, 0xEC44DFF3)
|
||||
#define OVPoly_ClassId_Metric OpenViBE::CIdentifier(0xA04E99E9, 0x020A6874)
|
||||
#define OVPoly_ClassId_SVM_Loss OpenViBE::CIdentifier(0xF05612EC, 0x139AFC45)
|
||||
#define OVPoly_ClassId_Penalty OpenViBE::CIdentifier(0xBA4193F2, 0xCD152A47)
|
||||
#define OVPoly_ClassId_SVM_MultiClass OpenViBE::CIdentifier(0x743F2BC9, 0xA84BC9DF)
|
||||
#define OVPoly_ClassId_Criterion OpenViBE::CIdentifier(0x7455C643, 0x5D1E74E7)
|
||||
|
||||
|
||||
// Logistic regression
|
||||
#define OVPoly_ClassId_Log_reg_solver OpenViBE::CIdentifier(0x8CF680DF, 0x9EA77031)
|
||||
#define OVPoly_ClassId_Log_reg_multi_class OpenViBE::CIdentifier(0xC0B45F28, 0x13AEBFD2)
|
||||
|
||||
// Decision Tree
|
||||
#define OVPoly_ClassId_DecisionTree_splitter OpenViBE::CIdentifier(0x4E3C6F6F, 0x9AC56CEA)
|
||||
|
||||
// MLP
|
||||
#define OVPoly_ClassId_MLP_activation OpenViBE::CIdentifier(0x324DA925, 0x58A1BCD9)
|
||||
#define OVPoly_ClassId_MLP_solver OpenViBE::CIdentifier(0xAD038F27, 0x9B0AB84F)
|
||||
#define OVPoly_ClassId_MLP_learning_rate OpenViBE::CIdentifier(0x5B10D3BC, 0x57658821)
|
||||
|
||||
// SGD
|
||||
#define OVPoly_ClassId_SGD_loss OpenViBE::CIdentifier(0x57CA4145, 0xB25841A5)
|
||||
#define OVPoly_ClassId_SGD_learning_rate OpenViBE::CIdentifier(0xB6075C69, 0x93BE696B)
|
||||
|
||||
// LDA
|
||||
#define OVPoly_ClassId_LDA_solver OpenViBE::CIdentifier(0x2B78F491, 0xB86A6DE7)
|
||||
|
||||
// ADA
|
||||
#define OVPoly_ClassId_ADA_algorithm OpenViBE::CIdentifier(0x27025481, 0x09BEDC31)
|
||||
@@ -0,0 +1,167 @@
|
||||
#if defined TARGET_HAS_ThirdPartyPython3 && !(defined(WIN32) && defined(TARGET_BUILDTYPE_Debug))
|
||||
|
||||
#include "box-algorithms/CPolyBox.hpp"
|
||||
#include "box-algorithms/DataViz.hpp"
|
||||
#include "box-algorithms/DatasetCreator.hpp"
|
||||
#include "box-algorithms/ProcessML.hpp"
|
||||
#include "box-algorithms/TrainerML.hpp"
|
||||
|
||||
#if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#ifdef TARGET_OS_Windows
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace PyBox {
|
||||
OVP_Declare_Begin()
|
||||
// <tag> OVP_Declare_New
|
||||
OVP_Declare_New(CBoxAlgorithmDatasetCreatorDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmDataVizDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmProcessMLDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmTrainerMLDesc);
|
||||
|
||||
// <tag> Custom Type Settings
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Classifier_Algorithm, "Classifier_Algorithm");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Nearest Centroid", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Nearest Neighbors", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Gaussian Naive Bayes", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Stochastic Gradient Descent", 3);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Logistic Regression", 4);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Decision Tree", 5);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Extra Trees", 6);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Bagging", 7);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Random Forest", 8);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Support Vector Machine", 9);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Linear Discriminant Analysis", 10);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "AdaBoost", 11);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Multi Layer Perceptron", 12);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Riemann Minimum Distance to Mean", 13);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "Riemann Tangent Space", 14);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Classifier_Algorithm, "None", 15);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Knn_Algorithm, "Knn_Algorithm");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Knn_Algorithm, "auto", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Knn_Algorithm, "ball_tree", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Knn_Algorithm, "kd_tree", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Knn_Algorithm, "brute", 3);
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Knn_Weights, "Knn_Weights");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Knn_Weights, "uniform", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Knn_Weights, "distance", 1);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Metric, "Metric");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "cityblock", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "cosine", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "euclidean", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "l1", 3);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "l2", 4);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "manhattan", 5);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "braycurtis", 6);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "canberra", 7);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "chebyshev", 8);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "correlation", 9);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "dice", 10);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "hamming", 11);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "jaccard", 12);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "kulsinski", 13);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "minkowski", 14);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "mahalanobis", 15);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "rogerstanimoto", 16);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "russellrao", 17);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "seuclidean", 18);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "sokalmichener", 19);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "sokalsneath", 20);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "sqeuclidean", 21);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Metric, "yule", 22);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Penalty, "Penalty");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Penalty, "l1", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Penalty, "l2", 1);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_SVM_Loss, "SVM_Loss");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SVM_Loss, "hinge", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SVM_Loss, "squared_hinge", 1);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_SVM_MultiClass, "SVM_MultiClass");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SVM_MultiClass, "ovr", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SVM_MultiClass, "crammer_singer", 1);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Criterion, "Criterion");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Criterion, "gini", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Criterion, "entropy", 1);
|
||||
|
||||
|
||||
// Logistic regression
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Log_reg_solver, "Solver");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_solver, "newton-cg", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_solver, "lbfgs", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_solver, "liblinear", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_solver, "sag", 3);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_solver, "saga", 4);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_Log_reg_multi_class, "Multi_class");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_multi_class, "auto", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_multi_class, "ovr", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_Log_reg_multi_class, "multinominal", 2);
|
||||
|
||||
|
||||
// Decision Tree Classifier
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_DecisionTree_splitter, "Splitter");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_DecisionTree_splitter, "best", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_DecisionTree_splitter, "random", 1);
|
||||
|
||||
// MLP
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_MLP_activation, "Activation");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_activation, "identity", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_activation, "logistic", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_activation, "tanh", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_activation, "relu", 3);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_MLP_solver, "Solver");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_solver, "lbfgs", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_solver, "sgd", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_solver, "adam", 2);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_MLP_learning_rate, "Learning rate");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_learning_rate, "constant", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_learning_rate, "invscaling", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_MLP_learning_rate, "adaptive", 2);
|
||||
|
||||
// SGD
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_SGD_loss, "Loss");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_loss, "hinge", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_loss, "log", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_loss, "modified_huber", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_loss, "squared_hinge", 3);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_loss, "perceptron", 4);
|
||||
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_SGD_learning_rate, "Learning rate");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_learning_rate, "optimal", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_learning_rate, "constant", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_learning_rate, "invscaling", 2);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_SGD_learning_rate, "adaptive", 3);
|
||||
|
||||
// LDA
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_LDA_solver, "Loss");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_LDA_solver, "svd", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_LDA_solver, "lsqr", 1);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_LDA_solver, "eigen", 2);
|
||||
|
||||
// ADA
|
||||
context.getTypeManager().registerEnumerationType(OVPoly_ClassId_ADA_algorithm, "Algorithm");
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_ADA_algorithm, "SAMME", 0);
|
||||
context.getTypeManager().registerEnumerationEntry(OVPoly_ClassId_ADA_algorithm, "SAMME.R", 1);
|
||||
OVP_Declare_End()
|
||||
|
||||
} // namespace PyBox
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
#else
|
||||
#pragma message ("WARNING: Python 3.7 headers are required to build the Python plugin, different includes found, skipped")
|
||||
#endif // #if defined(PY_MAJOR_VERSION) && (PY_MAJOR_VERSION == 3)
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyPython3
|
||||