在现代科技的浪潮中,面临着一个长久以来的挑战,那就是如何调试一个遗传算法(GA)应用程序。这个问题从大学时代就开始了,直到最近,一款现代工具的出现为提供了解决方案。决定重新审视尘封已久的GA API,这源于在加州利弗莫尔的一个联合办公空间与同行们的一次对话。尽管正在构建市场营销应用程序,但同事们却在研究激光和DNA条形码。与他们的工作相比,对自己的代码库感到有些焦虑。其中一家公司正在研究量子密码学。这让思考,构建能够抵御未来量子计算机的更强大加密和解密软件需要什么样的计算能力。而且,该如何构建这样的程序呢?
任何此类应用程序的真正问题在于,即使简单的算法在大规模运行时也会出现有趣的调试挑战。要在大规模上运行此类应用程序,唯一的方法是使用多个进程和多个线程。但当出现问题时,应用程序在所有这些工作线程上的分布式特性使得很难知道问题出在哪里。而GA应用程序既相对简单,又最好在许多代和许多种群(线程)中运行,每个种群由许多个体组成。
GA从达尔文的进化论中汲取了一些见解。基本上,构建的应用程序包括一个生态系统、个体以及它们生活、死亡和繁殖的规则。随机生成这些生态系统,并让它们以计算机速度进化许多次。规则由所谓的适应度函数决定。适应度函数为每个个体分配一个分数,以评估它们解决某个“问题”的适应程度。
决定使用GA来进化加密算法,同时测试加密强度以对抗模拟的解密算法。这很巧妙,因为每个算法都作为对方的适应度函数。但这需要大量的种群实例。为了正确实现,需要测试广泛的生态系统变量。
设计了应用程序,每个生态系统都有一个线程。可以保持简单,一次只运行一个生态系统,但正如稍后将看到的,构建多个生态系统是有益的。不是为了速度,因为想要测试许多变量,以查看哪些变量产生了最佳结果。看,GA的特点是,它是一个黑箱。即使得到了一个结果(一个能够解决适应度函数的超级适应个体),也不知道它是如何到达那里的。不一定知道它是否是最有效方法。虽然可以玩生态系统变量,如死亡率,甚至是疾病。这完全是一个猜测游戏,一种不太科学的方式来改进应用程序。
最后,这就是CodeDynamics发挥作用的地方。这个工具的基础是为超级计算机进行调试,这使得它非常适合管理和调试高度分布式的应用程序。凭借CodeDynamics中独特的调试、暂停和重放功能,终于能够以更有意的方式解决变量挑战。CodeDynamics允许深入黑箱,更好地了解最终输出是如何产生的。
没有使用旧的GA代码库,而是使用了来自MIT的经过更好验证的库,并添加了一些生态系统函数,如疾病。编码的应用程序进化了神经网络加密器,适应度函数是一个类似进化的解密器。这很有趣,因为同时进化了加密和解密,但这不是加密的实用方法。
首先需要在Mac上的Xcode中编译应用程序,然后将二进制文件移动到Linux机器上。之后,能够直接在CodeDynamics中打开并运行应用程序。或者,可以直接运行应用程序并将CodeDynamics附加到进程。
CodeDynamics中的所有操作都像DVD播放器(有关设置教程,请访问此页面)。除了播放,最让兴奋的是暂停按钮。就执行而言,这是相当直接的,有一个树状图来查看线程,只需要深入到问题所在的位置,或者在情况下是关注区域。一旦这样做了,就会得到有关线程/进程及其运行变量的详细信息。
后来发现,反向调试的ReplayEngine对来说更有价值。如果记录了应用程序的每次运行,那么就不需要像鹰一样盯着它,或者预测一个特定的代数来暂停并检查结果。相反,可以记录整个过程,然后反向进入看起来最有利的结果的种群,看看哪些环境变量最有利于适应度。
这还允许做了以前做不到的另一件事(本可以实现这一点,但很难以系统的方式知道它的影响,甚至不知道它是否真的发生了)。现在,比赛开始了。必须将代数限制在一个合理的范围内,以便快速确定变量。解密非常慢。然后一旦认为走对了路,就可以进行更大规模的运行。果然,当开始使用这个工具时,能够确定看起来最有用变量。直到……意识到适应度函数实际上引入了一个问题,阻止了超过局部最大值的收敛。
一旦运行起来就很容易了。但遇到了一些障碍,这让放慢了速度。首先是理解CodeDynamics与Xcode或Visual Studio直接使用之间的区别。虽然可以进入进程,但对堆栈的访问是有限的。在情况下,除非非常巧妙地设置断点,否则看不到影响代码的生态系统变量。它也更好地指示了一个种群是否完全死亡,但它并不清晰,因为它们仍然返回了一个结果。
以下是遇到的其他一些困难:不再是C++开发人员了。现在,使用C#和Java编写代码。看到对这些语言的更多支持将是很好的。同样,真的很想看到Windows和Mac版本。
有两个单独的工具,IDE和调试器,对来说并不熟悉。但一旦习惯了,并且对构建有更好的组织,就没问题了。产品发布相对较新,但很希望看到使用工具的视频,因为要花一段时间才能找到方向,然后变得容易。