示例#1
0
void LayerNet::gen_init (
   TrainingSet *tptr ,        // Training set to use
   struct LearnParams *lptr   // User's general learning parameters
   )
{
   int i, istart, individual, best_individual, generation, n_cross ;
   int first_child, parent1, parent2, improved, crosspt, nchoices, *choices ;
   int initpop, popsize, gens, climb, nvars, chromsize, split, ind ;
   float pcross, pmutate, error, besterror, *errors, *fitness, worst ;
   float fquit, favor_best, fitfac, maxerr, minerr, avgerr, overinit ;
   SingularValueDecomp *sptr ;
   struct GenInitParams *gptr ;  // User's genetic initialization parameters
   char *pool1, *pool2, *oldpop, *newpop, *popptr, *temppop, *best ;
   char msg[80] ;

   gptr = lptr->gp ;

   popsize = gptr->pool ;
   gens = gptr->gens ;
   climb = gptr->climb ;
   overinit = gptr->overinit ;
   pcross = gptr->pcross ;
   pmutate = gptr->pmutate ;

   fquit = lptr->quit_err ;

   favor_best = 3.1 ;
   fitfac = -20.0 ;


/*
--------------------------------------------------------------------------------

   Do all scratch memory allocation.

--------------------------------------------------------------------------------
*/

/*
   Allocate the singular value decomposition object for REGRESS.
*/

   if (nhid2 == 0)         // One hidden layer
      nvars = nhid1 + 1 ;
   else                    // Two hidden layers
      nvars = nhid2 + 1 ;

   MEMTEXT ( "GEN_INIT: new SingularValueDecomp" ) ;
   sptr = new SingularValueDecomp ( tptr->ntrain , nvars , 1 ) ;

   if ((sptr == NULL)  || ! sptr->ok) {
      memory_message("for genetic initialization. Try ANNEAL NOREGRESS.");
      neterr = 1.0 ;    // Flag failure to LayerNet::learn which called us
      if (sptr != NULL)
         delete sptr ;
      return ;
      }

   chromsize = nhid1 * (nin+1) ;        // Length of an individual's chromosome
   if (nhid2)                           // is the number of hidden weights
      chromsize += nhid2 * (nhid1+1) ;

   errors = fitness = NULL ;
   choices = NULL ;
   pool1 = pool2 = NULL ;
   MEMTEXT ( "GEN_INIT: errors, fitness, choices, best, pool1,pool2");
   if (((errors = (float*) MALLOC ( popsize * sizeof(float))) == NULL)
    || ((fitness = (float*) MALLOC ( popsize * sizeof(float))) == NULL)
    || ((best = (char*) MALLOC( chromsize )) == NULL)
    || ((choices = (int*) MALLOC ( popsize * sizeof(int))) == NULL)
    || ((pool1 = (char*) MALLOC( popsize * chromsize )) == NULL)
    || ((pool2 = (char*) MALLOC( popsize * chromsize )) == NULL)) {
      if (errors != NULL)
         FREE ( errors ) ;
      if (fitness != NULL)
         FREE ( fitness ) ;
      if (choices != NULL)
         FREE ( choices ) ;
      if (pool1 != NULL)
         FREE ( pool1 ) ;
      if (pool2 != NULL)
         FREE ( pool2 ) ;
      delete sptr ;
      memory_message("for genetic initialization.  Try ANNEAL NOREGRESS." ) ;
      neterr = 1.0 ;  // Flag failure to LayerNet::learn which called us
      return ;
      }

/*
   Generate initial population pool.

   We also preserve the best weights across all generations,
   as this is what we will ultimately return to the user.
   Its mean square error is besterror.
*/

   besterror = 1.e30 ;     // For saving best (across all individuals and gens)
   maxerr = avgerr = 0.0 ; // For progress display only
   best_individual = 0 ;   // Safety only
   initpop = popsize * overinit ; // Overinitialization of initial population
   progress_message ( "\nGenerating initial population" ) ;

   for (ind=0 ; ind<initpop ; ind++) { // Try overinitialization times

      if (ind<popsize)                 // If still in pop size limit
         individual = ind ;            // just use next avail space
      else {                           // Else we search entire pop
         worst = -1. ;                 // for the worst member
         for (i=0 ; i<popsize ; i++) { // which we will then replace
            if (errors[i] > worst) {
               worst = errors[i] ;
               individual = i ;
               }
            }
         avgerr -= worst ;             // Exclude discards from average
         }

      popptr = pool1 + individual * chromsize ; // Build init pop in pool1
      rand_ind ( popptr , chromsize ) ;         // Randomly generate individual
      decode ( popptr , nin , nhid1 , nhid2 ,   // Convert genotype (chromosome)
               hid1_coefs , hid2_coefs );       // to phenotype (weights)
      error = regress ( tptr , sptr ) ;         // Evaluate network error
      errors[individual] = error ;              // and keep all errors

      if (error < besterror) {                  // Keep track of best
         besterror = error ;                    // as it is returned to user
         best_individual = individual ;         // This is its index in pool1
         }

      if (error > maxerr)                       // Max and average error are
         maxerr = error ;                       // for progress display only
      avgerr += error ;

      if (error <= fquit)
         break ;

      progress_message ( "." ) ;
      }

   sprintf (msg , "\nInitial pop:    Min err=%7.4lf   Max=%7.4lf   Avg=%7.4lf",
	    100. * besterror, 100. * maxerr, 100.0 * avgerr / (float) popsize);
   progress_message ( msg ) ;


/*
   The initial population has been built in pool1.
   Copy its best member to 'best' in case it never gets beat (unlikely
   but possible!).
   Also, we will need best if the climb option is true.
*/

   popptr = pool1 + best_individual * chromsize ; // Point to best
   memcpy ( best , popptr , chromsize ) ;         // and save it

/*
   This is the main generation loop.  There are two areas for population pool
   storage: pool1 and pool2.  At any given time, oldpop will be set to one of
   them, and newpop to the other.  This avoids a lot of copying.
*/

   oldpop = pool1 ;       // This is the initial population
   newpop = pool2 ;       // The next generation is created here

   for (generation=0 ; generation<gens ; generation++) {

      if (error <= fquit) // We may have satisfied this in init pop
         break ;          // So we test at start of generation loop

      error_to_fitness ( popsize , favor_best , fitfac , errors , fitness ) ;

      fitness_to_choices ( popsize , fitness , choices ) ;

      nchoices = popsize ;         // Will count down as choices array emptied
      n_cross = pcross * popsize ; // Number crossing over
      first_child = 1 ;            // Generating first of parent's 2 children?
      improved = 0 ;               // Flags if we beat best

      if (climb) {                 // If we are to hill climb
         memcpy ( newpop , best , chromsize ) ; // start with best
         errors[0] = besterror ;   // Record its error
         istart = 1 ;              // and start children past it
         }
      else
         istart = 0 ;

/*
   Generate the children
*/

      maxerr = avgerr = 0.0 ;   // For progress display only
      minerr = 1.0 ;            // Ditto

      for (individual=istart ; individual<popsize ; individual++) {

         popptr = newpop + individual * chromsize ; // Will put this child here

         if (first_child)  // If this is the first of 2 children, pick parents
            pick_parents ( &nchoices , choices , &parent1 , &parent2 ) ;

         if (n_cross-- > 0)    // Do crossovers first
            reproduce ( oldpop + parent1 * chromsize , oldpop + parent2 * chromsize ,
                        first_child , chromsize , popptr , &crosspt , &split ) ;
         else if (first_child) // No more crossovers, so just copy parent
            memcpy ( popptr , oldpop + parent1 * chromsize , chromsize ) ;
         else
            memcpy ( popptr , oldpop + parent2 * chromsize , chromsize );

         if (pmutate > 0.0)
            mutate ( popptr , chromsize , pmutate ) ;

         decode ( popptr , nin , nhid1 , nhid2 , hid1_coefs , hid2_coefs ) ;
         error = regress ( tptr , sptr ) ; // Evaluate child's error
         errors[individual] = error ;      // and keep each

         if (error < besterror) {          // Keep track of best
            besterror = error ;            // It will be returned to user
            best_individual = individual ; // This is its index in newpop
            improved = 1 ;                 // Flag so we copy it later
            }

         if (error > maxerr)               // Min, max and average error
            maxerr = error ;               // for progress display only
         if (error < minerr)
            minerr = error ;
         avgerr += error ;

         if (error <= fquit)
            break ;

         first_child = ! first_child ;
         } // For all genes in population

/*
   We finished generating all children.  If we improved (one of these
   children beat the best so far) then copy that child to the best.
   Swap oldpop and newpop for the next generation.
*/

      if (improved) {
         popptr = newpop + best_individual * chromsize ; // Point to best
         memcpy ( best , popptr , chromsize ) ;          // and save it
         }

      temppop = oldpop ;   // Switch old and new pops for next generation
      oldpop = newpop ;
      newpop = temppop ;

      sprintf(msg, "\nGeneration %3d: Min err=%7.4lf   Max=%7.4lf   Avg=%7.4lf",
              generation+1, 100. * minerr, 100. * maxerr,
	      100.0 * avgerr / (float) popsize ) ;
      progress_message ( msg ) ;
      }

/*
   We are all done.
*/

   decode ( best , nin , nhid1 , nhid2 , hid1_coefs , hid2_coefs ) ;
   besterror = regress ( tptr , sptr ) ;              // Evaluate network error

   MEMTEXT ( "GEN_INIT: errors, fitness, choices, best, pool1,pool2");
   FREE ( errors ) ;
   FREE ( fitness ) ;
   FREE ( choices ) ;
   FREE ( best ) ;
   FREE ( pool1 ) ;
   FREE ( pool2 ) ;
   MEMTEXT ( "GEN_INIT: delete sptr" ) ;
   delete sptr ;
}
示例#2
0
double genetic (
      double (*func)( int n , double *x ) ,  // Function to be minimized
      int ngens ,        // Number of complete generations
      int popsize ,      // Number of individuals in population
      int climb ,        // Do we hill climb via elitism?
      double stddev ,    // Standard deviation for initial population
      double pcross ,    // Probability of crossover (.6-.9 typical)
      double pmutate ,   // Probability of mutation (.0001 to .001 typical)
      double favor_best ,// Factor for favoring best over average (2-3 is good)
      double fitfac ,    // Factor for converting fval to raw fitness (-20 good)
      double fquit ,     // Quit if function reduced to this amount
      int nvars ,        // Number of variables in x
      double *x ,        // Set to starting estimate when called; returns best
      double *best,      // Work vector nvars long
      int *choices ,     // Work vector popsize long
      double *fvals ,    // Work vector popsize long
      double *fitness ,  // Work vector popsize long
      double *pool1,     // Work vector nvars * popsize long
      double *pool2 )    // Work vector nvars * popsize long
{
   int istart, individual, best_individual, generation, n_cross ;
   int first_child, parent1, parent2, improved, crosspt, nchoices ;
   double fval, bestfval, *oldpop, *newpop, *popptr, *temppop ;

/*
   Generate initial population pool.

   We also preserve the best point across all generations, as this is what
   we will ultimately return to the user.  Its objective function value is
   bestfval.
*/

   bestfval = 1.e30 ;     // For saving best (across all individuals)
   best_individual = 0 ;  // Safety only

   for (individual=0 ; individual<popsize ; individual++) {

      popptr = pool1 + individual * nvars ;   // Build population in pool1
      shake ( nvars , x , popptr , stddev ) ; // Randomly perturb about init x
      fval = (*func) ( nvars , popptr ) ;     // Evaluate function there
      fvals[individual] = fval ;              // and keep function value of each

      if (fval < bestfval) {                  // Keep track of best
         bestfval = fval ;                    // as it will be returned to user
         best_individual = individual ;       // This is its index in pool1
         }

      if (fval <= fquit)
         break ;
      }

/*
   The initial population has been built in pool1.
   Copy its best member to 'best' in case it never gets beat (unlikely
   but possible!).
*/

   popptr = pool1 + best_individual * nvars ;           // Point to best
   memcpy ( best , popptr , nvars * sizeof(double) ) ;  // and save it

/*
   This is the main generation loop.  There are two areas for population pool
   storage: pool1 and pool2.  At any given time, oldpop will be set to one of
   them, and newpop to the other.  This avoids a lot of copying.
*/

   oldpop = pool1 ;   // This is the initial population
   newpop = pool2 ;   // The next generation is created here

   for (generation=0 ; generation<ngens ; generation++) {

      if (fval <= fquit)   // We may have satisfied this in initial population
         break ;           // So we test at start of generation loop

      fval_to_fitness ( popsize , favor_best , fitfac , fvals , fitness ) ;

      fitness_to_choices ( popsize , fitness , choices ) ;

      nchoices = popsize ;         // Will count down as choices array emptied
      n_cross = pcross * popsize ; // Number crossing over
      first_child = 1 ;            // Generating first of parent's 2 children?
      improved = 0 ;               // Flags if we beat best

      if (climb) {                  // If we are to hill climb
         memcpy ( newpop , best , nvars * sizeof(double) ) ; // start with best
         fvals[0] = bestfval ;      // Record its error
         istart = 1 ;               // and start children past it
         }
      else
         istart = 0 ;

/*
   Generate the children
*/

      for (individual=istart ; individual<popsize ; individual++) {

         popptr = newpop + individual * nvars ; // Will put this child here

         if (first_child)  // If this is the first of 2 children, pick parents
            pick_parents ( &nchoices , choices , &parent1 , &parent2 ) ;

         if (n_cross-- > 0)    // Do crossovers first
            reproduce ( oldpop + parent1 * nvars , oldpop + parent2 * nvars ,
                        first_child , nvars , popptr , &crosspt ) ;
         else if (first_child) // No more crossovers, so just copy parent
            memcpy( popptr , oldpop + parent1 * nvars , nvars * sizeof(double));
         else
            memcpy( popptr , oldpop + parent2 * nvars , nvars * sizeof(double));

         if (pmutate > 0.0)
            mutate ( popptr , nvars , stddev , pmutate ) ;

         fval = (*func) ( nvars , popptr ) ; // Evaluate function for this child
         fvals[individual] = fval ;          // and keep function value of each

         if (fval < bestfval) {              // Keep track of best
            bestfval = fval ;                // It will be returned to user
            best_individual = individual ;   // This is its index in newpop
            improved = 1 ;                   // Flag so we copy it later
            }

         if (fval <= fquit)
            break ;

         first_child = ! first_child ;
         } // For all genes in population

/*
   We finished generating all children.  If we improved (one of these
   children beat the best so far) then copy that child to the best.
   Swap oldpop and newpop for the next generation.
*/

      if (improved) {
         popptr = newpop + best_individual * nvars ;          // Point to best
         memcpy ( best , popptr , nvars * sizeof(double) ) ;  // and save it
         }

      temppop = oldpop ;   // Switch old and new pops for next generation
      oldpop = newpop ;
      newpop = temppop ;
      }

/*
   We are all done.  Copy the best to x, as that is how we return it.
*/

   memcpy ( x , best , nvars * sizeof(double) ) ;  // Return best
   return bestfval ;
}