From 87ae656445389ff7d08933f8c7c5b4f34e974204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Louf?= Date: Tue, 28 Nov 2023 11:16:08 +0100 Subject: [PATCH] Add models playing chess example --- docs/examples/models_playing_chess.md | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 docs/examples/models_playing_chess.md diff --git a/docs/examples/models_playing_chess.md b/docs/examples/models_playing_chess.md new file mode 100644 index 000000000..3d00d71b7 --- /dev/null +++ b/docs/examples/models_playing_chess.md @@ -0,0 +1,88 @@ +# Large language models playing chess + +In this example we will make Mistral-7B play chess against a simple chess engine, ... + +## The chessboard + +The game will be played on a standard checkboard. We will use the `chess` [library](https://github.com/niklasf/python-chess) to track the opponents' moves, and check that the moves are valid. We will use the `chessboard` [library](https://pypi.org/project/chess-board/) to get a graphical representation of the current state of the game: + +```python +import chess +import chessboard.display + +board = chess.Board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") +game_board = chessboard.display.start(board.fen()) +``` + +## The opponents + +Mistral-7B quantized will be playing White: + +```python +from outlines import models + +model = models.awq("model") +``` + +The X chess engine (3120 ELO) will be playing Black. We use the `chess` library to load the engine: + +```python +engine = chess.engine.SimpleEngine.popen_uci(ENGINE_PATH) +engine.configure({"UCI_LimitStrength": True,"UCI_Elo": 1320}) +``` + +## A little help for the language model + +To make sure Mistral-7B generates valid chess moves we will use Outline's regex-guided generation. We define a function that takes the current state of the board and returns a regex that matches all possible legal moves: + +```python +def generate_regex(board): + legal_moves = list(board.legal_moves) + move_strings = [board.san(move) for move in legal_moves] + # Remove + and # from the move strings + move_strings = [re.sub(r"[+#]", "", move) for move in move_strings] + regex_pattern = "|".join(re.escape(move) for move in move_strings) + regex_pattern = f"{regex_pattern}" + return regex_pattern +``` + +*Let's check how this works* + +## Prompting the language model + +The models' initial prompt + +```python +prompt = "Score: 1-0 WhiteElo: 1600 BlackElo: 1600 Timecontrol: 1800+0 Moves: 1." +``` + +Update the prompt: + +```python +def update_model_prompt(board, move): +``` + +## Let's play! + + +```python +while not board.is_game_over(): + if board.turn == chess.WHITE: # Mistral's turn + regex_pattern = generate_regex(board) + guided = generate.regex(model, regex_pattern, max_tokens=10)(prompt) + move = board.parse_san(guided) + else: # Engine's turn + result = engine.play(board, chess.engine.Limit(time=0.6)) + move = result.move + + prompt = update_model_prompt(board, move) + + board.push(move) + chessboard.display.update(board.fen(), game_board) +``` + + + + +Idea: website with chess tournament. +*This example was originally authored by [@903124S](@903124S) in [this gist](https://gist.github.com/903124/cfbefa24da95e2316e0d5e8ef8ed360d).*