License : Creative Commons Attribution 4.0 International (CC BY-NC-SA 4.0)
Copyright :
Hervé Frezza-Buet,
CentraleSupelec
Last modified : March 28, 2024 13:08
Link to the source : builder.md
The cxsom-builder
tools enable to rationalize the definition of a multi-map architecture. Once you have understood the following, have a look at the “experiments” section of the package. It provides examples of realistic experiments with cxsom-builder
that you can replay by following step by step instructions.
The maps in an architecture hosts variables belonging to different timelines. Indeed, all the variables in a timeline, for each instant, relax together in order to reach the consensus. If an update of a variable takes as argument variables in another timeline, it is not feasible if that variables are not computed beforehand. On the contrary, for the arguments in the same timeline at the same time instant, computation can start even if arguments are not computed with a final value yet… this is relaxation.
Each maps defined by cxsom-builder
organize the computation in the following timelines.
Each map can have multiple inputs, with a weight layer and a matching activity associated to it. There are two kinds of inputs:
external inputs: they are made of values which are stable (i.e. belonging to another timeline, or in the sale timeline but at some previous timestep).
contextual inputs: They are made of unstable inputs. These are the “rlx/BMU” f some other maps. The consensual setting up of the “rlx/BMU”s is the consensus, and the “rlx/BMU”, once stabilized, are copied onto the corresponding "out/BMU’.
This is performed by the following code.
#include <cxsom-builder.hpp>
#include <fstream>
#define CACHE 2
#define TRACE 10000
#define OPENED true
#define FORGET 0
#define WALLTIME TRACE-1
#define MAP_SIZE 500
// cxsom declarations
using namespace cxsom::rules;
context* cxsom::rules::ctx = nullptr;
int main(int argc, char* argv[]) {
context c(argc, argv);
kwd::parameters p_main, p_match, p_learn, p_external, p_contextual, p_global;
p_main | kwd::use("walltime", WALLTIME), kwd::use("epsilon", 0);
p_match | p_main, kwd::use("sigma", .1);
p_learn | p_main, kwd::use("alpha", .1), kwd::use("r", .1);
p_external | p_main;
p_contextual | p_main;
p_global | p_main, kwd::use("random-bmu", 1);
auto map_settings = cxsom::builder::map::make_settings();
map_settings.map_size = MAP_SIZE;
map_settings.cache_size = CACHE;
map_settings.internals_file_size = FORGET;
map_settings.weights_file_size = TRACE;
map_settings.bmu_file_size = TRACE;
map_settings.kept_opened = OPENED;
map_settings = {p_external, p_contextual, p_global};
auto archi = cxsom::builder::architecture();
auto input = cxsom::builder::variable("in", cxsom::builder::name("1D") / "xi", "Scalar", CACHE, FORGET, OPENED);
input->definition(); // Adds the definition rule for that input.
kwd::var(input->timeline, input->varname) << fx::random() | kwd::use("walltime", WALLTIME);
auto map = cxsom::builder::map::make_1D("SOM");
map->external(input, fx::match_gaussian, p_match, fx::learn_triangle, p_learn);
archi << map;
*archi = map_settings;
archi->realize();
map->internals_random_at(0);
// We describe the architecture in a dot file.
std::ofstream dot_file("som-archi.dot");
dot_file << archi->write_dot;
return 0;
}
This single map architecture is denoted by the following graph (generated by the C++ code, see the updates here))
A recurrent SOM is a map that receives two external inputs. One is an input as for usual SOM, except that the order is relevant (i.e. inputs are items of a sequence). The second is tue output of the map, taken at previous time step. Here, that output is the BMU.
This is performed by the following code.
#include <cxsom-builder.hpp>
#include <fstream>
#define CACHE 2
#define TRACE 10000
#define OPENED true
#define FORGET 0
#define WALLTIME -1 // Infinite walltime
#define MAP_SIZE 500
// cxsom declarations
using namespace cxsom::rules;
context* cxsom::rules::ctx = nullptr;
int main(int argc, char* argv[]) {
context c(argc, argv);
auto archi = cxsom::builder::architecture();
kwd::parameters p_main, p_match, p_learn, p_external, p_contextual, p_global;
p_main | kwd::use("walltime", WALLTIME), kwd::use("epsilon", 0);
p_match | p_main, kwd::use("r", .3);
p_learn | p_main, kwd::use("alpha", .05), kwd::use("r", .05);
p_external | p_main;
p_contextual | p_main;
p_global | p_main, kwd::use("random-bmu", 1), kwd::use("sigma", .0125);
auto map_settings = cxsom::builder::map::make_settings();
map_settings.map_size = MAP_SIZE;
map_settings.cache_size = CACHE;
map_settings.weights_file_size = TRACE;
map_settings.kept_opened = OPENED;
map_settings = {p_external, p_contextual, p_global};
map_settings.bmu_file_size = TRACE; // Default is 0.
auto input = cxsom::builder::variable("in", cxsom::builder::name("X"), "Scalar", CACHE, TRACE, OPENED);
input->definition();
auto map = cxsom::builder::map::make_1D("recSOM");
map->external(input, fx::match_triangle, p_match, fx::learn_triangle, p_learn);
map->external(map, fx::match_triangle, p_match, cxsom::builder::timestep::previous(), fx::learn_triangle, p_learn);
archi << map;
*archi = map_settings;
archi->realize();
map->internals_random_at(0);
std::ofstream dot_file("recsom-archi.dot");
dot_file << archi->write_dot;
return 0;
}
This single map architecture is denoted by the following graph (generated by the C++ code, see the updates here)
Here, we link two SOMs with a contextual relation. Their respective BMUs relax together in order to find a consensus.
This is performed by the following code.
#include <cxsom-builder.hpp>
#include <fstream>
#define CACHE 2
#define TRACE 10000
#define OPENED true
#define FORGET 0
#define WALLTIME -1 // Infinite walltime
#define MAP_SIZE 500
using namespace cxsom::rules;
context* cxsom::rules::ctx = nullptr;
int main(int argc, char* argv[]) {
context c(argc, argv);
auto archi = cxsom::builder::architecture();
kwd::parameters p_main, p_match, p_learn, p_learn_e, p_learn_c, p_external, p_contextual, p_global;
p_main | kwd::use("walltime", WALLTIME), kwd::use("epsilon", 0);
p_match | p_main, kwd::use("sigma", .2);
p_learn | p_main, kwd::use("alpha", .05);
p_learn_e | p_learn, kwd::use("r", .25 );
p_learn_c | p_learn, kwd::use("r", .075);
p_external | p_main;
p_contextual | p_main;
p_global | p_main, kwd::use("random-bmu", 1), kwd::use("sigma", .01), kwd::use("beta", .5), kwd::use("delta", .01), kwd::use("deadline", 100);
auto map_settings = cxsom::builder::map::make_settings();
map_settings.map_size = MAP_SIZE;
map_settings.cache_size = CACHE;
map_settings.weights_file_size = TRACE;
map_settings.kept_opened = OPENED;
map_settings = {p_external, p_contextual, p_global};
auto X = cxsom::builder::variable("in", cxsom::builder::name("X"), "Scalar", CACHE, TRACE, OPENED);
auto Y = cxsom::builder::variable("in", cxsom::builder::name("Y"), "Scalar", CACHE, TRACE, OPENED);
X->definition();
Y->definition();
auto Xmap = cxsom::builder::map::make_1D("X");
auto Ymap = cxsom::builder::map::make_1D("Y");
Xmap->external (X, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_e);
Ymap->external (Y, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_e);
Xmap->contextual(Ymap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Ymap->contextual(Xmap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
archi << Xmap << Ymap;
*archi = map_settings;
archi->realize();
Xmap->internals_random_at(0);
Ymap->internals_random_at(0);
std::ofstream dot_file("2soms-archi.dot");
dot_file << archi->write_dot;
return 0;
}
This 2 map architecture is denoted by the following graph (generated by the C++ code, see the updates here)
With cxsom-builder
, more complex architectures can be easily defined.
For example, the following code…
#include <cxsom-builder.hpp>
#include <fstream>
#define CACHE 2
#define TRACE 10000
#define OPENED true
#define FORGET 0
#define WALLTIME -1 // Infinite walltime
#define MAP_SIZE 500
using namespace cxsom::rules;
context* cxsom::rules::ctx = nullptr;
int main(int argc, char* argv[]) {
context c(argc, argv);
auto archi = cxsom::builder::architecture();
kwd::parameters p_main, p_match, p_learn, p_learn_e, p_learn_c, p_external, p_contextual, p_global;
p_main | kwd::use("walltime", WALLTIME), kwd::use("epsilon", 0);
p_match | p_main, kwd::use("sigma", .2);
p_learn | p_main, kwd::use("alpha", .05);
p_learn_e | p_learn, kwd::use("r", .25 );
p_learn_c | p_learn, kwd::use("r", .075);
p_external | p_main;
p_contextual | p_main;
p_global | p_main, kwd::use("random-bmu", 1), kwd::use("sigma", .01), kwd::use("beta", .5), kwd::use("delta", .01), kwd::use("deadline", 100);
auto map_settings = cxsom::builder::map::make_settings();
map_settings.map_size = MAP_SIZE;
map_settings.cache_size = CACHE;
map_settings.weights_file_size = TRACE;
map_settings.kept_opened = OPENED;
map_settings = {p_external, p_contextual, p_global};
auto X = cxsom::builder::variable("in", cxsom::builder::name("X"), "Scalar", CACHE, TRACE, OPENED);
auto Y = cxsom::builder::variable("in", cxsom::builder::name("Y"), "Scalar", CACHE, TRACE, OPENED);
auto Z = cxsom::builder::variable("in", cxsom::builder::name("Z"), "Scalar", CACHE, TRACE, OPENED);
X->definition();
Y->definition();
Z->definition();
auto Xmap = cxsom::builder::map::make_1D("X");
auto Ymap = cxsom::builder::map::make_1D("Y");
auto Zmap = cxsom::builder::map::make_1D("Z");
auto Amap = cxsom::builder::map::make_1D("Assoc");
Xmap->external (X, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_e);
Ymap->external (Y, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_e);
Zmap->external (Z, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_e);
Xmap->contextual(Amap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Ymap->contextual(Amap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Zmap->contextual(Amap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Amap->contextual(Xmap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Amap->contextual(Ymap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Amap->contextual(Zmap, fx::match_gaussian, p_match, fx::learn_triangle, p_learn_c);
Amap->external(Amap, fx::match_triangle, p_match, cxsom::builder::timestep::previous(), fx::learn_triangle, p_learn);
archi << Xmap << Ymap << Zmap << Amap;
*archi = map_settings;
archi->realize();
Xmap->internals_random_at(0);
Ymap->internals_random_at(0);
Zmap->internals_random_at(0);
Amap->internals_random_at(0);
std::ofstream dot_file("complex-archi.dot");
dot_file << archi->write_dot;
return 0;
}
implements this (the very complex graph can be viewed here.