训练代理通过自我游戏掌握 Tic-Tac-Toe |作者:塞巴斯蒂安·吉尔伯特 | 2023 年 9 月


令人惊讶的是,软件代理永远不会厌倦这个游戏。

啊!小学!这段时间我们学习了宝贵的技能,例如识字、算术和玩井字游戏。

拍摄者 至日汉南未飞溅

和你的朋友玩井字游戏而不被老师发现是一门艺术。您必须谨慎地将游戏纸递到桌子下面,同时给人留下专注于主题的印象。有趣的可能更多是关于卧底行动而不是游戏本身。

我们无法向软件代理传授避免在课堂上被抓的艺术,但我们可以训练代理掌握游戏吗?

在我之前的文章中,我们研究了一个学习游戏的智能体 总和100 通过自我对弈。这是一个简单的游戏,允许我们显示状态值,这有助于我们建立关于代理如何学习游戏的直觉。通过井字游戏,我们正在处理更大的状态空间。

您可以在以下位置找到 Python 代码 这个存储库。执行训练的脚本是 学习tictactoe.sh:

#!/bin/bash
声明 -i NUMBER_OF_GAMES=30000
声明 -i NUMBER_OF_EPOCHS=5

导出 PYTHONPATH='./'

python 预处理/generate_positions_expectations.py \
--outputDirectory=./learn_tictactoe/output_tictactoe_generate_positions_expectations_level0 \
--游戏=井字棋 \
--numberOfGames=$NUMBER_OF_GAMES \
--伽马=0.95 \
--randomSeed=1 \
--agentArchitecture=无 \
--agentFilepath=无 \
--opponentArchitecture=无 \
--opponentFilepath=无 \
--epsilons="[1.0]" \
--温度=0

dataset_filepath =“./learn_tictactoe/output_tictactoe_generate_positions_expectations_level0/dataset.csv”

蟒蛇火车/train_agent.py \
$数据集_文件路径\
--outputDirectory="./learn_tictactoe/output_tictactoe_train_agent_level1" \
--游戏=井字棋 \
--randomSeed=0 \
--validationRatio=0.2 \
--batchSize=64 \
--architecture=SaintAndre_1024 \
--dropoutRatio=0.5 \
--学习率=0.0001 \
--weightDecay=0.00001 \
--numberOfEpochs=$NUMBER_OF_EPOCHS \
--startingNeuralNetworkFilepath=无

对于 {1..16} 中的级别

dataset_filepath="./learn_tictactoe/output_tictactoe_generate_positions_expectations_level${level}/dataset.csv"
python 预处理/generate_positions_expectations.py \
--outputDirectory="./learn_tictactoe/output_tictactoe_generate_positions_expectations_level${level}" \
--游戏=井字棋 \
--numberOfGames=$NUMBER_OF_GAMES \
--伽马=0.95 \
--randomSeed=0 \
--agentArchitecture=SaintAndre_1024 \
--agentFilepath="./learn_tictactoe/output_tictactoe_train_agent_level${level}/SaintAndre_1024.pth" \
--opponentArchitecture=SaintAndre_1024 \
--opponentFilepath="./learn_tictactoe/output_tictactoe_train_agent_level${level}/SaintAndre_1024.pth" \
--epsilons="[0.5, 0.5, 0.1]" \
--温度=0

声明 -i next_level=$((level + 1))
蟒蛇火车/train_agent.py \
“./learn_tictactoe/output_tictactoe_generate_positions_expectations_level${level}/dataset.csv” \
--outputDirectory="./learn_tictactoe/output_tictactoe_train_agent_level${next_level}" \
--游戏=井字棋 \
--randomSeed=0 \
--validationRatio=0.2 \
--batchSize=64 \
--architecture=SaintAndre_1024 \
--dropoutRatio=0.5 \
--学习率=0.0001 \
--weightDecay=0.00001 \
--numberOfEpochs=$NUMBER_OF_EPOCHS \
--startingNeuralNetworkFilepath="./learn_tictactoe/output_tictactoe_train_agent_level${level}/SaintAndre_1024.pth"

完毕

该脚本循环调用两个程序:

代理对游戏的学习通过生成比赛和训练的循环进行,以根据游戏状态预测比赛结果:

图 1:匹配生成和神经网络训练的循环。图片由作者提供。

该循环从模拟随机玩家之间的比赛开始,即玩家在给定的游戏状态下从合法行动列表中随机选择。

为什么我们要随机生成比赛?

这个项目是通过自我对弈来学习,所以我们不能给智能体任何先验信息 怎么玩。在第一个周期中,由于智能体不知道好棋或坏棋,因此比赛必须通过随机游戏生成。

图 2 显示了随机玩家之间的比赛示例:

图 2:随机进行井字游戏的示例。图片由作者提供。

通过观察这场比赛我们能得到什么教训呢?从“X”玩家的角度来看,我们可以假设这是一个表现不佳的例子,因为它以失败告终。我们不知道哪一步棋导致了失败,所以我们假设 所有的决定 “X”玩家的作品很糟糕。如果某些决策是好的,我们就押注于统计数据(其他模拟可能会经历类似的状态)来纠正其预测的状态值。

玩家“X”的最后一个动作的值为 -1。其他动作会收到一个折扣负值,当我们向后移动到第一个动作时,该负值会以 γ (gamma) ∈ [0, 1] 的倍数几何衰减。

图 3:游戏状态的目标值。图片由作者提供。

取得胜利的比赛中的州会获得类似的正折扣值。从抽签中抽出的州的值为零。代理同时考虑第一个玩家和第二个玩家的观点。

游戏状态为张量

我们需要游戏状态的张量表示。我们将使用 [2x3x3] 张量,其中第一个维度表示通道(0 表示“X”,1 表示“O”),其他两个维度是行和列。 (行,列)方格的占用率在(通道,行,列)条目中被编码为 1。

图 4:[2x3x3] 张量表示的游戏状态。图片由作者提供。

通过生成匹配获得的(状态张量,目标值)对构成神经网络每轮训练的数据集。该数据集是在周期开始时构建的,利用了前几轮中发生的学习。虽然第一轮产生纯粹的随机比赛,但随后的比赛逐渐产生更加真实的比赛。

为游戏注入随机性

第一轮比赛生成对抗随机玩家。随后的回合将智能体与自身对抗(因此称为“自我对战”)。该代理配备了一个经过训练来预测比赛结果的回归神经网络,这使得它能够选择产生最高期望值的法律行动。为了促进多样性,智能体基于 epsilon-greedy 算法选择动作:以概率 (1-ε) 选择最佳动作;否则,将选择随机操作。

图 5 显示了最多 17 轮训练中五个时期的验证损失的演变:

图 5:各种训练轮数的验证损失的演变。图片由作者提供。

我们可以看到,前几轮训练显示验证损失快速下降,然后在均方误差损失 0.2 附近似乎出现了一个平台期。这一趋势表明,代理的回归神经网络能够更好地从给定的游戏状态预测与自身进行的比赛的结果。由于两名球员的行动都是不确定的,因此比赛结果的可预测性是有限的。这解释了为什么验证损失在几轮之后停止改善。

一轮又一轮的改进

随着游戏 总和100, 我们可以在一维网格上表示状态。然而,对于井字游戏,我们无法直接显示状态值的演变。为了衡量改进,我们可以做的一件事是将代理与它自己的先前版本进行比较,并观察胜利和失败之间的差异。

对双方玩家的第一个动作使用 ε = 0.5,对比赛的其余部分使用 ε = 0.1,每次比较运行 1000 场比赛,这就是我们得到的结果:

图 6:代理与其先前版本的比较。图片由作者提供。

直到10轮训练,胜场数超过负场数(显示出进步)。此后,该特工一轮又一轮没有进步。

是时候看看我们的特工如何玩井字游戏了!

回归神经网络的一个有用功能是可以显示代理对每个合法动作的评估。让我们与智能体玩一个游戏,展示它如何判断其选项。

手动播放

代理开始,播放“X”:

图 7:与智能体进行的一场比赛,以及动作评估。图片由作者提供。

这就是你被一台没有灵魂的井字游戏机残酷地压垮的原因!

当我把“O”放入(1, 0)方格时,预期收益从 0.142 增加到 0.419,我的命运就被注定了。

让我们看看当代理扮演第二个角色时它会怎样:

图 8:与智能体进行的一场比赛,并进行动作评估。图片由作者提供。

没有落入陷阱,比赛打成了平局。

与随机玩家进行比赛

要是我们 模拟 与随机玩家进行大量比赛,这就是我们得到的结果:

图 9:与随机玩家进行 1000 场比赛的结果。图片由作者提供。

在 1000 场比赛中(经纪人在一半的比赛中先发),经纪人赢了 950 场比赛,没有输掉一场,还有 50 场平局。这并不能证明我们的智能体表现最佳,但它确实已经达到了不错的水平。

作为后续 训练智能体通过自我对弈掌握简单的游戏 当游戏很容易破解并且状态空间很小时,我们使用相同的技术来掌握井字棋。尽管这仍然是一个玩具问题,但井字游戏的状态空间足够大,以至于需要代理的回归神经网络来查找状态张量中的模式。这些模式允许对看不见的状态张量进行泛化。

代码可用 在这个存储库中。尝试一下,让我知道你的想法!



来源链接

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

zh_CNChinese