使用 Python 进行遗传算法的动手优化

原文:towardsdatascience.com/hands-on-optimization-using-genetic-algorithms-with-python-bb7970dbbf0a

你听说过这个销售策略吗?

“你在 X 上浪费了几个小时吗?为什么不试试 Y?”

我确信你做到了。例如:“不要花几个小时编写自己的代码,用我们的软件代替!” 或者 “停止浪费几个小时在你的广告上,用 AI 代替!”(我的 YouTube 推荐算法喜欢这个,可能是因为我总是谈论 AI)。

这个销售策略基于这样一个事实,即你花在想要解决的问题上的时间可以被优化

“用点学术语言来说”,当你阅读这个销售策略时,你通常有两个选择:探索利用。我这是什么意思?我稍后会解释。现在,记住这个销售策略,把它放在你脑后。我们回头再谈。

假设你有一个工具,一个可以调整的旋钮。通过移动这个旋钮,你得到一个等待时间。想象一下,你在星巴克的咖啡队列中,旋钮有两个状态(0 和 1):0 可能意味着“留在同一个队列”而 1 可能是“换一个队列”。哪一个意味着“等待时间最少”?你应该换队列还是耐心等待同一个队列?我知道你至少遇到过这个问题一次。我是一个大换队人,而我的妻子是一个大留队者。

现在,让我们考虑一个可以连续移动的旋钮,这意味着你在 0 和 1 之间有无限的状态(如果你愿意,可以想象很多“线条”)。让我们称这个状态为x。从数学的角度来说,我们的问题有x(状态)y(等待时间)

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/54d22bfe8ab26a1b67ad07f388672b42.png

作者制作的照片

假设我们有状态0.2、0.4、0.6 和 0.8。对于这些状态,我们找到了相应的等待时间

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/eb2183da0c9b3eaa2bbe5abdeb21a555.png

作者制作的照片

现在,考虑到这 4 个点,我们可以说最低的等待时间是在状态 x=0.4。但我们能确定这真的是最短的时间吗?我们不知道,但我们只有 4 个点,所以我们高度怀疑我们已经找到了最短的时间,特别是考虑到 0.0 和 0.2 之间以及 0.8 和 1 之间的区域完全未被探索。我们能做什么?

  1. 我们探索其他区域(在 0 和 0.2 之间以及 0.8 和 1 之间)。

  2. 我们利用我们认为最小值可能存在的区域(在 0.2 和 0.6 之间)

你还记得那个销售策略的例子吗? 这相当于这样做:

  1. 我们信任销售人员,并探索未探索的区域:我们改变我们之前的行为,看看未探索的部分会发生什么。例如,我们购买他们试图销售的软件,并放弃我们的编码。

  2. 我们不信任销售人员,并利用我们所知道的信息:我们深入挖掘并细化我们的估计。我们不购买他们的软件,并提高我们自己的编码技能。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b61e4c0db1e5ab54312d296ce15da102.png

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/52869a3c4e0c69b3f89e4fc9a7e74a95.png

现在,做两者会很好,对吧?最好不是 100%信任销售人员,而是 0%信任自己,而是同时进行探索和利用。例如,你支付他告诉你的 20%(对于你不想处理的最难的部分),而你自己处理你想要处理的脏活,节省金钱。

有时候情况很混乱,故事比一个试图卖软件的人更复杂:这就是遗传算法(GAs)的用武之地。遗传算法是一种通常在考虑探索利用方面都做得很好的优化方法。遗传算法的根源在于生物学,我发现这种方法非常迷人且强大。

在这篇博客文章中,我们将做以下事情:

  1. 我们将非常简要地定义遗传算法试图解决的问题(优化和全局最优)

  2. 我们将从理论角度描述遗传算法。

  3. 我们将把遗传算法应用于一个多极值情况。

好吧,有很多东西要讲。准备好了吗?让我们开始吧。

0. 优化思想

我们在介绍中已经稍微涉及了一些优化思想,这里不需要用复杂的数学。我只是想稍微形式化一下问题,这样我们就能在整个文章中理解我们在谈论什么。

