2

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

GitHub 上的代码

TL;博士

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 用于从板上提取特征,然后传递到密集网络以减少到评估。这是基于 NN AlphaGo Zero 在其实现中使用的。

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 后的示例:

数据集评估 神经网络评估 区别
-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 层,因为谷歌在他们的实现中也这样做了
    • 删除了所有 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。

GitHub 上的代码

问题

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

4

1 回答 1

1

我的两个建议:

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

不是一个解决方案,但我发现循环学习率对我的 go-engine 非常有效

于 2022-01-24T15:40:10.673 回答