【问题标题】:Chess evaluation Neural Network is converging to the average国际象棋评估神经网络正在向平均水平收敛
【发布时间】:2022-01-04 01:59:42
【问题描述】:

我目前正在开发国际象棋 AI。 该项目背后的想法是创建一个神经网络,该网络学习如何评估棋盘状态,然后使用蒙特卡洛树搜索遍历接下来的走法,以找到“最佳”走法(由 NN 评估)。

Code on GitHub

TL;DR

NN 在预测数据集的平均评估时卡住了,因此无法学习预测棋盘状态的评估。

实施

数据集

数据集是国际象棋游戏的集合。游戏取自官方lichess 数据库。 仅包含具有评估分数(NN 应该学习)的游戏。 这将数据集的大小减少到原始数据的 11% 左右。

数据表示

每一步都是训练网络的数据点。 NN 的输入是 12 个大小为 8x8 的数组(所谓的位板),每个数组对应 6x2 不同的块和颜色。 使用缩放的tanh 函数将移动评估标准化为范围 [-1, 1]。 由于许多评估非常接近 0 和 -1/1,因此也删除了其中的一部分,以减少数据集中的变化。

如果不放弃一些评估接近 0 或 -1/1 的移动,数据集将如下所示:

删除一些后,数据集看起来像这样,并且在某一点上不太集中:

NN 的输出是介于 -1 和 1 之间的单个标量值,表示对棋盘状态的评估。 -1 表示棋盘非常受黑人玩家青睐,1 意味着棋盘非常受白人玩家青睐。

def create_training_data(dataset: DataFrame) -> Tuple[np.ndarray, np.ndarray]:
    def drop(indices, fract):
        drop_index = np.random.choice(
            indices,
            size=int(len(indices) * fract),
            replace=False)
        dataset.drop(drop_index, inplace=True)

    drop(dataset[abs(dataset[12] / 10.) > 30].index, fract=0.80)
    drop(dataset[abs(dataset[12] / 10.) < 0.1].index, fract=0.90)
    drop(dataset[abs(dataset[12] / 10.) < 0.15].index, fract=0.10)

    # the first 12 entries are the bitboards for the pieces
    y = dataset[12].values
    X = dataset.drop(12, axis=1)

    # move into range of -1 to 1
    y = y.astype(np.float32)
    y = np.tanh(y / 10.)

    return X, y

神经网络

神经网络是使用 Keras 实现的。

CNN 用于从棋盘中提取特征,然后传递到密集网络以简化为评估。这是基于 AlphaGo Zero 在其实现中使用的 NN。

CNN 实现如下:

model = Sequential()
model.add(Conv2D(256, (3, 3), activation='relu', padding='same', input_shape=(12, 8, 8, 1)))

for _ in range(10):
    model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
    model.add(BatchNormalization())

model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(Flatten())
model.add(Dense(units=64, activation='relu'))
# model.add(Rescaling(scale=1 / 10., offset=0)) required? Data gets scaled in create_training_data, does the Network learn that/does doing that explicitly help?
model.add(Dense(units=1, activation='tanh'))
model.compile(
    loss='mean_squared_error',
    optimizer=Adam(learning_rate=0.01),
    # metrics=['accuracy', 'mse'] # do these influence training at all?
)

培训

训练是使用 Keras 完成的。 使用多组 50k-500k 移动来训练网络。 网络在每个移动集上训练 20 个 epoch,批大小为 64,10% 的移动用于验证。

之后通过0.001 / (index + 1)调整学习率。

for i, chunk in enumerate(pd.read_csv("../dataset/nm_games.csv", header=None, chunksize=100000)):
    X, y = create_training_data(chunk)

    model.fit(
        X,
        y,
        epochs=20,
        batch_size=64,
        validation_split=0.1
    )
    
    model.optimizer.learning_rate = 0.001 / (i + 1)

问题

NN 目前没有学到任何东西。它会在几个 epoch 内收敛到对数据集的平均评估,并且不会根据棋盘状态预测任何内容。

20 个 epoch 后的示例:

Dataset Evaluation NN Evaluation Difference
-0.10164772719144821 0.03077016 0.13241789
0.6967725157737732 0.03180310 0.66496944
-0.3644430935382843 0.03119821 0.39564130
0.5291759967803955 0.03258476 0.49659124
-0.25989893078804016 0.03316733 0.29306626

NN 评估停留在 0.03,这是数据集的近似平均评估。 它也卡在那里,没有继续改进。

