-
Notifications
You must be signed in to change notification settings - Fork 558
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e1c9604
commit 87ae656
Showing
1 changed file
with
88 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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).* |