00001
00009 #include <vector>
00010 #include <functional>
00011 #include <string>
00012 using std::string;
00013 #include <time.h>
00014
00015 #include "inputs.h"
00016 #include "ipc.h"
00017 #include "cmdparam.h"
00018 #include "kernelfactory.h"
00019 #include "fixedwtregion.h"
00020 #include "retina.h"
00021 #include "pointermap.h"
00022 #include "kernelwrapper.h"
00023 #include "stringutils.h"
00024 #include "worldviews.h"
00025 #include "shuffledrand.h"
00026 #include "valuegencontainer.h"
00027 #include "generic_stdlib.h"
00028 #include "matrix.h"
00029 #include "tnt_gnuplot.h"
00030 #include "robj.h"
00031 #include "neuralregion.h"
00032 #include "neuralregionmap.h"
00033 #include "neuralregionmanager.h"
00034 #include "mathconstants.h"
00035
00036
00037 #ifdef EXPLICIT_INSTANTIATION_FOR_STATICS
00038 template class Msg::LevelHandler<Msg::MessageLevel,Msg::NumMessageLevels>;
00039 template class ShuffledRandom<double>;
00040 template class ValueGenerator_Increment<double>;
00041 template class ValueGenerator_Expression<double>;
00042 template class ValueGenerator_Correlate<double,synchronized_distribution<Distributions::uniform>,true>;
00043 template class ValueGenerator_Random<double,synchronized_distribution<Distributions::uniform> >;
00044 template class ValueGenerator_Random<double,synchronized_distribution<Distributions::normal> >;
00045 #endif
00046
00047
00048
00049
00050
00051
00053 class NamedValueGenerators : public ValueGenContainer {
00054 public:
00055 virtual cmdstat create(StringArgs args);
00056 };
00057
00058
00060 cmdstat NamedValueGenerators::create(StringArgs args)
00061 {
00062 DistributedValueGeneratorFactory<double> vgf;
00063
00064 const string name = args.next(string(""));
00065 ValueGenerator<>* valgen = vgf.create(args.recursiveparser());
00066 const string helpstring = args.next(string(""));
00067
00068
00069 if (blackboard.define_param(DECLARE_PARAM(PARAM_DOUBLE,name.c_str(),false,
00070 valgen->valueptr())) == 1) {
00071 if (helpstring != "") params_define_doc(name.c_str(),cmdparam_dupstr(helpstring.c_str()));
00072 push_back(valgen);
00073 ipc_notify(IPC_ONE,IPC_STD,"Defined ValueGenerator %s",name.c_str());
00074 }
00075 else {
00076 delete valgen;
00077 ipc_notify(IPC_ONE,IPC_STD,"Could not define ValueGenerator %s; perhaps already defined",name.c_str());
00078 }
00079 return CMD_NO_ERROR;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00094 class Eyes : public Inputs {
00095 public:
00096 Eyes() : last_object_drawn(&permanent_contents),
00097 neuralregions("Region",blackboard),
00098 default_region_command("define_region height=BaseN*area_scale width=BaseN*area_scale"),
00099 initialize_weights(true), size_scale_override(-1),
00100 input_define_convolution_in_use(false) { }
00101
00102 virtual ~Eyes() { }
00103
00104 virtual void uninit();
00105 virtual void init();
00106
00109 virtual void reset() {
00110 permanent_contents.reset();
00111 namedgenerators.reset();
00112 }
00115 virtual void reset(long int seed) {
00116 permanent_contents.reset(seed);
00117 namedgenerators.reset();
00118 }
00119
00120 virtual bool next();
00121
00122 virtual void activate(const WorldViews& views, const ParamMap& argparams) {
00123 activate(views,
00124 argparams.get_with_default("learning",False),
00125 argparams.get_with_default("settle",True),
00126 argparams.get_with_default("activate",True),
00127 argparams.get_with_default("verbose",False));
00128 }
00129
00130 virtual void activate(bool learn, bool settle_, bool activatefn=true)
00131 { activate(permanent_contents,learn,settle_,activatefn); };
00132
00134 virtual void activate(const WorldViews& views,bool learn, bool settle_, bool activatefn=true, bool verbose=false);
00135
00137 virtual bool is_active(int objnumber, int eye) const
00138 { return last_object_drawn->is_active(objnumber,eye); }
00139 virtual double angle_of_object(int objnumber, int eye) const
00140 { return last_object_drawn->angle_of_object(objnumber,eye); }
00141 virtual double angle_of_object_at_location(int i, int j, int eye) const
00142 { return last_object_drawn->angle_of_object_at_location(i,j,eye); }
00143
00144 private:
00145 static void message(Msg::MessageLevel m, const string& s)
00146 { NeuralRegionMap::message(m,s); }
00147
00148 CMDOBJ_DECLARE(Eyes,define_region);
00149 CMDOBJ_DECLARE(Eyes,connect_region);
00150
00151 bool has_default_region() { return default_region!=""; }
00152 string ensure_default_region();
00153
00154 void update_default_values();
00155 void register_params_and_commands( void );
00156 void select_worldview(const WorldViews& views);
00157
00158 void define_input_pathway(const string& region_downstream, const string& eyename,
00159 StringArgs& arglist, const double size_scale, const int layers_pereye );
00160 cmdstat training(StringArgs& arglist, const ParamMap& argparams);
00161
00162 CMDOBJ_DECLARE(Eyes,input_undefine);
00163 CMDOBJ_DECLARE(Eyes,input_define);
00164 CMDOBJ_DECLARE(Eyes,input_define_generator);
00165 CMDOBJ_DECLARE(Eyes,input_print);
00166 CMDOBJ_DECLARE(Eyes,input_reset);
00167 CMDOBJ_DECLARE(Eyes,input_clear);
00168 CMDOBJ_DECLARE(Eyes,input_draw);
00169 CMDOBJ_DECLARE(Eyes,input_present);
00170 CMDOBJ_DECLARE(Eyes,input_present_object);
00171
00172 CMDOBJ_DECLARE(Eyes,input_define_convolution);
00173
00174 CMDOBJ_DECLARE(Eyes,load_snapshot);
00175
00176 CMDOBJ_DECLARE(Eyes,step);
00177 CMDOBJ_DECLARE(Eyes,testing);
00178 CMDOBJ_DECLARE(Eyes,training);
00179
00180 CMDOBJ_DECLARE(Eyes,uninit_network);
00181 CMDOBJ_DECLARE(Eyes,init_network);
00182
00183
00184 SETFNOBJ_DECLARE2(Eyes,inputs_pereye_setfn2);
00185 SETFNOBJ_DECLARE2(Eyes,blur_type_setfn2);
00186 SETFNOBJ_DECLARE2(Eyes,double_blur_setfn2);
00187 SETFNOBJ_DECLARE2(Eyes,exc_rad_setfn2);
00188
00189
00190 SETFNOBJ_DECLARE2(Eyes,distribution_setfn2);
00191
00193 NamedValueGenerators namedgenerators;
00194
00196 const WorldViews* last_object_drawn;
00197 WorldViews permanent_contents;
00198 WorldViews temporary_contents;
00199
00201 typedef Retina retina_type;
00202
00204 typedef NeuralRegionMap neuralregions_type;
00205 neuralregions_type neuralregions;
00206
00207 KernelFactory kernel_factory;
00208
00212 string default_region;
00213
00214 string default_region_command;
00215
00220 bool initialize_weights;
00221
00227 string default_input_target;
00228
00229 static int current_object_angle;
00230 static double world_size_scale;
00231
00232 static Tristate progress_reports;
00233 static int progress_report_interval;
00234 static int startt;
00235
00239 double size_scale_override;
00240
00243 bool input_define_convolution_in_use;
00244
00245 HooklistNum before_input;
00246
00247 HooklistNum after_learning;
00249 void advance_iteration_counter(int old_t, int new_t);
00250 };
00251
00252
00253
00254
00255 int Eyes::current_object_angle=0;
00256 double Eyes::world_size_scale=1.0;
00257
00258 Tristate Eyes::progress_reports=Uninitialized;
00259 int Eyes::progress_report_interval=10;
00260 int Eyes::startt=0;
00261
00264 void Eyes::init()
00265 {
00266 startt=0;
00267
00268
00269 ensure_default_region();
00270
00271
00272 if (!permanent_contents.has_been_defined())
00273 cmd_input_define_convolution();
00274
00275
00276 if (permanent_contents.is_empty())
00277 permanent_contents.generate_default_contents();
00278
00279 ipc_notify(IPC_ONE,IPC_SUMMARY,"Defined %d-connection network; %.1fMB%s total required for weight storage",
00280 int(neuralregions.size_unique_connections()),
00281 neuralregions.size_connection_bytes()/1024.0/1024.0,
00282 (NPEs>1 ? " on each PE" : ""));
00283 }
00284
00285
00288 string Eyes::ensure_default_region()
00289 {
00290 if (default_region=="") cmddefs_exec_str(default_region_command);
00291 assert (default_region!="");
00292 return default_region;
00293 }
00294
00295
00296
00297 void Eyes::uninit( void )
00298 {
00299 cmddefs_declare_prereq_status( "init_network", CMD_NEVER_CALLED );
00300 iteration=0;
00301 presentation=0;
00302
00303 permanent_contents.uninit();
00304 neuralregions.erase();
00305 default_region="";
00306 default_input_target="";
00307 ::network_initialized=false;
00308 startt=0;
00309 input_define_convolution_in_use=false;
00310
00311
00312 hooklists_empty_list(before_input);
00313
00314 hooklists_empty_list(after_learning);
00315 }
00316
00317
00318
00319 bool Eyes::next(void)
00320 {
00321
00322
00323
00324 ipc_barrier();
00325 bool status1 = namedgenerators.next();
00326 bool status2 = permanent_contents.next();
00327 return status1 && status2;
00328 }
00329
00330
00331
00332 void Eyes::activate(const WorldViews& views,bool learn, bool settle_, bool activatefn, bool verbose)
00333 {
00334 static int iteration_of_last_presentation=Uninitialized;
00335 if (iteration!=iteration_of_last_presentation) {
00336 iteration_of_last_presentation=iteration;
00337 presentation=0;
00338 }
00339 else
00340 presentation++;
00341
00342 select_worldview(views);
00343 neuralregions.activate(learn,settle_,activatefn,verbose);
00344 }
00345
00346
00348 void Eyes::select_worldview(const WorldViews& views)
00349 {
00350 for (WorldViews::const_iterator eye=views.begin(); eye!= views.end(); eye++) {
00351 retina_type* retina = dynamic_cast<retina_type*>(neuralregions.getptr((*eye)->get_name())->region());
00352 if (retina)
00353 retina->set_input(*eye);
00354 }
00355
00356
00357 last_object_drawn = &views;
00358 current_object_angle = (int)floor(RADIANS_TO_DEGREES(CONSTRAIN_ANGLE(angle_of_object(0,0)))+0.5);
00359 }
00360
00361
00369 void Eyes::define_input_pathway(const string& region_downstream, const string& eyename,
00370 StringArgs& arglist, const double size_scale, const int layers_pereye )
00371 {
00372 const string eyenum = String::numeric_extension<string>(eyename);
00373
00374
00375 string default_reg = default_region;
00376
00377
00378 bool retina_defined = false;
00379
00380
00381
00382 const bool has_ganglia = (layers_pereye>0);
00383
00384
00385
00386 for (int layer=0; layer<std::max(1,layers_pereye); layer++) {
00387 double sscale=size_scale;
00388
00389
00390 string target = region_downstream;
00391 string connectionspec = "Blur_CircularRandom ::Region::"+default_region+"::rf_radius";
00392
00393
00394 if (has_ganglia) {
00395 const string convolvenum = eyenum + String::stringrep(layer);
00396 const string convolvename = "Ganglia" + convolvenum;
00397 size_scale_override=sscale;
00398 const string ssoverride = String::stringrep(size_scale_override,String::StreamFormat(-1,'0',16,false));
00399 const string command = string("connect_region")
00400 + " name=Afferent" + convolvenum
00401 + " target=" + target
00402 + " source=" + convolvename
00403
00404
00405 + " size_scale=" + ssoverride
00406 + " sourcespec='type=Convolution'"
00407 + " " + connectionspec;
00408 cmddefs_exec_str(command);
00409 size_scale_override=-1;
00410
00411 target=convolvename;
00412 sscale=1.0;
00413 connectionspec=arglist.stringrep();
00414 }
00415
00416
00417 size_scale_override=(has_ganglia? world_size_scale : 1.0)*sscale;
00418 const string ssoverride = String::stringrep(size_scale_override,String::StreamFormat(-1,'0',16,false));
00419 const string command = string("connect_region")
00420 + " name=Afferent" + eyenum
00421 + " target=" + target
00422 + " source=" + eyename
00423 + (retina_defined? "" : " sourcespec='type=Retina" +
00424 string(!has_ganglia ? "" : " size_scale=" + ssoverride) + "'")
00425 + " " + connectionspec;
00426 cmddefs_exec_str(command);
00427 size_scale_override=-1;
00428 retina_defined=true;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437 default_region=default_reg;
00438 cmddefs_exec_str("set default_region=" + default_reg);
00439 }
00440
00441
00442
00444 #define CMDARGP_DOC "Default value for the corresponding parameter for commands."
00445 #define CMDARGP(name,initial_value,options,doc) PARAM_A(blackboard.lookup_map("::cmd"),name,initial_value,options,doc);
00446
00447
00448
00449 void Eyes::register_params_and_commands( void )
00450 {
00451
00452 before_input = hooklists_define_list("before_input", "iteration");
00453
00454 after_learning = hooklists_define_list("after_learning", "iteration");
00455
00456
00459 PARAM_A(blackboard,"display",0,.add_lower_bound(0),
00460 "Plot network activation, etc. every (display)th training or testing\n"
00461 "iteration. If display==0, never do it; if display==1, do it every\n"
00462 "iteration, if display==2, do it every other iteration, etc.");
00463
00464 PARAM_A(blackboard,"learning",True,.add_lower_bound(False),
00465 "Whether learning (as controlled by the various alpha_ parameters)\n"
00466 "is enabled.");
00467
00468 PARAM_A(blackboard.lookup_map("::cmd"),"activate",True,.add_lower_bound(False),
00469 "Whether to pass a neuron's initial response through an activation function.\n"
00470 "Usually true, but this can be set to False for some commands to examine the\n"
00471 "initial response, or for commands like measure_stimulus_map which can work\n"
00472 "better with the smooth, continuous initial response than with the more patchy\n"
00473 "activated response.\n");
00474
00475 PARAM_A(blackboard.lookup_map("::cmd"),"settle",True,.add_lower_bound(False),
00476 "Whether settling (as controlled by the tsettle parameter) is enabled or\n"
00477 "disabled.");
00478
00479 PARAM_A(blackboard,"tend",50000,.add_lower_bound(0),
00480 "Upper bound for training iterations.");
00481
00482
00483 CMDOBJ_DOC(step,"init_network",this,0,"%s [<named_arguments>]* [<training_iterations>]",
00484 "Supported <named_arguments> include: <display>,<learning>,<settle>,<activate>.\n\n"
00485
00486 "Same as training except that it interprets the parameter as a value relative\n"
00487 "relative to the current iteration (1 by default), rather than an\n"
00488 "absolute iteration number, and defaults to display==1. Example: \"step\"\n"
00489 "just trains for one iteration and calls plot. Typically used at the\n"
00490 "command prompt for debugging or exploration, rather than in a command file.");
00491 blackboard.lookup_map("::cmd::step")
00492 .set_local("display",1);
00493
00494 CMDOBJ_DOC(testing,"init_network",this,0,"%s [<named_arguments>]* [<tend>]",
00495 "Supported <named_arguments> include: <display>,<learning>,<settle>,<activate>.\n\n"
00496
00497 "Same as training except that learning defaults to False. The iteration counter\n"
00498 "is still advanced.");
00499 blackboard.lookup_map("::cmd::testing")
00500 .set_local("learning",False);
00501
00502 CMDOBJ_DOC(training,"init_network",this,0,"%s [<named_arguments>]* [<tend>]",
00503 "Supported <named_arguments> include: <display>,<learning>,<settle>,<activate>.\n\n"
00504
00505 "Trains the network for the current iteration, then repeats training until\n"
00506 "the iteration counter 'iteration' has reached the <tend>. Sometimes it is\n"
00507 "appropriate to supply a specific tend iteration (e.g. `training 1000' trains\n"
00508 "until iteration 1000); other times it's more useful to supply an offset\n"
00509 "relative to the current iteration (e.g. `training iteration+1000' trains for\n"
00510 "1000 iterations more). After training, the global parameter 'iteration' is\n"
00511 "equal to the specified tend.");
00512
00513 CMDOBJ_DOC(uninit_network,NULL,this,0,"%s",
00514 "Marks network uninitialized so that network architecture parameters\n"
00515 "can be changed. All weight values and training iteration hook\n"
00516 "definitions will be lost, and the iteration counter will be reset to\n"
00517 "zero. However, other parameters keep their existing values, which can\n"
00518 "have surprising consequences. When in doubt, it may be safest to quit\n"
00519 "the program and restart if changing the underlying architecture.");
00520
00521 CMDOBJ_DOC(init_network,"uninit_network",this,0,"%s [<named_arguments>]*",
00522 "Supported <named_arguments> include:\n"
00523 "<initialize>,<essential_training_hooks_only>.\n\n"
00524
00525 "Initializes network with the current parameters, suitable for\n"
00526 "beginning training anew. A command file <filebase>.<iteration>.params\n"
00527 "is created with the current values of parameters, suitable for\n"
00528 "recreating the starting state later. A single cycle of testing\n"
00529 "is done, iterating t to 1, in order to verify that everything is\n"
00530 "working properly. This command is a prerequisite for most other\n"
00531 "commands, and will be called automatically the first time one of\n"
00532 "those commands is executed.");
00533
00534
00535
00536 PARAM_I(PARAM_3BOOL, progress_reports,False,True,
00537 "Whether or not to print messages during very long computations; defaults to\n"
00538 "True for interactive sessions and False otherwise.");
00539 params_define_default_expr("progress_reports","interactive");
00540
00541 PARAM_L(PARAM_INT, progress_report_interval,0,
00542 "The minimum number of seconds between messages printed during very long\n"
00543 "computations, such as training. Only used if progress_reports is True.");
00544
00545 PARAM_L(PARAM_INT, startt,0,
00546 "Starting iteration to be used the next time training or testing begins.\n"
00547 "This should not ordinarily be changed, but it can be used for debugging.");
00548
00549 PARAM_A(blackboard,"essential_training_hooks_only",False,.add_lower_bound(False).add_upper_bound(True),
00550 "If this is true, inessential hooks such as plotting and analysis will be\n"
00551 "ignored during training and initialization. (Whether or not a given command\n"
00552 "is ignored depends upon whether it was defined as a `catchup' command or not;\n"
00553 "see cmdparam.c.) This defaults to true for an interactive session to\n"
00554 "facilitate exploration using a saved batch session; this avoids having too\n"
00555 "many images displayed automatically.");
00556 params_define_default_expr("essential_training_hooks_only","interactive");
00557
00558 PARAM_A(blackboard,"rf_radius",6.0,.add_lower_bound(0.0),
00559 "Default radius (centered about the neuron) of an afferent receptive field.\n"
00560 "Must not be larger than half the width of the input region (usually RN/2).\n\n"
00561
00562 "For square radii, the floating-point value of the radius is rounded to the\n"
00563 "nearest integer. For circular radii, the digits after the decimal point\n"
00564 "determine the shape of the blocky circular outline. For small values of the\n"
00565 "radius you may want to set the decimal value precisely to achieve the most\n"
00566 "circular-looking outline; generally .5 works well.");
00567
00568 PARAM_A(blackboard,"inh_rad",9.0,.add_lower_bound(0.0),
00569 "Default connection radius for lateral inhibitory weights. See rf_radius\n"
00570 "for more information about using floating-point values.");
00571
00572 PARAM_A(blackboard,"exc_rad",4.0,.add_lower_bound(0.0),
00573 "Default connection radius for lateral excitatory weights. When the global\n"
00574 "value of this parameter is changed after a LISSOM map has been defined, each\n"
00575 "such map is converted into one with the smaller excitatory radius. To change\n"
00576 "only a particular map, change that region's value of this parameter instead.\n"
00577 "See rf_radius for more information about using floating-point values.");
00578
00579
00580
00581
00582
00583 CMDARGP("name", string(""), , CMDARGP_DOC);
00584 CMDARGP("objtype", string(""), , CMDARGP_DOC);
00585 CMDARGP("plotgroup", string(""), , CMDARGP_DOC);
00586 CMDARGP("parent", string(""), , CMDARGP_DOC);
00587 CMDARGP("child", string(""), , CMDARGP_DOC);
00588 CMDARGP("source", string(""), , CMDARGP_DOC);
00589 CMDARGP("target", string(""), , CMDARGP_DOC);
00590 CMDARGP("region", string(""), , CMDARGP_DOC);
00591 CMDARGP("type", string(""), , CMDARGP_DOC);
00592 CMDARGP("filename", string(""), , CMDARGP_DOC);
00593
00594 CMDARGP("height", 1,.add_lower_bound(1), CMDARGP_DOC);
00595 CMDARGP("width", 1,.add_lower_bound(1), CMDARGP_DOC);
00596
00597 CMDARGP("save_matrices", False, .add_lower_bound(False).add_upper_bound(True),
00598 "When using a plot routine, whether to save the matrices as ASCII in addition\n"
00599 "to any other plot format generated.");
00600
00601 CMDARGP("gnuplot_plots", False, .add_lower_bound(False).add_upper_bound(True),
00602 "When using a plot routine, whether to generate gnuplot PostScript plots\n"
00603 "and save them to disk.");
00604
00605 CMDARGP("ppm_plots", True, .add_lower_bound(False).add_upper_bound(True),
00606 "When using a plot routine, whether to generate .ppm bitmap images and\n"
00607 "save them to disk.");
00608
00609 CMDARGP("weight_situate", True, .add_lower_bound(False).add_upper_bound(True),
00610 "Whether to situate weight plots in their location on the network. If\n"
00611 "false, weights are shown in their own coordinate systems instead, which\n"
00612 "gives less information but requires less plot area.");
00613
00614 CMDARGP("weight_bare", False, .add_lower_bound(False).add_upper_bound(True),
00615 "If true, suppresses extraneous details from weight plots, such as borders\n"
00616 "outlines, etc., without having to turn off the various other parameters.");
00617
00618 CMDARGP("weight_fill_background",False, .add_lower_bound(False).add_upper_bound(True),
00619 "If true, weight plots fill in all area not containing weights with the\n"
00620 "ppm_page color so that the weight outlines are visible. At present,\n"
00621 "killed connections are not filled in with the background color, instead\n"
00622 "appearing as zero-strength connections, but at some point making\n"
00623 "them into the background color may be implemented.");
00624
00625
00626 WorldViews::register_params_and_commands();
00627 kernel_factory.register_params_and_commands();
00628 neuralregions.register_params_and_commands();
00629
00630
00631
00632
00633
00634
00635
00636
00637 SETFNOBJ_DEFINE2(this,inputs_pereye,inputs_pereye_setfn2);
00638 SETFNOBJ_DEFINE2(this,distribution,distribution_setfn2);
00639 SETFNOBJ_DEFINE2(this,blur_radius,double_blur_setfn2);
00640 SETFNOBJ_DEFINE2(this,blur_type,blur_type_setfn2);
00641 SETFNOBJ_DEFINE2(this,blur_radius_surround_multiplier,double_blur_setfn2);
00642 SETFNOBJ_DEFINE2(this,blur_range_multiplier,double_blur_setfn2);
00643 SETFNOBJ_DEFINE2(this,blur_scale,double_blur_setfn2);
00644 SETFNOBJ_DEFINE2(this,exc_rad,exc_rad_setfn2);
00645
00646 CMDOBJ_DEFINE_CATCHUP(this,0,define_region,
00647 "%s [<named_arguments>]* [<name> [<named_region_arguments>*]]",
00648
00649 "Supported <named_arguments> include: <name>,<type>,<initialize>,\n"
00650 "<height>,<width>,<xoffset>,<yoffset>.\n\n"
00651
00652 "Supported <type>s include: LISSOM (default), Convolution, Retina\n"
00653 "(At present only LISSOM accepts any <named_region_arguments>.)\n\n"
00654
00655 "Define a new neural region with the given <name>, which defaults to\n"
00656 "'Primary'. After definition, the value of default_region is set to\n"
00657 "this <name>, e.g. for plot_unit and plot_unit_range. (Often this\n"
00658 "command will only need to be called explicitly once, for a top-level\n"
00659 "region, and then the rest of the input pathway can be constructed to\n"
00660 "match it by connect_region using default_region.)\n\n"
00661
00662 "After the default_region is set, the command (if any) specified in\n"
00663 "'Region::.defaults::<type>::default_command' is executed.");
00664 blackboard.lookup_map("::cmd::define_region")
00665 .set_local("type",string("LISSOM"))
00666 .set_local("name",string("Primary"));
00667 PARAM_A(blackboard.lookup_map("::Region"),"num_aff_inputs",1,.add_lower_bound(0)
00668 .add_default_expr("num_eyes*(layers_pereye>?1)"),
00669 "Parameter for a LISSOM map specifying the number of afferent inputs that\n"
00670 "you will eventually connect. Most region types do not need this information,\n"
00671 "since it is implicit in the calls to connect_region, but LISSOM maps currently\n"
00672 "must know num_aff_inputs when they are created because they initialize all\n"
00673 "weights at that time. Warnings will be generated if the number of actual\n"
00674 "calls to connect_region before the first iteration does not match this\n"
00675 "parameter's value.\n");
00676
00677 PARAM_A(blackboard.lookup_map("::cmd"),"initialize",True,.add_lower_bound(False),
00678 "Whether to initialize the internal state of a region or a set of connections\n"
00679 "when creating it. Not usually changed to false by users, but some commands\n"
00680 "(e.g. load_snapshot) specify false because they will be initializing the\n"
00681 "objects themselves.");
00682 PARAM_A(blackboard.lookup_map("::cmd::define_region"),"xoffset",0.5,,
00683 "When creating a new region, where to place the horizontal (x) axis of the\n"
00684 "coordinate system origin. At present many region types ignore this parameter\n"
00685 "and always place the origin at (0.5,0.5).");
00686 PARAM_A(blackboard.lookup_map("::cmd::define_region"),"yoffset",0.5,,
00687 "When creating a new region, where to place the vertical (y) axis of the\n"
00688 "coordinate system origin. At present many region types ignore this parameter\n"
00689 "and instead always place the origin at (0.5,0.5).");
00690
00691 CMDOBJ_DEFINE_CATCHUP(this,0,connect_region,
00692 "%s [<named_arguments>]* [<connection_arguments>*]",
00693
00694 "Supported <named_arguments> include: <name>,<target>,<source>,<sourcespec>,\n"
00695 "<size_scale>.\n\n"
00696
00697 "Define a new set of connections from the neural region <target> to the\n"
00698 "region <source>. The <connection_arguments> are as for\n"
00699 "input_define_convolution, which see. (Exception: named arguments cannot\n"
00700 "be used in the <connection_arguments>, because they will be processed in\n"
00701 "this command instead, and will thus have no effect.)\n\n"
00702
00703 "The connection <name> defaults to 'Afferent'. All connections to a given\n"
00704 "<target> MUST have a unique <name>. In addition, it is usually a good idea\n"
00705 "to keep all connection <names> for a given <source> unique, since e.g. plotting\n"
00706 "parameters are stored with the <source> and not the target.\n\n"
00707
00708 "If a <sourcespec> is given, the <source> region will be created\n"
00709 "(or recreated) with a size that provides full connectivity (by default)\n"
00710 "for the target region with this size, connection radius, etc.");
00711 blackboard.lookup_map("::cmd::connect_region")
00712 .set_local("name",string("Afferent"));
00713 PARAM_A(blackboard.lookup_map("::cmd::connect_region"),"sourcespec",string(),,
00714 "If this argument is non-empty (even a quoted space will do), a new source\n"
00715 "region will be created (and will replace any old one by that name, if present.)\n"
00716 "Default sizes for the source are computed from the <target>, <size_scale>, and\n"
00717 "<connection_arguments>, and these values are combined with the value of this\n"
00718 "parameter and then passed to the define_region command to define the region.");
00719
00720
00721 CMDOBJ_DEFINE_CATCHUP(this,0,input_define,
00722 "%s [<name> [<parent> [<objtype> [<input_object_arguments>*]]]]",
00723
00724 "Define a new persistent input object with the given <name>.\n\n"
00725
00726 "The <parent> may be the name of one input region, e.g. EyeX, where\n"
00727 "X is a numeric digit representing a single eye, \"\", \'\', or 'All'\n"
00728 "for all input regions, or the name of a previously defined\n"
00729 "Input_Composite object. (To keep yourself from getting confused about\n"
00730 "which regions are included in `all input regions', you should probably\n"
00731 "not change num_eyes after you call this command.)\n\n"
00732
00733 "The <objtype> may be any of the following (prefixed with `Input_'):\n\n"
00734
00735 " Composite,UniformRandomNoise,Gaussian,CircularGaussian,\n"
00736 " SineGrating,Gabor,PGM,Clone,Rectangle\n"
00737 " FuzzyLine,FuzzyDisc,FuzzyRing\n\n"
00738
00739 "See the documentation for the corresponding constants for more\n"
00740 "information on that particular object type.\n\n"
00741
00742 "The remaining parameters are determined by the <objtype>. They\n"
00743 "can generally be specified either by position, i.e. by listing\n"
00744 "them in order, or by name, e.g. by specifying xsigma=5. All\n"
00745 "named arguments must follow any positional arguments.\n\n"
00746
00747 "Most or all floating-point parameters may be a ValueGenerator, i.e.\n"
00748 "any <valuegenerator> accepted by the input_define_generator command.\n"
00749 "If the object is being defined in more than one input region, the\n"
00750 "specified <valuegenerator>s apply only to the first region. Objects\n"
00751 "in the remaining regions are created with references to the\n"
00752 "corresponding parameters in the first, so that e.g. random values are\n"
00753 "fully correlated between the input regions.\n\n"
00754
00755 "If you wish to introduce some degree of uncorrelation between\n"
00756 "objects defined in more than one region, you may substitute for any\n"
00757 "ValueGenerator parameter the extended syntax:\n\n"
00758
00759 " \"Uncorrelate <uncorrelation-ratio> <lower-bound> <upper-bound> <valuegenerator>\"\n\n"
00760
00761 "This will add or subtract a random value to the value generated\n"
00762 "in the first region, scaled by the difference between the bounds times\n"
00763 "the uncorrelation-ratio, and cropped by the bounds. For instance,\n\n"
00764
00765 " \"Uncorrelate &uncorrelation 0 RN Random RN/2 RN/2\"\n\n"
00766
00767 "when uncorrelation=1.0 will create a random number generator\n"
00768 "in the range 0..RN in the first region, and will effectively\n"
00769 "uncorrelate the value entirely within that range in all the\n"
00770 "other input regions. (This is the default for <cx> and <cy>\n"
00771 "parameters, except that uncorrelation is not necessarily 1.0.)\n\n"
00772
00773 "Since ValueGenerators and input objects are extremely flexible, be\n"
00774 "sure to look at images of the inputs for a number of sample iterations\n"
00775 "so that you can verify that the inputs are being generated as you expect.\n"
00776 "You can also look at the logfile (when input_log is true) to verify\n"
00777 "the average and range for some of the generated values.");
00778
00779 CMDOBJ_DEFINE_CATCHUP(this,2,input_define_generator,
00780 "%s <name> <valuegenerator> [<helpstring>]",
00781
00782 "Define a new ValueGenerator whose value is updated before every input\n"
00783 "presentation. A ValueGenerator is like a generalization of a parameter\n"
00784 "of type PARAM_DOUBLE which supports automatic updating from e.g. a\n"
00785 "random distribution. This command allows you to define a named\n"
00786 "ValueGenerator which can be referred to when later defining input\n"
00787 "objects; this enables you to e.g. define a single random number\n"
00788 "which controls multiple objects in unison. The value also\n"
00789 "becomes a parameter, so it will henceforth show up in documentation,\n"
00790 "online help, etc., and can be set or queried like any parameter.\n\n"
00791
00792 "Possible values for a <valuegenerator>:\n\n"
00793
00794 " <expr> A floating-point expression. (Ex: 2*PI)\n\n"
00795
00796 " &<param> A reference to a parameter. (Ex: &xsigma)\n"
00797 " Future changes to the parameter will be\n"
00798 " reflected in the ValueGenerator, so this\n"
00799 " form provides a means for controlling a\n"
00800 " ValueGenerator after creation and linking\n"
00801 " multiple ValueGenerators together. This form\n"
00802 " is also accepted for the numeric arguments of\n"
00803 " all the other ValueGenerators defined below.\n\n"
00804
00805 " \"Random <m> <r>\" A random number from the uniform distribution\n"
00806 " centered at mean <m> and extending radius <r>\n"
00807 " in either direction (inclusively on the lower\n"
00808 " side, exclusively on the higher).\n"
00809 " (Ex: \"Random PI/2 PI/2\" or \"Random &mean &radius\"\n\n"
00810
00811 " \"Normal <m> <r>\" A random number from the normal distribution\n"
00812 " centered at mean <m> with sigma (approx. half-width at\n"
00813 " half-height) <r>.\n"
00814 " (Ex: \"Normal PI/2 PI/2\" or \"Normal &mean &radius\")\n\n"
00815
00816 " \"Increment <s> <i>\" Starts at value <s>; before each presentation, it\n"
00817 " is incremented by <i> (which may be negative or\n"
00818 " non-integer). Note that increment occurs *before*\n"
00819 " each presentation, so decrement the starting\n"
00820 " value if needed.\n"
00821 " (Ex: \"Increment -1 1\" to count from 0 by 1)\n\n"
00822
00823 " \"Correlate <m> <u> <lb> <ub> \" Generate a value correlated with\n"
00824 " the given master variable <m> within a correlation\n"
00825 " constant of <u>. Optionally crops to the given\n"
00826 " range [<lb>..<ub>]. This description may be\n"
00827 " seriously incomplete, so study the code a bit first.\n\n"
00828
00829 " \"Expression <e>\" Before each presentation, the given expression <e>\n"
00830 " is evaluated to get a value.\n"
00831 " (Ex: \"Expression theta+PI/2\" to get the current\n"
00832 " value of theta, plus PI/2, each time)\n\n"
00833
00834 "Single or double quotes are required for any form that has an embedded space,\n"
00835 "and are optional for the others.\n\n"
00836
00837 "Calling this command multiple times for the same name is not an error,\n"
00838 "but subsequent calls are ignored.");
00839
00840 CMDOBJ_DEFINE_CATCHUP(this,0,input_define_convolution,
00841 "%s [<named_arguments>]* [<parent> [<blur_type> [<blur_type_arguments>*]]]",
00842
00843 "Supported <named_arguments> include: <default_afferent_size_scale>,\n"
00844 "<num_eyes>,<layers_pereye>.\n\n"
00845
00846 "Defines a convolution kernel for the given input region(s) (specified as\n"
00847 "in input_define) to perform input blurring, smoothing, edge detection or\n"
00848 "(in general) convolution. This command is called automatically at network\n"
00849 "initialization and when any of the parameters blur_type, blur_radius,\n"
00850 "blur_scale, or blur_range_multiplier are changed. It can also be called\n"
00851 "explicitly for more precise control. Note that this command clears the\n"
00852 "the current activity values of the input regions, since some may be\n"
00853 "regenerated, so e.g. activity plots will show blank values until new\n"
00854 "activity is computed.\n\n"
00855
00856 "See the documentation for each type for more information. Convolution\n"
00857 "radii should be specified in terms of the retinal output; any scaling\n"
00858 "with respect to world_size_scale is handled automatically. Available\n"
00859 "types include the following (prefixed with 'Blur_'):\n"
00860 " CircularAverage,SquareAverage,Gaussian,DoG,LoG,GoD,DoGGoD");
00861 PARAM_A(blackboard,"default_afferent_size_scale",0.0,,
00862 "Default size ratio between a target region and a region connected to\n"
00863 "an input. This is the ratio between the areas mapped directly between\n"
00864 "the regions. For any given region, such an area can be less than the\n"
00865 "full area because other regions may be expanded to provide full receptive\n"
00866 "fields for this region. At present, see retina_edge_buffer for more\n"
00867 "details, although that parameter is likely to be replaced with one\n"
00868 "that does not depend on connection radii.");
00869 params_define_default_expr("default_afferent_size_scale","BaseN/BaseRN");
00870
00871
00872 CMDOBJ_DOC(input_draw,"init_network",this,0,
00873 "%s [<named_arguments>]* [<parent> [<objtype> [<input_object_arguments>*]]]",
00874 "Supported <named_arguments> include: <name>.\n\n"
00875
00876 "Same as input_define, but adds the unnamed object to a collection of\n"
00877 "temporary objects (e.g. for testing) to be presented using input_present.\n\n"
00878
00879 "The arguments are like those in input_define. If no arguments are supplied,\n"
00880 "the object specified by parameter input_default_object is created in all\n"
00881 "input regions, with default arguments.\n\n"
00882
00883 "The input_clear command can be called before this command to ensure\n"
00884 "that the object list is empty. This command may be called multiple times\n"
00885 "to define more than one object, either in the same or different input regions.\n"
00886 " The object is not seen by the network until input_present is called.\n\n"
00887
00888 "Objects created by this command are named 'input_draw' by default, but\n"
00889 "another can be supplied, e.g. if you are constructing composite objects.");
00890
00891 CMDOBJ_DOC(input_clear,"init_network",this,0,"%s [<named_arguments>]* [<parent>]",
00892 "Supported <named_arguments> include: <name>,<parent>.\n\n"
00893
00894 "Clears the specifed temporary objects (all objects, by default) defined\n"
00895 "for the given parent (all input regions, by default) in preparation for\n"
00896 "e.g. input_draw.");
00897
00898 CMDOBJ_DOC(input_present,"init_network",this,0,"%s [<named_arguments>]*",
00899 "Supported <named_arguments> include: <display>,<learning>,<settle>,<activate>,<reset>.\n\n"
00900
00901 "If <reset> is False (the default), presents the temporary objects currently\n"
00902 "defined by input_draw and activates the network, without advancing the\n"
00903 "iteration counter. By default, learning is disabled for this test pattern,\n"
00904 "but it can be enabled by setting <learning> to True. By default,\n"
00905 "pictures are saved using plot when the command completes; <display> can be\n"
00906 "set to zero to prevent this or to some integer higher than one to display only\n"
00907 "every <display>th presentation. Unless <settle> is set to False, the network\n"
00908 "is allowed to settle after the initial activity calculation (for region types\n"
00909 "for which settling is defined). Unless <activate> is False, the activation of\n"
00910 "each neuron is computed from using its activation function; if it's True then\n"
00911 "only the initial response is used.\n\n"
00912
00913 "If <reset> is True, then this command restores the permanent contents of the\n"
00914 "eye and presents that instead of the temporary patterns defined with input_draw.");
00915 blackboard.lookup_map("::cmd::input_present")
00916 .set_local("learning",False)
00917 .set_local("display",1);
00918
00919 CMDOBJ_DOC(input_present_object,"init_network",this,0,
00920 "%s [<named_arguments>] [<parent> [<objtype> [<input_object_arguments>*]]]",
00921 "Supported <named_arguments> include: <name>,<display>,<learning>,<settle>,\n"
00922 "<activate>.\n\n"
00923
00924 "Convenience macro for looking at the response to a single object.\n"
00925 "Calls input_clear, then passes all the arguments to input_draw and\n"
00926 "then input_present. (input_present ignores the <input_object_arguments>,\n"
00927 "if any).");
00928
00929 CMDOBJ_DOC(input_print,NULL,this,0,"%s [<name> [<parent>]]",
00930 "Print a textual representation of the specified input object in the specified\n"
00931 "parent. Parent defaults to all inputs, and name defaults to all persistent\n"
00932 "objects.");
00933
00934 CMDOBJ_DEFINE_CATCHUP(this,0,input_reset,
00935 "%s [input_seed]",
00936 "Reset all persistent retinal objects and the input random number generator to\n"
00937 "their starting states. For instance, if any Increment ValueGenerators have\n"
00938 "been defined (see input_define_generator), their values will be reset to the\n"
00939 "start value supplied initially.\n\n"
00940
00941 "The random number generator is reset to the specified seed (or the value of\n"
00942 "input_seed if none is given), so the same series of pseudo-random numbers will\n"
00943 "be seen as the last time this command was called. This means that the\n"
00944 "same sequence of input values will be generated unless other input settings\n"
00945 "have changed, which makes it possible to independently test the effect of\n"
00946 "unrelated changes such as to the network architecture.\n\n"
00947
00948 "This command is called automatically by init_network, so (in general) changes\n"
00949 "in architecture parameters or the number of PEs should not usually affect the\n"
00950 "input sequence generated. (Known exception: when Input_UniformRandom inputs\n"
00951 "are used, each processor computes the values independently instead of copying\n"
00952 "from a single master PE, so in that case the sequence will differ when the\n"
00953 "number of PEs changes.)");
00954
00955 CMDOBJ_DEFINE_CATCHUP(this,0,input_undefine,"%s [<name> [<parent>]]",
00956 "Remove specified input object from specified parent. Parent defaults to\n"
00957 "all input regions, and name defaults to all persistent objects.");
00958
00959 CMDOBJ_DOC(load_snapshot,NULL,this,0,"%s [<named_arguments>]* [<tend> [<filename>]]",
00960 "Supported <named_arguments> include: <tend>,<filename>,<verbose>,\n"
00961 "<regions>,<plastic>,<internal>.\n\n"
00962
00963 "Load weight files saved earlier at the specified iteration <tend>, in order to\n"
00964 "test it or continue training. If no filename is specified, one is constructed\n"
00965 "as for save_snapshot at the specified iteration. The load will fail if the\n"
00966 "architecture parameters do not match the current values.\n\n"
00967
00968 "Specific regions can be given in the regions parameter, in which case only\n"
00969 "those regions are restored. If using this option, you should ensure that\n"
00970 "the network has first been initialized (via init_network, called\n"
00971 "automatically by most commands), since otherwise regions whose state\n"
00972 "is not restored will have undefined (uninitialized) weight values.");
00973 blackboard.lookup_map("::cmd::load_snapshot")
00974 .set_local("essential_training_hooks_only",True)
00975 .set_local("plastic",True);
00976
00977 PARAM_A(blackboard.lookup_map("::Region"),"activity_threshold",-1.0,,
00978 "Threshold below which activation is set to zero, usually to save computation\n"
00979 "time. For an input region, judicious use of this parameter can reduce the\n"
00980 "amount of computation performed in later recurrent regions, since those often\n"
00981 "compute final activations only when a neuron has some initial activation.\n"
00982 "The values should be set high enough so that activations below it would rarely\n"
00983 "exceed the thresholds of subsequent states. For a recurrent region, an\n"
00984 "activation reaching this lower value is eliminated from future calculations,\n"
00985 "with similar results. Ignored if < 0.0.\n");
00986 PARAM_A(blackboard.lookup_map("::Region"),"activity_lbound",2.0,,
00987 "Activations below this value are set to it, e.g. to prevent overwhelming later\n"
00988 "regions. Ignored if > 1.0 (negative values are allowed).\n");
00989 PARAM_A(blackboard.lookup_map("::Region"),"activity_ubound",-1.0,,
00990 "Activations above this value are set to it, e.g. to prevent overwhelming later\n"
00991 "regions. Ignored if < 0.0.\n");
00992
00993 blackboard.define_param(DECLARE_PARAM(PARAM_INT,"current_object_angle",true,¤t_object_angle));
00994 params_define_doc("current_object_angle",
00995 "Read-only parameter which reports the top-level (nominal) angle of the object\n"
00996 "last drawn on an input surface, in degrees. This can be useful for\n"
00997 "constructing filenames for a series of images differing primarily by their\n"
00998 "orientations. The value is only guaranteed to be current during a call\n"
00999 "to the plot command.\n\n"
01000
01001 "Obviously, one might also wish to include positions, disparities, etc., in\n"
01002 "filenames, but rather than adding new parameters for each such possibility,\n"
01003 "the command language should probably be extended to be able to access all\n"
01004 "such quantities directly. Such support has not yet been provided because\n"
01005 "the command language is not yet sufficient to convert the angle in radians\n"
01006 "to a clean integer value in degrees.");
01007 SETFN_DEFINE2(current_object_angle,read_only_param_setfn2);
01008
01009 PARAM_LL(PARAM_DOUBLE,world_size_scale,&world_size_scale,0,
01010 "Scale of world model relative to the size of the retinal ganglia. Only\n"
01011 "used when layers_pereye>0. In such cases, it can be useful for the world\n"
01012 "to have a higher resolution than the network input in order to avoid aliasing\n"
01013 "effects for operations like rotation of image input.");
01014 SETFNOBJ_DEFINE2(this,world_size_scale,double_blur_setfn2);
01015
01016 PARAM_NN(PARAM_STRING,default_region,&default_region,
01017 "The name of a region to use as the default for commands expecting\n"
01018 "a single region, like plot_unit, plot_unit_range, and define_region.\n"
01019 "This default is used as the <region> for such commands when no non-empty\n"
01020 "<region> is specified in their arguments. Also used as the default\n"
01021 "<target> for commands expecting <source> and <target> regions, such as\n"
01022 "connect_region. Every time define_region is called, it changes the\n"
01023 "value of this parameter to be the <name> of the newly-defined region.");
01024
01025 PARAM_NN(PARAM_STRING,default_region_command,&default_region_command,
01026 "Command that will be used to construct a default region, if not has yet\n"
01027 "been defined when init_network is called. Usually this will be\n"
01028 "one or more define_region calls with options.");
01029
01030 PARAM_A(blackboard.lookup_map("::Region"),"default_command",string(""),,
01031 "Default command to be executed after a region of this type is created.");
01032
01033
01034
01035
01036
01037 BlackboardType* typedefaults = blackboard.lookup_map("::Region").new_child(".defaults",true);
01038
01039
01040
01041
01042
01043 (* typedefaults->new_child("LISSOM",true))
01044 .set_local("default_command",
01045 string("exec 'connect_region name=LateralExcitatory target=${default_region} source=${default_region}"
01046 " size_scale=1.0 Blur_CircularRandom ::Region::${default_region}::exc_rad' "
01047 " 'connect_region name=LateralInhibitory target=${default_region} source=${default_region}"
01048 " size_scale=1.0 Blur_CircularRandom ::Region::${default_region}::inh_rad' "))
01049 .set_local("activity_threshold",1.0E-09);
01050
01051 (* typedefaults->new_child("Retina",true))
01052 .set_local("activity_threshold",1.0/(Math::e*Math::e));
01053
01054 (* typedefaults->new_child("Convolution",true))
01055 .set_local("activity_threshold",1.0/(Math::e*Math::e));
01056 }
01057
01058
01059
01061 void Eyes::advance_iteration_counter(int old_t, int new_t)
01062 {
01063 int i;
01064 for (i=old_t; i<new_t; i++) {
01065 hooklists_run_list(before_input,i,True);
01066
01067 hooklists_run_list(after_learning,i,True);
01068 }
01069 }
01070
01071
01072
01073
01074
01075
01076
01077
01079 template <class InContainer, class OutContainer>
01080 class ParameterizedThreshold : public SequenceTransform::OneD<InContainer,OutContainer> {
01081 public:
01082 typedef typename InContainer::value_type value_type;
01083
01087 ParameterizedThreshold(const ParamMap& params_) : params(params_) { }
01088
01089 virtual void operator() (const InContainer& in, OutContainer& out) const {
01090 const double threshold = params.get_with_default("activity_threshold", -1.0);
01091 const double low_bound = params.get_with_default("activity_lbound", 2.0);
01092 const double upp_bound = params.get_with_default("activity_ubound", -1.0);
01093
01094 if (threshold>=0.0) Generic::lower_threshold(MSEQ(in),MBEGIN(out),threshold,0.0);
01095 if (low_bound<=1.0) Generic::lower_threshold(MSEQ(in),MBEGIN(out),low_bound,low_bound);
01096 if (upp_bound>=0.0) Generic::upper_threshold(MSEQ(in),MBEGIN(out),upp_bound,upp_bound);
01097 }
01098
01099 private:
01100 const ParamMap& params;
01101 };
01102
01103
01104 cmdstat Eyes::cmd_define_region( CMD_ARGS )
01105 {
01106 CMD_ARG_PARAMS(define_region);
01107
01108 if (!has_default_region()) update_default_values();
01109
01110 const string name = arglist.next(argparams.get_with_default("name",string("")));
01111 const string type = argparams.get_with_default("type",string(""));
01112 const int height = argparams.get_with_default("height",1);
01113 const int width = argparams.get_with_default("width",1);
01114 const double xoffset = argparams.get_with_default("xoffset",0.5);
01115 const double yoffset = argparams.get_with_default("yoffset",0.5);
01116 typedef ParameterizedThreshold<NeuralRegion::ActivityMatrix,NeuralRegion::ActivityMatrix> ThresholdActfn;
01117
01118 const NeuralRegion::Dimensions dims =
01119 NeuralRegion::Dimensions(height,width,xoffset,yoffset);
01120
01121
01122 if (name=="") {
01123 message(Msg::Error,"A <name> is required; no region defined");
01124 return CMD_PARAMETER_ERROR;
01125 }
01126
01127
01128 BlackboardType& region_params = blackboard.lookup_map("::Region");
01129 BlackboardType* new_params = &(region_params.lookup_map(name,false));
01130 if (new_params==®ion_params)
01131 new_params = region_params.new_child(name,true);
01132 new_params->merge(blackboard.lookup_map("::Region::.defaults::"+type),false);
01133 new_params->set_local("type",type)
01134 .set_local("height",height).set_local("width", width)
01135 .set_local("xoffset",xoffset).set_local("yoffset",yoffset);
01136 cmdparams_set(*new_params,arglist,true,false,false);
01137
01138
01140 if (type=="LISSOM")
01141
01142 neuralregions.new_manager(*LissomMap_create(name,dims,initialize_weights,new_params),
01143 new_params);
01144 #if 0
01145 else if (type=="OBJ-LISSOM")
01146
01147 neuralregions.new_manager(*ObjLissomMap_create(name,dims,initialize_weights,new_params),
01148 new_params);
01149 #endif
01150 else if (type=="Retina") {
01151 const double size_scale = argparams.get_with_default("size_scale",1.0);
01152 neuralregions.new_manager(*new retina_type(name,dims,new ThresholdActfn(*new_params),
01153 size_scale),
01154 new_params);
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167 const double nominal_width = (dims.width +2*(dims.xoffset-0.5))/world_size_scale;
01168 const double nominal_height = (dims.height+2*(dims.yoffset-0.5))/world_size_scale;
01169 permanent_contents.define(name,nominal_height,nominal_width);
01170 temporary_contents.define(name,nominal_height,nominal_width);
01171 }
01172 else if (type=="Convolution")
01173 neuralregions.new_manager(*new FixedWtRegion(name,dims,new ThresholdActfn(*new_params)),
01174 new_params);
01175 else {
01176 message(Msg::Error,"Unknown <type>: "+type+"; no region defined");
01177 return CMD_PARAMETER_ERROR;
01178 }
01179
01180
01181 default_region = name;
01182 const string default_command=new_params->get_with_default("default_command",string());
01183 if (!default_command.empty()) cmddefs_exec_str(default_command);
01184
01185
01186 CMD_ARG_ASSERT_EMPTY;
01187 return CMD_NO_ERROR;
01188 }
01189
01190
01192 std::ostream& operator<<(std::ostream &s, const NeuralRegion::Dimensions& d)
01193 {
01194 s << "height=" << d.height
01195 << " width=" << d.width
01196 << " xoffset=" << d.xoffset
01197 << " yoffset=" << d.yoffset;
01198 return s;
01199 }
01200
01201
01202
01203
01204 cmdstat Eyes::cmd_connect_region( CMD_ARGS )
01205 {
01206 CMD_ARG_PARAMS(connect_region);
01207
01208 if (!has_default_region()) update_default_values();
01209
01210 const string default_name = "Afferent";
01211 const string specified_name = argparams.get_with_default("name",string(""));
01212 const string name = (specified_name!=""? specified_name : default_name);
01213
01214 const string specified_target = argparams.get_with_default("target",string(""));
01215 const string targetstr = (specified_target!=""? specified_target : default_region);
01216 NeuralRegionManager* target = neuralregions.getptr(targetstr);
01217
01218 const string sourcestr = argparams.get_with_default("source",string(""));
01219 NeuralRegionManager* source = neuralregions.getptr(sourcestr);
01220
01221 const string sourcespec = argparams.get_with_default("sourcespec",string(""));
01223 const double size_scale = (size_scale_override>=0? size_scale_override :
01224 argparams.get_with_default("size_scale",1.0));
01225
01228 const int connectionnum = String::numeric_extension<int>(targetstr);
01229
01230 if (!target) {
01231 ipc_notify(IPC_ONE,IPC_ERROR, "Could not locate <target> region %s; no connection defined",targetstr.c_str());
01232 return CMD_PARAMETER_ERROR;
01233 }
01234 else if (!target->internalregion()) {
01235 ipc_notify(IPC_ONE,IPC_ERROR, "The <target> region %s cannot accept incoming connections",targetstr.c_str());
01236 return CMD_PARAMETER_ERROR;
01237 }
01238
01239
01240 KernelFactoryWrapper kfw(kernel_factory,arglist,connectionnum);
01241
01242
01243 if (!mat::size(kfw(size_scale))) {
01244 message(Msg::Error,"Empty connection matrix; no connection defined");
01245 return CMD_PARAMETER_ERROR;
01246 }
01247
01248
01249 if (sourcespec!="") {
01250 const NeuralRegion::Dimensions dims = target->internalregion()->input_dimensions(kfw,size_scale);
01251 const string command = "define_region name="+sourcestr+" "+String::stringrep(dims)+" "+sourcespec;
01252 cmddefs_exec_str(command);
01253 source = neuralregions.getptr(sourcestr);
01254 }
01255
01256 if (!source) {
01257 ipc_notify(IPC_ONE,IPC_ERROR, "The <source> region %s does not exist; no connection defined",sourcestr.c_str());
01258 return CMD_PARAMETER_ERROR;
01259 }
01260
01261
01262 target->add_input(name,*source,kfw,size_scale);
01263
01264 return CMD_NO_ERROR;
01265 }
01266
01267
01268
01270 cmdstat Eyes::cmd_uninit_network( CMD_UNUSED_ARGS )
01271 { uninit(); return CMD_NO_ERROR; }
01272
01273
01275 void Eyes::update_default_values()
01276 {
01277 int oldval=cmdparam_changes_verbose;
01278 cmdparam_changes_verbose=False;
01279 params_update_all_default_values();
01280 cmdparam_changes_verbose=oldval;
01281 }
01282
01283
01284
01285 cmdstat Eyes::cmd_init_network( CMD_ARGS )
01286 {
01287 CMD_ARG_PARAMS(init_network);
01288 cmdparam_changes_verbose = False;
01289
01290
01291
01292 cmddefs_exec_str("select_param_set ::");
01293
01294
01295 initialize_weights = argparams.get_with_default("initialize",True);
01296
01297
01298 iteration=0;
01299
01300 update_default_values();
01301
01302
01303 if (params_check_all() != 0) {
01304 const Tristate interactive = blackboard.get_with_default("interactive",True);
01305 if (interactive) {
01306 ipc_notify(IPC_ONE,IPC_WARNING, "init_network failed due to parameter problem; fix message(s) above and try again");
01307 return CMD_PARAMETER_ERROR;
01308 }
01309 else
01310 ipc_exit(IPC_EXIT_PARAM_VALUE_ERROR, "Parameter problem (see message(s) above)");
01311 }
01312
01313
01314
01315 shuffled_rand_reset();
01316 for(int i=0; i < 500+MyPE; i++)
01317 ShuffledRandom<double>::plain_rand();
01318
01319 init();
01320
01321
01322 ::network_initialized = True;
01323 cmddefs_declare_prereq_status( "init_network", CMD_NO_ERROR );
01324
01325
01326 argparams.set_local("tend",0).set_local("learning",False);
01327 training(arglist,argparams);
01328
01329
01330 reset();
01331
01332
01333 if (AMPARENTPE) cmddefs_exec_str("save_params");
01334 ipc_notify(IPC_ONE,IPC_STD, "Current parameters saved to .params file; future changes will be reported");
01335
01336 cmdparam_changes_verbose = True;
01337
01338 cmddefs_exec_str("select_param_set");
01339
01340 return CMD_NO_ERROR;
01341 }
01342
01343
01344
01345 #define PROGRESS_REPORT_NEEDED(last_msg_time) \
01346 (progress_reports && (time(NULL)-(last_msg_time) >= progress_report_interval))
01347
01348
01349
01351 cmdstat Eyes::cmd_training( CMD_ARGS )
01352 {
01353 CMD_ARG_PARAMS(training);
01354 return training(arglist,argparams);
01355 }
01356
01357 cmdstat Eyes::training(StringArgs& arglist, const ParamMap& argparams)
01358 {
01359 const bool incremental = (arglist.top(string(""))[0] == '+');
01360 const int tend = arglist.next(argparams.get_with_default("tend",1))
01361 + (incremental? iteration : 0);
01362 const bool learning = argparams.get_with_default("learning",True);
01363 const int display = argparams.get_with_default("display",1);
01364 const bool ess_h_only = argparams.get_with_default("essential_training_hooks_only",False);
01365
01366 time_t last_msg_time = time(NULL);
01367
01368 if (tend-startt>1) {
01369 if (learning)
01370 ipc_notify(IPC_ONE,IPC_STD,"Training until iteration %d", tend);
01371 else if (iteration!=0)
01372 ipc_notify(IPC_ONE,IPC_STD,"Testing until iteration %d", tend);
01373 }
01374
01375
01376 for(iteration=startt; iteration <= tend; iteration++) {
01377 ipc_barrier();
01378
01379 if (PROGRESS_REPORT_NEEDED(last_msg_time)) {
01380 last_msg_time = time(NULL);
01381 ipc_notify(IPC_ONE,IPC_STD,"%s has reached iteration %06d, %.24s",
01382 (learning ? "Training" : "Testing"),iteration,ctime(&last_msg_time));
01383 }
01384
01385
01386 hooklists_run_list(before_input,iteration,ess_h_only);
01387
01388
01389 next();
01390 #ifdef PRINT_TIME_PER_ITERATION
01391 clock_t time_before_iteration = clock();
01392 #endif
01393
01394 activate(permanent_contents,argparams);
01395
01396 #ifdef PRINT_TIME_PER_ITERATION
01397 ipc_log(IPC_ONE,"Iteration %06d took %04d milliseconds",
01398 iteration,(int)((clock()-time_before_iteration)*1000.0/CLOCKS_PER_SEC));
01399 #endif
01400
01401 hooklists_run_list(after_learning,iteration,ess_h_only);
01402 if (display && iteration%display==0)
01403 cmddefs_exec_str("plot");
01404 }
01405 startt = iteration;
01406 iteration--;
01407
01408 CMD_ARG_ASSERT_EMPTY;
01409
01410 return CMD_NO_ERROR;
01411 }
01412
01413
01414
01415 cmdstat Eyes::cmd_testing( CMD_ARGS )
01416 {
01417 CMD_ARG_PARAMS(testing);
01418 return training(arglist,argparams);
01419 }
01420
01421
01422
01423 cmdstat Eyes::cmd_step( CMD_ARGS )
01424 {
01425
01426 CMD_ARG_PARAMS(step);
01427 argparams.set_local("tend", iteration+arglist.next(1));
01428 return training(arglist,argparams);
01429 }
01430
01431
01432
01433 cmdstat Eyes::cmd_input_define_generator( CMD_ARGS )
01434 {
01435 CMD_ARG_LIST;
01436
01437 return namedgenerators.create(arglist);
01438 }
01439
01440
01441 cmdstat Eyes::cmd_input_define_convolution( CMD_ARGS )
01442 {
01443 CMD_ARG_PARAMS(input_define_convolution);
01444
01445 if (default_input_target=="")
01446 default_input_target=ensure_default_region();
01447
01448 const string parent = arglist.next(argparams.get_with_default("parent",string("")));
01449 const double size_scale = argparams.get_with_default("default_afferent_size_scale",1.0);
01450 const int number = argparams.get_with_default("num_eyes",1);
01451 const int numlayers = argparams.get_with_default("layers_pereye",1);
01452
01453 if (parent!="" && parent!="All")
01454 define_input_pathway( default_input_target, parent, arglist, size_scale, numlayers );
01455 else for (int e=0; e<number; e++)
01456 define_input_pathway( default_input_target, "Eye"+String::stringrep(e), arglist, size_scale, numlayers );
01457
01458 input_define_convolution_in_use=true;
01459
01460 CMD_ARG_ASSERT_EMPTY;
01461 return CMD_NO_ERROR;
01462 }
01463
01464
01465
01466 cmdstat Eyes::cmd_input_clear( CMD_ARGS )
01467 {
01468 CMD_ARG_PARAMS(input_clear);
01469 const string parent = arglist.next(argparams.get_with_default("parent",string("")));
01470 const string name = argparams.get_with_default("name",string(""));
01471 temporary_contents.remove_object(parent,name);
01472 ipc_notify(IPC_ONE,IPC_VERBOSE,"Cleared temporary objects");
01473 CMD_ARG_ASSERT_EMPTY;
01474 return CMD_NO_ERROR;
01475 }
01476
01477
01478
01479 cmdstat Eyes::cmd_input_draw( CMD_ARGS )
01480 {
01481 CMD_ARG_PARAMS(input_draw);
01482 const string spec_name = argparams.get_with_default("name",string(""));
01483 const string name = (spec_name != "") ? spec_name : "input_draw";
01484
01485
01486 if (temporary_contents.create_object(arglist,name,permanent_contents, false) != 0) {
01487 ipc_notify(IPC_ONE,IPC_ERROR,"Could not draw input object");
01488 return CMD_PARAMETER_ERROR;
01489 }
01490
01491 return CMD_NO_ERROR;
01492 }
01493
01494
01495
01496 cmdstat Eyes::cmd_input_define( CMD_ARGS )
01497 {
01498 CMD_ARG_PARAMS(input_define);
01499
01500 if (!permanent_contents.has_been_defined())
01501 cmd_input_define_convolution();
01502
01503 const string name = arglist.next(argparams.get_with_default("name",string("")));
01504
01505 if (permanent_contents.create_object(arglist,name,permanent_contents) != 0)
01506 ipc_notify(IPC_ONE,IPC_ERROR,"Could not define input object");
01507
01508 return CMD_NO_ERROR;
01509 }
01510
01511
01512
01513 cmdstat Eyes::cmd_input_present( CMD_ARGS )
01514 {
01515 CMD_ARG_PARAMS(input_present);
01516 const int plot = argparams.get_with_default("display",1);
01517 const bool reset = argparams.get_with_default("reset",False);
01518
01519 if (reset) {
01520 Eyes::activate(permanent_contents,argparams);
01521 ipc_notify(IPC_ONE,IPC_VERBOSE,"Reset contents of retina");
01522 }
01523 else {
01524 Eyes::activate(temporary_contents,argparams);
01525 if (plot && presentation%plot==0) cmddefs_exec_str("plot");
01526 ipc_notify(IPC_ONE,IPC_VERBOSE,"Presented currently-defined temp input");
01527 }
01528
01529
01530
01531
01532
01533 return CMD_NO_ERROR;
01534 }
01535
01536
01537
01539 cmdstat Eyes::cmd_input_present_object( CMD_ARGS )
01540 {
01541 cmdstat status=CMD_NO_ERROR;
01542
01543 cmd_input_clear();
01544 status = cmd_input_draw(CMD_CALL_ARGS);
01545 if (status >= 0) cmd_input_present(CMD_CALL_ARGS);
01546
01547 return status;
01548 }
01549
01550
01551
01552 cmdstat Eyes::cmd_input_print( CMD_ARGS )
01553 {
01554 CMD_ARG_PARAMS(input_print);
01555
01556 const string name = arglist.next(argparams.get_with_default("name",string("")));
01557 const string parent = arglist.next(argparams.get_with_default("parent",string("")));
01558
01559
01560 if (name == "" && parent == "")
01561 for (neuralregions_type::const_iterator e=neuralregions.begin(); e!=neuralregions.end(); e++) {
01562 const string ename = (*e).first;
01563 ipc_notify(IPC_ONE,IPC_REQUESTED,ename.c_str());
01564 }
01565
01566 permanent_contents.print_object(parent,name);
01567 temporary_contents.print_object(parent,name);
01568 CMD_ARG_ASSERT_EMPTY;
01569 return CMD_NO_ERROR;
01570 }
01571
01572
01573
01574 cmdstat Eyes::cmd_input_reset( CMD_ARGS )
01575 {
01576 CMD_ARG_PARAMS(input_reset);
01577 const int seed = arglist.next(argparams.get_with_default("input_seed",0));
01578 Eyes::reset(seed);
01579 CMD_ARG_ASSERT_EMPTY;
01580 return CMD_NO_ERROR;
01581 }
01582
01583
01584
01585 cmdstat Eyes::cmd_input_undefine( CMD_ARGS )
01586 {
01587 CMD_ARG_PARAMS(input_undefine);
01588 const string name = arglist.next(argparams.get_with_default("name",string("")));
01589 const string parent = arglist.next(argparams.get_with_default("parent",string("")));
01590
01591 permanent_contents.remove_object(parent,name);
01592 CMD_ARG_ASSERT_EMPTY;
01593 return CMD_NO_ERROR;
01594 }
01595
01596
01597 cmdstat Eyes::cmd_load_snapshot( CMD_ARGS )
01598 {
01599 CMD_ARG_PARAMS(load_snapshot);
01600 const int load_snap = arglist.next(argparams.get_with_default("tend",0));
01601 const string filename = arglist.next(argparams.get_with_default("filename",string()));
01602 const bool verbose = arglist.next(argparams.get_with_default("verbose",True));
01603
01604 const int oldipcverbosity = ipc_msg_level;
01605 const int newipcverbosity = IPC_SUMMARY;
01606 const bool setverbosity = (!verbose && (ipc_msg_level > newipcverbosity));
01607
01608 if (setverbosity)
01609 ipc_msg_level = newipcverbosity;
01610
01611
01612 if (!has_default_region())
01613 cmddefs_exec_str("init_network essential_training_hooks_only=True initialize=False");
01614
01615
01616 ipc_notify(IPC_ONE,IPC_STD,"Advancing to iteration %d", load_snap);
01617 advance_iteration_counter(iteration,load_snap);
01618 iteration=load_snap;
01619 startt=iteration;
01620 if (!AMPARENTPE) ipc_get(&iteration, IPC_INT, 1, PARENTPE);
01621
01622
01623 bool restored = neuralregions.restore_state(argparams,load_snap,filename);
01624
01625 if (restored) {
01626
01627 hooklists_run_list(before_input,load_snap,True);
01628 next();
01629
01630
01631 activate(permanent_contents,argparams);
01632 }
01633
01634 ipc_barrier();
01635
01636 if (restored) {
01637 iteration=load_snap;
01638 ipc_notify(IPC_ONE,IPC_STD,"Changing iteration to %d",iteration);
01639 startt=iteration+1;
01640
01641 hooklists_run_list(after_learning,load_snap,True);
01642 }
01643
01644 if (setverbosity)
01645 ipc_msg_level=oldipcverbosity;
01646
01647 return (restored? CMD_NO_ERROR : CMD_FILE_ERROR);
01648 }
01649
01650
01651
01652
01653
01654
01655
01656 cmdstat Eyes::distribution_setfn2(const string&, Typeless&, const Typeless& requested)
01657 {
01658 int dist = (int)requested.numericvalue();
01659 bool changed=false;
01660
01661 cmdstat status = WorldViews::set_distribution(dist,changed);
01662
01663
01664
01665
01666
01667
01668 if (changed && !permanent_contents.is_empty()) {
01669 message(Msg::Notify,"Regenerating input contents");
01670 permanent_contents.remove_object();
01671 permanent_contents.generate_default_contents();
01672 }
01673
01674 return status;
01675 }
01676
01677
01678
01679 cmdstat Eyes::blur_type_setfn2(const string& name, Typeless& existing, const Typeless& requested)
01680 {
01681 const bool differs = (existing != requested);
01682 int newvalue = (int)requested.numericvalue();
01683
01684 if (newvalue<0 || newvalue>kernel_factory.max_blur_type) {
01685 ipc_notify(IPC_ONE,IPC_WARNING,"No %s of %d is defined",name.c_str(),newvalue);
01686 return CMD_PARAMETER_ERROR;
01687 }
01688
01689 existing.set(requested);
01690 if (input_define_convolution_in_use &&
01691 permanent_contents.has_been_defined() && differs) {
01692 message(Msg::Notify,"Regenerating input pathways");
01693 cmd_input_define_convolution();
01694 }
01695
01696 return CMD_NO_ERROR;
01697 }
01698
01699
01700
01701 cmdstat Eyes::double_blur_setfn2(const string&, Typeless& existing, const Typeless& requested)
01702 {
01703 const bool differs = (existing != requested);
01704 existing.set(requested);
01705 if (input_define_convolution_in_use &&
01706 permanent_contents.has_been_defined() && differs) {
01707 message(Msg::Notify,"Regenerating input pathways");
01708 cmd_input_define_convolution();
01709 }
01710
01711 return CMD_NO_ERROR;
01712 }
01713
01714
01715
01716 cmdstat Eyes::inputs_pereye_setfn2(const string&, Typeless& existing, const Typeless& requested)
01717 {
01718 const bool differs = (existing != requested);
01719 existing.set(requested);
01720
01721 if (permanent_contents.has_been_defined() && differs) {
01722 message(Msg::Notify,"Regenerating input contents");
01723 permanent_contents.remove_object();
01724 permanent_contents.generate_default_contents();
01725 }
01726
01727 return CMD_NO_ERROR;
01728 }
01729
01730
01732 cmdstat Eyes::exc_rad_setfn2(const string&, Typeless& existing, const Typeless& requested)
01733 {
01734 const CmdParamStringParser sp(blackboard);
01735 if (::network_initialized)
01736 blackboard.set_matching(sp,"::Region::*::exc_rad", requested.stringrep(),true,true,true);
01737 existing.set(requested);
01738 return CMD_NO_ERROR;
01739 }
01740
01741
01742
01743
01744
01745
01746
01748 Inputs& Inputs::global_entry()
01749 {
01750 static Eyes eyes;
01751 return eyes;
01752 }
01753
01754