一切都从你的参数开始。回到旋钮的例子,假设你不止有一个旋钮,而是有多个。假设你有 k 个。这些就是你的参数。你的参数形成一个向量(或者如果你喜欢计算机,就是一个列表),用 x 表示:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b61e4c0db1e5ab54312d296ce15da102.png

由作者制作的照片

对于你给我的每一个 x,我会给你相应的损失(或成本)。损失用字母 L 表示。遗传算法的目标是使这个损失最小化,使其尽可能小。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0f0db7560a5f252823985d2ef088ce1d.png

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/52869a3c4e0c69b3f89e4fc9a7e74a95.png

其中 X 是你的“解空间”,由参数 1、参数 2、……、参数 k 的整个边界表示。

好的。这就是我要说的闲话了。现在,让我们具体谈谈遗传算法。

1. 遗传算法理论

1.1 定义一个种群

现在,你还记得我承诺过我们要 探索利用 吗?为了 探索,我们首先要用 N 个元素填充 X。这将确保我们有一个平等的机会去“看到”(或探索)一切,而不会错过可能的最佳“位置”。

遗传算法 的想法来源于生物学,因此你将看到很多生物学术语。原始的随机样本被称为 “种群”。种群会随着时间(t)的推移而 进化,因此我们将它定义为 P(t)。种群有 m元素,这些元素被称为 染色体

因此,这是我们第一个种群:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3e27d1476cc8b9f511e4eb0436486a1a.png

由作者制作的照片

正如我们所说的,P(0) 的元素是从 k 维参数空间中 随机采样 得到的。

如果你注意到我们的参数向量 x 成为了一个函数,那是因为当我们在寻找最优解时,这个向量会随着时间而进化。

1.2 选择过程

因此,这是我们第一个候选列表。从这个列表中,我们 already 可以看出哪个更好,哪个更差,对吧?例如,如果 m = 50,我们可能会有 L(x(0)_30)<L(x(0)_20),这意味着第 30 个染色体比第 20 个染色体具有更低的损失。

这是我们开始的地方。我们如何改进?首先,我们要选择 最好的那些(即更有可能成为最小值的那些)。在数学上,“最好的那些”意味着“最大化适应度函数的那些”。在最小化的情况下,适应度函数定义为 f(x) = -L(x)

因此,再次强调,在时间 0 时,适应度函数将给出以下值:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2bec73de033c3c3286f262998e1b0988.png

由作者制作的照片

现在,我们如何使用这个适应度函数来选择 “最好的那些” 呢?我们可以简单地选择“适应度值最大的那个”,这非常直观。然而,实现这一目标的一种最好的方式是进行“轮盘赌选择”,这意味着以与适应度函数成比例的概率提取它们。这意味着在时间 t=0 时,提取第 i 个染色体的概率是:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0aa2fe41e5efedc0dd6da79178d183f6.png

由作者制作的照片

这种方法很稳健:如果你只有一个染色体,概率是 1,因为你没有其他选择。

因此,根据上述定义的概率,我们开始 选择 k<m 个 染色体,我们将它们称为 父母,原因你将在下一秒知道**。** 这些父母是 随机选择 的,但它们很可能是具有 良好适应度值 的元素,因为我们定义了概率。

1.3 父亲和孩子

现在,遗传算法是进化算法的一部分,这意味着步骤 t 是步骤 t-1 的进化(如果你愿意的话,是改进)。那么我们如何进化呢?不幸的是,它不像宝可梦,你实际上需要至少两个“父母”来生成一个“孩子”,也称为“后代”。候选“父母”是我们在例如使用上述轮盘赌选择中选择的 k 个候选者。你需要生成与原始种群相同数量的后代(m)。

你可以通过多种方式选择一对父母。你可以随机选择他们,或者从第一个父母开始,并与所有其他父母“配对”。然后使用第二个父母,并与剩余的其他父母“配对”,以此类推,直到你达到“m”个后代。

