About the Meta-evolver

Author:   Mitchell Timin
Posted:  06/11/2006

Questions or comments should be sent to annevolve-devel@lists.sourceforge.net.
Metavolv is a free download from the ANNEvolve website: http://annevolve.sourceforge.net.

Contents:
1. What is it?
2. What's Required to Use it?
3. How to Use it
4. How Does it Work?
5. Output and Discussion


1. What it is:

Metavolv.py is a computer program that searches for a better set of parameters for some other program, which we call the target program.  The target program determines what "better" means, and it writes a merit value to the screen. The parameters appear in a configuration file for the target program. Although metavolv.py is written in Python, the target program can be any executable file that meets two conditions: It must read a configuration file to get values for parameters, and it must eventually write a result to the screen. Metavolv will repeatedly execute the target program, each time re-writing the configuration file with new parameter values. Metavolv.py will use two other Python files, modify.py and editThis.py.  The three files together comprise the program. Metavolv is primarily designed for stochastic target programs, and also for those that require significant execution time.   For such programs we cannot be sure of finding a global optimum in a reasonable time span; we are primarily interested in improving the set of parameters that we start with.  Hence we are primarily attempting to move toward a local optimum.


2. What's Required to Use it:

You need Python, a free download from www.python.org.  It should be version 2.4 or later.  You will also need a Python extension called NumPy (numerical python).  That's also a free download; from sf.net/projects/numpy (get NumPy 0.9.6 or later). Finally, you need another Python extension called ctypes.  This is included in Python 2.5, but if you are using any earlier version then get ctypes from sf.net/projects/ctypes.   (Of course you need a target program.  A demo target, hill.c, is supplied with the metavolv package; you will have to compile it, unless you use Windows.  In the latter case you can download an executable binary file.)  


3. How to Use it:

You must use a text editor to customize editThis.py, which configures metavolv.py for your particular target.  Some examples are supplied to illustrate this.  One example is editThis.4play, which is for use with 4play.  That can be used with no changes, but you must rename it to editThis.py.  There are other examples supplied also.  editThis.sail is for use with EvSail and editThis.hill is for use with the compiled form of hill.c.  The latter is an example target program that is included in the metavolv download.

Once editThis.py is suited to the target, and the target is ready to run, metavolv.py is executed from a command line window.  The command is simply metavolv.py followed by the desired number of trials.  For example "metavolv.py 100".  That can optionally be followed by a filename containing the initial parameter set.  Normally the parameter set is taken from the initializer in editThis.py, but if the name of a file containing the parameter values is given, then those values will be used.   This file should have all of the parameter names and values, and in the same order that they appear in the initializer.  (This is most commonly used with result.ini, which is created by metavolv during each run.  It contains the best parameter set found.)


4. How it Works:

(A pseudocode representation is below.)  The general idea is that metavolv.py writes a new version of the configuration file each time it executes the target program.   Metavolv receives all of the output that the target sends to the screen. From that output it finds the fitness value that the target produced.  (The target program outputs a fitness value or merit factor at the end of execution).  Then the parameters are changed, and the above steps are repeated.   The best fitness found is always kept, as well as the parameter set that produced it. Of course, the devil is in the details, and there are a lot more details here.  The most important have to do with how the parameter set is modified.  Initially, we take random jumps in parameter space. We save all of this data, both the parameter values and the resulting fitness. After we have enough points, then a linear function of all of the parameters is fitted to these points by the method of least squares.  (This is accomplished using the linalg.lstsq() function of NumPy.)  We treat this linear function as if it were a good approximation to the actual, unknown, function relating fitness to the parameters.  For a linear function we know which direction to move in order to raise the fitness.  That's the direction of the gradient vector, and we know what that is. So we take a step in that direction.  However, this step is not guaranteed to increase the fitness, for two reasons. 1) the linear function is only a rough approximation of the actual function, and 2) our function may be stochastic, so that there is great random variation in results returned by the target program.  (Programs involving simulated evolution are almost always stochastic.)

There are more details:  There is a variable, sigma, which is related to the step size.   When taking random steps it is the standard deviation of the random amount added to a parameter.  When taking a projected step using the linear fit, it is the Euclidean norm of the N dimensional step.  We would like to take large steps to rapidly find our maximum, but if the step is too large it is guaranteed to take us farther from the maximum.  Hence there is a best step size.  Furthermore, The best step size depends on how far we are from the maximum point; smaller steps are necessary as one approaches the maximum. Therefore we have incorporated a method of automatically adjusting sigma.  Whenever we take a projected step in the gradient direction, we also take another step with sigma 50% greater.  Hence we execute the target twice.  We keep only the result with the higher fitness, and discard the other.  However, if one result was significantly higher than the other, then we change the step size.  If the shorter step was better we reduce sigma.  If the longer step was better we increase it.

