最近,我在浏览Reddit时遇到了一个链接到“ JavaScript遗传算法”示例的帖子。我对遗传算法和编程的概念非常着迷,但是即使经过了谷歌搜索,我仍然感到有些困惑。它是如何工作的?
我想这些词汇对我来说比什么都使我更困惑。我希望能看到一些简短的例子,也许还有一些解释。只是基因编程的概念以及我如何在项目中实现它,为什么?
最近,我在浏览Reddit时遇到了一个链接到“ JavaScript遗传算法”示例的帖子。我对遗传算法和编程的概念非常着迷,但是即使经过了谷歌搜索,我仍然感到有些困惑。它是如何工作的?
我想这些词汇对我来说比什么都使我更困惑。我希望能看到一些简短的例子,也许还有一些解释。只是基因编程的概念以及我如何在项目中实现它,为什么?
Answers:
听起来您在谈论遗传算法,而不是在谈论遗传编程,但这是我对您的理解的贡献。
从GA的组成部分考虑GA可能很方便。
因此,假设您遇到某种问题。您需要的第一件事是表达解决方案外观的方法。如果您遇到城市A,B,C,D,E 的旅行推销员问题,那么您已经知道解决方案是什么样的,即城市名称的数组[B,C,A,D,E]。
这就是基因。
否则称为解决问题的潜在方法。就像史蒂文·A·劳(Steven A. Lowe)提到的那样,位串是编码基因的常用方法,但这不是必需的。它只是使某些事情变得容易。重要的部分是您可以用一种类似于数组的方式表示解决方案。
现在。您怎么知道解决方案是否有效?您需要一个可以告诉您并为解决方案评分的功能。因此,对于TSP,您可能还具有使用路径[B,C,A,D,E]测量行进距离的功能。您指定的“等级”可能只是行进的距离,但在更复杂的问题中,您可能会包括旅行成本和其他事项。
这是健身功能。
因此,现在您可以采用潜在的解决方案,并找出是否有什么好处。下一步是什么?
接下来,我们需要开始我们的第一代。因此,我们生成了一堆随机解。他们是否好没关系。这是您的初始人口或种子人口。您可以将其称为您的基因库。
因此,您需要使用最初的基因库,然后将适应度函数应用于所有这些对象,并为其评分。现在,您需要容纳其中两个,并从中获得新的人口-下一代。您选择谁?好吧,您不想只选择适合的最适合者,这可能会导致一些问题。相反,您需要选择功能。
一种易于观察的选择方法是使用一种转盘:每个基因都是转盘上的一个切片,其适应性得分表明其切片的大小(适应性越好,切片越大)。放置一个指向车轮的销钉并旋转一下(即生成一个随机数)。别针指向第一个父对象。再为第二个父母做。
现在,您需要创建新的子代。您想合并父母以产生新的人口。有多种方法可以做到这一点,但是它们都被称为交叉功能。您可以将它们分成两半,在父母之间交换两半,或者进行某种交织。这与哺育新子女的哺乳动物父母非常相似->他们都向新子女贡献自己的基因。
有了新一代后,您就会对每个孩子进行随机但罕见的突变。我经常看到突变发生率不到1%。该突变功能会随机改变你的编码基因的东西。如果您的基因是一个字符串,它可能会交换一点,如果它是一个城市数组,则可能会交换列表中的2个城市。重要的是,这是相对罕见的事件,并且会混杂在一起。
重复此过程,直到达到所需的世代数,或者直到您的健身功能使父母的健身得分一直保持较高,并且您找到了一个最佳的解决方案(希望您做对了)。
这有点罗word,所以让我用一个隐喻来总结一下:
希望这可以帮助。
将问题的解决方案编码为位字符串
编写一个函数(称为“适应性”函数)以评估编码后的解决方案的位字符串的“良好”程度-结果通常为0到1之间的数字
随机生成一堆这些位串并评估其适合度
选择一堆(通常是更适合的一堆),将其切成两半,交换成两半,以制作一些新的比特串(交叉)
然后有时候,在一些新的位字符串中随机翻转一些位(突变)
重复进行,直到找到一个好的解决方案
为什么这样做:某些问题具有巨大的可能解决方案空间,太大了,以至于无法评估所有可能性(请参阅旅行商问题)
我强烈推荐《搜索,优化和机器学习中的遗传算法》一书
基因编程是让计算机为您编写程序的一种方式!
不要认为像MS Word这样的“程序”,而应将“程序”视为以下内容:
function(x){ return x*2; }
此功能(或程序)本身没有理由存在。我们正在寻找问题的解决方案。如果您需要找到两个数字的和,则只需打开计算器并进行数学运算即可。如果什么人给你下面的表格,并要求你找出之间的关系result
,并x
和y
:
x y result
99 1 (3.02)
79 88 2.01
21 62 5.01
84 52 (6.58)
12 70 5.54
67 18 0.73
此数据是您的“培训”数据。您的计算机将使用此数据生成一些假设,然后将其与实际数据进行比较。
假设您不了解统计信息,并认为很难独自解决此问题,那么计算机将为您解决。
您让计算机生成一百万个答案,然后看是否有任何答案(猜测...一百万次!)。以下是一些猜测的示例:
function(x,y){ return x+y; } // wrong
function(x,y){ return x/1*1*1*1*1*1+y; } //wrong, silly
您可能知道也可能不知道,但是功能或程序也可以表示为树,例如,第二个功能为:
(+ (/ x (* 1 (* 1 (* 1 (* 1 (* 1 1)))) y)
通过像这样缩进,可以使它看起来更像一棵树(顺便说一句,查找反向修饰符号和lisp语法...但是您很快就会理解为什么我们代表这样的程序):
(+
(/ x
(* 1
(* 1
(* 1
(* 1
(* 1 1))))
y)
(+
是有两个的“叶子”顶部/
和y
。/
本身有几个孩子等)
这就是为什么您对遗传编程中的“树”有如此多的了解的原因。在任何情况下,我们插上的价值观x
和y
这个功能,它为我们提供了错误的答案。不过这并不奇怪,因为我们是随机生成的。
您现在决定生成一百万个这样的解决方案。他们都是错的。但是,您注意到某些答案比其他答案更接近正确答案。换句话说,某些解决方案比其他解决方案更“适合”。请注意,计算机不知道什么是“正确”和“错误”,因此您必须提供自己的“健身功能”。该功能将提供潜在的解决方案,培训数据,并负责告诉GP系统该解决方案的“适用性”。可以想象,此函数运行数百万次。
这就是使基因编程与狂野猜测不同的原因。您决定再进行一轮猜测。但是,您可以更智能地进行操作。您将前10%的猜测(接近实际值的猜测)作为第二代的一部分。您还可以采用许多这样的解决方案(也许是10%的比例...我不记得了),然后决定“混合使用”。
您随机选择两个解决方案,随机选择子树并开始交换它们。因此,解决方案A的一部分最终落在解决方案B之下,反之亦然-您只需“交叉”它们即可。您还可以采用一些解决方案,然后简单地对其进行“变异” ...采用一些子树并将其“拧紧”(嘿,如果解决方案很糟糕,“无缘无故地耕种”实际上可能会改善它)。
对此有一个好的思考方式:您的父母有某些属性-头发的颜色,身高,患病的可能性等。作为孩子,您从父母双方那里继承了不同的属性。如果您的父母都是奥运会运动员,那么您也将成为超级运动员,对吗?好吧,生物学家,社会学家甚至历史学家可能会对这个想法持怀疑态度,但是计算机科学家并不关心优生学的道德。他们只是看到一个“系统”在提供解决方案方面做得很好,因此他们决定在软件中对其进行建模。
如果它实际上与生物学不匹配,但仍能提供良好的答案,那么……许多计算机科学家会集体说:“不管怎么说,谢谢您的术语。” 另请注意,您的所有兄弟姐妹并不一定完全一样……即使他们的父母相同。每个人都有因任何原因而变异的基因(请不要向生物学家展示,这是要了解许多术语背后的动机)。
因此,现在我们正在使计算机生成数百万个程序并测量其适用性。最好的解决方案可以存入下一代。我们还对“种群”进行“变异”和交叉(注意如何使用遗传学和生物学的语言)。创建第二代后,将再次测量适合度。由于这一代人拥有上一代人的最佳解决方案,并且我们越过了最好的解决方案并对其进行了变异(以及中等水平的人口-以保持多样性),因此这一代人至少应比上一代人好一点。
我们将这一代延续了很多代。每一代(希望如此)都会提供越来越好的解决方案,直到我们得到正确的答案。例如:
(+ (- 2.2 (/ x 11) (* 7 (cos y))))
好看看,这是正确的!
(我从http://en.wikipedia.org/wiki/Genetic_programming复制了此文件,该文件也对此树做了图形表示)
这里有一些重要的问题,例如如何确定+, -, *, /, cos, sin, tan
GP系统可以使用哪些“端子”(),如何编写适应度函数以及系统如何处理非感性程序,例如(1 + cos)
或(2 / "hello")
(以及其他)。
发展方程式很无聊。如果您的终端机看起来像以下内容,它将变得更加有趣:(开火,感知敌人,移动,...)并且您的健身功能可以衡量您的健康状况以及武术怪物的尸体数量。
我大部分是从内存中写的,但这是基本思想。我上大学时曾做过GP。您绝对应该玩弄它。不必担心了解所有术语,只需下载一些免费的GP系统,通过几个示例进行操作,即可体会到它,并编写自己的有趣示例(查找不同数据集之间的关系,尝试将其连接到游戏中) API等)
适者生存:Windows窗体的自然选择是我入门遗传编程的方法。易于阅读,提供可供下载的代码。不利的一面是GP需要一种方法来执行在运行时创建的代码,而在撰写本文时,C#不太适合此任务。这就是该示例在运行时使用CodeDOM生成,编译和运行代码的原因,这本身为其添加了另一层复杂性。
从那时起,情况发生了变化,.NET现在拥有自己的ExpressionTree API,与本文中介绍的方法相比,它可能允许在C#中使用更优雅的GP实现。但这足以了解GP的工作原理。
在这里,您可以下载有关GP的免费电子书,其中还包括一个非常简短的Java代码示例,您可能也会觉得很有趣。