什么是遗传算法?
遗传算法(GA)是解决搜索和优化问题的一个非常强大的工具,它包括尝试几个解决方案,并利用在每次尝试中收集的信息来提高下一个建议的质量。遗传算法的灵感来自达尔文的进化理论,并实现了适者生存、自然选择、变异等概念。它们被认为是仿生的,因为它们是受大自然的启发来解决问题的。我写了一篇关于它的文章,你可以在这里查阅:生物仿生学:为什么出去 "摸摸草 "可能真的是你问题的答案
在这篇文章中,我将解释遗传算法是如何工作的,以及我是如何用它来解决一个实际问题的。
你可以在这里访问项目库:遗传算法-旅行的小偷
遗传算法是如何工作的?
如前所述,GA实现了达尔文的进化理论的功能。为了在谈论该算法之前有一个更好的背景,我们需要了解这个理论是如何工作的。
达尔文的进化论
随着时间的推移,生物经历了随机的遗传变化(突变),这些变化可以在它们生活的环境中引起适应性优势。通过自然选择,最适应的个体有更多机会生存和繁殖,将这些遗传优势转移到下一代。
遗传算法的组成
-
基因
将被遗传算法改变的信息。 -
染色体
数据结构,包含基因的集合。 -
个体
对象,包含染色体并存储适配度值。 -
群体
个体的集合。 -
突变
将改变个体基因的函数。突变将使基因发生微小的变化。 -
交叉
函数将对群体中个体的染色体进行交叉。交叉是一种突变,它结合了两个个体。 -
健身
对个体进行评分的函数。健身函数是GA中最重要的部分之一。它定义了每个个体的表现如何,因此它的适应性如何。 -
选择
决定哪些个体将成为下一代的初始种群的函数。这个函数负责分析每个个体的适应性,并选择哪些个体应该 "生存"。
遗传算法的步骤
遗传算法的工作方式如下:
- 产生一个由个体组成的初始种群。这个群体可以是随机的,也可以不是,取决于你需要的代码的优化程度。
- 从初始种群中产生经历过变异的种群和经历过交叉的种群。这些被合并成一个。我将在后面详细介绍突变和交叉。
- 整个种群中的所有个体都要经过选择,那些具有最高适配度的个体(最适应的)"幸存 "下来,成为下一代的起始种群。
- 这个过程不断重复,直到达到某种停止条件,如最小误差或最大世代。
遗传算法的实践
一切都在良好的解释下更容易理解。从这一点出发,我将解释我是如何使用GA来解决一个问题的!
这个问题
问题的介绍
AIC(国际犯罪署)向Joana提出了一个挑战,即在72小时内在几个城市进行抢劫。Joana必须谨慎地使用付费的公共交通工具,并将偷来的物品装在一个重达20公斤的背包里。每个城市都有贵重物品可供偷盗,但每次偷盗都需要时间来完成。此外,城市之间的旅行有经济成本,也需要时间。如果她成功地偷到了最大数量的物品,她必须回到埃斯康迪多斯的AIC总部领取她的奖品。
问题数据
所提供的数据是:
- 一张包含物品数据的表格:
- 一个包含城市间旅行的成本和时间数据的表格:
上述表格是不完整的,因为它非常长。它的完整版本可以在项目库中找到。
遗传算法的应用
数据处理
为了处理这些数据,我们创建了一个 "数据工厂 "类。它负责处理表格并创建字典,以便在代码中使用它们。
类和函数的建模
为了使用GA,有必要对我们的问题进行建模,以适应GA的组成。对于这个问题,它被定义了:
- 基因:每个城市都在一个列表中
- 染色体:一个包含城市的列表
- 个体:"路线 "类的一个对象,它包含染色体并存储健身值。
- 群体:"Routes "类的一个对象,包含 "Route "对象的一个列表。
个体
个体被定义为Route类的一个对象。该个体可以用随机或预定义的路线进行实例化。这对于在初始种群中或在突变和交叉功能中使用是很有用的。该个体还存储了它的健身值。
路线的生成确保第一个城市总是 "Escondidos",因为它是Joana离开的地方。因为它也是Joana完成抢劫后必须返回的地方,所以 "Escondidos "是唯一一个在路线中出现超过一次的城市。
由于健身和变异函数是针对每个人的,所以它们也被定义在路线类中。
健身
健身是GA中最重要的函数之一。它负责评估该个体的优秀程度。
这就好像是Fitness定义了哪些个体可以生存,哪些不可以。例如,如果一个人的体重是23公斤,那么健身就会说他不适合,并对他进行负面评价。这就使得我们没有必要去阐述超级复杂的突变和交叉函数,因为如果生成的个体是坏的,那就由适配度来决定。
由于这个问题定义了我们要使利润最大化,所以它就成了一个最佳的健身函数返回,因为越大越好。
然而,在计算利润之前,要检查路线是否有效,路线是否没有超过重量和时间限制。
为了计算这一切,路线被认为是从 "隐藏 "的第一次到第二次出现。第二次出现后的所有内容都不被考虑。这使得我们的路线总是有一个固定的大小,并使交叉和变异更容易。
变异
突变使个体的染色体发生微小变化。由于我把染色体定义为一个城市列表,突变使两个城市的位置随机改变(除了第一个)。
在GA代码中,产生了新的变异个体群体,并将其加入到原始个体中。由于这个原因,突变函数生成了一个新的个体。另一个原因是,每当一个新的个体被生成时,它的适配度会被自动计算。
群体
种群是一个Routes类的对象。
群体类负责实现个体的交叉和选择。
交叉
在这种情况下,种群被分成两半,每个个体与另一半的同类个体结合。
为了交叉选择个体,我创建了一个合并染色体的函数,如下图所示:
结果:
与突变一样,交叉返回一个新个体的列表。
选择
选择负责确定哪些个体将传给下一代。它通过对整个种群列表进行排序,并将新种群定义为前10名。
有了这些,GA就可以运行了
结果、问题和限制
问题和限制
尽管很吸引人,但GA并不完美。在实施过程中,我注意到关于GA的两个常见问题
过早收敛
GA的一个大问题是过早收敛。当一个相当好的个体过早出现时,算法倾向于使用它作为生成新个体的模型。这是一个问题,因为它阻碍了更好的个体的产生。为了更好地理解,下面的图片举例说明了全局和局部的最大值和最小值:
有一些方法可以缓解这个问题,如更好的交叉和变异功能或消除相同的个体,但这仍然是一个没有明确解决方案的问题。
缺乏对优化的保证
GAs是启发式算法,不能保证在所有情况下都能获得最优解。虽然它们可以收敛到高质量的解决方案,但不能保证找到的解决方案是最好的。当算法运行数次而答案不同时,人们注意到了这一点。这一点可以通过增加代数来缓解,但其代价是需要更多的时间和处理。
结果
来自GA的最适合的个体是:
结论
就个人而言,GA让我着迷。在这个项目上工作并能与大家分享是一件非常愉快的事情。在这个过程中我学到了很多东西,这促使我在这个领域寻找更多的知识。在开发过程中,我与Estefane George Macedo de Lacerda的博士论文《通过遗传算法选择RBF网络的模型》有过接触,这对了解GA的工作原理有很大帮助,我想公开祝贺她的精彩研究。