548. Lux AI Season 2 | lux-ai-season-2
当 Lux AI 2 的最终比赛仍在进行,而我尚未确定最终排名(看起来可能在 2-5 名之间)时,我想做一个(较长的)总结。我认为这是一次令人兴奋的比赛,游戏深度十足且平衡性极佳,真正奖励了不同类型的策略。我想我们可能只是触及了这个游戏的表层,即使比赛结束后,我也强烈推荐大家为了乐趣或研究而体验一下。
我在本次比赛中采用的主要方法是使用 C++ 逻辑作为骨架,构建约 1500 个自定义参数,并使用定制的统计分析工具进行调优。从目标选择到战斗微操和移动冲突管理,一切都深受这些参数的影响。这些参数范围广泛,从更远地块的欲望调整、工厂生成地块评估,到可以调整关键 if 语句甚至关闭整个功能的布尔值,再到像 META_SIMCITY 这样的总体乘数,它会调整我在战略层面对和平行动(收集资源、清理碎石)与侵略行动(试图击杀敌方单位或挖掘敌方苔藓)的偏好。我试图将大多数"有主见的"逻辑至少用某个参数来捕捉,以便发现我的直觉是否准确。大多数时候确实如此,但也有一些真正的糟糕判断。
我选择这种方法是因为我知道这是我取得好成绩的可靠途径,而且非常有趣。我认为它结合了基于规则的机器人的优点,比如能够在某些地方计算出最优解(例如寻路),以及在策略和游戏机制上的一定灵活性,同时也吸收了强化学习的一些优点,比如你的软件慢慢领悟不同类型行动的最佳比例。我确实相信强化学习策略在这里可能有更高的潜力,但我没有采用,因为这个过程对我来说总是感觉有点不可预测,而且不够有趣。而且,我不是一个拥有充足硬件资金的研究团队,无法可靠地实现它。
我试图通过运行大量游戏来调整参数,在每一局中我会随机化相当比例的参数(浮点数用正态分布,整数用均匀分布)。每局游戏中,我都会生成一个文件,记录所有参数的值、胜负结果,以及我认为可能有用的各种游戏统计数据,例如我建造了轻型单位数量、单位花费在挖掘碎石上的回合数、地图上起始碎石量等。然后,在游戏外的统计工具中(这个工具是我为 Halite 2 构建的),我会检查是否有改进参数的方法。
为此,我尝试了多种方法和奖励指标。对于奖励,我选择了一些选项:胜率、与对手的苔藓差异、我产生的能量量、相关版本的匹配评分,甚至是一个神经网络输出,试图基于诸如我的单位开采冰的时间比例等统计数据来估计我的匹配评分。
使用这些奖励,我会尝试通过几种自动和手动方法来寻找更好的值:我使用了基本统计工具,如皮尔逊相关系数和斯皮尔曼等级相关系数来查看数据中是否存在趋势(也许如果我的单位多开采一点矿石,我会赢得更多)。神经网络和随机森林树学习方法来尝试找到更好的值。简单的整数平均值或浮点数的加权平均值。有时我只是自己盯着图表,希望能理解其中的含义。基本上,我将参数奖励空间视为一个未知的、有噪声的多维函数来寻找最大值,但通常假设参数之间复杂的相互作用会小到足以让我通过单独调整每个参数在其个体贡献上的表现来进行相当有效的爬山法优化。我只是无法生成足够的数据来尝试其他方法。
我选择这种方法而不是模拟退火等更标准化的方法,是因为我能运行的游戏数量与参数数量相比太少了,而且存在大量噪声,我在过程中不断修改代码。在这种情况下,那种方法往往表现不佳。
参数更改后,我会检查排行榜上是否有改进,如果没有就回滚。排行榜极其嘈杂,所以这并不总是正确的判断,但我认为多数时候是正确的。这种数据导向方法的一个很好的优势是,我经常可以用低时间和脑力投入做出改进。我经常会在上班前花5分钟自动调整并上传一两个新版本,睡觉前也做同样的事。在我没有时间折腾代码的那些星期,这种学习方式带来了一些最大的成长期。
最初我 mostly 让游戏中的两个智能体都随机化并学习,实现双重学习率。后来我切换到静态参考玩家,以更好地追踪我的进度。最终我仍然不太确定哪种更好。静态参考玩家提供更纯粹的数据,但数据量更少,我觉得与更多随机化玩家对战也有一些优势,可以防止过拟合。
这里学到的一些教训是:
作为收集游戏内数据的一个有趣的副作用,我可以轻松发现有趣的观察并绘制酷炫的图表。老实说,我大部分时间没有充分利用这一点,但有一张图表对我的策略产生了巨大影响。但首先,让我们向那些不太熟悉的人介绍一下苔藓发电。
对于你拥有的每一块苔藓地块,你每回合会产生1点能量。能量是一个超级关键的瓶颈,所以这很不错。要创造苔藓,你需要在工厂花费水来浇灌你的地块。这对新老苔藓地块都会消耗ceil(地块数/10)的水。在你没有浇水的回合,所有苔藓地块会衰减1。在大多数游戏中,大部分水来自重型单位开采的冰。你可以预期每单位水至少花费12点能量,加上可能的一些低效损失。现在已经有很多关于这个机制的分析,但基础是,忽略浇水的奇怪整数阈值,你可以预期在你浇水的回合,每块地成本为1.2能量,获得1,总变化为-0.2。在你没浇水的地块,你每块地获得1点能量。所以如果你交替浇水和不浇水,你可以预期每块地每回合获得0.4能量的收益,同时保持你的苔藓田完好。
这听起来相当不错。只需花费一点前期能量,你就能长出巨大的、有利可图的苔藓田,这还是游戏结束时你的分数来源。通过能量收益,你可以投资回工厂,收集更多冰,更多苔藓,更多能量。大约1-2个月进入比赛,我认为主流想法是,这是让经济运转的完全显而易见的方式。
主要的陷阱是,它实际上并没有真正起作用。现在,其他玩家的结果可能有所不同,但对我来说看起来是这样的:

