英特尔实验室的两位研究人员,利用遗传算法和图灵完备语言,号称实现了首个能够自动编程的AI系统“AI Programmer”。文章共三篇,以下是网络翻译的详细内容:
近年来,随着计算机技术、硬件、内存和CPU速度的进步,人工智能一直在稳步发展。随着计算机速度的提高,可以进行更多的计算,从而提高许多人工智能算法所需的计算密集型处理能力。
这对我来说有点像是一种爱好,我涉猎人工智能程序,试图编写一个本身就可以编写程序的程序。当然,我并不是指那些将程序指令或代码块的子集组合在一起或以其他方式优化以产生最终结果的程序。我指的是从头开始,人工智能完全不知道如何用目标语言编程。人工智能必须自己学习如何为特定目的创建一个功能完备的程序。
我最初是在20世纪90年代末开始这项冒险的,当时我试图用简单的if/then/else语句创建程序,用BASIC编程语言输出程序。这是一项艰巨的任务,原因很多。首先,使用if/then/else条件来编写随机程序似乎一点也不聪明。第二,BASIC中可用的计算机指令太多了。更麻烦的是,有些指令非常危险(Shell(“format c:”)!我还尝试用C、C++和其他几种语言生成程序。然而,这种天真的方法从来没有产生一个工作的孩子计划。尽管这不仅仅是因为使用简单的if/then/else语句,还因为所选的编程语言是为了供人类使用而不是计算机,因此,对于人工智能来说,自动化要复杂得多。
虽然最终的目标是产生一个能够编写自己的文字处理软件、图像编辑工具、网络浏览器或磁盘碎片整理程序的计算机程序,但我更感兴趣的是一个简单的概念证明,证明这个想法是可能的。
我最初的动机来自于【无限猴子】定理,它说如果你有1000多只猴子在打字机上敲打足够长的时间,它们最终会重演莎士比亚写的剧本。这听起来很荒谬,但如果有足够的时间,猴子们最终肯定会碰到“一些”随机的字符序列,最终产生书面作品。简化这个想法,其中一只猴子肯定会在键盘的敲击声中敲出莎士比亚戏剧的第一个字母;这当然是可能的。
如果你能引导猴子呢?每次一只猴子按正确的顺序按正确的键,你就用香蕉奖励他?经过足够长的时间,也许猴子会开始发现一个模式?如果他真的很犀利,也许他甚至会开始学习英语中哪些字母通常一起组成单词,从而比同龄人利用更多的香蕉。
这是遗传算法的基本思想。遗传算法是一种模仿生物进化的人工智能,除了可用的工具和有效的指令外,它一开始对这个学科一无所知。人工智能随机挑选一系列指令(作为一段DNA)并检查结果的适用性。它是在人口众多的情况下完成的,比如说100个项目。当然,有些节目比其他节目好。那些身体最健康的人被交配在一起产生后代。每一代人都从轮盘赌选择、交叉和变异等进化技术中获得了一点额外的多样性。每个子代都会重复这个过程,希望产生越来越好的结果,直到找到目标解决方案。遗传算法是适者生存的编程实现。他们也可以被归类为人工智能搜索算法,就他们如何搜索一个巨大的问题空间的具体解决方案。
虽然使用BASIC、C、C++和其他语言的原始实验未能产生结果,但我能够成功地通过将一个自组织的编程语言(包括加法、减法、循环等)与遗传算法和神经网络结合来生成人工智能编写的程序。虽然这很有趣,但最终的结果是简单的数学计算和编程语言本身,是未知的,并且对它最终能产生什么有严重的限制。
我开始寻找一种简单的编程语言,指令数量有限,可以训练人工智能程序使用。汇编(ASM)很接近,但仍然包含了太多的排列。虽然听起来很幽默,但我最终还是尝试了brainf ck,并最终成功地生成了上面显示的代码。
虽然brainf ck被设计成一种笑话编程语言,但由于人类使用它有多困难,它实际上对计算机有几个明显的优势。
1。它是图灵完备的
图灵完全编程语言意味着它在理论上能够解决宇宙中的任何计算问题。一种具有这种能力的编程语言提供了大量的可能性。毕竟,大多数(如果不是所有的话)计算机程序的设计都是为了执行某种计算并以某种方式输出结果。
2。它只由一组简化的8条指令组成
简化的指令集减少了可以找到目标程序代码的搜索空间。随着计算机越来越快,可以搜索更大的问题空间。然而,在个人计算机上,搜索空间需要受到限制。通过将编程指令集限制为8个不同的字符,AI可以更快地运行,并在合理的时间内(即,分钟、小时,甚至可能是一天)获得最佳适应度分数。
3。建立一个解释器很容易
指令集有很好的文档记录,易于理解。因此,创建一个可以执行程序的简单解释器非常简单。通过将解释器包含在AI程序+遗传算法本身中,代码可以优化为比调用外部编译器来执行每个子程序快得多。这也提供了安全约束,因为子程序是在人工智能程序的受控环境中运行的。AI还可以访问解释器的内部组件,例如内存、指令和输出。这在计算健康评分时很有用。然而,使用第三方编译器,这些组件将更难访问。
4。每条指令为1字节
本文中使用的人工智能程序是在C#.NET中设计的,它使用一个双倍数组作为基因组。基因组中的每个double(基因)对应于编程语言中的一条指令。因为每条指令只有1个字节,所以很容易将每个基因映射到一个编程代码(注意,1 double=8字节;仍然相当于数组中的一个插槽)。
5。存在扩展指令的可能性
大多数编程语言的解释器只是执行代码,维护内存值,并支持控制台输入/输出。但是,可以扩展解释器以包括对生成图形、网络功能、文件系统访问等的支持。想想你能给人工智能开发自己程序的能力吧!;)
人工智能程序的工作原理如下:
1 一个基因组由一系列双倍体组成。
2 每个基因对应于brainf ck编程语言中的一条指令。
3 从一群随机的基因组开始。
4 通过将每个double转换成相应的指令并执行程序,将每个基因组解码成结果程序。
5 根据每个程序写入控制台的输出(如果有),获取每个程序的适应度得分,并对它们进行排序。
6 使用轮盘赌选择、交叉和变异将最好的基因组配对,产生新一代。
7 对新一代重复此过程,直到达到目标适应度分数。
由于适应度方法fitness是计算成本最高的部分(它必须为人口中的每个成员执行程序代码,这可能包括无限循环和其他讨厌的东西),人工智能程序使用Parallel.ForEach方法,可在.NET4.5中找到。以这种方式,它可以在每一代对群体中的多个基因组执行多个适应度算法。这允许程序利用最大的CPU资源并利用多个CPU核。程序还每隔10000代保存一次状态,以防程序或PC关闭,并且可以从停止的位置继续搜索。
适应度方法的工作原理是对生成的程序的输出进行评分。通过查看程序输出的每个字符(如果产生任何输出)并从所需字符中减去其值来计算分数:
fitness += 256 - Math.Abs(console[i] - targetString[i]);
当然,最初大多数生成的程序甚至不会编译,更不用说将文本输出到控制台了。这些都被简单地丢弃,偏向于至少输出一些东西的程序;并进一步引导和进化,直到输出结果越来越接近所需的解决方案。
如果我们剪裁多余的代码,则会看到以下语法上有效的代码:
-----------<++[[++>++<+][]>-.+[+++++++++++++++++++++++++++++><+++.<><-->>>+].]
+[+++++>++<]+>++++++[[++++++.-------------.-.-+.+++++.+++++],.,+,-+-,+>+.++<<+<><+]
-[-<>.]>+.-.+..]<
这次是个挑战。这可能是由于它的长度,或可能是由于d的位置棘手。人工智能会反复陷入局部最大值。局部极大值是指当遗传算法在其当前参数内找到它能看到的最佳适应度时,即使可能存在更好的适应度。人工智能无法跳出洞来获得更好的适应度,因为这样做需要适应度先下降,然后再增加,这通常违反遗传算法的规则。
+[<.<],]<<<>].[--+[<<->--],-+>]-,[,
如果去掉多余的部分,打印文本的实际代码就会短得多:
如果删去多余的部分,打印文本的实际代码将变短:
+[>+<+++]+>------------.+<+++++++++++++++++++++++++++++++.>++++++++++++++++++++++++++++++
++++.+++.+++++++.-----------------.--<.>--.+++++++++++..---<.>-.+++++++++++++.--------.--
----------.+++++++++++++.+++++.
在上面的运行中,为AI提供了300条指令的起始程序数组大小(即300字节,或者更确切地说是2400字节,因为1 double=8字节)。人工智能不需要完整的程序代码。它能用209条指令编写程序。
与所有遗传算法一样,设计适应度函数也涉及很多工作。适应性功能等效于向AI描述您要查找的内容。这样,创建适应性函数本身就有点像编程(代表人类)。如果AI有可能开发自己的适应功能,这将是向前迈出的一步。同时,可能仍可以扩展该项目以创建更复杂的子程序,例如那些接受用户输入并计算结果的子程序。
十年前,该计划在任何合理的时间内都不会成功。五年前,该计划可能要花费几天到几周的时间,甚至可能更长。今天,执行只花了几分钟。明天,该程序可能会在几毫秒内运行。随着计算机变得越来越快,功能越来越强大,可以计算出越来越大的搜索空间。我等不及了
如果您发现这很有趣并且想了解更多信息,请在GitHub上下载完整的源代码或联系Kory Becker。阅读我的有关在C#.NET中使用遗传算法和神经网络的教程。本文中的程序可执行文件是使用Brainfuck.NET编译器编译的。
是否想了解AI还能做什么?我也是!在后续文章中阅读更多内容:突破自我编程人工智能的极限和自我编程人工智能学习使用功能。