Changeset 1145 for framspy/evolalg


Ignore:
Timestamp:
07/07/21 14:38:57 (3 years ago)
Author:
Maciej Komosinski
Message:

Added niching and novelty search with limited (i.e., local) competition ("nearest neighbors" according to dissimilarity measure)

Location:
framspy/evolalg
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • framspy/evolalg/dissimilarity/dissimilarity.py

    r1113 r1145  
    77class Dissimilarity(Step, ABC):
    88
    9     def __init__(self, reduction="mean", output_field="dissim", *args, **kwargs):
     9    def __init__(self, reduction="mean", output_field="dissim", knn=None, *args, **kwargs):
    1010        super(Dissimilarity, self).__init__(*args, **kwargs)
    1111
    1212        self.output_field = output_field
    1313        self.fn_reduce = None
    14         if reduction == "mean":
     14        self.knn = knn
     15        if reduction == "mean": # TODO change this 'elif' sequence to dictionary?
    1516            self.fn_reduce = np.mean
    1617        elif reduction == "max":
     
    2021        elif reduction == "sum":
    2122            self.fn_reduce = np.sum
    22         elif reduction == "none" or reduction == None:
     23        elif reduction == "knn_mean":
     24            self.fn_reduce = self.knn_mean
     25        elif reduction == "none" or reduction is None:
    2326            self.fn_reduce = None
    2427        else:
    25             raise ValueError("Unknown reduction type. Supported: mean, max, min, sum, none")
     28            raise ValueError("Unknown reduction type. Supported: mean, max, min, sum, knn_mean, none")
    2629
    2730    def reduce(self, dissim_matrix):
     
    2932            return dissim_matrix
    3033        return self.fn_reduce(dissim_matrix, axis=1)
     34
     35    def knn_mean(self, dissim_matrix,axis):
     36        return np.mean(np.partition(dissim_matrix, self.knn)[:,:self.knn],axis=axis)
  • framspy/evolalg/dissimilarity/frams_dissimilarity.py

    r1139 r1145  
    66from evolalg.dissimilarity.dissimilarity import Dissimilarity
    77
     8#TODO eliminate overlap with dissimilarity.py
     9
    810
    911class FramsDissimilarity(FramsStep):
    1012
    11     def __init__(self, frams_lib, reduction="mean", output_field="dissim", *args, **kwargs):
     13    def __init__(self, frams_lib, reduction="mean", output_field="dissim", knn=None, *args, **kwargs):
    1214        super(FramsDissimilarity, self).__init__(frams_lib, *args, **kwargs)
    1315
    1416        self.output_field = output_field
    1517        self.fn_reduce = None
     18        self.knn = knn
    1619        if reduction == "mean":
    1720            self.fn_reduce = np.mean
     
    2225        elif reduction == "sum":
    2326            self.fn_reduce = np.sum
     27        elif reduction == "knn_mean":
     28            self.fn_reduce = self.knn_mean
    2429        elif reduction == "none" or reduction is None:
    2530            self.fn_reduce = None
    2631        else:
    27             raise ValueError("Unknown reduction type. Supported: mean, max, min, sum, none")
     32            raise ValueError("Unknown reduction type. Supported: mean, max, min, sum, knn_mean, none")
    2833
    2934    def reduce(self, dissim_matrix):
     
    4146            setattr(ind, self.output_field, d)
    4247        return population
     48
     49    def knn_mean(self, dissim_matrix,axis):
     50        return np.mean(np.partition(dissim_matrix, self.knn)[:,:self.knn],axis=axis)
  • framspy/evolalg/examples/niching_novelty.py

    r1140 r1145  
    2323from evolalg.statistics.statistics_deap import StatisticsDeap
    2424from evolalg.base.union_step import UnionStep
    25 from evolalg.utils.name_propagation import propagate_names
    2625from evolalg.utils.population_save import PopulationSave
    27 import time
    2826
    2927
     
    4745    niching = "niching"
    4846    novelty = "novelty"
     47    knn_niching = "knn_niching"
     48    knn_novelty = "knn_novelty"
    4949
    5050    def __str__(self):
     
    5858    parser.add_argument('-path', type=ensureDir, required=True, help='Path to the Framsticks library without trailing slash.')
    5959    parser.add_argument('-opt', required=True,
    60                         help='optimization criteria : vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections (or other as long as it is provided by the .sim file and its .expdef). Single or multiple criteria.')
     60                        help='optimization criteria: vertpos, velocity, distance, vertvel, lifespan, numjoints, numparts, numneurons, numconnections (or other as long as it is provided by the .sim file and its .expdef). For multiple criteria optimization, see multicriteria.py.')
    6161    parser.add_argument('-lib', required=False, help="Filename of .so or .dll with the Framsticks library")
    6262
     
    6868    parser.add_argument('-dissim', required=False, type=Dissim, default=Dissim.frams,
    6969                        help='Dissimilarity measure, default: frams', choices=list(Dissim))
     70    parser.add_argument('-knn', type=int, help="'k' value for knn-based fitness criteria (knn-niching and knn-novelty).")
    7071    parser.add_argument('-popsize', type=int, default=50, help="Population size, default: 50.")
    7172    parser.add_argument('-generations', type=int, default=5, help="Number of generations, default: 5.")
     
    8182    parser.add_argument('-checkpoint_path', required=False, default=None, help="Path to the checkpoint file")
    8283    parser.add_argument('-checkpoint_interval', required=False, type=int, default=100, help="Checkpoint interval")
    83     parser.add_argument('--debug', dest='debug', action='store_true', help="Prints names of steps as they are executed")
     84    parser.add_argument('-debug', dest='debug', action='store_true', help="Prints names of steps as they are executed")
    8485    parser.set_defaults(debug=False)
    8586    return parser.parse_args()
     
    129130    def remove(self, individual):
    130131        return individual.numconnections > self.max_number
     132
    131133
    132134class ReplaceWithHallOfFame(Step):
     
    138140        return list(self.hof.halloffame)
    139141
     142
    140143def func_niching(ind): setattr(ind, "fitness", ind.fitness_raw * (1 + ind.dissim))
    141144
     
    145148
    146149def func_novelty(ind): setattr(ind, "fitness", ind.dissim)
     150
     151
     152def func_knn_novelty(ind): setattr(ind, "fitness", ind.dissim)
     153
     154
     155def func_knn_niching(ind): setattr(ind, "fitness", ind.fitness_raw * (1 + ind.dissim))
    147156
    148157
     
    214223    # -------------------------------------------------
    215224    # Novelty or niching
     225    knn = parsed_args.knn
     226    if parsed_args.fit == Fitness.knn_novelty or parsed_args.fit == Fitness.knn_niching:
     227        reduction_method = "knn_mean"
     228        assert knn is not None, "'k' must be set for knn-based fitness."
     229        assert knn > 0, "'k' must be positive."
     230        assert knn < parsed_args.popsize, "'k' must be smaller than population size."
     231    else:
     232        reduction_method = "mean"
     233        assert knn is None, "'k' is irrelevant unless knn-based fitness is used."
     234
    216235    dissim = None
    217236    if parsed_args.dissim == Dissim.levenshtein:
    218         dissim = LevenshteinDissimilarity(reduction="mean", output_field="dissim")
     237        dissim = LevenshteinDissimilarity(reduction=reduction_method, knn=knn, output_field="dissim")
    219238    elif parsed_args.dissim == Dissim.frams:
    220         dissim = FramsDissimilarity(frams_lib, reduction="mean", output_field="dissim")
     239        dissim = FramsDissimilarity(frams_lib, reduction=reduction_method, knn=knn, output_field="dissim")
    221240
    222241    if parsed_args.fit == Fitness.raw:
     
    241260        init_stages.append(novelty)
    242261        generation_modifications.append(novelty)
     262   
     263    if parsed_args.fit == Fitness.knn_niching:
     264        knn_niching = UnionStep([
     265            dissim,
     266            LambdaStep(func_knn_niching)
     267        ])
     268        init_stages.append(knn_niching)
     269        generation_modifications.append(knn_niching)
     270   
     271    if parsed_args.fit == Fitness.knn_novelty:
     272        knn_novelty = UnionStep([
     273            dissim,
     274            LambdaStep(func_knn_novelty)
     275        ])
     276        init_stages.append(knn_novelty)
     277        generation_modifications.append(knn_novelty)
    243278
    244279    # -------------------------------------------------
Note: See TracChangeset for help on using the changeset viewer.