00001 /* These are notes from my (itti@usc.edu) trying to cleanup the src3/ 00002 source tree through the creation of a basic ModelComponent class */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; filed July 23, 2001, following provisional applications // 00014 // No. 60/274,674 filed March 8, 2001 and 60/288,724 filed May 4, 2001).// 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu> 00035 // $Id: src31notes.dxy 11683 2009-09-10 22:51:55Z beobot $ 00036 // 00037 00038 00039 // ###################################################################### 00040 // ###################################################################### 00041 /*! \page src31overview Changes from Revisions 3.0 to 3.1 in src3/ 00042 00043 <h1>NOTE</h1> 00044 00045 Note that the 'src3' directory discussed below has now been renamed 00046 back to just 'src' (2005-06-12). 00047 00048 <h1>Overview of changes in src3/ with Revision 3.1</h1> 00049 - <b>\ref src31components</b> 00050 - --><i>Towards a neural simulation environment</i> 00051 00052 - <b>\ref src31tips</b> 00053 - --><i>Tips and frequently asked questions</i> 00054 00055 */ 00056 00057 // ###################################################################### 00058 // ###################################################################### 00059 /*! \page src31components Towards a neural simulation environment 00060 00061 00062 Over the many years of development of this toolkit by many independent 00063 developers, several bad things have been growing to intolerable 00064 proportions: 00065 - only one executable, vision.C, had complex command-line parsing 00066 capability, although in principle many other executables could have 00067 had such capability through the OptionSet and OptionParser 00068 classes. Thus, vision.C had become the only program that could be 00069 tuned to do various things using command-line options, and as such 00070 people would keep adding new stuff into vision.C to the point that 00071 it had become an incredibly complicated mess; 00072 - many little programs were developed to test out and use new classes 00073 added to the toolkit. Typically those programs all shared 00074 substantial components (e.g., get a bottom-up visual attention model 00075 going, which meant instantiate a bunch of ChannelBase derivative 00076 objects, a VisualCortex, a Brain, etc), which was achieved through 00077 cut-and-paste from similar programs. Consequently, any core 00078 modification of the toolkit required updating of all those 00079 duplications of code. 00080 - people had a tendency to develop undocumented classes in their 00081 little corner, and the lack of doc and availability to core programs 00082 would make this unknown to other developers; thus, several 00083 almost-equivalent classes had been created for, e.g., access to a 00084 serial port and other functionality. 00085 00086 With release 3.1 of the toolkit in early 2003, we attempted to fix 00087 those problems through the following strategy: 00088 - a mechanism was implemented to create tunable model parameters, 00089 whose values could be easily set via the command line or via config 00090 files. A set of classes (ModelParam, ModelComponent, ModelManager) 00091 was provided to ease the management of hierarchies of model 00092 components that would have such tunable params, and to automate the 00093 process of tuning those parameters via the command line or config 00094 files. 00095 - thus, vision.C was obsoleted and replaced by ezvision.C, which is a 00096 truly minimalistic program. Instead of doing all the work of parsing 00097 the command-line and deciding what to do based on the command-line 00098 options in the main() of various programs, that work was shifted 00099 main() to where it belonged in the first place: the various 00100 components of a model. The main paradigm shift, hence, was that a 00101 given model component (e.g., VisualCortex) should itself declare 00102 which of its parameters could be tuned, rather than the main() of 00103 vision.C or other executables deciding on that. With this new 00104 framework, adding a new tunable parameter to a given model component 00105 would automatically make it available to all programs that used that 00106 component, without any modification necessary on those programs' 00107 main() function. 00108 - ModelComponent was developed to be a base class for substantial 00109 computational modules of a neuromorphic model. The functionalities 00110 included in the base class (mechanisms to build hierarchies of 00111 ModelComponent objects, automatic setting of ModelParam values via 00112 the command-line, etc) would not need to be duplicated anymore as it 00113 had been the case previously. 00114 - Hopefully, documenting code and making it available to other 00115 programs should become more common in this framework too; indeed, if 00116 you wish to introduce new functionality into ezvision.C, typically 00117 you should not do so by adding code to ezvision.C itself, but rather 00118 by adding new components or new parameters to the existing 00119 components that are used by ezvision.C. 00120 00121 Thus, the main idea behind revision 3.1 was to push as much code as 00122 possible out of main() and back to where it truly belonged in the 00123 first place, scattered across the various components of a model. See 00124 \ref modelbuilding "here" for a quick overview of how this was 00125 implemented and how to use this framework to build your new classes 00126 and models. 00127 00128 */ 00129 00130 00131 00132 // ###################################################################### 00133 // ###################################################################### 00134 /*! \page src31tips Tips and frequently asked questions 00135 00136 00137 00138 00139 <h3>How do command-line options work?</h3> 00140 00141 For a general introduction without which the details below may be 00142 difficult to understand, see \ref modelbuilding "here". 00143 00144 Command-line options use a shared namespace and are all defined in 00145 ModelOptionDef.C. See \ref modelbuilding "here" for an explanation of 00146 why that is. The general behavior is as follows: only ModelParam<T> 00147 data members from ModelComponent objects may be exported as 00148 command-line options; each ModelComponent requests to the ModelManager 00149 that some or all of its ModelParam<T> data members be exported to the 00150 command-line; the ModelManager is in charge of parsing the 00151 command-line, and will set the ModelParam<T> value to the parsed 00152 command-line value for each ModelComponent that requested the 00153 corresponding command-line option. The process is entirely dynamic: if 00154 no ModelComponent requested a given option, it will not be available 00155 (and will not show up in the --help page); if parsing an option and 00156 setting the corresponding ModelParam<T> values triggers new options to 00157 be exported, they will become available immediately (see below for 00158 more detailed explanations of how to add command-line options that 00159 depend upon previously parsed command-line option values). 00160 00161 Typically, things go as follows: 00162 00163 - as ModelComponent derivative objects are instantiated, they 00164 instantiate any ModelParam<T> data member they may have. By default, 00165 those members remain private to the component and its derivatives 00166 (thus, they usually are in the protected section of the class 00167 definition). If the component is not registered with the 00168 ModelManager using ModelManager::registerComponent(), then the 00169 Manager will not interact with the component at all. If the 00170 component is registered, the ModelParam becomes accessible through 00171 calls to ModelComponent::setModelParamVal(), 00172 ModelComponent::setModelParamString(), etc. run on the manager 00173 object (see ModelComponent.H), since the ModelManager is a 00174 ModelComponent whose registered components are SubComponents. So, 00175 once a ModelComponent has been registered, you may not need to keep 00176 a pointer to it around, as you can modify its parameters through 00177 accesses to the ModelManager. This is the way to change ModelParam 00178 values for those parameters which ate not command-line options. See 00179 below for the parameters that will also become tunable via the 00180 command-line. 00181 00182 - some time before the command-line is parsed, one typically calls 00183 ModelComponent::exportOptions() on the manager; this will propagate 00184 down to all its registered components and their subcomponents. When 00185 this is called, the caller, who has some meta-knowledge about what 00186 other components are available in the overall model, chooses which 00187 classes of command-line options should be exported (e.g., all 00188 options that have to do with saving results; see the OPTEXP_XXX 00189 defines in ModelOptionDef.H). Typically, in 00190 ModelComponent::exportOptions(), components decide on what they wish 00191 to export and then make appropriate calls to 00192 ModelManager::requestOption() on the manager, to actually request 00193 each option. If exportOptions() has not been called by the time the 00194 command-line is parsed, it will be called automatically with 00195 OPTEXP_ALL. 00196 00197 - The manager keeps a list of default values for all possible options, 00198 and, for each option, a list of all the components that have 00199 requested it. When the manager is instantiated, the default values 00200 are taken from the hard-coded list in ModelOptionDef.C. When a 00201 component requests an option for one of its ModelParam<T> members, 00202 by default the parameter value will be set to the default value from 00203 the manager. Subsequent calls to 00204 ModelManager::setOptionValString() on the manager will change 00205 that default value as well as change the ModelParam values of all 00206 the components that have requested the option. 00207 00208 - Thus, it does not matter whether you call 00209 ModelManager::setOptionValString() before or after your 00210 component is instantiated (if it exists, the ModelParam value will 00211 be changed immediately; if it does not exist yet, the ModelParam 00212 value will be changed when the component is instantiated and calls 00213 ModelManager::requestOption() on the manager). 00214 00215 - Do not use ModelComponent::setModelParamVal() on the manager to 00216 change option values! This will change the values of the 00217 corresponding ModelParam members of all components currently 00218 registered with the manager, but it will not change the default 00219 option value; so any new component will still get the old default 00220 value rather than the value you have just set. 00221 00222 - During parsing of the command-line, 00223 ModelManager::setOptionValString() is internally called onto the 00224 manager, for each parsed command-line option. This will change the 00225 default in the manager and the internal value of all the registered 00226 components, using ModelComponent::setModelParamString() on each 00227 registered component and its subcomponents. If you need to do 00228 something each time one of your ModelParam values is changed, you 00229 can overload ModelComponent::setModelParamString(). This is for 00230 example used by OrientationChannel in Channels.C (to instantiate a 00231 bunch of GarborChannels each time the number of orientations is 00232 changed) and by SaccadeControllerConfigurator in 00233 SaccadeControllers.C (to instantiate a saccade controller of 00234 appropriate type and export its command-line options each time a 00235 saccade controller type is specified). With this mechanism, you can 00236 thus create new command-line options on the basis of the values of 00237 previous command-line options. This is exactly what 00238 SaccadeControllerConfigurator is about. Compare the list of options 00239 related to saccade controllers when you type "ezvision --help" and 00240 "ezvision --sc-type=Monkey2 --help" 00241 00242 - To debug the process, simply use "--debug" or 00243 "--save-config-to=debug.pmap" and check whether the value specified 00244 on the command-line was properly propagated down to all components 00245 that requested it. Otherwise check that you are following the 00246 sequence described here and \ref modelbuilding "there" in your 00247 model. You can also use a call to "manager.printout(std::cerr)" to 00248 print out the model hierarchy and ModelParam values. 00249 00250 00251 00252 00253 00254 00255 <h3>What if I want to hide options from the user except for a couple?</h3> 00256 00257 If you need to be more specific than the general export classes 00258 defined for ModelComponent::exportOptions() with OPTEXP_XXX in 00259 ModelOptionDef.H, you will need to manually request the options using 00260 ModelComponent::doRequestOption() on your ModelComponent objects. 00261 00262 An example of this is provided in the implementation of 00263 RadioDecoder::exportOptions() in RadioDecoder.C. Radiodecoder has an 00264 AudioGrabber subcomponent; we would like to let the users choose the 00265 device file name for the grabber, but we don't want them to change the 00266 audio recording frequency, otherwise the radio decoding will not 00267 work. So we explicitly block recursion in the call to exportOptions() 00268 at the level of the RadioDecoder, and manually export the device name 00269 option of the AudioGrabber subcomponent. 00270 00271 Another possible approach is to make a very conservative call to 00272 ModelComponent::exportOptions(), for example, exporting nothing, and 00273 then to explicitly export some select options by calling 00274 ModelComponent::doRequestOption(), on the manager (which will propagate 00275 to all components of the model), or on some model components. 00276 00277 00278 00279 00280 00281 00282 <h3>How do I use my own custom option values instead of those provided 00283 in ModelOptionDef.C?</h3> 00284 00285 There are several ways of doing that. You can change an option value 00286 using ModelManager::setOptionValString() before you parse the command 00287 line, to set a new default value. See how this is used in bmcvfigs.C 00288 for an example. 00289 00290 Another approach is that you may want to change a bunch of default 00291 values depending on the type of derivation of an object which you will 00292 instantiate on a given run of your model. Furthermore, in such case, 00293 typically the object type initially is not known, and becomes known 00294 only while parsing the command-line. An example of that is for 00295 FrameGrabber objects; we would like to set the defaults that are most 00296 likely to work for either a V4Lgrabber or an IEEE1394grabber, but both 00297 sets of defaults differ substantially. To solve this, first, we use a 00298 FrameGrabberConfigurator to select the type of FrameGrabber derivative 00299 to use (see definition in FrameGrabber.H). Then, in 00300 FrameGrabber::exportOptions(), we instruct the ModelManager to use our 00301 current ModelParam values as option defaults, rather than the global 00302 defaults in ModelOptionDef.C; this is achieved by setting the third 00303 argument of the ModelManager::requestOption() calls to true (it is 00304 false by default). Finally, in the constructors of V4Lgrabber (see 00305 V4Lgrabber.C) and IEEE1394grabber (see IEEE1394grabber.C), we set our 00306 custom defaults. So as a V4Lgrabber or an IEEE1394grabber gets 00307 instantiated and gets a chance to exportOptions(), the correct 00308 defaults are being pushed into the ModelManager. Be careful with this, 00309 typically you would want to use this technique only if you expect to 00310 have only one object of the type in question in your model. 00311 00312 00313 00314 00315 00316 00317 <h3>Ok, that sounds cool, but what if I have several instances of a 00318 given object but want to have different options for each 00319 instance?</h3> 00320 00321 In this kind of case, you typically will set the parameters that 00322 differentiate your objects by hand, and then will export by hand only 00323 those options which may be shared by your objects. 00324 00325 An example of that is in test-stereo.C, which uses two IEEE1394grabber 00326 objects, for the left and right eyes. The first grabber is manually 00327 configured to use FrameGrabber subchannel 0 using 00328 ModelComponent::setModelParamVal(), and the second one to use 00329 subchannel 1. Clearly, it hence does not make sense for this setup to 00330 export a command-line option to set the subchannel. So instead, we 00331 export no option through the standard ModelManager::exportOptions() 00332 call. Then we only export a few options like image size and grab mode, 00333 by hand, calling ModelComponent::doRequestOption() on the 00334 manager. This will recurse and both grabbers will request the option 00335 since we have registered both with the manager, and when command-line 00336 options are parsed, they will affect both grabbers equally. 00337 00338 00339 00340 00341 00342 00343 <h3>How do I replace one of my regular internal parameters by a 00344 ModelParam<T>?</h3> 00345 00346 - First, make sure than you can create a ModelParam of the type of 00347 your parameter. For that, check the list of instantiations of 00348 ModelParam<T> in InstantiateAll.H. If your parameter type is 00349 in this list, move on to the next step. Otherwise: 00350 - Enter a new instantiation in the list in InstantiateAll.H, and 00351 #include in ModelParam.C (towards top) whatever file is required to 00352 define the type you are using, so that the instantiation will work 00353 as ModelParam.C is compiled; 00354 - If operator>> and operator<< exist for your new type, move on to 00355 the next step; 00356 - If that type is an enum, create a .H file for it, and model it 00357 after the PyramidType enum in PyramidTypes.H; make sure you number 00358 your enum values and provide the xxxName() function; 00359 - We need to be able to convert to/from string for your new 00360 parameter type; to this end, edit StringConversions.H and add 00361 prototypes for convertToString() and convertFromString() 00362 specializations for your new type. Then implement those functions in 00363 StringConversions.C; look at how the other conversions were 00364 implemented and just do the same for your type. 00365 - If you are going to export your new type as a command-line option, 00366 edit ModelOptionDef.H and add a key for your new type in the 00367 ModelOptionType enum. 00368 00369 - At this point, 'make ModelParam.o' and 'make StringConversions.o' 00370 should work. 00371 00372 - Add the new data member in the protected section of your class that 00373 will use the parameter; your class must derive from ModelComponent 00374 or one of its derivatives. Make sure you put doxygen comments as to 00375 what the ModelParam data member does; see for example the protected 00376 section of class Brain in Brain.H. 00377 00378 - In your constructor for your class, add an initialization for your 00379 parameter, with a default value. See the constructor in Brain.C for 00380 an example. 00381 00382 - If you want to export your new parameter as a command-line option, 00383 you will need to implement an overload of the 00384 ModelComponent::exportOptions() function. Decide when you want to 00385 export the option, depending on how much it relies on the presence 00386 of other components in the model; look in ModelOptionDef.H at the 00387 OPTEXP_XXX defines. Typically, models that will only use your 00388 component will call exportOptions() with only OPTEXP_CORE on. Then 00389 implement exportOptions() for your new class, looking for example at 00390 the implementation for class Brain in Brain.C. Make sure your 00391 overload calls the base ModelComponent::exportOptions() at some 00392 point. Finally, create a new entry in ModelOptionDef.C for your new 00393 option. The name for your ModelParam should be chosen so that: 00394 - if it is unlikely to be used by other components, prefix it with 00395 something that has to do with your class, so that you will be 00396 sure that nobody will use the same name by mistake (e.g., 00397 "AudioGrabberStereo" rather than "Stereo"); 00398 - if you expect that several components will share the value set by 00399 your option, then use a more generic name (e.g., 00400 "FOAradius"). Look at the top for the format of the entries in 00401 the AllModelOptions array in ModelOptionDef.C. Choose an option 00402 category for your option; this will place your option along with 00403 related options when --help is requested. 00404 00405 - Everything should now compile and models using your class will all 00406 benefit from the presence of the new ModelParam and possible 00407 associated command-line option. 00408 00409 00410 00411 00412 00413 00414 <h3>How do I set the FOA radius?</h3> 00415 00416 That's a good one. Once you have called ModelComponent::start() on 00417 your manager, you can't change option values anymore (that's to 00418 prevent people from changing, e.g., the number of orientations in an 00419 OrientationChannel while a simulation is running). But you need to 00420 start the model and load the first input image in order to get its 00421 dims and compute the FOA radius. We solve this in two ways: 00422 00423 - the preferred way is to just use an InputFrameSeries to load your 00424 input frames (see FrameSeries.H). The InputFrameSeries will peek the 00425 dims of the first frame during start(), and set a few options that 00426 are dependent on these dims, like FOAradius, FoveaRadius, etc, if 00427 those currently are set to zero (which means that they should be set 00428 from input image dims). 00429 00430 - or there is the manual way, but it is non-preferred. You can just 00431 use a raw Raster::ReadRGB() call to read your first frame before you 00432 call start() and after you have parsed the command-line. Then you 00433 manually compute your FOA radius, then set the option by calling 00434 setOptionValString() on the manager (you will need to convert your 00435 radius to string, and can use convertToString() from 00436 StringConversions.H to do that). Then start your model. 00437 00438 */ 00439