Changeset 1289


Ignore:
Timestamp:
01/15/24 05:43:37 (6 weeks ago)
Author:
Maciej Komosinski
Message:

fitness_set_negative_to_zero boolean (a.k.a. "only positive fitness", needed for novelty and niching diversity control) becomes a command-line flag instead of a hardcoded value

Location:
framspy
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • framspy/evolalg/base/experiment_abc.py

    r1283 r1289  
    2323    current_generation = 0
    2424    time_elapsed = 0
    25    
    26 
    27     def __init__(self, popsize, hof_size, save_only_best=True) -> None:
     25
     26
     27    def __init__(self, popsize, hof_size, save_only_best) -> None:
    2828        self.hof = HallOfFame(hof_size)
    2929        self.popsize = popsize
     
    126126        # instead of single best, could add all individuals in population here, but then the outcome would depend on the order of adding
    127127        self.hof.add(best)
    128         self.stats.append(
    129             best.rawfitness if self.save_only_best else best)
    130         print("%d\t%d\t%g\t%g" % (generation, len(
    131             all_individuals), worst.rawfitness, best.rawfitness))
     128        self.stats.append(best.rawfitness if self.save_only_best else best)
     129        print("%d\t%d\t%g\t%g" % (generation, len(all_individuals), worst.rawfitness, best.rawfitness))
    132130
    133131    def initialize_evolution(self, initialgenotype):
     
    149147            # saved generation has been completed, start with the next one
    150148            self.current_generation += 1
    151             print("...Resuming from saved state: population size = %d, hof size = %d, stats size = %d, archive size = %d, generation = %d/%d" % (len(self.population_structures.population), len(self.hof),
    152                                                                                                                                                  len(self.stats),  (len(self.population_structures.archive)), self.current_generation, generations))  # self.current_generation (and g) are 0-based, parsed_args.generations is 1-based
    153 
     149            print("...Resuming from saved state: population size = %d, hof size = %d, stats size = %d, archive size = %d, generation = %d/%d" % (len(self.population_structures.population), len(self.hof), len(self.stats), (len(self.population_structures.archive)), self.current_generation, generations))  # self.current_generation (and g) are 0-based, parsed_args.generations is 1-based
    154150        else:
    155151            self.initialize_evolution(initialgenotype)
     
    192188    def get_args_for_parser():
    193189        parser = argparse.ArgumentParser()
    194         parser.add_argument('-popsize',type= int, default= 50,
     190        parser.add_argument('-popsize', type=int, default=50,
    195191                            help="Population size, default: 50.")
    196         parser.add_argument('-generations',type= int, default= 5,
     192        parser.add_argument('-generations', type=int, default=5,
    197193                                help="Number of generations, default: 5.")
    198         parser.add_argument('-tournament',type= int, default= 5,
     194        parser.add_argument('-tournament', type=int, default=5,
    199195                            help="Tournament size, default: 5.")
    200         parser.add_argument('-pmut',type= float, default= 0.7,
     196        parser.add_argument('-pmut', type=float, default=0.7,
    201197                        help="Probability of mutation, default: 0.7")
    202         parser.add_argument('-pxov',type= float, default= 0.2,
     198        parser.add_argument('-pxov', type=float, default=0.2,
    203199                        help="Probability of crossover, default: 0.2")
    204         parser.add_argument('-hof_size',type= int, default= 10,
     200        parser.add_argument('-hof_size', type=int, default=10,
    205201                            help="Number of genotypes in Hall of Fame. Default: 10.")
    206         parser.add_argument('-hof_savefile',type= str, required= False,
     202        parser.add_argument('-hof_savefile', type=str, required=False,
    207203                                help= 'If set, Hall of Fame will be saved in Framsticks file format (recommended extension *.gen. This also activates saving state (checpoint} file and auto-resuming from the saved state, if this file exists.')
    208         parser.add_argument('-save_only_best',type= bool, default= True, required= False,
     204        parser.add_argument('-save_only_best', type=bool, default=True, required=False,
    209205                            help="")
     206        parser.add_argument('-fitness_set_negative_to_zero', action='store_true',
     207                            help="This flag forces fitness to become max(0,fitness), so it is always made non-negative. Using niching or novelty techniques without this flag (thus allowing negative fitness values) requires verifying/improving fitness diversification formulas to work as intended for both positive and negative fitness values.")
    210208       
    211209        return parser
  • framspy/evolalg/base/experiment_niching_abc.py

    r1272 r1289  
    2424    archive_size: int = None
    2525
    26     def __init__(self, fit, normalize, popsize, hof_size, save_only_best=True, knn_niching=5, knn_nslc=10, archive_size=0) -> None:
     26    def __init__(self, fit, normalize, popsize, hof_size, save_only_best, knn_niching, knn_nslc, archive_size) -> None:
    2727        ExperimentABC.__init__(self,popsize=popsize, hof_size=hof_size, save_only_best=save_only_best)
    2828        self.fit = fit
     
    5151            divide_by = np.sum(dissim_matrix)
    5252        else:
    53             raise Exception(f"Wrong normalization method,", self.normalize)
     53            raise ValueError("Wrong normalization method: '%s'" % self.normalize)
    5454        if divide_by != 0:
    5555            return dissim_matrix/divide_by
     
    6565            dissim_list = np.mean(np.partition(
    6666                self.normalize_dissim(dissim_matrix), self.knn_niching)[:, :self.knn_niching], axis=1)
     67
     68        if Individual.fitness_set_negative_to_zero is False and ("niching" in self.fit or "novelty" in self.fit):
     69                raise ValueError("Negative fitness values not tested in combination with niching or novelty. When using these techniques, verify formulas or consider using the flag -fitness_set_negative_to_zero") # once the formulas are verified/improved, the command-line flag and this conditional check can be removed.
    6770
    6871        if "niching" in self.fit:
     
    7376                i.fitness = d
    7477        else:
    75             raise Exception("Wrong fit type: ", self.fit,
    76                             f" choose the correct one or implement a new behavior.")
     78            raise ValueError("Unsupported fit type: '%s'. Use the correct type or implement a new behavior." % self.fit)
    7779        population_structures.update_archive(dissim_matrix, population_archive)
    7880
  • framspy/evolalg/run_frams_islands.py

    r1205 r1289  
    11from FramsticksLib import FramsticksLib
    2 
     2from .structures.individual import Individual
    33from .frams_base.experiment_frams_islands import ExperimentFramsIslands
    44
     
    88    # must be set before FramsticksLib() constructor call
    99    FramsticksLib.DETERMINISTIC = False
    10     parsed_args =ExperimentFramsIslands.get_args_for_parser().parse_args()
     10    parsed_args = ExperimentFramsIslands.get_args_for_parser().parse_args()
     11    Individual.fitness_set_negative_to_zero = parsed_args.fitness_set_negative_to_zero # setting the "static" field once
    1112    print("Argument values:", ", ".join(
    1213        ['%s=%s' % (arg, getattr(parsed_args, arg)) for arg in vars(parsed_args)]))
     
    2223                  }
    2324
    24     print('Best individuals:')
    2525    experiment = ExperimentFramsIslands(frams_lib=framsLib,
    2626                                        optimization_criteria=opt_criteria,
  • framspy/evolalg/run_frams_niching.py

    r1270 r1289  
    11from FramsticksLib import FramsticksLib
     2from .structures.individual import Individual
    23
    34from .frams_base.experiment_frams_niching import ExperimentFramsNiching
     
    910    FramsticksLib.DETERMINISTIC = False
    1011    parsed_args = ExperimentFramsNiching.get_args_for_parser().parse_args()
     12    Individual.fitness_set_negative_to_zero = parsed_args.fitness_set_negative_to_zero # setting the "static" field once
    1113    print("Argument values:", ", ".join(
    1214        ['%s=%s' % (arg, getattr(parsed_args, arg)) for arg in vars(parsed_args)]))
     
    2224                  }
    2325
    24     print('Best individuals:')
    2526    experiment = ExperimentFramsNiching(frams_lib=framsLib,
    2627                                        optimization_criteria=opt_criteria,
  • framspy/evolalg/run_numerical_example.py

    r1190 r1289  
     1import numpy as np
    12from .numerical_example.numerical_example import ExperimentNumerical
     3from .structures.individual import Individual
    24
    35
    46def main():
    57    parsed_args = ExperimentNumerical.get_args_for_parser().parse_args()
     8    Individual.fitness_set_negative_to_zero = parsed_args.fitness_set_negative_to_zero # setting the "static" field once
    69    print("Argument values:", ", ".join(
    710        ['%s=%s' % (arg, getattr(parsed_args, arg)) for arg in vars(parsed_args)]))
    811
    9     initialgenotype = [100, 100, 100, 100]
    10     print('Best individuals:')
     12    initialgenotype = np.array([100, 100, 100, 100])
    1113    experiment = ExperimentNumerical(
    1214        hof_size=parsed_args.hof_size,
     
    2022                                   pxov=parsed_args.pxov,
    2123                                   tournament_size=parsed_args.tournament)
    22     print(len(hof))
     24    print('Best individuals:')
    2325    for ind in hof:
    24         print(ind.genotype, ind.rawfitness)
     26        print(ind.rawfitness, '\t-->\t', ind.genotype)
    2527
    2628
  • framspy/evolalg/run_numerical_islands_example.py

    r1190 r1289  
    1 from .numerical_example.numerical_islands_example import \
    2     ExperimentNumericalIslands
     1import numpy as np
     2from .numerical_example.numerical_islands_example import ExperimentNumericalIslands
     3from .structures.individual import Individual
    34
    45
    56def main():
    67    parsed_args = ExperimentNumericalIslands.get_args_for_parser().parse_args()
     8    Individual.fitness_set_negative_to_zero = parsed_args.fitness_set_negative_to_zero # setting the "static" field once
    79    print("Argument values:", ", ".join(
    810        ['%s=%s' % (arg, getattr(parsed_args, arg)) for arg in vars(parsed_args)]))
    911
    10     initialgenotype = [100, 100, 100, 100]
    11     print('Best individuals:')
     12    initialgenotype = np.array([100, 100, 100, 100])
    1213    experiment = ExperimentNumericalIslands(
    1314        hof_size=parsed_args.hof_size,
     
    2324                                   pxov=parsed_args.pxov,
    2425                                   tournament_size=parsed_args.tournament)
    25     print(len(hof))
     26    print('Best individuals:')
    2627    for ind in hof:
    27         print(ind.genotype, ind.rawfitness)
     28        print(ind.rawfitness, '\t-->\t', ind.genotype)
    2829
    2930
  • framspy/evolalg/structures/individual.py

    r1272 r1289  
    33
    44class Individual:
    5     only_positive_fitness = True # Note: when using diversification techniques (e.g. niching), setting this to False and allowing negative fitness values requires verifying/improving diversification formulas. Dividing fitness by similarity (or multiplying by diversity) may have undesired consequences when fitness can be both positive and negative (e.g. low similarity may make positive fitness values higher and negative fitness values lower, while the intention would be to improve fitness for low similarity).
     5    fitness_set_negative_to_zero = False # "static" field. Note: when using diversification techniques (e.g. niching or novelty), leaving this as False and allowing negative fitness values requires verifying/improving diversification formulas. Dividing fitness by similarity (or multiplying by diversity) may have undesired consequences when fitness can be both positive and negative (e.g. low similarity may make positive fitness values higher and negative fitness values lower, while the intention would be to improve fitness for low similarity).
    66
    77    def __init__(self):
     
    2929        fitness = evaluate(genotype)
    3030        if fitness is not BAD_FITNESS:  # BAD_FITNESS indicates that the genotype was not valid or some other problem occurred during evaluation
    31             if self.only_positive_fitness:
    32                 if fitness < 0:
    33                     fitness = 0
     31            if Individual.fitness_set_negative_to_zero and fitness < 0:
     32                fitness = 0
    3433        self.fitness = self.rawfitness = fitness
    3534
  • framspy/run-evolalg-examples.cmd

    r1207 r1289  
    99
    1010rem evolution with niching
    11 python -m evolalg.run_frams_niching  -path %DIR_WITH_FRAMS_LIBRARY%  -sim "eval-allcriteria.sim;deterministic.sim;sample-period-longest.sim" -opt velocity -genformat 0 -dissim 1 -fit knn_niching -archive 50 -max_numparts 15 -max_numneurons 15 -max_numjoints 30 -max_numconnections 30  -max_numgenochars 10000 -popsize 50 -generations 10 -normalize none -hof_savefile HoF-niching.gen
     11python -m evolalg.run_frams_niching  -path %DIR_WITH_FRAMS_LIBRARY%  -sim "eval-allcriteria.sim;deterministic.sim;sample-period-longest.sim" -opt velocity -genformat 0 -dissim 1 -fit knn_niching -archive 50 -fitness_set_negative_to_zero  -max_numparts 15 -max_numneurons 15 -max_numjoints 30 -max_numconnections 30  -max_numgenochars 10000 -popsize 50 -generations 10 -normalize none -hof_savefile HoF-niching.gen
    1212
    1313rem a generic island model example
Note: See TracChangeset for help on using the changeset viewer.