Another important detail is the transformation of the parameters so that they all have similar behavior.  The original parameter set often has parameters that are very different.  For example, one parameter may be probability, and must stay between zero and one.  Another parameter may be a population size that can vary from 20 to 2000.  Clearly, an appropriate step size cannot be defined that suits both of those parameters.   Hence, we permit the user to define as many custom transformations as are required by his active parameter set.   However, in most cases some or all of the transformations that are in modify.py may be used.

To specify that a particular transformation function is to be used by a particular parameter, put its name into the appropriate line of the initializer in editThis.py.   Note that these transformation functions must include the inverse transformation.  For example, the function floatXform() uses the natural log function to transform a parameter. For the inverse transformation it uses the exponential function.  If you add any new function names, they must be included in the line that begins "from modify import ....." in metavolv.py.

The goal of each transformation function is to cause the corresponding active parameter value to vary across a good portion of the range -10 to +10.  In many cases all that is required is the log() function, with exp() for its inverse.  However, if the value of the parameter must be limited, then the transformation function must also enforce the limits. There are two examples of that in modify.py, namely probXform() and declineXform().  Finally, the active parameter set must consist only of floating point numbers.  If some of the original parameters are integers, the transformation function must translate.  An example of this is intXform(), in modify.py.  

If no transformation is needed, then use the null transformation function, noXform().  This is done when hill.c is the target program, so you can see it used in editThis.hill.   noXform() can be used with any parameter and any target, but the search results may not be as good, depending on the behavior of the parameters.   Also, some of the parameters may reach unreasonable values; the effect of that depends on the target program.

It is the transformed parameters that are used for the search.  The initial parameter set is transformed after it is read in from the initializer.  It is de-transformed in order to re-write the configuration file, or to display it.


pseudocode explanation of how it works:

write new .ini file for target program
(this includes initial vector of parameters)
set bestFitness to very unfit value
set currentParams to transformed values from the .ini
loop forever:
    invoke target program
    capture its output scanning for termination
    when termination occurs:
        scan for the fitness
        if fitness > bestFitness:
            bestFitness <- fitness
            bestParams <- currentParams
        else:
            restore params to best    
    store the fitness value
    store the xformed param set that produced it        
    make some changes to currentParams
        (these may be based on linear projection, or may be random)
    de-transform them and write new .ini file


5. Output and Discussion:

Two text files are include in the package, output.hill & output.4play.  output.hill is a run of 100 trials using editThis.hill (renamed to editThis.py).  Similarly, output.4play is for 4Play, but in this case the editThis.py that was used has been pasted into the file ahead of the output.  (It is not exactly the same as editThis.4Play.)   The first line of output shows the name of the executable, the specified run time per trial, and the allowed overtime per trial.  If the target program does not use a specified run time then the latter two numbers are meaningless.  After that, when one or more numbers appear on a line, those are merit values which were reached by random steps. Whenever a new best fitness is found the parameter values will be printed.  Note that the "best fitness" might decrease slightly.  This is because we accept anything very close, or even a little worse, as a new best.  This is done to keep the search point moving through parameter space, instead of getting stuck for a long time.  This is controlled by the value of epsilon, in editThis.py. Whenever a gradient step is taken a line like this is printed:

grad->  3.066  fitness  0.7664 sigma 0.1800

The shows the magnitude of the gradient, the merit value found, and the new step size.

Before examining output.hill, look at the illustration below. This shows the merit output of the hill executable for values of X & Y between 0 and 6, but with no "jitter" (random noise).  For the test run the jitter was set at .05.  The test run began its search at the point (.75, 1.5), where the surface is almost flat.  It can be seen that metavolv made no real progress until trial 38, when it finally found a little bit of slope.  From that point on it made fairly steady progress until by trial 75 it was quite close to the maximum point.  (The true maximum is at (3.0, 4.0) and its value is 5.0 plus the "jitter".  The latter is a normal random variable with zero mean and, in this case, std. dev. of .05.)  Note that after trial 77, sigma is steadily declining, as it should be when we are closing in on a maximum.

Hill is a very easy problem, being a very smooth function with no local maxima other than the global maximum, and a parameter space of only two dimensions.  It also executes almost instantaneously.  Its purpose is just to show that there is nothing grossly wrong with metavolv.  Next we will discuss output.4Play, a much more challenging problem.

    
  