我尝试了什么

  • 增加和减少 NN 大小
    • 添加了多达 20 个额外的 Conv2D 层,因为 google 在他们的实现中也这样做了
    • 删除了所有 10 个额外的 Conv2D 层,因为我了解到许多 NN 对于数据集来说太复杂了
  • 一次训练几天
    • 由于 NN 停留在 0.03,并且也没有从那里移动,因此浪费了。
  • 密集 NN 代替 CNN
    • 没有消除 NN 卡住的点,但训练速度更快(也就是卡住更快:))
      model = Sequential()
      model.add(Dense(2048, input_shape=(12 * 8 * 8,), activation='relu'))
      model.add(Dense(2048, activation='relu'))
      model.add(Dense(2048, activation='relu'))
      model.add(Dense(1, activation='tanh'))
      model.compile(
          loss='mean_squared_error',
          optimizer=Adam(learning_rate=0.001),
          # metrics=['accuracy', 'mse']
      )
    
  • Sigmoid 激活而不是 tanh 将评估从 -1 到 1 的范围移动到 0 到 1 的范围,但其他方面并没有改变任何关于卡住的情况。
  • Epochs、batchsize 和 chunksize 增加和减少 所有这些变化都没有显着改变 NN 评估。
  • 学习率添加
    • 较大的学习率 (0.1) 使 NN 不稳定,每次训练都会收敛到 -1、1 或 0。
    • 较小的学习率 (0.0001) 使 NN 收敛速度较慢,但​​仍停留在 0.03。

Code on GitHub

问题

怎么办?是我遗漏了什么还是有错误?

【问题讨论】:

  • train loss vs crossval vs test loss 是什么?您是否随机化了数据的顺序?您是否尝试过在没有 tanh 归一化的情况下学习评估的训练?
  • - 一旦模型稳定下来,训练损失 = crossval = 测试损失 = 0.22(到达那里最多需要 5 个时期)。 - 使用 Keras model.fit 参数 shuffle=True 默认情况下,我相信这是用来重新排序的。 - 我使用 sigmoid 归一化和激活进行训练,但没有得到不同的结果。我不知道如何在没有标准化的情况下进行训练,因为输出在 -100 到 100 的范围内。

标签: machine-learning deep-learning neural-network regression custom-training


【解决方案1】:

我的两个建议:

  • 使用完整的数据集并根据该玩家是否赢得比赛的事实对每个位置进行评分。我不知道这个数据集,并且其他人的评估可能存在某些问题(或者他们是否经过验证?)即使您确定它的有效性,我也会对此进行测试,因为它可以提供有关问题可能的更多信息是
  • 检查您的数据表示。可能您已经这样做了几次,但我可以根据经验告诉您,很容易介绍一个并忽略它们。从长远来看,添加测试可能会对您有所帮助。我的一些问题:
    • 当前播放器颜色的指示?不确定您是否有玩家颜色平面或切换当前玩家棋子?
    • 从 1d 到 3d 的转换不正确,反之亦然。 (不应该阻止您进行培训,但如果您想移植到其他设备,可以为您节省大量时间)
    • 我训练了一个围棋游戏引擎,但不知道国际象棋使用什么表示法,我花了一些时间才找到适合跳棋的表示法。

不是一个解决方案,但我发现循环学习率对我的 go-engine 非常有效,当其余的工作时可能需要考虑

【讨论】:

  • 评估是由 Stockfish 引擎 dataset 生成的,因此,我非常确信这些是有效的。数据表示是位板wiki,白色玩家为+1,黑色玩家为-1。然后它们被展平为一个长度为 768 的数组。这就是从 3d 到 1d 的转换发生的点,我希望通过添加一个Reshape((12, 8, 8, 1), input_shape=(12 * 64,)) 层来逆转这一点,该层应该在网络的最开始重新格式化为 12 位板.这有什么问题吗?
  • 这听起来很合法。我仍然会尝试它只是为了消除它的可能性。 reshape 看起来不错,您是否验证了位板是否正确生成?一目了然,您的方法和代码看起来不错,因此可以通过消除过程找出问题所在
  • 我刚刚意识到您不会以任何方式对玩家回合进行编码。转黑的位置与转白的位置会有不同的评价。
  • 是的,打印 Bitboards 显示正确的结果。是的,这是真的,没有转牌,尽管这不应该是评估几乎立即收敛到某个值的原因。你知道为什么它收敛得这么快吗?它可能找不到数据集的任何模式,对吧?
  • 是的,在我看来就是这样。我从未训练过只有当前棋盘状态的模型,我总是添加某种历史记录或当前玩家指示。对我来说,您似乎需要它,但我从未测试过它,所以我不能 100% 确定。
猜你喜欢
  • 2020-05-18
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 2016-05-13
  • 2016-07-10
  • 2013-10-14
相关资源
最近更新 更多