FlappingChance commited on
Commit
eb7fed3
Β·
verified Β·
1 Parent(s): f5db658

model card

Browse files
Files changed (1) hide show
  1. README.md +284 -0
README.md ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: onnxruntime
4
+ tags:
5
+ - chess
6
+ - onnx
7
+ - gan
8
+ - computer-vision
9
+ ---
10
+
11
+ # King's Vision β€” models
12
+
13
+ ONNX artifacts for [King's Vision](https://github.com/RyanMatthew04/kings-vision):
14
+ mate-in-one puzzle generators steered by a Cross-Entropy Method search, and a
15
+ board square classifier that reads a chessboard image into a FEN.
16
+
17
+ Every model runs on `onnxruntime` alone β€” no TensorFlow, no PyTorch.
18
+
19
+ ```python
20
+ from huggingface_hub import hf_hub_download
21
+ import onnxruntime as ort
22
+
23
+ path = hf_hub_download("FlappingChance/kings-vision-models", "queen_mate_generator.onnx")
24
+ session = ort.InferenceSession(path)
25
+ ```
26
+
27
+ The application fetches these automatically; see `src/kings_vision/artifacts.py`.
28
+
29
+ ---
30
+
31
+ ## mate-type generators and CEM agents
32
+
33
+ Five DCGAN generators that synthesise chess checkmate positions, each paired with
34
+ a multi-modal Cross-Entropy Method agent that steers its latent input.
35
+
36
+ | | |
37
+ |---|---|
38
+ | **Version** | 1.0 (weights migrated from the original Keras training run; not retrained) |
39
+ | **Format** | ONNX opset 18, float32, single self-contained file |
40
+ | **Size** | 20.8 MB per generator Β· 8.8 KB per CEM agent |
41
+ | **Parameters** | 5,193,997 per generator |
42
+ | **Licence** | MIT (this repository) |
43
+ | **Contact** | https://github.com/RyanMatthew04/kings-vision/issues |
44
+
45
+ ## Intended use
46
+
47
+ Generating mate-in-one training puzzles for the King's Vision trainer. The
48
+ generator produces a *finished* checkmate; `kings_vision.puzzles.backtrack`
49
+ reconstructs the position one move earlier and verifies by replaying forward.
50
+
51
+ **Out of scope.** These models do not play chess, do not evaluate positions, and
52
+ have no notion of a game. They sample from a distribution over checkmate-shaped
53
+ board states. They are not a substitute for a curated puzzle set such as the
54
+ Lichess database, which carries human difficulty ratings these do not.
55
+
56
+ ## Architecture
57
+
58
+ Generator: 100-d latent β†’ `Dense(32768)` β†’ `Reshape(8, 8, 512)` β†’ four
59
+ `Conv2DTranspose` blocks (256 β†’ 128 β†’ 64 β†’ 32, stride 1, `same` padding, kernels
60
+ 3/3/5/5), each with `LeakyReLU(0.2)` and batch normalisation β†’ `Conv2D(13, k=7)`
61
+ β†’ softmax over the channel axis.
62
+
63
+ Output is an 8Γ—8Γ—13 tensor: channel 0 is an empty square, 1–6 are white
64
+ pawn…king, 7–12 are black. `argmax` per square decodes it to a board. That
65
+ encoding is shared with the board classifier β€” see `kings_vision.core.encoding`.
66
+
67
+ ## Training data
68
+
69
+ **The training data no longer exists.** The original run derived checkmate
70
+ positions from Lichess PGN archives, split them by mating piece into five
71
+ datasets, and trained one generator per mate type. Neither the intermediate CSV
72
+ nor the extraction script survived into either predecessor repository or its
73
+ history.
74
+
75
+ This is a real limitation and the main reason these weights were migrated rather
76
+ than retrained: they are not reproducible from anything in this repository. The
77
+ pipeline in `ml/data/` reconstructs the *method*, not the exact dataset.
78
+
79
+ ## Training procedure
80
+
81
+ Recovered from telemetry embedded in the original notebook
82
+ (`docs/data/gan_training_log.csv`):
83
+
84
+ - 10,000 epochs, batch size 128, Adam
85
+ - β‰ˆ67 minutes wall clock on CPU
86
+ - Discriminator settles at 46–50% accuracy β€” near chance, the healthy adversarial
87
+ equilibrium β€” after an unstable first ~800 epochs
88
+
89
+ The inherited README claimed 200–300 epochs at batch 32 over 2–4 hours. None of
90
+ those figures matched the logs.
91
+
92
+ ## The CEM agents
93
+
94
+ Each agent is five Gaussians over the generator's 100-dimensional input, trained
95
+ by Cross-Entropy Method against a binary reward (is this a legal checkmate?) with
96
+ a penalty for repeating a position. **The generator's weights are frozen.** Only
97
+ the input distribution is optimised, which is why the learned artifact is 8.8 KB
98
+ rather than another 20.8 MB.
99
+
100
+ One shipped agent (queen) has a mode whose weight decayed to 2Γ—10⁻¹⁴ β€” an
101
+ effectively collapsed mode. `MultiModalCEM.collapsed_modes` reports this.
102
+
103
+ ## Evaluation
104
+
105
+ `python -m ml.eval.eval_gan --n 1000 --seed 0`, Wilson intervals on validity and
106
+ bootstrap intervals on uniqueness:
107
+
108
+ | Mate type | Valid, raw | Valid, + CEM | Ξ” | Unique, raw | Unique, + CEM | Ξ” | Puzzle yield |
109
+ |---|--:|--:|--:|--:|--:|--:|--:|
110
+ | Queen | 47.4% | 88.2% | +40.8 | 100.0% | 50.8% | βˆ’49.2 | 83.6% |
111
+ | Rook | 62.1% | 77.6% | +15.5 | 100.0% | 73.7% | βˆ’26.3 | 73.6% |
112
+ | Bishop | 40.8% | 73.6% | +32.8 | 99.3% | 62.6% | βˆ’36.6 | 72.5% |
113
+ | Knight | 53.4% | 93.9% | +40.5 | 100.0% | 73.1% | βˆ’26.9 | 93.7% |
114
+ | Pawn | 46.9% | 82.7% | +35.8 | 99.8% | 74.8% | βˆ’24.9 | 27.5% |
115
+ | **Mean** | **50.1%** | **83.2%** | **+33.1** | **99.8%** | **67.0%** | **βˆ’32.8** | **70.2%** |
116
+
117
+ "Valid" is the fraction of samples that are legal positions in which the side to
118
+ move is genuinely checkmated. "Unique" is the distinct fraction among valid
119
+ samples. "Puzzle yield" is the fraction of all samples that convert to a
120
+ mate-in-one with exactly one solution.
121
+
122
+ ## Limitations and honest caveats
123
+
124
+ **Diversity is traded for validity, roughly one for one.** Concentrating
125
+ probability mass on elite samples is simultaneously what raises the hit rate and
126
+ what narrows the output distribution. The diversity-aware reward limits this but
127
+ does not remove it. Anyone wanting maximum variety should sample unsteered and
128
+ filter, accepting a ~50% rejection rate.
129
+
130
+ **Validity overstates usefulness for pawn mates.** 82.7% valid but only 27.5%
131
+ convert to a unique-solution puzzle, because a pawn has few squares it could have
132
+ come from. Judge by puzzle yield, not validity.
133
+
134
+ **Puzzles are non-capturing mates.** The backtracking construction moves a piece
135
+ backwards to an empty square, so mates delivered by a capture are unreachable.
136
+ Discovered and promotion mates are reachable.
137
+
138
+ **No difficulty rating.** These puzzles are not calibrated to human skill. Every
139
+ one is mate-in-one, but "mate in one" spans a wide difficulty range and nothing
140
+ here estimates where a given puzzle sits.
141
+
142
+ **Positions are synthetic.** They are legal and reachable-looking, but not drawn
143
+ from real games, and some carry the slightly artificial texture of GAN output.
144
+
145
+ **Numerical fidelity.** The ONNX artifacts agree with the original Keras models
146
+ to 100% argmax agreement across fixed-seed reference batches β€” identical puzzles,
147
+ verified by `ml/export/build_onnx_generator.py`. Probability residuals of ~1eβˆ’5
148
+ are float32 accumulation differences across frameworks.
149
+
150
+ ## Ethical considerations
151
+
152
+ Low risk. The models generate chess positions. They carry no personal data, and
153
+ the training corpus was public game archives. The most plausible harm is a user
154
+ being served an artificial-feeling puzzle, which the limitations above cover.
155
+
156
+
157
+ ---
158
+
159
+ ## board square classifier
160
+
161
+ A 13-class CNN that reads one square of a chessboard image. Sixty-four
162
+ invocations produce a position.
163
+
164
+ | | |
165
+ |---|---|
166
+ | **Version** | 1.0 |
167
+ | **Format** | ONNX opset 18, float32, single self-contained file |
168
+ | **Size** | ~0.4 MB |
169
+ | **Parameters** | 95,373 |
170
+ | **Input** | `(N, 3, 32, 32)` uint8-valued float, **0–255** |
171
+ | **Output** | `(N, 13)` logits |
172
+ | **Licence** | MIT |
173
+
174
+ Scaling to `[0, 1]` happens *inside* the graph. The serving code passes raw
175
+ pixel values and there is no preprocessing contract to get subtly wrong, which
176
+ is a common and silent source of train/serve skew.
177
+
178
+ ## Intended use
179
+
180
+ Turning a screenshot of a chessboard into a FEN, so a position can be analysed
181
+ without retyping it. Output is a *placement* only β€” a picture cannot show whose
182
+ move it is, and the API returns the placement field rather than inventing the
183
+ rest.
184
+
185
+ **Out of scope.** Photographs of physical boards (this is trained on rendered
186
+ 2D boards), boards at an angle, 3D piece sets, and any board that is not
187
+ axis-aligned and square in the crop.
188
+
189
+ ## Classes
190
+
191
+ Channel order is shared with the mate generators β€” the same 8Γ—8Γ—13 encoding they
192
+ emit into. `0` empty, `1–6` white pawn…king, `7–12` black.
193
+
194
+ ## Training data
195
+
196
+ **Fully synthetic, and that is the interesting part.** No corpus of screenshotted
197
+ boards with per-square labels exists, and none is needed: rendering a known
198
+ position makes every label exact and free.
199
+
200
+ `ml/data/render_boards.py` draws positions sampled from random legal playouts β€”
201
+ real piece densities and structures, including near-empty endgames β€” then
202
+ degrades them the way a screenshot is degraded between a website and a file:
203
+ rendered at 3Γ— and downsampled so pieces land on fractional pixels, JPEG ringing,
204
+ last-move highlights, coordinate labels bleeding into edge squares, blur, and
205
+ brightness/contrast drift.
206
+
207
+ - 4,000 boards / 256,000 squares for training across 6 themes
208
+ - 600 boards / 38,400 squares for validation across 2 unseen themes
209
+ - 600 boards / 38,400 squares for test across 2 further unseen themes
210
+
211
+ **Splits are by theme, three ways.** A validation set drawn from the training
212
+ themes reports 100% and measures memorisation. One drawn from the test themes
213
+ lets epoch selection peek at the reported number. Six themes train, two select,
214
+ two are looked at once.
215
+
216
+ ## Training procedure
217
+
218
+ 8 epochs, AdamW with one-cycle scheduling, batch 512, label smoothing 0.02,
219
+ ~22 minutes on CPU. Best epoch selected on validation board-exact match.
220
+
221
+ **Colour augmentation is the whole ballgame.** Per-channel gain, channel
222
+ permutation, random greyscale, brightness/contrast, and noise β€” all applied at
223
+ batch time. Every one is label-preserving because piece identity in these sprites
224
+ is carried by *luminance* (white pieces are light with a dark outline, black the
225
+ reverse), never by hue. So hue can be attacked freely, and must be.
226
+
227
+ ## Evaluation
228
+
229
+ Board-level exact match is the metric that matters. A FEN wrong in one square is
230
+ wrong, and per-square accuracy hides that.
231
+
232
+ | Themes | Per-square | **Board exact** |
233
+ |---|--:|--:|
234
+ | Seen (training) | 100.0000% | 100.00% |
235
+ | Unseen (validation) | 100.0000% | 100.00% |
236
+ | **Unseen (test)** | **99.8724%** | **94.50%** |
237
+
238
+ ### The augmentation ablation
239
+
240
+ `--no-augment` reproduces the failure the augmentation was written to fix:
241
+
242
+ | | Per-square (test) | **Board exact (test)** |
243
+ |---|--:|--:|
244
+ | Without augmentation | 96.1745% | **58.83%** |
245
+ | With augmentation | 99.8724% | **94.50%** |
246
+ | Ξ” | +3.70 pts | **+35.67 pts** |
247
+
248
+ Without it the model reached 100.0000% per-square accuracy on the six themes it
249
+ trained on and collapsed on an unfamiliar palette. It had learned colour schemes,
250
+ not chess pieces.
251
+
252
+ ## Limitations
253
+
254
+ **94.5%, not 99%.** One board in eighteen is still wrong somewhere on an
255
+ unfamiliar theme. The legality repair search recovers some of those, but it can
256
+ only fix boards whose errors make the position *illegal* β€” a bishop misread as a
257
+ queen usually leaves a perfectly legal board and passes through silently.
258
+
259
+ **Evaluated on synthetic themes, not real screenshots.** Unseen renders are a
260
+ proxy for transfer, not a measurement of it. A hand-labelled set of real captures
261
+ from Lichess and Chess.com would be the honest test and does not exist here.
262
+
263
+ **Two held-out splits disagreed sharply.** In the ablation the validation themes
264
+ scored 99.17% board exact and the test themes 58.83% β€” same model, same run.
265
+ Transfer depends heavily on *which* unfamiliar theme, so 94.50% should be read as
266
+ one sample from a wide distribution rather than a guarantee.
267
+
268
+ **Assumes a square, axis-aligned, tightly-cropped board.** `autocrop` handles
269
+ uniform page background and deliberately gives up rather than guess. A skewed or
270
+ partially occluded board is out of scope and will fail without saying so.
271
+
272
+ **Piece sets.** Trained on one sprite set (the Wikipedia pieces) with geometric
273
+ and colour augmentation. A visually distinct set β€” Lichess's `cburnett`,
274
+ Chess.com's `neo` β€” is untested.
275
+
276
+ ## Ethical considerations
277
+
278
+ Low risk. The model reads chessboards. It processes user-supplied images, which
279
+ are held in memory for the duration of a request and not stored; uploads are
280
+ capped at 8 MB.
281
+
282
+
283
+ ---
284
+