4Play is a difficult problem in parameter optimization.  There are 8 active parameters.   The existence of many local maxima is likely, but unknown.  The fitness function is highly stochastic, with very large variation.  Finally, the execution time per trial needs to be very long.  We chose 15 minutes for this sample run because we wanted the total run time to be less than 24 hours.  That is not really long enough for 4Play to evolve the perfect solutions that it is capable of.    It is relevant here that this took place on a fairly fast desktop computer with an AMD Athlon 64 3200+ CPU.

The fitness output seen during  the run (output.4play) varies from a little over .5 to a maximum of .8907.  1.0 is the maximum possible, and that has been achieved in the past, but it required runs lasting several hours.  Nevertheless, metavolv achieved a respectable result.  In looking at the parameter set, we see that most of the parameters changed very little, indicating that our initial choices were not bad.  However, some did change a lot.  mutmax went from 1.0 to .422, giving us some useful information about that parameter.  Most problematic was the neuron count which went from 40 to 15.  This tells us that we can get to .89 fitness with only 15 neurons, and do it quickly.  But we are primarily interested in perfect solutions of 1.0 fitness.  Past experience has given the impression that about 40 neurons were necessary for this.   It seems that a series of runs is needed with at least one hour of execution time per trial, perhaps more.   This will require several days of computer time.


Definitions:

parameter - A number whose value you would like to determine.  A variable with a numerical value.  (For use with metavolv.py it must appear in a configuration file for the target program.)

active parameters - the parameters whose values will be varied during the search.  The configuration file will usually contain other parameters also.  The flag field in the initializer determines which parameters are active.

parameter space - The set of all possible values of all active parameters.  If there are N active parameters then this is an N-dimensional space.

target - (or target program) An executable file which can be invoked by metavolv.py.  (It will be invoked over and over again.)  The target program can be any executable file that meets three conditions: It must be executable from a command line window, it must read a configuration file to get values for parameters, and it must eventually write a merit value to the screen via stdout.

configuration file - A text file containing names and values of parameters. The target program will read it when it begins execution and use the values found there.

4Play - A neuroevolution software package which is a free download from http://annevolve.sourceforge.net

EvSail - A neuroevolution software package which is a free download from http://annevolve.sourceforge.net

merit value or merit factor or fitness - A number that estimates how good the parameter set is; larger meaning better. This is usually a random variable, so a given parameter set will produce different merit values each time it is used.

stochastic - containing random influences

initializer - a list structure at the beginning of editThis.py.  Each item of the list consists of a name, value, flag, and function name.  This mirrors the configuration file of the target program, but with the flag & function fields added.

trial - a single determination of the merit value.  Metavolv obtains this by running the target program once or twice.

linear function - f(x, y, z, ....) = k + a*x + b*y + c*z + .........  In this case f is the fitness, x, y, z.... are the parameters of the target program, and a, b, c .... are the estimated components of the gradient vector.

gradient vector - for a function of several variables, a vector that points in the direction of greatest rate of change of the independent variable.  This is at a particular point in the space of the dependent variables.

method of least squares - minimize the sum of the squares of the errors.  The errors are the differences between a set of given values and corresponding estimated values.

transformation - putting a variable through a function that changes its characteristics.  For example, if x is replaced by z = x squared, then z will never be negative, like x could be, and z will vary very slowly when near 0, and very rapidly when far from zero.

step - distance between successive trial points in parameter space.  In two or three dimensions this is the familiar quantity, distance.  In higher dimensions it is the analogous quantity, the Euclidean norm.



Driftwood :: Harnessing the Power of Many Computers for Simulated Evolution

Author:  Mitchell Timin
Posted:  03/21/2004

Meet ANNEvolve's founder and leader

Author:  Mitchell Timin
Posted:  02/16/2004

4-Play Procedure Analysis

Author:  Mr. Emile Richard
Posted:  01/23/2004

Shakespeare, Darwin, and the Monkeys

Author:  Mitchell Timin
Posted:  12/26/2003

How Simulated Evolution Works

Author:  Mitchell Timin
Posted:  11/16/2003

Meet Annevolve's skydiving, mouseball collecting Unix Admin

Author:  Eric Anderson
Posted:  11/14/2003

Species Learning and a Hypothesis About Brain Learning

Author:  Mitchell Timin
Posted:  10/02/2003

When doing GA, expect a very large variance in the time required to accomplish a certain amount of evolution.

Author:  Kent Pault Dolan
Posted:  09/09/2003

An Aspect of Natural Evolution

Author:  Mitchell Timin
Posted:  08/31/2003

Genuine Artificial Intelligence  :)

Author:  Mitchell Timin
Posted:  08/27/2003