Observables
General
This page explains the observables framework. It is designed to profile certain model parameter properties at certain timestamps during the adaptive modelling process.
Example timestamps are
- A new best model has been constructed
- A new model has been constructed for the sequential model builder
- A complete generation has been built for the genetic model builder
The observables currently split into two groups, observables on a model, and observables on a batch (or generation) of models. Examples of the first kind are:
- Weights, flags and percentage for polynomial models
- Kernel parameter (=spread) for a RBFNN model
Examples of the second kind are
- Model parameters of the best model in a generation
- Spread (=largest/average/smallest value) of model parameters for a generation
- Distribution of different model types in a generation when using the heterogeneous modelinterface
To accomodate this framework, a few key components have been implemented:
- The getObservables() member function that each model interface should implement. This method returns a cell array of Observable objects.
- The getBatchObservables() member function of BatchInterface (superclass of GeneticInterface). This method return a cell array of observable objects on a Batch/Generation of models.
- The methods registerObserver() and observe() of the AdaptiveModelBuilder base class
The sequel will elaborate on all different classes and components.
Observable
The Observable class is just an `abstract' base class corresponding to `a thing that can be observed'. It has following methods:
- Observable( (string) name, (string) description ). The constructor (doh)
- (string) getName( void ) { return name; }
- (string) getDescription( void ) { return description; }
- (struct) getColumns( void )
- (vector) process( (void*) object )
getColumns() returns names and descriptions for the outputs of this observable. For example, suppose we work in input dimension 3: An Observable that extracts the weight parameters out of a polynomial model, returns names [weight1, weight2, weight3] and suitable descriptions. The return type of getColumns() is a struct array with 2 fields, `name' and `description'.
process() processes the object (e.g. a model) out of which something has to be extracted (e.g. the weights) and returns the extracted values. It is mandatory the length of the double vector returned matches the number of columns returned by getColumns(). If it is impossible to extract the data from the model, process() SHOULD return an empty vector []
Things will become clearer as you read on!
SimpleObservable
Most Observables are quite simple, e.g. they just extract a field from a model object. Therefore, we have the SimpleObservable class, it has following methods:
- SimpleObservable( name, description, classtype, functor [, numColumns] ). If numColumns unspecified, use 1.
- (struct) getColumns( void )
- (vector) process( (void*) object )
process() checks whether the object passed is of type `classtype'. If not, it returns []. Else, it returns `feval( functor, object )'.
getColumns() returns a struct array with names [name_1, ..., name_`numColumns'] and suitable descriptions.
As an example, following extract of PolynomialInterface::getObservables() constructs an Observable which processes only PolynomialModels, and has as a functor an implicit function which extract the config.parameters.weights field.