class Logger(object):
Constructor: Logger(obj_or_name, attributes, callables, path, ...)
log an arbitrary number of data (a data row) per "timestep".
The add
method can be called several times per timestep, the push
method must be called once per timestep. Callables are called in the
push
method and their output is logged. push
finally also dumps the
current data row to disk. load
reads all logged data in and, like
plot
, will only work if the same number of data was pushed each and
every time.
To-be-logged "values" can be scalars or iterables (like lists or nparrays).
The current data is saved to a file and cleared after each timestep.
The name
and filename
attributes are based on either the name or
the logged instance class as given as first argument. Only if a name
was given, push
overwrites the derived file if it exists.
To append data, set self.counter
> 0 or call load
before to call
push
the first time (make sure that the _name
attribute has the
desired value either way). len(self.load().data) is the number of
current data.
A minimal practical example logging some nicely transformed attribute
values of an object (looping over Logger
and LoggerDummy
for
testing purpose only):
>>> import numpy as np >>> import cma >>> for Logger in [cma.logger.Logger, cma.logger.LoggerDummy]: ... es = cma.CMAEvolutionStrategy(3 * [1], 2, dict(maxiter=9, verbose=-9)) ... lg = Logger(es, # es-instance serves as argument to callables and for attribute access ... callables=[lambda s: s.best.f, ... lambda s: np.log10(np.abs(s.best.f)), ... lambda s: np.log10(s.sigma), ... ], ... labels=['best f', 'lg(best f)', r'lg($\sigma$)']) ... _ = es.optimize(cma.ff.sphere, callback=lg.push) ... # lg.plot() # caveat: requires matplotlib and clears current figure like gcf().clear() ... lg2 = Logger(lg.name).load() # same logger without callables assigned ... lg3 = Logger(lg.filename).load() # ditto ... assert len(lg.load().data) == lg.count == 9 or isinstance(lg, cma.logger.LoggerDummy) ... assert np.all(lg.data == lg2.data) and np.all(lg.data == lg3.data) ... assert lg.labels == lg2.labels ... lg.delete() # delete data file, logger can still be (re-)used for new data
Method | __call__ |
see also method push . |
Method | __del__ |
Undocumented |
Method | __init__ |
obj_or_name is the instance that we want to observe, |
Method | add |
data may be a value, or a list , or a numpy array. |
Method | delete |
delete current data file and reset count to zero |
Method | load |
Undocumented |
Method | plot |
plot logged data using the plot function. |
Method | push |
call stack() and finalize the current timestep, ignore input arguments. |
Method | push |
Undocumented |
Class Variable | extension |
Undocumented |
Class Variable | fields |
names of attributes written to and read from file |
Instance Variable | attributes |
Undocumented |
Instance Variable | callables |
Undocumented |
Instance Variable | count |
Undocumented |
Instance Variable | current |
Undocumented |
Instance Variable | data |
Undocumented |
Instance Variable | format |
Undocumented |
Instance Variable | labels |
Undocumented |
Instance Variable | name |
Undocumented |
Instance Variable | obj |
Undocumented |
Instance Variable | path |
Undocumented |
Instance Variable | plot |
Undocumented |
Property | filename |
full filename as absolute path (stored in attribute _name ) |
Method | _add |
add data from registered attributes and callables, called by push |
Method | _autoname |
set name and _name attributes. |
Method | _compose |
add unique_id to name before ".logdata" |
Method | _create |
return absolute path or '' if not name_prefix |
Method | _stack |
stack data into current row managing the different access... |
Method | _unique |
return id:str that makes name or self._name unique |
Instance Variable | _delete |
Undocumented |
Instance Variable | _name |
Undocumented |
obj_or_name
is the instance that we want to observe,
or a name, or an absolute path to a file.
attributes
are attribute names[:str
] of obj_or_name
, however
callables
are more general in their usage and hence recommended.
They allow attribute access and transformations, for example like
lambda es: np.log10(sum(es.mean**2)**0.5 / es.sigma).
When a callable
accepts an argument, it is called with
obj_or_name
as argument. The returned value of callables
and
the current values of attributes
are logged each time when
push
is called.
Details: path
is not used if obj_or_name
is an absolute path
name, e.g. the filename
attribute from another logger. If
delete is True, the data file is deleted when the instance is
destructed. This can also be controlled or prevented by setting the
boolean _delete
attribute.
plot logged data using the plot
function.
If clear
, this calls matplotlib.pyplot.gca().clear()
before
to plot in the current figure. The default value of clear
may
change in future.
If transformations[i] is a callable
it is used to transform the i-th
data column like i_th_column = transformations[i](data[:,i]).
set name
and _name
attributes.
Loggers based on the same class are separted by calling
_unique_name_addition
afterwards.