Our prize winning AWS Hackathon entry
explaining the project that won runner up Computer Vision award.
layout: post title: “Training a Chess AI using TensorFlow” subtitle: “Using the power of deep learning and Stockfish to train a neural network to play the game of chess.” background: ‘/img/posts/chessai/chess.jpeg’ —
To put it plainly, I love chess. Don’t get me wrong, I’m not a great player. But, I have been playing chess since I was 5 or 6. Although I have never been good enough to compete, the game has been around me a lot and its a part of my life.
recently during the lockdown I have started playing chess again and it really peaked my interest. But after being exposed to machine learning and deep learning I always wanted to build my own ChessBot/ChessAI.
First step ofcourse is to come up with a plan and here’s mine
Now that we know what to do, its time to first install stockfish. You can clone my github repo here (contains all files including stockfish).
To generate the board and dictate the general play we will use the python-chess library.
I will be sharing some code and they key ideas and concepts that are involved, the complete code can be found here.
# this function will create our x (board)
def random_board(max_depth=200):
board = chess.Board()
depth = random.randrange(0, max_depth)
for _ in range(depth):
all_moves = list(board.legal_moves)
random_move = random.choice(all_moves)
board.push(random_move)
if board.is_game_over():
break
return board
# this function will create our f(x) (score)
def stockfish(board, depth):
with chess.engine.SimpleEngine.popen_uci('stockfish/13/bin/stockfish') as sf:
result = sf.analyse(board, chess.engine.Limit(depth=depth))
score = result['score'].white().score()
return score
Using this code we can evaluate any chess position. A positive number “White is winning” or negative number meaning “Black is winning”. Using this function we can create a dataset that can evaluate a set of random positions. We can then create a model that can use this information to evaluate future predictions.
Now we need to convert the board representation to something meaningful. A 3d matrix of sizes 8 x 8 x 14 where 8x8 repersents the board and the 14 represents the 7 different pieces.
squares_index = { 'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 'g': 6, 'h': 7 }
def square_to_index(square):
letter = chess.square_name(square)
return 8 - int(letter[1]), squares_index[letter[0]]
def split_dims(board):
# this is the 3d matrix
board3d = numpy.zeros((14, 8, 8), dtype=numpy.int8)
for piece in chess.PIECE_TYPES:
for square in board.pieces(piece, chess.WHITE):
idx = numpy.unravel_index(square, (8, 8))
board3d[piece - 1][7 - idx[0]][idx[1]] = 1
for square in board.pieces(piece, chess.BLACK):
idx = numpy.unravel_index(square, (8, 8))
board3d[piece + 5][7 - idx[0]][idx[1]] = 1
aux = board.turn
board.turn = chess.WHITE
for move in board.legal_moves:
i, j = square_to_index(move.to_square)
board3d[12][i][j] = 1
board.turn = chess.BLACK
for move in board.legal_moves:
i, j = square_to_index(move.to_square)
board3d[13][i][j] = 1
board.turn = aux
return board3d
This function above maps the pieces to the squares and stacks them into an array of size (8,8,14). We can use this multi-dimentional array as an input into our Convolutional Neural Network(CNN) to predict our evaluation.
I have made a function through which you can train a model on a parameter of depth. Its a simple Convolutional layer with a flatten layer proceeding it. It contains a ‘same’ padding parameter as we do not want to change the overall dimensions of the input during the flow.
def build_model(conv_size, conv_depth):
board3d = layers.Input(shape=(14, 8, 8))
x = board3d
for _ in range(conv_depth):
x = layers.Conv2D(filters=conv_size, kernel_size=3,
padding='same', activation='relu')(x)
x = layers.Flatten()(x)
x = layers.Dense(64, 'relu')(x)
x = layers.Dense(1, 'sigmoid')(x)
return models.Model(inputs=board3d, outputs=x)
There a bunch of designs you can try I’ve experimented with a few ones. You can find them in my repo.
The only step left is to train the model. I’ve trained my models on google colab. and tested them out on my local machine. I have run the following tests:
What I have learned from these results is that the AI knows how to play chess, but it does’nt really play at a good level. Stockfish was very easily able to beat it, this was expected as the AI was trying to imitate stockfish and we can’t expect it to be better than the data it was trained on. My over the board rating is around 1300 elo and I was comfortably able to beat it. My guesstimate is that this AI might be around 600 elo or even lower like a beginner in the game. It starts of well, but makes blunders quite often and ends up losing the games. I will try other methods like reinforcement learning later on. You can contact me at my socials linked below and with that peace out!