Skip to content

Commit

Permalink
🏟 Tournament selection (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
dymitrlubczyk authored Sep 22, 2021
1 parent eedea71 commit 4029b88
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 22 deletions.
11 changes: 4 additions & 7 deletions base_evolutionary_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,14 @@ def run(self):
# fitness is an array of fitnesses of individuals.
# fitness[i] is a fitness of population[i]
fitness = self.fitness(self.population, self.env)


# Checks if best candidate appeared in the newest generation
self.update_best(fitness)

# CROSSOVER
parents = self.selection(fitness, self.population) # KEEPS ADDING SELECTION
parents = self.selection(fitness, self.population) # KEEPS ADDING SELECTION
offspring = self.crossover(parents)

print(f"PARENTS INFO: {parents.shape}")
print(f"POPULATION INFO: {self.population.shape}")

# MUTATION
selected = self.mutation_selection(parents, offspring, self.population)
mutants = self.mutation(selected)
Expand All @@ -66,7 +62,8 @@ def run(self):
self.population = self.insertion(fitness, self.population, offspring)

if DEBUG:
print(f'Current Generation {generation}; Best fitness: {self.best_fitness}')
print(
f'Generation {generation} - Best: {self.best_fitness} Mean: {np.mean(fitness)} Std: {np.std(fitness)}')

# INCREMENT GENERATION
generation += 1
Expand Down Expand Up @@ -96,7 +93,7 @@ def initialise_environment(self):
os.makedirs(self.experiment_name)

self.env = Environment(experiment_name=self.experiment_name,
enemies=[1],
enemies=[2],
playermode="ai",
player_controller=player_controller(self.hidden_layer_size),
enemymode="static",
Expand Down
1 change: 0 additions & 1 deletion fitness.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ def niche(population, env):

distances = np.array([])
fitness = Fitness.basic(population, env)
print('Best in popularion:', np.amax(fitness))

for individual in population:
distance = 0
Expand Down
8 changes: 4 additions & 4 deletions mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ class Mutation:
success_rate(mutant, parent) : TODO: proportion of successful mutations where child is superior to parent; helps evaluate mutation_rate parameter
"""
mutation_ratio = 0.05

@staticmethod
def basic(selected_group):
# selected_group is a subset of population selected to be mutated
#
# selected_group is a subset of population selected to be mutated
#
# TODO: ITERATE THROUGH WHOLE POPULATION! PICK CANDIDATES WITH MUTATION_RATE PROBABILITY (draw value
# from uniform distribution and check if value is smaller than probability - if yes then add to selected group --> CHANGE MUTATION_SELECTION)
# Mutates mutation_ratio % of genes of selected individual, creating mutant
Expand All @@ -46,7 +47,6 @@ def basic(selected_group):

return mutants.reshape(selected_group_count, genome_length)


def uniform_mutation(selected_group):

genome_length = selected_group.shape[1]
Expand All @@ -64,4 +64,4 @@ def uniform_mutation(selected_group):

mutants = np.concatenate((mutants, mutant), axis=None)

return mutants.reshape(selected_group_count, genome_length)
return mutants.reshape(selected_group_count, genome_length)
22 changes: 19 additions & 3 deletions selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,28 @@ class Selection:
@staticmethod
def basic(fitness, population):
# Selects selection_ratio % of best individuals based on their fitness

selected_count = round(Selection.selection_ratio * population.shape[0])
population_size = population.shape[0]
selected_count = round(Selection.selection_ratio * population_size)
sorted_indexes = np.flip(np.argsort(fitness), axis=None)
selected_indexes = sorted_indexes[:selected_count]

return population[selected_indexes, :]

@staticmethod
def tournament_selection(fitness, population):
pass
population_size = population.shape[0]
genome_length = population.shape[1]
selected_count = round(Selection.selection_ratio * population_size)

parents = np.array([])

for i in range(selected_count):
index1 = np.random.randint(population_size)
index2 = np.random.randint(population_size)

if fitness[index1] > fitness[index2]:
parents = np.concatenate((parents, population[index1]))
else:
parents = np.concatenate((parents, population[index2]))

return parents.reshape(selected_count, genome_length)
12 changes: 5 additions & 7 deletions specialist_1.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from experiment import Experiment
from base_evolutionary_algorithm import EvolutionaryAlgorithm

from fitness import Fitness
Expand All @@ -18,23 +17,22 @@


Mutation.mutation_ratio = 0.05
Selection.selection_ratio = 0.3
MutationSelection.selection_ratio = 0.3
Selection.selection_ratio = 0.4
MutationSelection.selection_ratio = 0.4

# HYPERPARAMS
population_size = 20
generations_number = 5
population_size = 100
generations_number = 10

evolutionary_algorithm = EvolutionaryAlgorithm(_experiment_name='solution_1',
_population_size=population_size,
_generations_number=generations_number,
_hidden_layer_size=10,
_fitness=Fitness.niche,
_fitness=Fitness.basic,
_selection=Selection.basic,
_crossover=Crossover.basic,
_mutation=Mutation.uniform_mutation,
_mutation_selection=MutationSelection.only_parents,
_insertion=Insertion.basic)

print(f'Mutation Ratio: {Mutation.mutation_ratio}')
evolutionary_algorithm.run()
38 changes: 38 additions & 0 deletions specialist_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from base_evolutionary_algorithm import EvolutionaryAlgorithm

from fitness import Fitness
from crossover import Crossover
from selection import Selection
from insertion import Insertion
from mutation import Mutation
from mutation_selection import MutationSelection


# Before you run evolutionary algorithm you can adjust following variables:

# Crossover.offspring_ratio - says what's the offspring/parents ratio, default 1.5
# Selection.selection_ratio - says how many % of population should be selected, default 0.3
# Mutation.mutation_ratio - says how many % of genes will be mutated, default 0.1
# MutationSelection.selection_ratio - says how many % of given group should be selected, default 0.3


Mutation.mutation_ratio = 0.05
Selection.selection_ratio = 0.4
MutationSelection.selection_ratio = 0.4

# HYPERPARAMS
population_size = 100
generations_number = 10

evolutionary_algorithm = EvolutionaryAlgorithm(_experiment_name='solution_2',
_population_size=population_size,
_generations_number=generations_number,
_hidden_layer_size=10,
_fitness=Fitness.basic,
_selection=Selection.tournament_selection,
_crossover=Crossover.basic,
_mutation=Mutation.uniform_mutation,
_mutation_selection=MutationSelection.only_parents,
_insertion=Insertion.basic)

evolutionary_algorithm.run()

0 comments on commit 4029b88

Please sign in to comment.