【问题标题】:Trying to make a genetic algorithm尝试制作遗传算法
【发布时间】:2021-08-04 04:08:08
【问题描述】:

我最近一直在研究遗传算法,我决定使用 Python 自己制作。我将在下面分享我所做的工作。

这些是我在驱动程序函数中使用的一些帮助函数:

注意:我相信这些功能都很好,可以照原样使用。

# Generates Random Population
def generate_random_population(npop, limits=list(zip(np.zeros(5),np.ones(5))), ngenes=5):
  
  def new_ind():
    return [random.uniform(limits[i][0], limits[i][1]) for i in range(ngenes)]

  return np.array([new_ind() for n in range(npop)])


# Function to evaluate all individuals and give them a score
# fopt1 only has a minimum (unimodal) at x = (0,0, ..., 0) in which fopt1 = 0.
def fopt1(ind):
  
    x0 = [ind[len(ind)-1]]
    xlast = [ind[0]]
    working_array = np.concatenate((x0,ind,xlast))
    res = 0

    for j in range(1, len(ind)+1):
        res += (2*working_array[j-1] + (working_array[j]**2)*working_array[j+1] - working_array[j+1])**2

    return res

# Receives a certain population of individuals and an evaluation function (usually called * fitness function *) and returns an ordered list of tuples
def eval_pop(pop, f):
  # Returns a list of tuples in descending order of the goodness of f. Shape of tuples are (individual, score), e.g., ([2.3,0.004,1,8.2,6], 0.361).
  
    list = []
    
    for i in pop:
        j = (pop, f(pop))
        list.append(j)
    

    return list


# Function to produce a next generation of individuals is to select the pairs that will interbreed to have offspring
def couples_selection(ordered_pop, n_elitism):
    if len(ordered_pop) < 10:
        print("Error: population's size should be higher than 9")
        return
  
    len_a = int(len(ordered_pop)/10)
    len_b = len_a * 3
    len_c = len_a * 4

    a = np.ones(len_a) * 0.5 / len_a
    b = np.ones(len_b) * 0.3 / len_b
    c = np.ones(len_c) * 0.15 / len_c
    d = np.ones(len(ordered_pop) - len_a*8)
    d = d * 0.05 / len(d)

    prob = np.concatenate((a,b,c,d))
    indices = range(len(ordered_pop))
    selected_indices = [choice(indices, 2, p=prob) for i in range(len(ordered_pop) - n_elitism)]
    couples = [[ordered_pop[i1], ordered_pop[i2]] for [i1,i2] in selected_indices]
    return np.array(couples)

def mutate(ind, limits):
    # print("Mutating individual ", ind)
    factor = 1 + (0.2 * choice([-1,1], 1))
    gene_index = choice(range(len(ind)), 1)[0]
    mutated_val = ind.item(gene_index) * factor

    if mutated_val < limits[gene_index][0]:
        mutated_val = limits[gene_index][0]
    elif mutated_val > limits[gene_index][1]:
        mutated_val = limits[gene_index][1]

    ind[gene_index] = mutated_val

    return

def crossover(couple):
    ancestor1 = couple[0]
    ancestor2 = couple[1]

    c1, c2 = ancestor1.copy(), ancestor2.copy()
    
    pt = randint(1, len(ancestor1)-2)
    # perform crossover
    c1 = ancestor1[:pt] + ancestor2[pt:]
    c2 = ancestor2[:pt] + ancestor1[pt:]

    return [c1, c2]
  

def get_offspring(couples, mutp, limits):

    children = [crossover(couple) for couple in couples]
    mutation_roulette = [choice([True, False], 1, p=[mutp, 1-mutp]) for _ in children]
    children_roulette = list(zip(children, mutation_roulette))

    for child in children_roulette:
        if child[1][0]:
            mutate(child[0], limits) 
            # print("Mutated: ",child[0])

    return np.array([child[0] for child in children_roulette])

问题:

当我使用以下函数调用运行以下驱动程序函数时:

runGA(100, 5, list(zip(np.ones(5)*-2,np.ones(5)*2)), fopt13, 4, 0.4, 25)

def runGA(npop, ngenes, limits, fitness, nelitism, mutp, ngenerations):
    pop = generate_random_population(npop, limits, ngenes)
    sorted_pop_with_score = eval_pop(pop, fitness)
    new_pop = np.array([p[0] for p in sorted_pop_with_score])

    for g in range(ngenerations):

    # TO DO: Complete your GA!
    
        couples = couples_selection(new_pop, nelitism)
        popp = get_offspring(couples,mutp, limits)
        eval_pop_result = eval_pop(pop,fitness)
    
    
    # END OF TO DO
    
        print("Winner after generation", g, ":", eval_pop_result[0])

    print("Absolute winner:")
    return sorted_pop_with_score[0]

