File size: 12,188 Bytes
eb7fed3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
---

license: mit
library_name: onnxruntime
tags:
  - chess
  - onnx
  - gan
  - computer-vision
---


# King's Vision β€” models

ONNX artifacts for [King's Vision](https://github.com/RyanMatthew04/kings-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.

```python

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.


---