quantik-models
Policy/value networks for Quantik, and the training, evaluation and play tooling behind them. Four architectures, parameter-matched, trained on positions labelled by an exact solver — and four sets of weights published on the Hugging Face Hub.
Quantik is a 4×4 board game with a group-wise placement rule: you may not place a shape in a row, column or 2×2 zone where your opponent already has that shape, and you win by completing a line of four different shapes in either colour. It is small enough to solve exactly, which is what makes it a useful place to ask whether an architectural prior is worth having — the ground truth is available to check the answer against.
pip install 'quantik-models[torch,hub]'
from quantik_models import hub
from quantik_models.env import fastboard as fb
evaluator = hub.load_evaluator("cpool") # downloads and verifies the weights
boards = fb.empty_boards(1) # (1, 8) uint16
legal = fb.legal_masks(boards) # (1, 64) bool
policy, value = evaluator(boards, legal) # masked priors, value in [-1, 1]
Working on this package rather than with it: DEVELOPMENT.md.
Install
| you want | install |
|---|---|
| the published models, on torch | pip install 'quantik-models[torch,hub]' |
| the published models, no torch | pip install 'quantik-models[serve,hub]' |
| to train your own | pip install 'quantik-models[torch,onnx]' |
| the library only | pip install quantik-models |
The base install is numpy and quantik-core and nothing else. torch is a
529 MB dependency and onnxruntime is 80 MB; neither is imposed on someone who
does not need it. The full table is in
DEVELOPMENT.md.
Python 3.12+.
Getting the weights
The weights are not in the wheel. They are ~7 MB each, they carry a different
licence from the code, and they version independently of it — so
load_evaluator fetches them from the Hub on first use and reads them from
the Hugging Face cache ($HF_HOME, default ~/.cache/huggingface) every time
after. One network call, once per model, and never again.
To fill that cache ahead of time — a container build, a machine that is about to go offline, an air-gapped copy — use the fetch command. It needs neither torch nor onnxruntime, so it runs before either is installed:
quantik-models-fetch --all # or: quantik-models-fetch cpool attn
Once a model is cached, everything works with no network at all.
Nothing else needs special attention. Every way this can fail raises
hub.HubError with the remedy in the message rather than a traceback through
huggingface_hub:
| what went wrong | what you get |
|---|---|
| offline, model already cached | it just works — the cache is used |
| offline, nothing cached | the cache path, and the quantik-models-fetch line to run while online |
| truncated download | re-fetched once automatically; a second failure names the cache to clear |
| typo in the model name | the four names that do exist |
bad revision |
a link to the repo's commit list |
| rate limited | that it clears on its own, and that logging in raises the limit |
hub.resolve() returns the commit the download actually resolved to, which is
what to record when you report a number — revision="main" is not a pin.
The models
Four networks answering the same question in different ways, all interchangeable because they agree on one contract:
input (B, 9, 4, 4) float32 tensor-board.v1, mover-relative
output (B, 64) policy logits action_index = shape * 16 + position
(B,) value in [-1, 1] +1 = good for the side to move
Legality masking is applied outside every model, using the same code path in training and at inference — so no engine here can return an illegal move.
| model | Hub repository | IID top-1 | vs minimax-d2 |
|---|---|---|---|
cpool |
quantik-cpool-c191-b6 |
0.9893 | 49.4% |
attn |
quantik-attn-d192-b6 |
0.9879 | 43.1% |
resnet |
quantik-resnet-c128-b6 |
0.9701 | 36.5% |
mlp |
quantik-mlp-h455-b4 |
0.9516 | 31.9% |
minimax-d2 is a fixed two-ply alpha-beta search — the only opponent whose
strength does not move with the field, and so the only column that answers
"is any of this good" rather than "which of these is better". cpool playing
raw policy, one forward pass per move, is even with it. Full numbers, the
four measurements that disagree, and what not to conclude from them:
docs/models.md.
The weights are CC BY-NC 4.0; this package is MIT. A commercial application may use the pipeline, the rules engine and the evaluation harness freely, and may not ship these weights. Train your own and they are yours.
cpool — the constraint model
Quantik's rule is group-wise, not spatial: twelve overlapping groups (4 rows, 4 columns, 4 zones), every cell in exactly three. Each block pools the sixteen cell tokens into those groups, transforms them there, and scatters back.
flowchart LR
IN["board<br/>(B,9,4,4)"] --> TOK["16 cell tokens<br/>Linear 9→C"]
TOK --> BLK
subgraph BLK["constraint block × B"]
direction LR
N["LayerNorm"] --> POOL["pool to 12 groups<br/>4 rows · 4 cols · 4 zones"]
POOL --> KIND["+ kind embedding<br/>line | zone"]
KIND --> GM["group MLP"]
GM --> SC["scatter to member cells"]
SC --> MG["merge with cell features<br/>+ FFN, residual"]
end
BLK --> PH["policy head<br/>Linear C→4 per cell<br/>transpose → 64"]
BLK --> VH["value head<br/>mean over cells · MLP · tanh"]
PH --> POL["policy logits (B,64)"]
VH --> VAL["value (B,)"]
docs/architecture-constraint-pool.md
attn — the same bet without the prior
Transformer encoder over the sixteen cells, told nothing about rows,
columns or zones. It is the test of whether cpool's explicit wiring was
necessary: on policy accuracy it ties, on the value head it does not.
docs/architectures.md ·
docs/attention-negative-result.md
resnet — the incumbent
Convolutional residual trunk, and the architecture every hyperparameter here was originally chosen for. 99.2% of its parameters are the trunk.
mlp — the control
Throws spatial structure away entirely: 144 flat features through dense residual blocks. It exists to make "convolution is worth having on a 4×4 board" falsifiable rather than assumed. It loses, so the spatial prior is real.
The dashed lines are two architectures trained at 2e-3, the rate the ResNet
was tuned for and everything added later inherited by silence. attn did not
learn at all at that rate; cpool converged perfectly well, to a lower place.
A single-rate comparison cannot tell either of those apart from "this
architecture is worse" — which is how three published conclusions here turned
out to be hyperparameter artifacts.
docs/learning-rate-sweep.md.
Playing against them
The play service serves the board and the models on one port, and records finished games:
pip install 'quantik-models[serve,hub]'
quantik-models-play --models staging
It prints a LAN address to open on a phone. --no-store opens no database,
which is the configuration the public container runs.
docs/play-service.md.
Training your own
pip install 'quantik-models[torch,onnx]'
# check the assumptions before a long run (~1 min/arch)
python -m quantik_models.train.preflight --preset medium --epochs 16
# train to convergence: --epochs is the cap, --patience the rule
python -m quantik_models.train.supervised --arch cpool --preset medium \
--corpus runs/oracle/corpus/exact-sampled.npz --name my-run \
--epochs 60 --patience 5
# regenerate every published number for it
scripts/evaluate_lineup.sh runs/eval/today cpool=runs/train/my-run/best
# stage it as a Hugging Face model repository (writes files; uploads nothing)
quantik-models-hf-stage runs/train/my-run/best staging/my-model
Training writes weights.safetensors, model.onnx, a
model-checkpoint.v1 manifest.json and a training report. Corpora, the
label strategy and the retrain/fine-tune path — including freezing part of a
network — are in docs/.
Documentation
docs/README.md is the reading order. The four to start
with:
docs/models.md |
the published models: how to load one, what the numbers mean, what not to conclude |
docs/decisions/0001-architecture-lineup.md |
which architectures were trained, which six were declined, and the methodology |
docs/benchmarks.md |
the figures, and what each does and does not establish |
docs/oracle-benchmark.md |
the field against a fixed classical engine |
Related
quantik-core— the rules engine, QFEN, bitboards and the exact solver. Also on crates.io.- The models on the Hub — weights, ONNX graphs and model cards.
License
MIT — see LICENSE. The published weights are CC BY-NC 4.0 and are not distributed with this package.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quantik_models-1.0.0.tar.gz.
File metadata
- Download URL: quantik_models-1.0.0.tar.gz
- Upload date:
- Size: 308.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4187587428896fcba5c7113acc10299b366b56c91ba5c35e3efd9c7f6dca02e3
|
|
| MD5 |
f4343dbc5b53faf83baa64bce02dd4c9
|
|
| BLAKE2b-256 |
9731c86155623d2df3782fc675950b47613e76d25ce4069659b3b83d15368b39
|
File details
Details for the file quantik_models-1.0.0-py3-none-any.whl.
File metadata
- Download URL: quantik_models-1.0.0-py3-none-any.whl
- Upload date:
- Size: 186.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
334d7c6344d39fbedeeff628754e763224f31721c3027d7b92a03f4003c94ea0
|
|
| MD5 |
601ceaa22c33b49ac5c3bc7e876f67c1
|
|
| BLAKE2b-256 |
22de1d286e5b0ccf3d7b3c6e3eb7e22aa7cbe71f7439d48922fc4ce33136d07e
|