但我们如何结合两个父母呢?我们通过应用一种称为交叉的技术来实现。我们选择索引 k,然后从该索引开始混合,就像你在下面的方案中看到的那样:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/8fdd78ab61ef333702e0da0f473d97b1.png

作者制作的照片

这个想法有两个原则:

  • 试图从两个父母中获取最佳品质:我们的目标是获取使父母 P 成为良好适应染色体品质的品质,以及使父母 Q 成为良好适应染色体品质的品质,并将它们混合。

  • 探索新区域:从几何学的角度来说,通过这样做,你正在积极探索新区域

这是探索与利用的核心,这也是为什么进化方法在历史上被认为在这两种期望效果之间有很好的权衡。

通过这样重复 m 次,我们将得到 m 个后代。这些后代构成了新的种群,我们将在时间 t 时称这个新的后代集合为:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/75b8457514980dba33442c08936e1f96.png

作者制作的照片

因此,让我们回顾一下到目前为止我们所做的一切:

  1. 我们随机地选择了样本

  2. 我们使用适应度函数作为概率指示器来采样父母候选者列表

  3. 我们从候选人的名单中选择了父母,并将他们配对

  4. 我们从每一对中生成一个后代,从而增强了最小值的探索和利用。

美丽。我们几乎就要完成了,我保证。

1.4 突变

现在下一步是突变我们的后代。我的意思是,我们想要添加某种随机性,这意味着我们不一定希望 x(t)只是 x(t-1)的混合,我们希望它不同。如果你这么想,在生活中,你不仅仅是遗传混合的结果,你也是随机性的结果:你周围发生的事情如何改变你。

抛开哲学不谈,这是你添加突变的方法:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/2e386bfddb24377bbb00d8bedc064836.png

作者制作的照片

这允许你探索xs 的不同实现,同时,你也在利用你最佳最大值(或最小值)的周围环境。记住,这将给我们 m 个元素,因为 X(t)是一个有 m 行的矩阵,所以你的种群已经准备好进行 t+1 步。

1.5 停止标准

我们何时停止这个过程?有多种方法可以做到这一点。第一种方法就是设置迭代次数。例如,t*max = 10:经过 10 次改进后,你停止(在 P(10)处)。或者,你可以将适应度作为参考:当从时间 t 到时间 t+1 的适应度没有足够增加,或者它达到一定阈值时,你停止优化。无论你的标准是什么:

  • 如果未满足标准,你重新执行步骤 1.2–1.4

  • 如果满足了标准,你就停止。

2. 遗传算法实现

现在,这个流程在实践中相当简单:随机选择种群,通过交叉和变异改进它,如果满足停止标准就停止。

令人惊讶的是,在实践中实现它甚至更简单。让我们一步步来看。

2.1 库

PyGAD是一个库,它让你可以完全控制参数(种群大小、父代数量、停止标准等等),但它也非常易于使用。让我公平地说:遗传算法的数学并不复杂,你可以使用面向对象编程从头开始开发它。然而,为了简单和效率,我们将使用 PyGAD 实现。

让我们使用以下命令安装它:

pip install pygad

这个库还提供了非常酷的集成,例如,他们使用 GA 训练神经网络,这非常有趣。

2.2 参数

根据你的最佳需求调整遗传算法(所谓的超参数调整过程)本身就是一门艺术。这里有那么多你可以改变的事情,以找到比刚刚找到的更小的最小值并改进你的结果。所有可能的参数列表可以在这里找到。让我给你一个想法:

  1. fitness_funcgene_space:它们非常重要,因为它们是适应度函数(你定义的“最佳解”)和你要寻找的空间边界

  2. keep_parents:这是一个很酷的功能,它给你提供了在种群 P(t+1)中保留父代的选项,这样你不仅只有后代,还保留了父代以供下一次迭代。

  3. parent_selection_type:有多种方法可以从种群中选择父代。上面我们描述了“轮盘赌选择”,但还有像“稳态选择”或“随机均匀选择”这样的方法。这个参数允许你修改这个方法

  4. mutation_type: “突变”你的种群有多种方式。我们讨论了“随机”,但也有“交换”或“反转”。

  5. crossover_type: 进行“交叉”操作也有多种方式。我们描述了“单点”(我们称之为 k),但你也可以应用“两点”或“均匀”交叉策略来组合基因。

