【问题标题】:Why is this genetic algorithm taking too many iterations?为什么这个遗传算法需要太多的迭代?
【发布时间】:2020-07-12 04:09:48
【问题描述】:

我正在学习遗传算法,为了更好地理解概念,我尝试使用 python 从头构建遗传算法,而不使用任何外部模块(只是标准库和一点点 numpy)

目标是找到一个目标字符串,所以如果我给它字符串 hello 并定义 26 个字符 + 一个空格,则有 26^5 种可能性,这是巨大的。因此需要使用遗传算法来解决这个问题。

我定义了以下函数:

生成总体:我们生成给定大小 n 的总体,我们生成具有随机字符 len(target) 的 n 个字符串的目标,我们将总体作为 str 列表返回

计算适应度分数:如果位置 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

问题 问题在于生成 hello 需要的迭代次数过多(大多数时候迭代次数超过 200 次),而在本例中,它只需要很少的迭代次数: https://jbezerra.github.io/The-Shakespeare-and-Monkey-Problem/index.html

当然问题不是以相同的方式编码的,我使用 python 和一种程序方式来编码,但逻辑是相同的。那么我做错了什么?

【问题讨论】:

    标签: python optimization genetic-algorithm heuristics


    【解决方案1】:

    遗传算法的理念支持最好的算法生存并创造新一代

    首先,您应该为下一代保留每一代中最好的(例如,每一代中最好的 40% 继续生活在下一代中),并且您应该将这 40% 的人相互繁殖,并且只变异有限的数量每一代的个体中,这些数字应该很低,比如低于 5% 的个体发生突变,我相信这将减少世代的数量

    【讨论】:

      【解决方案2】:

      我建议在字典中定义你的字符串并给它们一个数字 然后分析这个数组 例子

      我的字典是

      我:1 吃:23 想要:12 到:2

      所以我想吃 转换为 [ 1 , 12, 2, 23] 所以随机性减少了一个因素。 这里的词是从字典中推断出来的 所以唯一的变量是你的字符串中出现的顺序和单词。

      用字典重写你的算法 您的算法运行时间将提高一个因素。 带着敬意 光辉

      【讨论】:

        【解决方案3】:

        你会 100% 发生变异。您选择可能产生适合后代的“合适”父母,但随后您应用的突变更有可能“抛弃它”。如果您将突变率提高到 100%,您提供的示例链接的行为方式相同。

        突变的目的是如果您似乎陷入局部最优,则将搜索“推向”不同的方向,始终应用它会将其从进化算法转变为更接近随机搜索的算法。

        【讨论】:

        • 谢谢你,这正是问题所在,我引入了一个突变率,事情变得更好了,但它仍然需要 170 - 210 次迭代,尽管现在每次迭代都比前一次好,如何减少迭代次数?
        • 很难提供明确的答案 - 您需要尝试解决方案。尝试为解决方案的某些组件微调元参数和不同的策略。示例:突变率、交叉方法、父适应度阈值、下一代新流行/旧流行比率等
        猜你喜欢
        • 2011-11-24
        • 2021-09-27
        • 1970-01-01
        • 2020-10-08
        • 1970-01-01
        • 2018-07-30
        • 1970-01-01
        • 2010-11-12
        • 1970-01-01
        相关资源
        最近更新 更多