这是一张图表,x轴上是我在整个游戏中收集的冰量。y轴是我的总冰收益。两者都除以起始工厂数量。这里的冰收益是我从苔藓获得的能量,减去我花在挖掘苔藓用冰上的能量(工厂维护用的冰不计入)。蓝线是不同的拟合线,紫色点是胜利,红点是失败。绿/红线显示运行平均值,红色表示数据点很少。
现在我看到了两个主要问题。首先,我在任何游戏中都没有真正从冰中获得太多利润。其次,我收集的冰量并不像你希望的那样影响利润。你似乎在最右端获得更多利润的唯一原因是那些是压倒性的胜利。对于大部分游戏和失败,甚至可能有一点下降趋势。现在重要的是,这张图表没有包括该过程所需的碎石清理成本和移动/重排成本。如果我包含碎石清理成本,你会得到这张图:

除了这种看似缺乏利润的情况,大部分收益往往出现在游戏末期,那时能量已经不那么有用了。基本上,大型苔藓发电是个骗局!这里没有利润。原因从苔藓田经常不得不形成的尴尬形状(这意味着你需要更长的投资浇水阶段),到敌方单位清理你的碎石等等。
当然你需要分数,所以你不如早点浇水,至少保持收支平衡。但它就是不太像宣传的那样。无论如何,所有这些都是为了说明收集这类数据可能非常有用。在这种情况下,它让我更早地转向基于单位的能量生成,并让我意识到流行的苔藓运河实际上并不是个好主意。虽然它们节省了你在工厂周围挖掘所有东西的碎石挖掘成本,但苔藓的形状实际上意味着你在苔藓本身上损失更大,而且运河非常容易受到骚扰。
另一方面,建造单位进行能量生成显然更有利可图。你只需要让你的单位经常静止不动,这样它们就不会只是燃烧它们产生的能量。在我这种多单位风格的方法中,这远非易事。特别是工厂周围的堵塞情况,当可怕的敌方单位经过时,会迫使你进行多次移动,你必须处理冲突,防止单位相互碰撞。让单位冷静下来停止堵塞一直是我最大的战斗之一。最终,我的大多数单位都实现了自给自足,从未从工厂获取任何能量,这样我就可以将大部分工厂能量用于制造更多单位。这里有两张图表显示了我典型游戏中冰和矿石的能量利润(这里的冰利润忽略了碎石成本):

