经典优化算法——遗传算法

想象你要完成一个超难的拼图游戏,这个拼图碎片超级多,组合方式多得数不清,靠瞎拼根本找不到最佳拼法。

遗传算法就像是一群机智的“拼图小能手”在帮你解决这个难题。第一,这些“小能手”们会随机地拼出一些图案,这些图案就是初始的“拼图方案”,每个方案都像是一个独特的“个体”。

接着,要看看这些“个体”到底拼得怎么样,也就是给它们打分,得分高的就是拼得好的,更接近完整拼图的样子。那些得分高的“个体”就像在拼图比赛中表现出色的选手,它们有更大机会把自己的拼图方法传递下去,就像生物界中优秀的基因更容易遗传给下一代。

然后呢,这些优秀“个体”之间会“交流合作”,交换一下彼此拼图的部分,产生新的“拼图方案”,这就好比生物的繁殖过程,父母的基因组合产生新的后代。有时候,还会有一些小小的“意外”发生,个别碎片的位置会随机改变,这就是所谓的“变异”。

经过一轮又一轮这样的操作,“拼图小能手”们拼出的图案越来越接近完整的拼图,最终就能找到最佳的拼图方案啦。遗传算法就是通过这种模拟生物遗传、进化的方式,在复杂的问题里找到最优解。


一、遗传算法简介

  1. 适合场景:广泛应用于各类优化问题,尤其是复杂的非线性问题。列如在工程设计中,寻找最优的结构参数;在机器学习中,优化神经网络的连接权重等。
  2. 基本原理:遗传算法借鉴了生物进化中的遗传、变异和自然选择等思想。把问题的每个解看作是一个 “个体”,每个个体都有一组 “基因” 来描述其特征。算法第一随机生成一个初始种群,然后让这些个体像生物一样进行 “繁殖”。在繁殖过程中,优秀的个体(适应度高,即目标函数值好的解)有更大的概率将自己的基因传递给下一代,同时还会有必定概率发生基因 “变异”,产生新的特征。经过多代的进化,种群整体的适应度会不断提高,最终得到接近最优解的个体。例如在优化一个函数值时,每个可能的输入值组合就是一个个体,函数值就是适应度,通过不断进化找到使函数值最优的输入组合。
  3. 优势
  4. 具有较强的全局搜索能力,能在复杂的解空间中寻找最优解。
  5. 对问题的依赖性不强,不需要对问题有深入的数学理解,只要能定义适应度函数就行。
  6. 可以并行处理,由于每个个体的进化过程相对独立,便于在多核处理器或分布式系统上实现加速。
  7. 劣势
  8. 计算量较大,尤其是种群规模大、迭代次数多的时候。
  9. 容易出现 “早熟” 现象,即算法过早收敛到局部最优解,而错过全局最优解。这可能是由于某些优秀个体在种群中迅速占据主导,导致基因多样性过早丧失。

二、什么是“适应度”?

在上述遗传算法代码中,适应度(fitness)是衡量个体优劣的一个量化指标,它在遗传算法中起着核心作用,具体含义如下:

  1. 与优化目标的关联:适应度函数定义为 fitness(individual),在这个特定例子里,适应度值等于解码后的个体值 x 的平方,即 x ** 2,这里的 x 需满足 0 <= x <= 100。这是由于我们的优化目标是寻找函数 f(x) = x^2 在区间 [0, 100] 内的最大值。所以,适应度直接反映了个体与优化目标的契合程度,适应度越高,代表该个体对应的 x 值使得目标函数 f(x) 的值越大,也就意味着这个个体在解决问题(找到目标函数最大值)上表现得越好。
  2. 指导选择过程:在轮盘赌选择环节,个体被选中进入下一代的概率取决于其适应度。适应度越高的个体,在轮盘赌选择中被选中的概率就越大。例如,一个个体的适应度是另一个个体的两倍,那么它被选中的概率也大致是另一个个体的两倍。这就使得适应度高的个体有更多机会将自身基因传递给下一代,推动种群朝着更优解的方向进化。
  3. 评估种群优劣:通过计算种群中各个个体的适应度,我们可以了解整个种群在当前迭代下的优劣程度。在遗传算法的每一代中,跟踪最优个体的适应度(如代码中记录的 best_fitness),可以直观地看到种群是否朝着更好的方向进化。如果适应度在多代中持续增加,说明遗传算法正在有效地搜索更优解;若适应度过早停滞或不再提升,可能暗示算法陷入局部最优解等问题。
  4. 遗传算法的驱动力:适应度是遗传算法进化的驱动力。它引导着选择、交叉和变异等遗传操作,使得种群不断进化,逐渐逼近全局最优解。整个遗传算法的运行过程,就是通过不断调整个体(改变基因组合),提高个体适应度,进而提升整个种群适应度,最终找到最优解的过程。

三、如何选择种群的大小和变异率?

选择合适的种群大小和变异率在遗传算法中至关重大,它们会显著影响算法的性能和结果。以下是关于如何选择它们的一些指导原则:

种群大小的选择

  1. 问题的复杂度
  2. 简单问题:对于相对简单、解空间较小的优化问题,较小的种群规模可能就足够了。例如,求解一个只有几个变量且取值范围有限的函数优化问题,种群大小可以设为 20 – 50。由于问题简单,较小的种群就能包含足够多的潜在解模式,过大的种群反而会增加计算量,减慢算法收敛速度。
  3. 复杂问题:当处理复杂的、解空间庞大的问题时,如高维函数优化或复杂的组合优化问题(如大规模旅行商问题),需要较大的种群规模。这是由于复杂问题可能存在众多局部最优解,较大的种群有更多机会包含不同的基因组合,覆盖更广泛的解空间,从而增加找到全局最优解的可能性。对于这类问题,种群大小可能需要设置为几百甚至上千。
  4. 计算资源
  5. 资源有限:如果计算资源(如内存、CPU 时间)有限,应选择较小的种群规模。较大的种群需要更多的内存来存储个体信息,并且在每一代的计算中,评估适应度、进行选择、交叉和变异等操作都需要更多的计算时间。例如,在运行于资源受限的移动设备或老旧计算机上的算法,种群大小可能需要限制在较小范围内,以确保算法能够在合理时间内运行。
  6. 资源充足:若有充足的计算资源,可适当增大种群规模,利用更多个体探索解空间,有可能获得更好的优化结果。例如在高性能集群环境下运行遗传算法,可以尝试较大的种群规模,观察算法性能的提升情况。
  7. 算法的收敛特性
  8. 收敛过快:如果在实验过程中发现遗传算法收敛过快,可能意味着种群规模过小,个体之间的基因多样性不足,算法过早地聚焦在局部最优解附近。此时,可以适当增大种群规模,引入更多的基因组合,给算法更多探索解空间的机会,避免过早收敛。
  9. 收敛过慢:相反,如果算法收敛过慢,计算量过大,可能种群规模过大。此时可以尝试减小种群规模,提高计算效率,同时观察算法是否仍能保持较好的优化效果。

变异率的选择

  1. 问题的特性
  2. 高度非线性问题:对于高度非线性、复杂的问题,解空间中可能存在许多不连续或难以通过常规遗传操作(选择和交叉)到达的区域。此时,较高的变异率有助于算法跳出局部最优解,探索更广泛的解空间。例如,在一些复杂的神经网络结构优化问题中,较高的变异率(如 0.1 – 0.2)可能更合适,以便引入更多新的基因组合,发现更好的网络结构。
  3. 线性或规律性强的问题:对于相对线性或规律性较强的问题,较低的变异率就可以满足需求。由于这类问题的最优解往往可以通过选择和交叉操作逐步逼近,过高的变异率可能会破坏已经形成的较好的基因组合,导致算法在搜索过程中出现波动,难以稳定收敛。例如,简单的线性回归模型参数优化问题,变异率可以设置在 0.01 – 0.05 之间。
  4. 算法的阶段
  5. 初始阶段:在遗传算法的初始阶段,为了快速探索解空间,发现潜在的优秀基因模式,可以适当设置较高的变异率。这样能使种群在开始时更加多样化,增加找到全局最优解的可能性。
  6. 后期阶段:随着算法的运行,种群逐渐收敛到必定区域,此时应降低变异率。由于在后期,算法已经找到了一些较好的解模式,过高的变异率可能会破坏这些优良基因组合,使算法偏离已经接近的最优解。可以采用动态变异率的方法,让变异率随着代数的增加而逐渐降低,如使用公式 mutation_rate = initial_mutation_rate * (1 – generation / total_generations),其中 initial_mutation_rate 是初始变异率,generation 是当前代数,total_generations 是总代数。
  7. 实验和经验
  8. 多次实验:通过多次实验,尝试不同的变异率值,并观察算法的性能指标(如最优解的质量、收敛速度等)。记录每次实验的结果,分析哪种变异率能使算法在当前问题上表现最佳。这是选择变异率的一种常用且有效的方法。
  9. 借鉴经验:参考相关领域的文献或前人在类似问题上使用遗传算法的经验,了解他们所采用的变异率范围,并以此作为初始尝试的依据,再结合自己的实验进行调整。

选择种群大小和变异率一般需要综合思考问题的特性、计算资源以及通过实验不断调整,以找到最适合特定问题的参数设置,使遗传算法达到最佳性能。

四、种群与解空间子集

种群的确 可以看作是全部解空间的一个子集 。遗传算法通过对这个子集(种群中的个体)进行一系列操作(选择、交叉、变异)来逐步搜索最优解。

