【发布时间】:2022-01-04 01:59:42
【问题描述】:
我目前正在开发国际象棋 AI。 该项目背后的想法是创建一个神经网络,该网络学习如何评估棋盘状态,然后使用蒙特卡洛树搜索遍历接下来的走法,以找到“最佳”走法(由 NN 评估)。
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。
问题
怎么办?是我遗漏了什么还是有错误?
【问题讨论】:
-
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