Почему все сгенерированные популяции становятся одинаковыми? - PullRequest
0 голосов
/ 30 марта 2020

Итак, я создаю генетические c алгоритмы, в которых наиболее подходящей хромосомой является одна из них [1,1,1,1 ...]. Я кодировал все это ниже во время отладки, я обнаружил, что кроссовер, мутация, generate_population работает, и я прошел через код для других моих функций, и все они имеют смысл. Но всякий раз, когда я запускаю его, я обнаруживаю, что после второго или третьего поколения все остальные мои поколения одинаковы. поэтому мои вопросы таковы: почему это происходит, потому что я просмотрел свой код, и у каждого нового поколения должно быть разное и более «подходящее» население, и среди каждого населения должно быть разнообразие. Любая помощь могла бы быть полезна. изображение результата

import random

def generate_population(size):
    population = []
    for i in range(size):
        individual = []
        for g in range(64):
          x = random.randrange(0,2)
          individual.append(x)
        population.append(individual)
    return population

def fitnessFunc(individual):
  fit = 0
  for i in individual:
    if i == 1:
      fit += 1
    else:
      fit = fit 
  return fit


def choice_by_roulette(sorted_population, fitness_sum):
    offset = 0
    normalized_fitness_sum = fitness_sum
    lowest_fitness = fitnessFunc(sorted_population[0])
    if lowest_fitness < 0:
        offset = lowest_fitness
        normalized_fitness_sum += offset * len(sorted_population)

    draw = random.uniform(0, 1)

    accumulated = 0
    for individual in sorted_population:
        fitness = fitnessFunc(individual)+offset
        probability = fitness / normalized_fitness_sum
        accumulated += probability

        if draw <= accumulated:
            return individual

def sort_population_by_fitness(population):
    return sorted(population, key=fitnessFunc)

def crossover(individual_a, individual_b):
  for i in range(64):
    pop = random.randint(1,2)
    if pop == 1:
      individual_a[i] = individual_b[i]
    else:
      individual_a = individual_a
  return individual_a

def mutate(individual):
    rand = random.randrange(0,10)
    if rand == 5:
      if individual[rand]==1:
        individual[rand]=0
      else:
        individual[rand]=1
    return individual

def make_next_generation(previous_population):
    next_generation = []
    sorted_by_fitness_population = sort_population_by_fitness(previous_population)
    population_size = len(previous_population)
    fitness_sum = sum(fitnessFunc(individual) for individual in population)
    for i in range(population_size):
        choice = choice_by_roulette(sorted_by_fitness_population, fitness_sum)
        schoice = choice_by_roulette(sorted_by_fitness_population, fitness_sum)
        if choice != None:
          first_choice = choice
        if schoice != None:
          second_choice = schoice
        individual = crossover(first_choice, second_choice)
        individual = mutate(individual)
        next_generation.append(individual)
    return next_generation


population = generate_population(size=10)
generations = 1000

i = 1
while True:
    print(f" GENERATION {i}")

    for individual in population:
        print(individual, fitnessFunc(individual))
    if i == generations:
        break
    i += 1
    population = make_next_generation(population)

best_individual = sort_population_by_fitness(population)[-1]
print(" FINAL RESULT")
print(best_individual, fitnessFunc(best_individual))

1 Ответ

0 голосов
/ 30 марта 2020

Я обнаружил три основные проблемы. Постараюсь разбить его, но так как я не совсем уверен, каков был ожидаемый результат, трудно сказать наверняка, как это должно быть сделано.

Проблема 1: Функция кроссовера изменяет родительское поколение "на месте" при создании следующего поколения. Это означает, что ~ 25% генов одного из родителей будут мутировать в отношении набора генов других родителей.

Проблема 2: make_next_generation () не гарантирует, что два разных человека будут отправлены в кроссовер. Иногда это приводит к тому, что индивидуумы переходят без изменений к следующему поколению.

Проблема 3: мутирование (индивидуум) затрагивает только один ген из 64. (Угадай не специально)

import random


def generate_individual():
    # Use list comprehensions
    return [random.randrange(0,2) for g in range(64)]


def generate_population(size):
    # Same result, only less code
    return [generate_individual() for i in range(size)]

def fitnessFunc(individual):
  # Yes, this line does the same work.
  return sum(individual)
  # fit = 0
  # for i in individual:
  #   if i == 1:
  #     fit += 1
  # The following two lines did nothing
  #   else:
  #     fit = fit 
  # return fit

В choice_by_roulette () есть реальная проблема. Не знаю, как это должно работать, хотя. Комментарий ниже.

def choice_by_roulette(sorted_population, fitness_sum):
    offset = 0
    normalized_fitness_sum = fitness_sum
    lowest_fitness = fitnessFunc(sorted_population[0])
    # Lower than 0? fitnessFunc() will never return that.
    # Could it be lowest_fitness > 0?
    if lowest_fitness < 0:
        offset = lowest_fitness
        normalized_fitness_sum += offset * len(sorted_population)

    draw = random.random()

    accumulated = 0
    for individual in sorted_population:
        fitness = fitnessFunc(individual)+offset
        probability = fitness / normalized_fitness_sum
        accumulated += probability

        if draw <= accumulated:
            return individual

def sort_population_by_fitness(population):
    return sorted(population, key=fitnessFunc)

Кроссовер не должен мутировать старых людей (?). Поскольку одни и те же люди могут быть выбраны более одного раза, они будут мутировать примерно на 50% по отношению к другому человеку в том же поколении. Это, вероятно, ваша самая большая проблема.

def crossover(individual_a, individual_b):
  for i in range(64):
    pop = random.randint(1,2)
    if pop == 1:
      individual_a[i] = individual_b[i]
    else:
      individual_a = individual_a
  return individual_a

Мое предложение:

def crossover(individual_a, individual_b):
  return [random.choice(genes) for genes in zip(individual_a, individual_b)]

Здесь вам не нужно ничего возвращать. Вы буквально мутируете человека на месте. Кроме того, только ген 5 может мутировать, но, возможно, это должно быть?

def mutate(individual):
    rand = random.randrange(0,10)
    if rand == 5:
      individual[rand] = 1 - individual[rand]  # Toggle: 1-0=1, 1-1=0
      # if individual[rand]==1:
      #   individual[rand]=0
      # else:
      #   individual[rand]=1

def make_next_generation(previous_population):
    next_generation = []
    sorted_by_fitness_population = sort_population_by_fitness(previous_population)
    population_size = len(previous_population)
    fitness_sum = sum(fitnessFunc(individual) for individual in population)
    for i in range(population_size):
        choice = choice_by_roulette(sorted_by_fitness_population, fitness_sum)
        schoice = choice_by_roulette(sorted_by_fitness_population, fitness_sum)
        # This code will not work. first_choice will be user without being declared below if any of there are None.
        # if choice != None:
        #   first_choice = choice
        # if schoice != None:
        #   second_choice = schoice
        # choice and schoice will sometimes be the same individual. That will definitely diminish the genetic diversity.
        while choice == schoice:
            schoice = choice_by_roulette(sorted_by_fitness_population, fitness_sum)
        individual = crossover(choice, schoice)
        mutate(individual)
        next_generation.append(individual)
    return next_generation


population = generate_population(size=10)
generations = 1000

for i in range(1, generations+1):
    print(f" GENERATION {i}")
    for individual in population:
        print(individual, fitnessFunc(individual))
    population = make_next_generation(population)

best_individual = sort_population_by_fitness(population)[-1]
print(" FINAL RESULT")
print(best_individual, fitnessFunc(best_individual))
...