Llevo mucho tiempo jugando al ajedrez y, desde que comencé con CS, siempre quise crear un robot de ajedrez. ¿Por fin lo he conseguido?.
Aquí hay un video en el que mi robot (negro) me aplasta a mí (blanco).
Aquí está su perfil de chess.com: https://www.chess.com/member/chessables_with_chat_gpt.
git clone https://github.com/samliu21/chess-ai
. Navegue al directorio con cd chess-ai
.python -m venv .
y actívelo con source bin/activate
.python -m pip install -r requirements.txt
.cd gui
y llama python main.py
para jugar! Utilicé la base de datos oficial de Lichess, que contenía juegos en formato PGN estándar. Aquí está el proceso de limpieza de datos:
pgn-extract
para agregar FEN después de cada movimiento Para obtener más información, consulte la carpeta data_cleaning
.
Inicialmente, intenté crear una red neuronal de evaluación de placa para emparejarla con un algoritmo minimax. Hubo dos problemas con este enfoque:
La red de evaluación no cumplió con mis expectativas. Podía detectar desequilibrios materiales pero no podía detectar simples jaques mate.
Debido al gran espacio de acción en el ajedrez, el algoritmo minimax es muy lento, incluso cuando se optimiza con poda alfa-beta.
Juntos, estos factores me impulsaron a descartar esta idea inicial y probar con otra.
La GUI se hizo a mano utilizando los módulos pygame
y python-chess
.
Esta arquitectura se inspiró en gran medida en este artículo de Standford.
La IA utiliza dos modelos. Ambos reciben una posición del tablero como entrada y generan una matriz de 8x8
de probabilidades softmax. El "modelo de origen" predice el cuadrado del que se moverá y el "modelo de destino" predice el cuadrado al que se moverá.
Este enfoque se ilustra mejor con un ejemplo. Considere la posición inicial del tablero y el movimiento: Nf3
. La evaluación de este movimiento es el producto del valor en el cuadrado g1
del modelo de origen y el valor en el cuadrado f3
del modelo de destino.
Entre todos los movimientos legales, el producto más importante es el movimiento seleccionado.
Las redes neuronales constan de seis capas convolucionales, seguidas de dos capas afines y una capa de salida. A continuación se puede encontrar un boceto más detallado de la arquitectura:
Model: "model"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_1 (InputLayer) [(None, 8, 8, 12)] 0 []
conv2d (Conv2D) (None, 8, 8, 32) 3488 ['input_1[0][0]']
batch_normalization (BatchNorm (None, 8, 8, 32) 128 ['conv2d[0][0]']
alization)
activation (Activation) (None, 8, 8, 32) 0 ['batch_normalization[0][0]']
conv2d_1 (Conv2D) (None, 8, 8, 64) 18496 ['activation[0][0]']
batch_normalization_1 (BatchNo (None, 8, 8, 64) 256 ['conv2d_1[0][0]']
rmalization)
activation_1 (Activation) (None, 8, 8, 64) 0 ['batch_normalization_1[0][0]']
conv2d_2 (Conv2D) (None, 8, 8, 256) 147712 ['activation_1[0][0]']
batch_normalization_2 (BatchNo (None, 8, 8, 256) 1024 ['conv2d_2[0][0]']
rmalization)
activation_2 (Activation) (None, 8, 8, 256) 0 ['batch_normalization_2[0][0]']
concatenate (Concatenate) (None, 8, 8, 512) 0 ['activation_2[0][0]',
'activation_2[0][0]']
conv2d_3 (Conv2D) (None, 8, 8, 256) 1179904 ['concatenate[0][0]']
batch_normalization_3 (BatchNo (None, 8, 8, 256) 1024 ['conv2d_3[0][0]']
rmalization)
activation_3 (Activation) (None, 8, 8, 256) 0 ['batch_normalization_3[0][0]']
concatenate_1 (Concatenate) (None, 8, 8, 320) 0 ['activation_3[0][0]',
'activation_1[0][0]']
conv2d_4 (Conv2D) (None, 8, 8, 256) 737536 ['concatenate_1[0][0]']
batch_normalization_4 (BatchNo (None, 8, 8, 256) 1024 ['conv2d_4[0][0]']
rmalization)
activation_4 (Activation) (None, 8, 8, 256) 0 ['batch_normalization_4[0][0]']
concatenate_2 (Concatenate) (None, 8, 8, 288) 0 ['activation_4[0][0]',
'activation[0][0]']
conv2d_5 (Conv2D) (None, 8, 8, 256) 663808 ['concatenate_2[0][0]']
batch_normalization_5 (BatchNo (None, 8, 8, 256) 1024 ['conv2d_5[0][0]']
rmalization)
activation_5 (Activation) (None, 8, 8, 256) 0 ['batch_normalization_5[0][0]']
dense (Dense) (None, 8, 8, 256) 65792 ['activation_5[0][0]']
batch_normalization_6 (BatchNo (None, 8, 8, 256) 1024 ['dense[0][0]']
rmalization)
dense_1 (Dense) (None, 8, 8, 64) 16448 ['batch_normalization_6[0][0]']
batch_normalization_7 (BatchNo (None, 8, 8, 64) 256 ['dense_1[0][0]']
rmalization)
dense_2 (Dense) (None, 8, 8, 1) 65 ['batch_normalization_7[0][0]']
batch_normalization_8 (BatchNo (None, 8, 8, 1) 4 ['dense_2[0][0]']
rmalization)
softmax (Softmax) (None, 8, 8, 1) 0 ['batch_normalization_8[0][0]']
==================================================================================================
Total params: 2,839,013
Trainable params: 2,836,131
Non-trainable params: 2,882
__________________________________________________________________________________________________