我在交叉函数中遇到了这个错误:

ValueError                                Traceback (most recent call last)
<ipython-input-20-375adbb7b149> in <module>
----> 1 runGA(100, 5, list(zip(np.ones(5)*-2,np.ones(5)*2)), fopt13, 4, 0.4, 25)

<ipython-input-12-6619b9c7d476> in runGA(npop, ngenes, limits, fitness, nelitism, mutp, ngenerations)
      8     # TO DO: Complete your GA!
      9         couples = couples_selection(new_pop, nelitism)
---> 10         popp = get_offspring(couples,mutp, limits)
     11         eval_pop_result = eval_pop(pop,fitness)
     12 

<ipython-input-16-5e8ace236573> in get_offspring(couples, mutp, limits)
     34 def get_offspring(couples, mutp, limits):
     35 
---> 36     children = [crossover(couple) for couple in couples]
     37     mutation_roulette = [choice([True, False], 1, p=[mutp, 1-mutp]) for _ in children]
     38     children_roulette = list(zip(children, mutation_roulette))

<ipython-input-16-5e8ace236573> in <listcomp>(.0)
     34 def get_offspring(couples, mutp, limits):
     35 
---> 36     children = [crossover(couple) for couple in couples]
     37     mutation_roulette = [choice([True, False], 1, p=[mutp, 1-mutp]) for _ in children]
     38     children_roulette = list(zip(children, mutation_roulette))

<ipython-input-16-5e8ace236573> in crossover(couple)
     25     print(len(ancestor1))
     26     print(len(ancestor2))
---> 27     c1 = ancestor1[:pt] + ancestor2[pt:]
     28     c2 = ancestor2[:pt] + ancestor1[pt:]
     29 

ValueError: operands could not be broadcast together with shapes (39,5) (61,5) 

注意:

我也尝试了 np.concatenate 函数,但它在同一步骤中给出了以下错误: TypeError: only integer scalar arrays can be converted to a scalar index 任何帮助将不胜感激!

【问题讨论】:

  • 所以看起来你需要对每一代的人口运行couples_selection(),然后对从couples_selection()返回的夫妇运行get_offspring(),然后对返回的人口运行eval_pop()来自get_offspring()。然后,那一代的获胜者将是返回列表中得分最高的eval_pop() 中的个人。看起来eval_pop() 应该按分数的降序对其返回的列表进行排序,但似乎没有;否则,返回列表的[0] 索引将是得分最高的索引,即获胜者。
  • 另外,如果您将sorted_pop_with_score[0] 作为绝对赢家返回,那么您似乎需要将每一代的赢家添加到某个列表中,然后在该列表上运行eval_pop()在完成所有世代之后,将sorted_pop_with_score 设置为最终eval_pop() 的结果。到目前为止,我所说的一切有意义吗?看起来你已经接近完成了,真的没有什么可做的了,基本上你剩下的就是把你到目前为止所做的所有东西放在一起,除了实现排序。
  • @RandomDavis 非常感谢您抽出宝贵时间阅读并回答我的问题。是的,这是有道理的。但是,如果您愿意花一分钟时间帮助我,并在答案部分重写此函数。非常感谢,我很乐意接受它作为解决方案。
  • 我认为我给你的信息应该足以让你自己尝试解决方案;如果您遇到困难,那么我和其他人可以就如何继续提供建议,但是给您完整的答案意味着我必须编写所有内容并对其进行测试,这比我愿意做的工作更多除了我已经做过的分析和解释。如果您对实现我到目前为止提到的任何内容有任何具体问题,我会尽力回答。
  • @RandomDavis 我尝试了您的解决方案,我想它会起作用,但是我在交叉功能中遇到了一些问题。你介意看看吗?我重新编辑了我的问题。非常感谢!

标签: python machine-learning genetic-algorithm


【解决方案1】:

我的cmets变成了答案:

所以看起来您需要对每一代的总体运行couples_selection(),然后对从couples_selection() 返回的夫妇运行get_offspring(),然后对从get_offspring() 返回的总体运行eval_pop()。然后,那一代的获胜者将是返回列表中得分最高的eval_pop() 中的个人。看起来eval_pop() 应该按分数的降序对其返回的列表进行排序,但似乎没有;否则,返回列表的[0] 索引将是得分最高的索引,即获胜者。

另外,如果您将 sorted_pop_with_score[0] 作为绝对赢家返回,那么您似乎需要将每一代的获胜者添加到某个列表中,然后在完成所有操作后在该列表上运行 eval_pop()代,并将sorted_pop_with_score 设置为最终eval_pop() 的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 2016-09-11
    • 1970-01-01
    • 2012-07-07
    • 2011-07-22
    • 1970-01-01
    • 2016-03-10
    • 1970-01-01
    相关资源
    最近更新 更多