为什么我的神经网络 Q-learner 不学习井字游戏
Why doesn't my neural network Q-learner doesn't learn tic-tac-toe
好的,所以我使用与 DeepMind 的 Atari 算法相同的想法创建了一个神经网络 Q-learner(除了我提供的是原始数据而不是图片(还))。
神经网络构建:
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 值。我的错误似乎也没有缩小。
无效的解决方案
我试过把rewards改成(0, 0.5, 1)和(0, 1)还是没学会
我曾尝试将状态呈现为 0 表示空,0.5 表示 O,1 表示 X,但是没有用。
我试图在移动后直接给出下一个状态,但没有帮助。
我试过 Adam 和 vanilla back prop,但结果还是一样。
- 我试过重放记忆和随机梯度下降的批次,但还是一样
- 将 sigmoid 更改为 ReLU 但没有帮助。
- 各种想不起来了
Project in GitHub: https://github.com/Dopet/tic-tac-toe (Sorry for
ugly code mostly due to all of these refactorings of code, also this was supposed to be easy test to see if the algorithm works)
要点:
- TicTac class 有游戏本身(使用抽象游戏 class 中的模板方法模式制作)
- NeuralNetwork class 将一些数据记录到当前目录中名为 MyLogFile.log 的文件中
- Block 和 Combo classes 只是用来创造获胜的情况
- jblas-1.2.4.jar 包含 DoubleMatrix 库
我认为你的表述是错误的。您正在使用 NN 为下一个状态提供的最大值更新状态的值。
expectedValue[i] = replay.getReward() + gamma *targetNetwork.forwardPropagate(replay.getNextState()).max();
这适用于单人游戏设置。但由于井字游戏是 2 人游戏,'next state'(对手)的较高值不利于当前状态的值。
您可以将最大值向前移动 2 个状态(使用 NN 向前预测 2 个状态),但这也不太奏效,因为您假设您进行的第二步移动是最优的并且会导致很多错误更新。
对于传播值不是很清楚的设置,我建议您使用 policy gradients。在这种方法中,你玩随机游戏(两个玩家都随机移动),然后说如果玩家 'O' 赢了,你奖励所有 'O' 移动积极(减少折扣因子,即最后一步获得更多奖励,然后reward 减少一个因子)并且 reward 'X' 以相同的方式负向移动。如果游戏结果平局,您可以奖励两个玩家较少的正奖励。
您最终可能会积极奖励次优动作,反之亦然,但在大量游戏中,事情对您有利。
这是输出层的rewards/removing激活函数的问题。大多数时候我得到 [-1, 1] 的奖励,我的输出层激活函数是从 [0, 1] 开始的 sigmoid。这导致网络在用 -1 奖励时总是出错,因为输出永远不会小于零。这导致值变为零,因为它试图修复错误但它不能
好的,所以我使用与 DeepMind 的 Atari 算法相同的想法创建了一个神经网络 Q-learner(除了我提供的是原始数据而不是图片(还))。
神经网络构建:
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 值。我的错误似乎也没有缩小。
无效的解决方案
我试过把rewards改成(0, 0.5, 1)和(0, 1)还是没学会
我曾尝试将状态呈现为 0 表示空,0.5 表示 O,1 表示 X,但是没有用。
我试图在移动后直接给出下一个状态,但没有帮助。
我试过 Adam 和 vanilla back prop,但结果还是一样。
- 我试过重放记忆和随机梯度下降的批次,但还是一样
- 将 sigmoid 更改为 ReLU 但没有帮助。
- 各种想不起来了
Project in GitHub: https://github.com/Dopet/tic-tac-toe (Sorry for ugly code mostly due to all of these refactorings of code, also this was supposed to be easy test to see if the algorithm works)
要点:
- TicTac class 有游戏本身(使用抽象游戏 class 中的模板方法模式制作)
- NeuralNetwork class 将一些数据记录到当前目录中名为 MyLogFile.log 的文件中
- Block 和 Combo classes 只是用来创造获胜的情况
- jblas-1.2.4.jar 包含 DoubleMatrix 库
我认为你的表述是错误的。您正在使用 NN 为下一个状态提供的最大值更新状态的值。
expectedValue[i] = replay.getReward() + gamma *targetNetwork.forwardPropagate(replay.getNextState()).max();
这适用于单人游戏设置。但由于井字游戏是 2 人游戏,'next state'(对手)的较高值不利于当前状态的值。
您可以将最大值向前移动 2 个状态(使用 NN 向前预测 2 个状态),但这也不太奏效,因为您假设您进行的第二步移动是最优的并且会导致很多错误更新。
对于传播值不是很清楚的设置,我建议您使用 policy gradients。在这种方法中,你玩随机游戏(两个玩家都随机移动),然后说如果玩家 'O' 赢了,你奖励所有 'O' 移动积极(减少折扣因子,即最后一步获得更多奖励,然后reward 减少一个因子)并且 reward 'X' 以相同的方式负向移动。如果游戏结果平局,您可以奖励两个玩家较少的正奖励。
您最终可能会积极奖励次优动作,反之亦然,但在大量游戏中,事情对您有利。
这是输出层的rewards/removing激活函数的问题。大多数时候我得到 [-1, 1] 的奖励,我的输出层激活函数是从 [0, 1] 开始的 sigmoid。这导致网络在用 -1 奖励时总是出错,因为输出永远不会小于零。这导致值变为零,因为它试图修复错误但它不能