再次强调,这远非完整的列表,因为你可以调整的参数有很多。但这是一件好事**!调整参数是调整你的遗传算法以找到最佳最优解并收敛到全局最优解的方法。

2.3 代码

整个故事可以总结为一块代码。我将给你代码,然后我们将讨论它。

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjovian.com%2Fembed%3Furl%3Dhttps%3A%2F%2Fjovian.ml%2Fpiero-paialunga%2Fgenetic-algorithm%2Fv%2F7%26cellId%3D1&dntp=1&display_name=Jovian&url=https%3A%2F%2Fjovian.ml%2Fpiero-paialunga%2Fgenetic-algorithm%2Fv%2F7%26cellId%3D1&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&scroll=auto&schema=jovian

这就是我们所做的事情:

  • 定义了我们的适应度函数,即“减去我们试图优化的函数”。如果你试图优化的函数是一个黑盒(可能来自复杂的模型或其他东西),根据定义,适应度仍然是减去那个函数。

  • 设置参数,如“m”(种群大小)、“num_generations”(你进行的循环改进次数)或“num_genes”,即你的输入的维度。

  • 我们将这些参数作为输入传递给遗传算法实例。

  • 我们通过执行 ga_instance.run()来运行优化

2.3 应用

我不想过多关注结果,但为了展示它确实有效,我将展示它们的样子。如果你成功运行了前面的代码,ga_instance.solutions 将是一个 kD x N 矩阵,其中:

  • k 是输入的维度

  • N 是迭代次数

我们可以绘制这个矩阵来跟踪我们的遗传算法是如何优化我们的函数的:

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fjovian.com%2Fembed%3Furl%3Dhttp%3A%2F%2Fjovian.ml%2Fpiero-paialunga%2Fgenetic-algorithm%2Fv%2F9%26cellId%3D2&dntp=1&display_name=Jovian&url=http%3A%2F%2Fjovian.ml%2Fpiero-paialunga%2Fgenetic-algorithm%2Fv%2F9%26cellId%3D2&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&scroll=auto&schema=jovian

在这个例子中,我们试图最小化二维中 x 和 y 的奇异函数,我们可以看到 GA 是如何正确猜测最小面积的(即使存在多个局部最小值)。

但再次强调,这篇博客文章的重点是描述如何使用 GA 以及如何使用 PyGAD 来解决你自己的优化任务,所以请绝对自由地更改适应度/损失函数以及所有其他参数。

3. 结论

感谢您与我同行,希望这篇文章是对您时间的良好利用 😃

在这篇文章中,我们探讨了遗传算法是如何从理论到实践工作的。以下是亮点:

  1. 我们讨论了局部全局****最优解以及探索利用问题

  2. 我们逐步描述了遗传算法的理论。

  3. 我们讨论了PyGAD对遗传算法的实现,强调了设置这个库提供的广泛参数的重要性(因为存在多种遗传算法变体)

  4. 我们在一个玩具多最小值示例上展示了结果,突出了这种方法是如何正确迁移到最低最小值(全局最小值)区域的。

4. 关于我!

再次感谢您抽出宝贵时间。这对我们意义重大 ❤

我的名字是 Piero Paialunga,我就是这里这个人:

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/9bb6bb0ed5340cc448765190883769a4.png

由作者制作的照片

我是在辛辛那提大学航空航天工程系的博士候选人,同时也是 Gen Nine 的机器学习工程师。我在博客文章和领英上谈论人工智能和机器学习。如果你喜欢这篇文章,并想了解更多关于机器学习的内容,以及跟随我的研究,你可以:

如果你想向我提问或开始合作,请在这里或**领英**上留言:

点击这里

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值