license: mit
library_name: onnxruntime
tags:
- chess
- onnx
- gan
- computer-vision
King's Vision β models
ONNX artifacts for King's Vision: mate-in-one puzzle generators steered by a Cross-Entropy Method search, and a board square classifier that reads a chessboard image into a FEN.
Every model runs on onnxruntime alone β no TensorFlow, no PyTorch.
from huggingface_hub import hf_hub_download
import onnxruntime as ort
path = hf_hub_download("FlappingChance/kings-vision-models", "queen_mate_generator.onnx")
session = ort.InferenceSession(path)
The application fetches these automatically; see src/kings_vision/artifacts.py.
mate-type generators and CEM agents
Five DCGAN generators that synthesise chess checkmate positions, each paired with a multi-modal Cross-Entropy Method agent that steers its latent input.
| Version | 1.0 (weights migrated from the original Keras training run; not retrained) |
| Format | ONNX opset 18, float32, single self-contained file |
| Size | 20.8 MB per generator Β· 8.8 KB per CEM agent |
| Parameters | 5,193,997 per generator |
| Licence | MIT (this repository) |
| Contact | https://github.com/RyanMatthew04/kings-vision/issues |
Intended use
Generating mate-in-one training puzzles for the King's Vision trainer. The
generator produces a finished checkmate; kings_vision.puzzles.backtrack
reconstructs the position one move earlier and verifies by replaying forward.
Out of scope. These models do not play chess, do not evaluate positions, and have no notion of a game. They sample from a distribution over checkmate-shaped board states. They are not a substitute for a curated puzzle set such as the Lichess database, which carries human difficulty ratings these do not.
Architecture
Generator: 100-d latent β Dense(32768) β Reshape(8, 8, 512) β four
Conv2DTranspose blocks (256 β 128 β 64 β 32, stride 1, same padding, kernels
3/3/5/5), each with LeakyReLU(0.2) and batch normalisation β Conv2D(13, k=7)
β softmax over the channel axis.
Output is an 8Γ8Γ13 tensor: channel 0 is an empty square, 1β6 are white
pawnβ¦king, 7β12 are black. argmax per square decodes it to a board. That
encoding is shared with the board classifier β see kings_vision.core.encoding.
Training data
The training data no longer exists. The original run derived checkmate positions from Lichess PGN archives, split them by mating piece into five datasets, and trained one generator per mate type. Neither the intermediate CSV nor the extraction script survived into either predecessor repository or its history.
This is a real limitation and the main reason these weights were migrated rather
than retrained: they are not reproducible from anything in this repository. The
pipeline in ml/data/ reconstructs the method, not the exact dataset.
Training procedure
Recovered from telemetry embedded in the original notebook
(docs/data/gan_training_log.csv):
- 10,000 epochs, batch size 128, Adam
- β67 minutes wall clock on CPU
- Discriminator settles at 46β50% accuracy β near chance, the healthy adversarial equilibrium β after an unstable first ~800 epochs
The inherited README claimed 200β300 epochs at batch 32 over 2β4 hours. None of those figures matched the logs.
The CEM agents
Each agent is five Gaussians over the generator's 100-dimensional input, trained by Cross-Entropy Method against a binary reward (is this a legal checkmate?) with a penalty for repeating a position. The generator's weights are frozen. Only the input distribution is optimised, which is why the learned artifact is 8.8 KB rather than another 20.8 MB.
One shipped agent (queen) has a mode whose weight decayed to 2Γ10β»ΒΉβ΄ β an
effectively collapsed mode. MultiModalCEM.collapsed_modes reports this.
Evaluation
python -m ml.eval.eval_gan --n 1000 --seed 0, Wilson intervals on validity and
bootstrap intervals on uniqueness:
| Mate type | Valid, raw | Valid, + CEM | Ξ | Unique, raw | Unique, + CEM | Ξ | Puzzle yield |
|---|---|---|---|---|---|---|---|
| Queen | 47.4% | 88.2% | +40.8 | 100.0% | 50.8% | β49.2 | 83.6% |
| Rook | 62.1% | 77.6% | +15.5 | 100.0% | 73.7% | β26.3 | 73.6% |
| Bishop | 40.8% | 73.6% | +32.8 | 99.3% | 62.6% | β36.6 | 72.5% |
| Knight | 53.4% | 93.9% | +40.5 | 100.0% | 73.1% | β26.9 | 93.7% |
| Pawn | 46.9% | 82.7% | +35.8 | 99.8% | 74.8% | β24.9 | 27.5% |
| Mean | 50.1% | 83.2% | +33.1 | 99.8% | 67.0% | β32.8 | 70.2% |
"Valid" is the fraction of samples that are legal positions in which the side to move is genuinely checkmated. "Unique" is the distinct fraction among valid samples. "Puzzle yield" is the fraction of all samples that convert to a mate-in-one with exactly one solution.
Limitations and honest caveats
Diversity is traded for validity, roughly one for one. Concentrating probability mass on elite samples is simultaneously what raises the hit rate and what narrows the output distribution. The diversity-aware reward limits this but does not remove it. Anyone wanting maximum variety should sample unsteered and filter, accepting a ~50% rejection rate.
Validity overstates usefulness for pawn mates. 82.7% valid but only 27.5% convert to a unique-solution puzzle, because a pawn has few squares it could have come from. Judge by puzzle yield, not validity.
Puzzles are non-capturing mates. The backtracking construction moves a piece backwards to an empty square, so mates delivered by a capture are unreachable. Discovered and promotion mates are reachable.
No difficulty rating. These puzzles are not calibrated to human skill. Every one is mate-in-one, but "mate in one" spans a wide difficulty range and nothing here estimates where a given puzzle sits.
Positions are synthetic. They are legal and reachable-looking, but not drawn from real games, and some carry the slightly artificial texture of GAN output.
Numerical fidelity. The ONNX artifacts agree with the original Keras models
to 100% argmax agreement across fixed-seed reference batches β identical puzzles,
verified by ml/export/build_onnx_generator.py. Probability residuals of ~1eβ5
are float32 accumulation differences across frameworks.
Ethical considerations
Low risk. The models generate chess positions. They carry no personal data, and the training corpus was public game archives. The most plausible harm is a user being served an artificial-feeling puzzle, which the limitations above cover.
board square classifier
A 13-class CNN that reads one square of a chessboard image. Sixty-four invocations produce a position.
| Version | 1.0 |
| Format | ONNX opset 18, float32, single self-contained file |
| Size | ~0.4 MB |
| Parameters | 95,373 |
| Input | (N, 3, 32, 32) uint8-valued float, 0β255 |
| Output | (N, 13) logits |
| Licence | MIT |
Scaling to [0, 1] happens inside the graph. The serving code passes raw
pixel values and there is no preprocessing contract to get subtly wrong, which
is a common and silent source of train/serve skew.
Intended use
Turning a screenshot of a chessboard into a FEN, so a position can be analysed without retyping it. Output is a placement only β a picture cannot show whose move it is, and the API returns the placement field rather than inventing the rest.
Out of scope. Photographs of physical boards (this is trained on rendered 2D boards), boards at an angle, 3D piece sets, and any board that is not axis-aligned and square in the crop.
Classes
Channel order is shared with the mate generators β the same 8Γ8Γ13 encoding they
emit into. 0 empty, 1β6 white pawnβ¦king, 7β12 black.
Training data
Fully synthetic, and that is the interesting part. No corpus of screenshotted boards with per-square labels exists, and none is needed: rendering a known position makes every label exact and free.
ml/data/render_boards.py draws positions sampled from random legal playouts β
real piece densities and structures, including near-empty endgames β then
degrades them the way a screenshot is degraded between a website and a file:
rendered at 3Γ and downsampled so pieces land on fractional pixels, JPEG ringing,
last-move highlights, coordinate labels bleeding into edge squares, blur, and
brightness/contrast drift.
- 4,000 boards / 256,000 squares for training across 6 themes
- 600 boards / 38,400 squares for validation across 2 unseen themes
- 600 boards / 38,400 squares for test across 2 further unseen themes
Splits are by theme, three ways. A validation set drawn from the training themes reports 100% and measures memorisation. One drawn from the test themes lets epoch selection peek at the reported number. Six themes train, two select, two are looked at once.
Training procedure
8 epochs, AdamW with one-cycle scheduling, batch 512, label smoothing 0.02, ~22 minutes on CPU. Best epoch selected on validation board-exact match.
Colour augmentation is the whole ballgame. Per-channel gain, channel permutation, random greyscale, brightness/contrast, and noise β all applied at batch time. Every one is label-preserving because piece identity in these sprites is carried by luminance (white pieces are light with a dark outline, black the reverse), never by hue. So hue can be attacked freely, and must be.
Evaluation
Board-level exact match is the metric that matters. A FEN wrong in one square is wrong, and per-square accuracy hides that.
| Themes | Per-square | Board exact |
|---|---|---|
| Seen (training) | 100.0000% | 100.00% |
| Unseen (validation) | 100.0000% | 100.00% |
| Unseen (test) | 99.8724% | 94.50% |
The augmentation ablation
--no-augment reproduces the failure the augmentation was written to fix:
| Per-square (test) | Board exact (test) | |
|---|---|---|
| Without augmentation | 96.1745% | 58.83% |
| With augmentation | 99.8724% | 94.50% |
| Ξ | +3.70 pts | +35.67 pts |
Without it the model reached 100.0000% per-square accuracy on the six themes it trained on and collapsed on an unfamiliar palette. It had learned colour schemes, not chess pieces.
Limitations
94.5%, not 99%. One board in eighteen is still wrong somewhere on an unfamiliar theme. The legality repair search recovers some of those, but it can only fix boards whose errors make the position illegal β a bishop misread as a queen usually leaves a perfectly legal board and passes through silently.
Evaluated on synthetic themes, not real screenshots. Unseen renders are a proxy for transfer, not a measurement of it. A hand-labelled set of real captures from Lichess and Chess.com would be the honest test and does not exist here.
Two held-out splits disagreed sharply. In the ablation the validation themes scored 99.17% board exact and the test themes 58.83% β same model, same run. Transfer depends heavily on which unfamiliar theme, so 94.50% should be read as one sample from a wide distribution rather than a guarantee.
Assumes a square, axis-aligned, tightly-cropped board. autocrop handles
uniform page background and deliberately gives up rather than guess. A skewed or
partially occluded board is out of scope and will fail without saying so.
Piece sets. Trained on one sprite set (the Wikipedia pieces) with geometric
and colour augmentation. A visually distinct set β Lichess's cburnett,
Chess.com's neo β is untested.
Ethical considerations
Low risk. The model reads chessboards. It processes user-supplied images, which are held in memory for the duration of a request and not stored; uploads are capped at 8 MB.