除了我的统计工具,我还使用了一个为我自己回放格式设计的自定义回放查看器,这可以说更有用。我在我的智能体代码内生成回放数据,让我不仅能呈现客观的游戏数据,还能呈现各种调试数据。
这里是我的回放查看器的一个快速预览。单位的形状显示他们的移动。单位的填充显示他们的能量,便于一目了然地查看。还有一些小功能,如单位死亡高亮(洋红色)和传输(黄色)以及水运输者高亮。

这张图片显示了地图上每个地块的"基础"欲望,这对应于单位想去那里的程度,在单位特定调整(如与地块的距离)之前。

这个查看器对于调试来说极其有用。当你能像这样在整个屏幕上轻松看到发生了什么,而不是必须挖掘日志时,会容易得多。例如,我之前的生成逻辑中有一个bug,我搞混了x和y坐标,所以工厂会优先在与冰相邻的地块同一列生成。如果我没有在我的生成欲望输出中发现奇怪的垂直线,可能永远找不到这个问题。
对于任何喜欢参加这类比赛的人来说,我强烈建议花点时间投资构建一个可重用的自定义回放查看器,可能还有一个分析统计数据的工具。在任何此类基础设施上投入的时间都能通过简化的调试轻松收回成本,否则这也是一个很棒的学习体验。
说到学习体验。我 mostly 选择C++作为我的智能体语言,因为我想学习这门语言。这个任务 mostly 失败了,因为我最终只是坚持使用了一些非常基本的语言用法,但至少它比替代方案性能要高得多。我 mostly 使用了一种丑陋但有效的方式,我有大量全局变量,可以在任何地方以极低的性能成本轻松访问。一个关键技巧是尽可能预计算一切。也许我在整个代码库中最常用的东西是迭代一个地块的邻居。只需在开始时将这一切预计算一次,就再也不用担心性能影响和字面意义上的边缘情况,这帮助巨大。除了一个在~900个单位附近失控的尴尬O(n^2)算法外,我从未真正遇到过超时。游戏本地仍然相当慢,但很大一部分是I/O,如果不彻底重新设计就无法加速。哦对了,使用预处理宏来避免日志开销也很酷。
长而准确的行动队列在这里非常有益,我 mostly 通过逐回合进入未来来做队列,让每个单位确定该回合的行动方案,解决任何移动、传输或拾取冲突,然后向前模拟下一回合。不幸的是,它经常失败,特别是当单位需要为战斗调整时,让其他人移开,这会阻止传输落地等。不过总的来说,我的重排成本还不错,因为我至少让重型单位在工厂(和太阳能板)相邻的矿上可预测地工作。我真正希望我能做到的一件事是某种系统,能让预测的更远回合的重要信息真正传递回更早的回合。这对我来说证明有点太具挑战性,无法想出一个好的性能系统,也许在后续比赛中!
在整个比赛的大部分时间里,直到最后,我一直与其他几位竞争者进行着激烈的竞争。特别是ry_andy_、Tigga和Harm Buisman。后来加入了强化学习玩家flg。感谢他们让这场比赛非常激动人心,当然也要感谢Stone Tao和Bovard Doerschuk-Tiberi组织这场比赛并创造了如此有趣的游戏。希望这些信息对某人有所帮助,我想我会在未来的比赛中见到你们中的一些人!