种群大小对寻找最优解的影响

  1. 种群过小
  2. 较快找到局部最优解:种群较小时,个体数量有限,基因多样性不足。这使得算法在搜索过程中更容易在较小的解空间范围内聚集,因此可能相对较快地找到局部最优解。例如,在一个简单的函数优化问题中,由于种群个体少,它们很快就聚焦在某个局部最优区域。
  3. 难找到全局最优解:由于种群规模小,无法充分覆盖整个解空间,很可能遗漏全局最优解所在的区域。就像在一个复杂地形中寻找最低点,只有少数几个探索者,他们很容易被困在某个小山谷(局部最优),而错过更大范围内的最低点(全局最优)。
  4. 耗时过长且可能无法收敛:这部分理解不太准确。实际上,种群过小时,算法收敛速度往往较快,但容易陷入局部最优,而不是耗时过长。由于个体数量少,算法在较少的迭代次数内就可能使种群中的个体趋于类似,即收敛到局部最优解,而不是难以收敛。
  5. 种群过大
  6. 错过全局最优解:种群过大并不直接导致错过全局最优解。相反,较大的种群理论上有更多机会包含全局最优解附近的个体,由于它能更全面地覆盖解空间。不过,种群过大会带来一些问题。第一,计算量会显著增加,由于对每个个体都要进行适应度评估、遗传操作等,这会导致算法运行时间大幅延长。其次,过大的种群可能会使种群的多样性过于分散,算法在搜索过程中难以聚焦,导致收敛速度变慢。例如,在大规模的旅行商问题中,过大的种群使得每个个体都在探索不同的路径,很难形成有效的信息积累和进化方向,从而影响找到全局最优解的效率,但不是错过全局最优解本身。

总体而言,合适的种群大小能在解空间的探索和利用之间达到平衡,从而较快找到最优解。种群过小易陷入局部最优,收敛快但可能错过全局最优;种群过大虽理论上更易找到全局最优,但计算成本高且收敛速度可能变慢。

五、Python遗传算法库

在 Python 中有一些库提供了遗传算法的实现,可直接使用:

1、DEAP(Distributed Evolutionary Algorithms in Python)

特点:这是一个功能强劲且灵活的遗传算法库,提供了丰富的工具和类来实现各种遗传算法的组件。它支持多种编码方式(如整数编码、实数编码、二进制编码等),允许用户自定义遗传算子(选择、交叉、变异),并且易于扩展,适用于解决不同类型的优化问题,无论是简单的函数优化还是复杂的组合优化问题。

import numpy as np
from deap import base, creator, tools


# 定义适应度函数
def evalOneMax(individual):
    return sum(individual),


# 创建适应度和个体类
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)


# 初始化工具盒
toolbox = base.Toolbox()
toolbox.register("attr_bool", np.random.randint, 0, 2)
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, 100)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

toolbox.register("evaluate", evalOneMax)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)
toolbox.register("select", tools.selTournament, tournsize=3)


# 遗传算法流程
def main():
    pop = toolbox.population(n=300)
    CXPB, MUTPB, NGEN = 0.5, 0.2, 40

    fitnesses = list(map(toolbox.evaluate, pop))
    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit

    for g in range(NGEN):
        offspring = toolbox.select(pop, len(pop))
        offspring = list(map(toolbox.clone, offspring))

        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            if np.random.random() < CXPB:
                toolbox.mate(child1, child2)
                del child1.fitness.values
                del child2.fitness.values

        for mutant in offspring:
            if np.random.random() < MUTPB:
                toolbox.mutate(mutant)
                del mutant.fitness.values

        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = map(toolbox.evaluate, invalid_ind)
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        pop[:] = offspring

    best_ind = tools.selBest(pop, 1)[0]
    print("Best individual is: ", best_ind)
    print("Its fitness is: ", best_ind.fitness.values)


if __name__ == "__main__":
    main()

2、PyGAD(Python Genetic Algorithm Library)

特点:PyGAD 是一个易于使用的遗传算法库,它提供了简洁的 API,使得用户能够快速实现遗传算法来解决优化问题。它支持多种选择方法、交叉和变异算子,并且能够处理连续和离散的优化问题。该库还提供了可视化功能,可协助用户理解遗传算法的运行过程。

import pygad
import numpy as np


# 目标函数
def fitness_func(solution, solution_idx):
    return np.sum(solution)


num_generations = 50
num_parents_mating = 10
sol_per_pop = 20
num_genes = 10
init_range_low = -2
init_range_high = 5
parent_selection_type = "sss"
keep_parents = -1
crossover_type = "single_point"
mutation_type = "random"
mutation_percent_genes = 10


ga_instance = pygad.GA(num_generations=num_generations,
                       num_parents_mating=num_parents_mating,
                       sol_per_pop=sol_per_pop,
                       num_genes=num_genes,
                       init_range_low=init_range_low,
                       init_range_high=init_range_high,
                       parent_selection_type=parent_selection_type,
                       keep_parents=keep_parents,
                       crossover_type=crossover_type,
                       mutation_type=mutation_type,
                       mutation_percent_genes=mutation_percent_genes,
                       fitness_func=fitness_func)


ga_instance.run()
solution, solution_fitness, solution_idx = ga_instance.best_solution()
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))
print("Index of the best solution : {solution_idx}".format(solution_idx=solution_idx))
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 共1条

请登录后发表评论