🤖 1M-Parameter Lightweight Tic-Tac-Toe Transformer Bot
A compact, ultra-fast GPT-style transformer model (~1.59M parameters) trained to play optimal, unbeatable Tic-Tac-Toe.
📊 Performance & Benchmarks
🏆 10,000,000 Parallel Games Benchmark (vs Minimax)
Tested on an NVIDIA GeForce RTX 4060 Laptop GPU:
- Total Games Played: 10,027,008 games
- Throughput: 17,943 games / second (~64.6 million games/hour)
- Per-Position Service Latency: 0.0124 ms
- GPU Utilization: 99.9% (Inference bound)
- Model as Player X (5,013,504 games):
- Wins: 0 | Draws: 5,013,504 (100.00%) | Losses: 0 (0.00%)
- Model as Player O (5,013,504 games):
- Wins: 0 | Draws: 5,013,504 (100.00%) | Losses: 0 (0.00%)
🎯 Accuracy & Rule Adherence
- Legal Move Rate: 100.00% (Never plays an illegal move)
- Validation Dataset Accuracy: >97.00%
📐 Architecture
- Parameters: 1,588,992 (~1.6 Million)
- Layers: 2 Transformer Blocks
- Hidden Dimension (Width): 256
- Attention Heads: 8
- Model Checkpoint Size: ~19.1 MB
🎮 Tokenization & Input Format
The board is represented by 11 tokens:
[turn] [cell 0] [cell 1] ... [cell 8] [dummy prediction token]
- Turn tokens:
0(X's turn),1(O's turn) - Board cells:
4(Empty),5(X),6(O) - Dummy prediction token:
7 - Output logits: positions
8..16mapping to cells0..8
🚀 How to Load and Play in Python
import torch
import numpy as np
from model import ModelConfig, build_model
from tokenization import encode_board, EMPTY
# Download 'best.pt' from this repo
checkpoint = torch.load("best.pt", map_location="cpu", weights_only=False)
config = ModelConfig(**checkpoint["model_config"])
model = build_model(config)
model.load_state_dict(checkpoint["model_state"])
model.eval()
# Board state: 0 for empty, 1 for X, -1 for O
board = (0,) * 9 # Empty board
player = 1 # X to move
# Tokenize and predict move
inputs = torch.from_numpy(encode_board(board, player).astype(np.int64)).unsqueeze(0)
with torch.no_grad():
logits = model(inputs)[0]
legal = inputs[0, 1:10] == EMPTY
move = int(logits.masked_fill(~legal, -torch.inf).argmax().item())
print(f"Model chose cell index: {move}")