Почему этот алгоритм genti c занимает слишком много итераций? - PullRequest
1 голос
/ 31 марта 2020

Я изучаю алгоритмы geneti c и, чтобы лучше понять концепции, я попытался построить алгоритм geneti c с нуля, используя python без использования какого-либо внешнего модуля (только стандартная библиотека и немного из numpy)

Цель состоит в том, чтобы найти целевую строку, поэтому, если я передам ей строку привет и определю 26 символов + пробел, есть 26 ^ 5 возможностей, которые огромны. Таким образом, необходимо использовать GA для решения этой проблемы.

Я определил следующие функции:

Генерируем популяцию : мы генерируем популяцию с заданным размером n и целевым объектом мы генерируем n строку, имеющую len(target) случайных символов, мы вернуть население в виде списка чисел

. Вычислить фитнес-оценку : если символ в позиции i равен символу в позиции i цели, мы увеличиваем счет, вот код:

def fitness(indiv,target):
    score = 0
    #print(indiv," vs ",target)
    for idx,char in enumerate(list(target)):

        if char == indiv[idx]:
            score += 1
        else:
            score = 0
    return score

Выбор родителей, скрещивание между родителями и формирование новой популяции детей

Вот функция, ответственная за это:

from numpy.random import choice

def crossover(p1,p2):
    # we define a crossover between p1 and p2 (single point cross over)
    point = random.choice([i for i in range (len(target))])
    #print("Parents:",p1,p2)
    # C1 and C2 are the new children, before the cross over point they are equalt to their prantes, after that we swap
    c = [p1[i] for i in range(point)]

    #print("Crossover point: ",point)

    for i in range(point,len(p1)):
        c.append(p2[i])
    #print("Offsprings:", c1," and ", c2)
    c = "".join(c)
    # we mutate c too
    c = mutate(c)
    return c


def mutate(ind):
    point = random.choice([i for i in range (len(target))])
    new_ind = list(ind)
    new_ind[point] = random.choice(letters)
    return "".join(new_ind)

def select_parent(new_pop,fit_scores):
    totale = sum(fit_scores)
    probs = [score/totale for score in fit_scores]
    parent = choice(new_pop,1,p=probs)[0]
    return parent

Я выбираю родителей, вычисляя вероятности каждого индивидуума (индивидуальный балл / общий балл населения), а затем использую взвешенный случайный выбор , чтобы выбрать родителя (это numpy функция ).

Для кроссовера я создаю дочерний элемент c и случайную точку разделения, все символы до этой случайной точки являются первыми родительскими символами, а все символы после точки разделения - это символы родителя.

Кроме того, я определил функцию под названием should_stop, которая проверяет, нашли ли мы цель, и print_best, которая выбирает лучших людей из популяции (самый высокий показатель пригодности).

Затем я создал поиск функция, которая использует все функции, определенные выше:

def find(size,target,pop):
    scores = [fitness(ind,target) for ind in pop]
    #print("len of scores is ", len(scores))
    #good_indiv = select_individuals(pop,scores)
    #print("Length of good indivs is", len(good_indiv))
    new_pop = []
    # corssover good individuals
    for ind in pop:
        pa = select_parent(pop,scores)
        pb = select_parent(pop,scores)
        #print(pa,pb)
        child = crossover(pa,pb)
        #print(type(child))
        new_pop.append(child)
    best = print_best(new_pop,scores)
    print("********** The best individual is: ", best, " ********")
    return (new_pop,best)


n = 200
target = "hello"
popu = generate_pop(n,target)

#find(n,target,popu)


for i in range(1000):
    print(len(popu))
    data = find(n,target,popu)
    popu = data[0]
    print("iteration number is ", i)
    if data[1] == target:

        break

Проблема Проблема в том, что для создания приветствия требуется слишком много итераций (чем 200 итераций, большинство время), хотя в этом примере это занимает всего несколько итераций: https://jbezerra.github.io/The-Shakespeare-and-Monkey-Problem/index.html

Конечно, проблема не закодирована таким же образом, я использовал python и процедурный способ код вещи, но логика c то же самое. Так что я делаю не так?

Ответы [ 3 ]

1 голос
/ 31 марта 2020

Идея генетических c алгоритмов предполагает, что лучшие выживают и создают новые поколения

Прежде всего, вы должны сохранить лучшие в каждом поколении для следующего поколения (например, лучшие 40% каждого поколение продолжает жить в следующем поколении), и вы должны размножать эти 40 процентов друг с другом и мутировать только ограниченное число особей в каждом поколении, эти цифры должны быть низкими, как менее чем 5% мутировавших особей, я считаю, что это уменьшит количество поколения

1 голос
/ 31 марта 2020

Вы мутируете 100% времени. Вы выбираете «подходящих» родителей, которые, вероятно, произведут подходящее потомство, но затем вы применяете мутацию, которая более вероятна, чем «выбрасывает» ее. Пример ссылки, которую вы предоставили, ведет себя так же, если вы увеличиваете частоту мутаций до 100%.

Цель мутации - «подтолкнуть» поиск в другом направлении, если вы застряли в локальном оптимуме, постоянное его применение превращает это из эволюционного алгоритма в нечто гораздо более близкое к случайному поиску.

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

Я бы предложил определить ваши строки в словаре и дать им число, а затем проанализировать этот пример массива

мой словарь

Я: 1 есть: 23 хочу: 12 хочу: 2

так что я хочу есть конвертировать в [1, 12, 2, 23], чтобы случайность была уменьшена в несколько раз. здесь слова выводятся из словаря, поэтому единственная переменная - это порядок и слова, которые появляются в вашей строке.

переписать ваш алгоритм со словарем, в котором ваше время выполнения al go улучшится с коэффициентом. с уважением

...