【问题标题】:Why doesn't my neural network Q-learner doesn't learn tic-tac-toe为什么我的神经网络 Q-learner 不学习井字游戏
【发布时间】:2017-04-15 06:47:38
【问题描述】:

好的,所以我创建了一个神经网络 Q-learner,使用与 DeepMind 的 Atari 算法相同的想法(除了我提供原始数据而不是图片(还))。

神经网络构建:

  • 9 个输入(0 表示空白点,1 表示“X”,-1 表示“O”)

  • 1 个隐藏层,9-50 个神经元(尝试不同大小,激活函数 sigmoid)

  • 9 个输出(每个动作 1 个,输出 Q 值,激活函数 sigmoid)

  • MSE 损失函数
  • 亚当反向传播

由于梯度检查和大量测试,我 100% 确信网络是正确构建的。

Q 参数:

  • -1 输掉比赛奖励
  • -1 奖励,如果尝试移动到已经占据的位置(例如,X 已经在玩家 O 试图放置“O”的位置)
  • 0 抽奖奖励
  • 0 奖励移动,不会导致终止状态
  • +1 游戏获胜奖励
  • 下一个状态(在 s,a,r,s' 中)是您自己和对手移动之后的状态。例如。空棋盘,玩家 X 首先转牌并将“X”放在左上角。然后玩家O把“O”放在右上角。那么 s,a,r,s' 将是 s = [0,0,0,0,0,0,0,0,0], a = 0, r = 0, s' = [1,0,- 1,0,0,0,0,0,0]

问题

如果我在移动到已经占据的位置时给予 -1 奖励,我所有的 Q 值都会归零。如果我不这样做,网络就不会知道它不应该移动到已经被占用的地方,并且似乎学习任意 Q 值。我的错误似乎也没有缩小。

无效的解决方案

  • 我曾尝试将奖励更改为 (0, 0.5, 1) 和 (0, 1),但仍然无法学习。

  • 我尝试将状态显示为 0 表示空,0.5 表示 O,1 表示 X,但没有成功。

  • 我试图在移动后立即给出下一个状态,但没有帮助。

  • 我尝试过使用 Adam 和 vanilla back prop,但结果仍然相同。

  • 我尝试过使用重放内存和随机梯度下降中的批次,但还是一样
  • 将 sigmoid 更改为 ReLU,但没有帮助。
  • 各种我现在想不起来了

GitHub 中的项目:https://github.com/Dopet/tic-tac-toe(对不起 丑陋的代码主要是由于所有这些代码重构,而且这应该很容易测试以查看算法是否有效)

要点:

  • TicTac 类拥有游戏本身(使用抽象 Game 类的模板方法模式制作)
  • NeuralNetwork 类将一些数据记录到当前目录中名为 MyLogFile.log 的文件中
  • Block 和 Combo 类仅用于创建获胜情况
  • jblas-1.2.4.jar 包含 DoubleMatrix 库

【问题讨论】:

  • 这个帖子非常好。问题是(a)我认为您的方法没有任何问题; (b) 您没有提供重现错误的代码。
  • 我将项目添加到 GitHub。请问有什么不清楚的地方! github.com/Dopet/tic-tac-toe
  • 没有什么我可以从中删除的。它只包含井字游戏和我的 AI。两者都在单独的包装中。如果有人感兴趣,我还包括测试。可能出现问题的文件:包含游戏的 TicTac; NeuralNetwork,包含神经网络和 NeuralQLearner,它使用 NeuralNetwork 提供 Q-learning。
  • 老鼠。不,我的直觉是问题更基本,在配置参数的某个地方。如果你真的进入了一个适当的前后模式,你应该会看到比直接拒绝学习更好的东西。

标签: machine-learning neural-network deep-learning reinforcement-learning q-learning


【解决方案1】:

这是一个奖励/从输出层移除激活函数的问题。大多数时候我的奖励是 [-1, 1],我的输出层激活函数是从 [0, 1] 开始的 sigmoid。这导致网络在用 -1 奖励它时总是出错,因为输出永远不会小于零。这导致值变为零,因为它试图修复错误但它不能

【讨论】:

  • 修复错误后你是怎么做的? IE。您的网络在井字游戏中的表现如何?
【解决方案2】:

我认为你的表述是错误的。您正在使用 NN 为下一个状态提供的最大值更新状态的值。

expectedValue[i] = replay.getReward() + gamma *targetNetwork.forwardPropagate(replay.getNextState()).max();

这适用于单人游戏设置。但由于井字游戏是 2 人游戏,“下一个状态”(对手)的较高值不利于当前状态的值。

您可以将最大值 2 个状态向前(使用 NN 来预测 2 个状态向前),但这也不能很好地工作,因为您假设您所做的第二步是最佳的,并且会导致很多错误的更新。

对于传播值不是很清楚的设置,我建议您使用policy gradients。在这种方法中,您玩随机游戏(两个玩家都进行随机移动),并说如果玩家“O”获胜,您会积极奖励所有“O”移动(减少折扣因子,即最终移动获得更多奖励,然后奖励减少因子)和奖励“X”以相同的方式负向移动。如果比赛结果为平局,您可以用较小的积极奖励奖励两名玩家。

您最终可能会积极地奖励次优动作,反之亦然,但在大量游戏中,事情对您有利。

【讨论】:

  • 这应该不是问题,因为我的下一个状态是你自己和对手移动之后的状态(参见上面的 Q 参数部分,例如我的意思)。但我实际上得到了这个工作。这是一个奖励/从输出层移除激活函数的问题。大多数时候我的奖励是 [-1, 1],我的输出层激活函数是从 [0, 1] 开始的 sigmoid。这导致网络在用 -1 奖励它时总是出错,因为输出永远不会小于零。这导致值变为零,因为它试图修复错误但它不能
猜你喜欢
  • 1970-01-01
  • 2017-06-07
  • 2017-02-28
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 2016-12-18
相关资源
最近更新 更多