get the generation number and pass it to the fitness function PyGAD

1.2k Views Asked by At

I am trying to set up the fitness function in PyGAD but inside this I am calling and external process for each solution(individual) get the resulting data and perform the fitness. So I'll have a folder for each generation and each individual for each process execution, I can get the individual number with the solution_idx but I want the generation number so i can create the folders with each index (generation and individual). The format for a fitness function in PyGAD documentation is:

def fitness_func(solution, solution_idx):
    #perform fitness
    return fitness

For what I want it would look something like this:

def fitness_func(solution, solution_idx,ga_instance):

    generation=ga_instance.generation_completed

    data=function2callprocess(solution,solution_idx,generation)

    fitness=fitness(data)

    return fitness

so the function2callprocess needs the solution index and generation number to keep track of the GA so it creates the folders or each run of the process.

I wonder if this is possible or anybody had any suggestions.

1

There are 1 best solutions below

2
On BEST ANSWER

Thanks for using PyGAD, Maria :)

Based on your question, you need to pass 3 parameters instead of just 2 to the fitness function where the third parameter is the current generation number.

Because PyGAD expects the fitness function to only have 2 parameters, you cannot pass a third parameter. But it is super easy to work around it.

You already know that the current generation number can be accessed through the generations_completed property of the pygad.GA instance. If the instance is ga_instance, then we can access this parameter using:

ga_instance.generations_completed

Based on the fact that the fitness function is only called after an instance of the pygad.GA class is created, then we can use this instance inside the fitness function to access the generations_completed attribute.

This is how the fitness function should be. The trick is accessing the global variable ga_instance which is defined outside the fitness function. You can read this article for more information about global variables in Python.

def fitness_func(solution, solution_idx):
    global ga_instance

    print("generations_completed", ga_instance.generations_completed)

    # fitness = ...

    return fitness

This is a complete example which generates random fitness values. Just edit the fitness function to calculate the fitness properly.

import pygad
import random

def function2callprocess(solution, solution_idx, generation_number):
    return random.random()

def fitness_func(solution, solution_idx):
    global ga_instance

    print("generations_completed", ga_instance.generations_completed)

    generation = ga_instance.generations_completed

    data = function2callprocess(solution, solution_idx, generation)

    # fitness = ...
    fitness = data

    return fitness

last_fitness = 0
def on_generation(ga_instance):
    global last_fitness
    print("Generation = {generation}".format(generation=ga_instance.generations_completed))
    print("Fitness    = {fitness}".format(fitness=ga_instance.best_solution(pop_fitness=ga_instance.last_generation_fitness)[1]))
    print("Change     = {change}".format(change=ga_instance.best_solution(pop_fitness=ga_instance.last_generation_fitness)[1] - last_fitness))
    last_fitness = ga_instance.best_solution(pop_fitness=ga_instance.last_generation_fitness)[1]

ga_instance = pygad.GA(num_generations=5,
                       num_parents_mating=5,
                       sol_per_pop=10,
                       num_genes=2,
                       fitness_func=fitness_func,
                       on_generation=on_generation)

ga_instance.run()

ga_instance.plot_fitness()

solution, solution_fitness, solution_idx = ga_instance.best_solution(ga_instance.last_generation_fitness)
print("Solution", solution)
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))