作者在《杀戮尖塔》AI 项目中发现传统评分表方法的局限性,改用逻辑回归推导卡牌评分,揭示了端到端学习与人工特征工程的等效性。
前文略过了如何教 Agent 选择卡牌奖励。新手玩家通常会在网上搜索"强度榜"——给每张卡评定等级的评分资源。然后他们在每个卡牌奖励节点选择最高等级的卡,最终因为牌组笨重而惨死。
我们克隆的专家(spirecomm)选择卡牌的方式完全相同:它定义了所有卡牌的严格排序,并设置了上限,这样就不会因为选了 6 张蹈距而崩溃。"跳过"选项也在其中,这意味着在每个卡牌奖励节点,Agent 会选择排名高于"跳过"且未达到配额的最高评分卡牌。有趣的是,另一个 StS AI 项目(bottled AI)采用了类似的方法。
当我看到我的 Agent 反复在第一幕 Boss 面前崩溃、拿着一堆垃圾牌死去时,我自然认为问题在于卡牌选择的质量。即使修复了卡牌 ID 不匹配的问题,Agent 的牌组仍然很烂。我以为是启发式规则太粗糙了,于是决定采用另一种方法。具有讽刺意味的是,这在数学上最终等价于创建了一个强度榜。
卡牌评分来自逻辑回归。"牌组"简单说就是一个数字列表,表示 113 张可能卡牌中每种各有多少张。"模型"将每个数字乘以一个学习到的权重,加上一个常数,然后对结果做 sigmoid。输出的数字在 0 到 1 之间,代表预测的胜率。
我的想法是,一旦有了这个,我们就可以测试每张卡牌,看看它如何提升牌组质量——即牌组的获胜概率。这是一个高尚的想法,但由于模型的数学特性,它完全等价于直接选择权重最高的卡牌:权重越高的卡牌对输出的贡献越大,从而带来更高的胜率。我们最终创建了一个……用科学方法的强度榜。
即使在"提升获胜概率"的说辞下,这种方法仍然有局限。从根本上讲,它试图从相关性中学习因果关系。回合越长,遇到稀有卡的预期越多,因此模型可能会过度高估稀有卡,因为它们与成功的相关性很高。另一个问题则更加微妙:模型在我们训练它的目标上"获胜"——如果它能区分赢家和平庸者。我们在训练中没有任何机制强制它给卡牌正确的大小。如果我问它两个相似的牌组哪个更可能获胜,而它在这项任务上表现良好,那会让我更相信它对卡牌的评估权重。
尽管如此,我还是着手获取数据。第一个数据来源是我自己的 A20 回合。当时我有 334 个回合,胜率 41%。为了扩充数据,我使用了每一层楼的牌组——也就是说,如果 50 层楼后我打败了心之魔,那堆 strikes、defends 和一张伤害普通卡就会被标注为"获胜"。模型在预测获胜牌组上表现很好,但在卡牌排名上不太行,所以我决定获取更多数据。
我用 Jorbs 的 53 个 Silent A20H 回合来扩充我的数据,他的胜率在 60% 多一点。把这些加进来后,模型变得困惑了。显然我们对卡牌的估值差异很大,这使得数据看起来呈双峰分布,让"猜我是否赢了"这个游戏对模型不公平(事实上这个游戏本质上就不公平,因为获胜不仅仅取决于牌组,还取决于玩法质量、遗物、药水以及抽牌运气)。
所以,我最终只用自己的回合数据,由此结束了第一次尝试:一个被过度吹捧的强度榜,参数太少,无法泛化到单个玩家的风格之外。模型需要考虑更多东西。缺失的成分是协同性。在一个没有飞刀卡片的牌组中,准确率惨不忍睹,但在一个有 3 张刀舞的牌组中却很强大。卡牌的价值来源于牌组构成,以及当前楼层、幕 Boss、可能遇到的精英、遗物等等。StS 是一款复杂的游戏。为了捕捉这种复杂性,我们为遗物添加了特征(161 个遗物每个 0 或 1)和 22 个游戏参数:楼层、HP(占最大值的百分比)、幕、Boss ID 等等。我们改变的另一件事是模型的功能。之前的模型评估的是一个牌组(或一张卡)有多强。这个模型则通过获取关键信息来做卡牌选择:机会成本。模型需要玩"猜人类选了哪张"的游戏——面对三张卡牌奖励和"跳过",并能获取上述上下文。
模型本身要复杂得多。"状态编码器"通过一系列 MLP 将 308 个特征转换为 128 维向量,表示当前状态。"卡牌编码器"同样通过几个 MLP 将我们之前的 25 个特征丰富为 32 维向量。最后,打分层接收 128+32 个数字,导出一个标量来表示应该选择哪张卡。整体上,202,000 个可学习参数,与之前的 114 个相去甚远。更重要的是额外的 MLP 层确保了它具有超越聪明强度榜的表达能力。
正如我们在讨论卡牌属性时看到的,特征和参数数量的增加必然需要更多数据。幸运的是,我在网上找到的另一个数据源是一个 7700 万回合的数据库,包含 34,210 个 Silent 回合和 358,870 个卡牌选择决策,涵盖了各种 ascension(和玩家技能)水平,其中 A20 的胜率是 1.5%。在这个庞大数据集上运行,模型收敛到了一个合理(53.5%)的准确率,表明它能相当好地预测在给定情况下人类会选择什么。令人鼓舞的是,它显示出学到了协同性的概念——例如,当牌组中有施加中毒的卡牌时,对 Catalyst 的评估会高于没有的时候。模型做到了我们设计它做的事。
糟糕的是,我们设计它的目的不是在 Slay the Spire 中获胜。不出所料,更大、更准确的模型表现更差了:
这是同一个 Agent,只是使用了不同的卡牌选择引擎,玩的是同一组 50 个 seed。更擅长预测人类会选择什么/什么牌组会获胜的模型,在指导卡牌选择时表现更差。在我的尝试中,简单的"学习到的强度榜"表现最好,但它仍然输给了直接使用 bottled AI 手工编写的列表。引用负责设计实验和解释结果的 Claude 实例的话来说:"嵌入向量学会了更准确地预测人类选择,但人类选择包含系统性偏差。v1 中的机械特征部分纠正了这些偏差,因为它们无法区分受欢迎但平庸的卡牌与不受欢迎但强大的卡牌。"
这里有一个有趣的张力:模型越健壮,需要的数据越多。数据越多,游玩质量越低。我的希望是用中等质量的数据引导,然后用自我对弈来改进。但在进一步尝试将自身强化到 100% 胜率对抗尖塔之前,我们先设定一个更谦虚的目标:持续击败一个邪教徒。
1 — 眼睛敏锐的读者可能会注意到 Busted Crown、Binary 和 Question Card 都影响卡牌奖励的选择数量。我们在前两种情况下用 -1 填充,在后一种情况下静默丢弃第四个选项。