소연이의 메모장

PyGAD를 활용한 유전 알고리즘의 구현 본문

ML\DL/알고리즘의 이해

PyGAD를 활용한 유전 알고리즘의 구현

xoyeon 2023. 10. 2. 16:20
반응형

1. PyGAD란?

PyGAD는 파이썬 언어에서 유전알고리즘을 쉽게 구현할 수 있도록 배포한 오픈소스이다.

 

직접 구현하지 왜 오픈소스를 활용하냐고?

인류의 편의를 위해 오픈 소스를 배포한 개발자들의 호의를 무시할 순 없지 않은가.

 

우리 친절한 개발자님의 깃허브는 아래와 같다.

 

GitHub - ahmedfgad/GeneticAlgorithmPython: Source code of PyGAD, a Python 3 library for building the genetic algorithm and train

Source code of PyGAD, a Python 3 library for building the genetic algorithm and training machine learning algorithms (Keras & PyTorch). - GitHub - ahmedfgad/GeneticAlgorithmPython: Source code ...

github.com

피드백도 빠른 편이니 궁금하면 질문해도 좋다.

실제로 궁금한 걸 묻고 답변을 받았다!

 

아래는 PyGAD 설명서다.

유용한 함수들이 많으니 참고하여 적용해 보자.

 

PyGAD - Python Genetic Algorithm! — PyGAD 3.2.0 documentation

PyGAD - Python Genetic Algorithm! PyGAD is an open-source Python library for building the genetic algorithm and optimizing machine learning algorithms. It works with Keras and PyTorch. PyGAD supports different types of crossover, mutation, and parent selec

pygad.readthedocs.io

PyGAD의 유전 알고리즘 순서도

PyGAD에서 제공한 순서도이다.

앞서 살펴본 것과 크게 다르지 않다는 것을 알 수 있다.

2. PyGAD의 예제 코드 설명

PyGAD 예제 코드는 NP-Hard에 속하는 조합 최적화 문제로서

6개의 항으로 몫이 44가 되는 최적의 값을 찾는 것이 목적이다.

y = f(w1:w6) = w1x1 + w2x2 + w3x3 + w4x4 + w5x5 + w6x6
where (x1,x2,x3,x4,x5,x6)=(4,-2,3.5,5,-11,-4.7) and y=44

우선 pip install을 이용해서 pygad를 설치한다.

pip install pygad

설치한 pygad와 numpy 라이브러리를 불러온다

import pygad
import numpy

예제에서는 초기값을 function_inputs와 같이 넣어주었다.

function_inputs = [4,-2,3.5,5,-11,-4.7]
desired_output = 44

몫이 44가 되는 값을 찾기 위해 예제에서는 아래와 같이 적합도 함수를 설정하였다.

def fitness_func(ga_instance, solution, solution_idx):
    output = numpy.sum(solution*function_inputs)
    fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)
    return fitness
    
# 적합도 함수를 변수에 저장한다.
fitness_function = fitness_func

초기값과 적합도 함수만 입력하면 GA구현은 사실 끝이다.

PyGAD에 내장된 함수를 사용하여 유전 알고리즘을 불러온다.

def on_start(ga_instance):
    print("on_start()")

def on_fitness(ga_instance, population_fitness):
    print("on_fitness()")

def on_parents(ga_instance, selected_parents):
    print("on_parents()")

def on_crossover(ga_instance, offspring_crossover):
    print("on_crossover()")

def on_mutation(ga_instance, offspring_mutation):
    print("on_mutation()")

def on_generation(ga_instance):
    print("on_generation()")

def on_stop(ga_instance, last_population_fitness):
    print("on_stop()")

아래 코드에서는 유전 알고리즘에서의 파라미터 값을 조정할 수 있다.

ga_instance = pygad.GA(num_generations=3, ## Number of generations.
                       num_parents_mating=5, ## Number of solutions to be selected as parents.
                       fitness_func=fitness_function,
                       sol_per_pop=10, ## Number of solutions (i.e. chromosomes) within the population. 
                       num_genes=len(function_inputs), ## Number of genes in the solution/chromosome. 
                       on_start=on_start,
                       on_fitness=on_fitness,
                       on_parents=on_parents,
                       on_crossover=on_crossover,
                       on_mutation=on_mutation,
                       on_generation=on_generation,
                       on_stop=on_stop)

실행시킨다.

ga_instance.run()

3. 전체 코드

pip install pygad

import pygad
import numpy

function_inputs = [4,-2,3.5,5,-11,-4.7]
desired_output = 44

def fitness_func(ga_instance, solution, solution_idx):
    output = numpy.sum(solution*function_inputs)
    fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)
    return fitness

fitness_function = fitness_func

def on_start(ga_instance):
    print("on_start()")

def on_fitness(ga_instance, population_fitness):
    print("on_fitness()")

def on_parents(ga_instance, selected_parents):
    print("on_parents()")

def on_crossover(ga_instance, offspring_crossover):
    print("on_crossover()")

def on_mutation(ga_instance, offspring_mutation):
    print("on_mutation()")

def on_generation(ga_instance):
    print("on_generation()")

def on_stop(ga_instance, last_population_fitness):
    print("on_stop()")

ga_instance = pygad.GA(num_generations=3,
                       num_parents_mating=5,
                       fitness_func=fitness_function,
                       sol_per_pop=10,
                       num_genes=len(function_inputs),
                       on_start=on_start,
                       on_fitness=on_fitness,
                       on_parents=on_parents,
                       on_crossover=on_crossover,
                       on_mutation=on_mutation,
                       on_generation=on_generation,
                       on_stop=on_stop)

ga_instance.run()

결과에 대한 그래프를 출력하고 싶을 땐 아래와 같은 코드를 활용하면 된다.

실제로 주피터에서 예제 코드를 실행하였고 출력값은 >>로 나타내었다. 

# After the generations complete, some plots are showed that summarize the how the outputs/fitenss values evolve over generations.
ga_instance.plot_fitness()

위 그래프를 살펴보면 세대(Generation)가 거듭될수록 적합도(Fitness) 값이 높아지는 걸 볼 수 있다.

즉 진화하면서 몫이 44가 되는 최적의 값을 찾아가고 있는 것이다.

# Returning the details of the best solution.
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print(f"Parameters of the best solution : {solution}")
print(f"Fitness value of the best solution = {solution_fitness}")
print(f"Index of the best solution : {solution_idx}")

>> Parameters of the best solution : [-0.63649561 -1.23770069  2.15119783  1.43895046 -2.15393229 -1.21023452]
>> Fitness value of the best solution = 28.800151921252137
>> Index of the best solution : 7
prediction = numpy.sum(numpy.array(function_inputs)*solution)
print(f"Predicted output based on the best solution : {prediction}")

>> Predicted output based on the best solution : 44.03472103906196

위에서 설정한 function_inputs = [4,-2,3.5,5,-11,-4.7] 가

solution = [-0.63649561,-1.23770069,2.15119783,1.43895046,-2.15393229,-1.21023452]

곱하고 더해지면 44.03472103906196가 나오기 때문에 best solution이라고 한다.

 

진짜일까?

진짜였다.

if ga_instance.best_solution_generation != -1:
    print(f"Best fitness value reached after {ga_instance.best_solution_generation} generations.")
    
>> Best fitness value reached after3generations.

세 번째 세대에서 가장 최적의 값을 찾았다고 한다.

# Saving the GA instance.
filename = 'genetic' # The filename to which the instance is saved. The name is without extension.
ga_instance.save(filename=filename)

# Loading the saved GA instance.
loaded_ga_instance = pygad.load(filename=filename)
loaded_ga_instance.plot_fitness()

위 코드는 모델을 저장하고 다시 불러와서 그래프를 그리는 코드다.

 

PyGAD 설명은 여기까지!

다음 포스팅에서는 유전 알고리즘을 활용한 내 논문의 코드를 살펴보겠다.

궁금한 사람 손 🙋🏻‍♀️ 🙋🏻‍♀️ 🙋🏻‍♀️