quantik-models 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quantik_models-1.0.0/AGENTS.md +46 -0
- quantik_models-1.0.0/CHANGELOG.md +107 -0
- quantik_models-1.0.0/LICENSE +21 -0
- quantik_models-1.0.0/MANIFEST.in +26 -0
- quantik_models-1.0.0/PKG-INFO +294 -0
- quantik_models-1.0.0/README.md +242 -0
- quantik_models-1.0.0/pyproject.toml +156 -0
- quantik_models-1.0.0/setup.cfg +4 -0
- quantik_models-1.0.0/src/quantik_models/__init__.py +12 -0
- quantik_models-1.0.0/src/quantik_models/arena/__init__.py +25 -0
- quantik_models-1.0.0/src/quantik_models/arena/agents.py +305 -0
- quantik_models-1.0.0/src/quantik_models/arena/autoplay.py +379 -0
- quantik_models-1.0.0/src/quantik_models/arena/match.py +232 -0
- quantik_models-1.0.0/src/quantik_models/arena/pack.py +406 -0
- quantik_models-1.0.0/src/quantik_models/arena/parallel.py +97 -0
- quantik_models-1.0.0/src/quantik_models/arena/probe.py +149 -0
- quantik_models-1.0.0/src/quantik_models/arena/registry.py +213 -0
- quantik_models-1.0.0/src/quantik_models/data/__init__.py +5 -0
- quantik_models-1.0.0/src/quantik_models/data/dataset.py +171 -0
- quantik_models-1.0.0/src/quantik_models/data/exact_corpus.py +153 -0
- quantik_models-1.0.0/src/quantik_models/data/labels.py +44 -0
- quantik_models-1.0.0/src/quantik_models/data/materialize.py +242 -0
- quantik_models-1.0.0/src/quantik_models/data/merge_corpus.py +158 -0
- quantik_models-1.0.0/src/quantik_models/env/__init__.py +21 -0
- quantik_models-1.0.0/src/quantik_models/env/fastboard.py +414 -0
- quantik_models-1.0.0/src/quantik_models/eval/__init__.py +1 -0
- quantik_models-1.0.0/src/quantik_models/eval/shift.py +379 -0
- quantik_models-1.0.0/src/quantik_models/export/__init__.py +1 -0
- quantik_models-1.0.0/src/quantik_models/export/cards.py +113 -0
- quantik_models-1.0.0/src/quantik_models/export/checkpoint.py +205 -0
- quantik_models-1.0.0/src/quantik_models/export/devdata.py +571 -0
- quantik_models-1.0.0/src/quantik_models/export/digest.py +22 -0
- quantik_models-1.0.0/src/quantik_models/export/huggingface.py +923 -0
- quantik_models-1.0.0/src/quantik_models/hub.py +526 -0
- quantik_models-1.0.0/src/quantik_models/model/__init__.py +1 -0
- quantik_models-1.0.0/src/quantik_models/model/attention_net.py +147 -0
- quantik_models-1.0.0/src/quantik_models/model/constraint_pool_net.py +220 -0
- quantik_models-1.0.0/src/quantik_models/model/mlp_net.py +107 -0
- quantik_models-1.0.0/src/quantik_models/model/policy_value_net.py +114 -0
- quantik_models-1.0.0/src/quantik_models/model/registry.py +191 -0
- quantik_models-1.0.0/src/quantik_models/model/spec.py +68 -0
- quantik_models-1.0.0/src/quantik_models/model_spec.py +9 -0
- quantik_models-1.0.0/src/quantik_models/play/__init__.py +32 -0
- quantik_models-1.0.0/src/quantik_models/play/__main__.py +132 -0
- quantik_models-1.0.0/src/quantik_models/play/export.py +128 -0
- quantik_models-1.0.0/src/quantik_models/play/opponents.py +216 -0
- quantik_models-1.0.0/src/quantik_models/play/puzzles.py +275 -0
- quantik_models-1.0.0/src/quantik_models/play/record.py +244 -0
- quantik_models-1.0.0/src/quantik_models/play/registry.py +187 -0
- quantik_models-1.0.0/src/quantik_models/play/server.py +311 -0
- quantik_models-1.0.0/src/quantik_models/play/service.py +479 -0
- quantik_models-1.0.0/src/quantik_models/play/store.py +348 -0
- quantik_models-1.0.0/src/quantik_models/py.typed +0 -0
- quantik_models-1.0.0/src/quantik_models/report/__init__.py +1 -0
- quantik_models-1.0.0/src/quantik_models/report/build_figures.py +144 -0
- quantik_models-1.0.0/src/quantik_models/report/figures.py +419 -0
- quantik_models-1.0.0/src/quantik_models/selfplay/__init__.py +12 -0
- quantik_models-1.0.0/src/quantik_models/selfplay/duel.py +90 -0
- quantik_models-1.0.0/src/quantik_models/selfplay/evaluator.py +125 -0
- quantik_models-1.0.0/src/quantik_models/selfplay/generate.py +155 -0
- quantik_models-1.0.0/src/quantik_models/selfplay/mcts.py +330 -0
- quantik_models-1.0.0/src/quantik_models/train/__init__.py +1 -0
- quantik_models-1.0.0/src/quantik_models/train/alphazero.py +330 -0
- quantik_models-1.0.0/src/quantik_models/train/convergence.py +25 -0
- quantik_models-1.0.0/src/quantik_models/train/freezing.py +131 -0
- quantik_models-1.0.0/src/quantik_models/train/metrics.py +25 -0
- quantik_models-1.0.0/src/quantik_models/train/preflight.py +345 -0
- quantik_models-1.0.0/src/quantik_models/train/provenance.py +172 -0
- quantik_models-1.0.0/src/quantik_models/train/supervised.py +437 -0
- quantik_models-1.0.0/src/quantik_models/train/trainer.py +304 -0
- quantik_models-1.0.0/src/quantik_models.egg-info/PKG-INFO +294 -0
- quantik_models-1.0.0/src/quantik_models.egg-info/SOURCES.txt +127 -0
- quantik_models-1.0.0/src/quantik_models.egg-info/dependency_links.txt +1 -0
- quantik_models-1.0.0/src/quantik_models.egg-info/entry_points.txt +7 -0
- quantik_models-1.0.0/src/quantik_models.egg-info/requires.txt +32 -0
- quantik_models-1.0.0/src/quantik_models.egg-info/top_level.txt +1 -0
- quantik_models-1.0.0/tests/boards.py +41 -0
- quantik_models-1.0.0/tests/fixtures/checkpoints/smoke-best/manifest.json +21 -0
- quantik_models-1.0.0/tests/fixtures/checkpoints/smoke-best/training-report.json +22 -0
- quantik_models-1.0.0/tests/fixtures/checkpoints/smoke-best/weights.safetensors +0 -0
- quantik_models-1.0.0/tests/fixtures/puzzle-corpus.json +425 -0
- quantik_models-1.0.0/tests/test_action_layout.py +56 -0
- quantik_models-1.0.0/tests/test_agent_temperature.py +187 -0
- quantik_models-1.0.0/tests/test_architecture_registry.py +160 -0
- quantik_models-1.0.0/tests/test_arena.py +171 -0
- quantik_models-1.0.0/tests/test_arena_pack.py +342 -0
- quantik_models-1.0.0/tests/test_autoplay.py +171 -0
- quantik_models-1.0.0/tests/test_batched_mcts.py +226 -0
- quantik_models-1.0.0/tests/test_checkpoint_fixture.py +45 -0
- quantik_models-1.0.0/tests/test_checkpoint_roundtrip.py +87 -0
- quantik_models-1.0.0/tests/test_constraint_groups.py +60 -0
- quantik_models-1.0.0/tests/test_convergence_budget.py +144 -0
- quantik_models-1.0.0/tests/test_dataset.py +78 -0
- quantik_models-1.0.0/tests/test_devdata_staging.py +159 -0
- quantik_models-1.0.0/tests/test_docs_crossrefs.py +171 -0
- quantik_models-1.0.0/tests/test_documented_snippets.py +121 -0
- quantik_models-1.0.0/tests/test_export_checkpoint.py +89 -0
- quantik_models-1.0.0/tests/test_fastboard.py +251 -0
- quantik_models-1.0.0/tests/test_finetune_cli.py +100 -0
- quantik_models-1.0.0/tests/test_freezing.py +127 -0
- quantik_models-1.0.0/tests/test_hub.py +513 -0
- quantik_models-1.0.0/tests/test_huggingface_export.py +336 -0
- quantik_models-1.0.0/tests/test_learning_rate_resolution.py +142 -0
- quantik_models-1.0.0/tests/test_materialize.py +108 -0
- quantik_models-1.0.0/tests/test_merge_corpus.py +124 -0
- quantik_models-1.0.0/tests/test_occupancy_split.py +115 -0
- quantik_models-1.0.0/tests/test_onnx_evaluator_agreement.py +114 -0
- quantik_models-1.0.0/tests/test_oracle_corpus.py +144 -0
- quantik_models-1.0.0/tests/test_packaging.py +148 -0
- quantik_models-1.0.0/tests/test_parameter_matching.py +59 -0
- quantik_models-1.0.0/tests/test_play_analysis.py +146 -0
- quantik_models-1.0.0/tests/test_play_export.py +176 -0
- quantik_models-1.0.0/tests/test_play_puzzles.py +144 -0
- quantik_models-1.0.0/tests/test_play_record.py +216 -0
- quantik_models-1.0.0/tests/test_play_registry.py +217 -0
- quantik_models-1.0.0/tests/test_play_server.py +308 -0
- quantik_models-1.0.0/tests/test_play_service.py +275 -0
- quantik_models-1.0.0/tests/test_play_store.py +283 -0
- quantik_models-1.0.0/tests/test_policy_value_net.py +58 -0
- quantik_models-1.0.0/tests/test_preflight.py +121 -0
- quantik_models-1.0.0/tests/test_probe.py +108 -0
- quantik_models-1.0.0/tests/test_report_figures.py +304 -0
- quantik_models-1.0.0/tests/test_selfplay.py +197 -0
- quantik_models-1.0.0/tests/test_shift_evaluation.py +159 -0
- quantik_models-1.0.0/tests/test_solve_opening.py +105 -0
- quantik_models-1.0.0/tests/test_split_leakage.py +119 -0
- quantik_models-1.0.0/tests/test_trainer.py +100 -0
- quantik_models-1.0.0/tests/test_training_provenance.py +147 -0
- quantik_models-1.0.0/tests/test_uniform_mcts_control.py +53 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Instructions for humans and AI agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## Read these first, in this order
|
|
6
|
+
|
|
7
|
+
| | |
|
|
8
|
+
|---|---|
|
|
9
|
+
| [`README.md`](README.md) | what the package is and how it is used |
|
|
10
|
+
| [`DEVELOPMENT.md`](DEVELOPMENT.md) | **environment, tests, CI, the release process, and the non-negotiable invariants.** Everything about working on this repository is there. |
|
|
11
|
+
| [`docs/README.md`](docs/README.md) | the reading order for `docs/` |
|
|
12
|
+
|
|
13
|
+
**Do not grep your way in.** This repository's hard-won conclusions are
|
|
14
|
+
written down, and most of them are not derivable from the code — several are
|
|
15
|
+
about measurements that turned out to be wrong. `DEVELOPMENT.md`'s
|
|
16
|
+
"Invariants that are not negotiable" is the shortest path to not repeating
|
|
17
|
+
one.
|
|
18
|
+
|
|
19
|
+
## What is specific to working here as an agent
|
|
20
|
+
|
|
21
|
+
**Verify before anything expensive.** Training runs and arenas cost hours,
|
|
22
|
+
and this repository has paid more than once for skipping the smoke test.
|
|
23
|
+
`DEVELOPMENT.md` has the rules; the shortest version is that a timing taken
|
|
24
|
+
under load is an upper bound, often a wild one, and an average from a
|
|
25
|
+
differently-shaped workload does not transfer.
|
|
26
|
+
|
|
27
|
+
**Say what you actually ran.** `mypy` is a gate now, but claiming a check
|
|
28
|
+
passed without running it has happened here. So has drawing a 16-epoch
|
|
29
|
+
conclusion from one epoch of evidence, and publishing a plausible, detailed,
|
|
30
|
+
statistically significant story that was entirely an artifact of a
|
|
31
|
+
hyperparameter inherited from another architecture.
|
|
32
|
+
|
|
33
|
+
**When you recommend something, write down what you rejected.** Both
|
|
34
|
+
architecture decision records in `docs/decisions/` are structured that way,
|
|
35
|
+
and the rejected options are the part that has aged best.
|
|
36
|
+
|
|
37
|
+
**A measurement disagreeing with an earlier one is the interesting case.**
|
|
38
|
+
Do not split the difference. Held-out accuracy has failed to predict play
|
|
39
|
+
strength four separate times; when it disagrees with the arena, say so.
|
|
40
|
+
|
|
41
|
+
## Where work is tracked
|
|
42
|
+
|
|
43
|
+
`quantik-workspace` is the control plane and the source of truth for what
|
|
44
|
+
work exists — initiatives under `tasks/active/QW-NNN/`, repository packets
|
|
45
|
+
under `context/repositories/`, decisions under `docs/adr/`. It is a sibling
|
|
46
|
+
checkout, not part of this repository.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `quantik-models` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
What counts as a breaking change here is written down in
|
|
8
|
+
[`docs/decisions/0002-versioning-and-release.md`](docs/decisions/0002-versioning-and-release.md).
|
|
9
|
+
|
|
10
|
+
## Unreleased
|
|
11
|
+
|
|
12
|
+
## 1.0.0 - 2026-09-05
|
|
13
|
+
|
|
14
|
+
First release on PyPI. The package has been usable from a checkout for
|
|
15
|
+
months; what changes is that it is now installable, versioned and documented
|
|
16
|
+
as a library rather than as this workspace's training directory.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`quantik_models.hub`** — load the four published networks from the
|
|
21
|
+
Hugging Face Hub in one call:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from quantik_models import hub
|
|
25
|
+
evaluator = hub.load_evaluator("cpool") # torch
|
|
26
|
+
evaluator = hub.load_evaluator("cpool", runtime="onnx") # no torch
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Short names resolve through a table of the published repo ids rather than
|
|
30
|
+
a Hub query, a full `owner/repo` passes through unresolved so a fork needs
|
|
31
|
+
no code change, and the downloaded artifact is checked against the digest
|
|
32
|
+
in `manifest.json` for the runtime that will load it — `weights_hash` for
|
|
33
|
+
safetensors, `onnx_hash` for the graph. The module is importable without
|
|
34
|
+
torch.
|
|
35
|
+
|
|
36
|
+
Every fetch failure is re-raised as `hub.HubError` carrying the remedy —
|
|
37
|
+
the cache path and the command to run when offline with a cold cache, the
|
|
38
|
+
terms link for a gated repo, the valid names for a typo, the commit list
|
|
39
|
+
for an unknown revision — with the Hub's own exception kept as `__cause__`.
|
|
40
|
+
A digest mismatch is re-fetched once before it is raised, because the usual
|
|
41
|
+
cause is a truncated cache entry that would otherwise fail identically
|
|
42
|
+
forever. `resolve()` reports the commit `main` resolved to, so a run made
|
|
43
|
+
without an explicit `revision` is still reproducible.
|
|
44
|
+
- **`quantik-models-fetch` console script** (`hub.prefetch()` from Python) —
|
|
45
|
+
fills the Hugging Face cache without loading anything, so a container build
|
|
46
|
+
or an air-gapped host can be prepared before torch or onnxruntime exist.
|
|
47
|
+
- **`hub` extra** (`pip install 'quantik-models[hub]'`) carrying
|
|
48
|
+
`huggingface-hub`. Kept out of the base install because nothing in
|
|
49
|
+
training, evaluation or the arena fetches anything.
|
|
50
|
+
- **`quantik-models-play` console script**, so the play service starts the
|
|
51
|
+
same way from an installed package as from a checkout.
|
|
52
|
+
- **`py.typed`**: the package now ships its type information.
|
|
53
|
+
- **`arena.registry.weights_path`**, the resolver behind the loader fix
|
|
54
|
+
below.
|
|
55
|
+
- **[`DEVELOPMENT.md`](DEVELOPMENT.md)**, [`CHANGELOG.md`](CHANGELOG.md), and
|
|
56
|
+
[`docs/models.md`](docs/models.md) — the published models, their numbers,
|
|
57
|
+
and how to load them.
|
|
58
|
+
|
|
59
|
+
### Fixed
|
|
60
|
+
|
|
61
|
+
- **`load_evaluator` could not read a downloaded Hub repository.** It
|
|
62
|
+
required `weights.safetensors`; `export.huggingface.stage` renames the
|
|
63
|
+
file to `model.safetensors` on the way to the Hub, and that is the name in
|
|
64
|
+
all four published repositories. The result was that the primary Python
|
|
65
|
+
snippet on every published model card raised `FileNotFoundError`. The
|
|
66
|
+
loader now resolves both names and, when it finds neither, says so naming
|
|
67
|
+
both candidates instead of pointing at a file that was never meant to
|
|
68
|
+
exist.
|
|
69
|
+
- **The build declared `setuptools>=68` while using PEP 639 metadata that
|
|
70
|
+
needs 77.** A resolver that honoured the stated floor produced a wheel
|
|
71
|
+
with no licence, or failed outright.
|
|
72
|
+
- **The generated model cards told readers `quantik-models` was not on PyPI**
|
|
73
|
+
and to install from a git ref. They now name the release.
|
|
74
|
+
- **The card's Python snippet called a method that does not exist.**
|
|
75
|
+
`evaluator.evaluate(boards)` is wrong twice over — an evaluator is
|
|
76
|
+
callable, and the legality mask is a required argument with no default —
|
|
77
|
+
so a reader following the card got an `AttributeError` on the one line the
|
|
78
|
+
card exists to provide. Both live snippets were verified against a real
|
|
79
|
+
download from the Hub before this release, and
|
|
80
|
+
`tests/test_documented_snippets.py` now executes the documented call and
|
|
81
|
+
fails if `Evaluator.__call__` and the documents disagree.
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- Version **0.1.0 → 1.0.0**. The package's public surface — the `(B, 9, 4, 4)`
|
|
86
|
+
mover-relative input contract, the 64-logit policy and tanh value output,
|
|
87
|
+
the architecture registry and the checkpoint manifest — has been stable
|
|
88
|
+
across four trained architectures and four published model repositories.
|
|
89
|
+
`0.1.0` understated that, and semantic versioning only says anything once
|
|
90
|
+
the first stable release exists.
|
|
91
|
+
- `quantik-core` dependency pinned to `>=1.2,<2` rather than `>=1.2`, so a
|
|
92
|
+
future major release of the core cannot silently satisfy this constraint.
|
|
93
|
+
- `mypy` is now configured in `pyproject.toml` and **enforced in CI**. It was
|
|
94
|
+
previously declared in the `dev` extra and wired into nothing.
|
|
95
|
+
- Packaging metadata filled in: authors, classifiers, keywords, project URLs
|
|
96
|
+
(including the Hub namespace), and a `MANIFEST.in` that ships the tests
|
|
97
|
+
with the fixtures they need and excludes `runs/`, `docs/` and `staging/`.
|
|
98
|
+
|
|
99
|
+
### Documentation
|
|
100
|
+
|
|
101
|
+
- `README.md` is now about using the library and the models. Everything
|
|
102
|
+
about checking out the workspace, the smoke pipeline, the corpora and the
|
|
103
|
+
release process moved to `DEVELOPMENT.md`.
|
|
104
|
+
- The twenty-three documents in `docs/` were consolidated. Superseded
|
|
105
|
+
narrative and dated working journals were removed in favour of the
|
|
106
|
+
standing conclusions, which are what a reader can act on. See
|
|
107
|
+
`docs/README.md`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mauro Berlanda
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# What ships in the sdist beyond the package itself.
|
|
2
|
+
#
|
|
3
|
+
# The rule: an sdist must be enough to build the wheel *and* verify it. That
|
|
4
|
+
# means the tests and the 80 KB smoke checkpoint they load — shipping
|
|
5
|
+
# `tests/` without `tests/fixtures/` gives a source distribution whose test
|
|
6
|
+
# suite cannot run, which is worse than shipping neither.
|
|
7
|
+
include LICENSE
|
|
8
|
+
include CHANGELOG.md
|
|
9
|
+
include AGENTS.md
|
|
10
|
+
recursive-include tests *.py *.json *.safetensors
|
|
11
|
+
|
|
12
|
+
# Everything below is deliberately excluded.
|
|
13
|
+
#
|
|
14
|
+
# `runs/` is gitignored and holds every corpus and checkpoint — tens of GB,
|
|
15
|
+
# none of it publishable, and the reason this list is explicit rather than
|
|
16
|
+
# implicit. `docs/` is 664 KB of Markdown and figures that are one link away
|
|
17
|
+
# on GitHub. `docker/staging/` is materialized weights.
|
|
18
|
+
prune runs
|
|
19
|
+
prune docs
|
|
20
|
+
prune docker
|
|
21
|
+
prune experiments
|
|
22
|
+
prune examples
|
|
23
|
+
prune scripts
|
|
24
|
+
prune staging
|
|
25
|
+
global-exclude *.pyc *.npz *.parquet *.jsonl
|
|
26
|
+
global-exclude .DS_Store
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quantik-models
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Policy/value networks, training and evaluation for the Quantik board game
|
|
5
|
+
Author-email: Mauro Berlanda <mauro.berlanda@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mberlanda/quantik-models-py
|
|
8
|
+
Project-URL: Repository, https://github.com/mberlanda/quantik-models-py
|
|
9
|
+
Project-URL: Documentation, https://github.com/mberlanda/quantik-models-py#readme
|
|
10
|
+
Project-URL: Changelog, https://github.com/mberlanda/quantik-models-py/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/mberlanda/quantik-models-py/issues
|
|
12
|
+
Project-URL: Model Weights, https://huggingface.co/brpoplpush
|
|
13
|
+
Keywords: quantik,board-games,game-ai,policy-value-network,reinforcement-learning,mcts,alphazero,onnx,pytorch
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Games/Entertainment :: Board Games
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: numpy<3,>=2.0
|
|
28
|
+
Requires-Dist: quantik-core<2,>=1.2
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest<10,>=8; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy<3,>=1.8; extra == "dev"
|
|
32
|
+
Requires-Dist: build<2,>=1; extra == "dev"
|
|
33
|
+
Requires-Dist: twine<7,>=6; extra == "dev"
|
|
34
|
+
Provides-Extra: arrow
|
|
35
|
+
Requires-Dist: pyarrow<22,>=16; extra == "arrow"
|
|
36
|
+
Provides-Extra: torch
|
|
37
|
+
Requires-Dist: torch>=2.4; extra == "torch"
|
|
38
|
+
Requires-Dist: safetensors>=0.4; extra == "torch"
|
|
39
|
+
Provides-Extra: onnx
|
|
40
|
+
Requires-Dist: onnx>=1.16; extra == "onnx"
|
|
41
|
+
Requires-Dist: onnxscript>=0.1; extra == "onnx"
|
|
42
|
+
Requires-Dist: onnxruntime>=1.18; extra == "onnx"
|
|
43
|
+
Provides-Extra: serve
|
|
44
|
+
Requires-Dist: onnxruntime>=1.18; extra == "serve"
|
|
45
|
+
Provides-Extra: hub
|
|
46
|
+
Requires-Dist: huggingface-hub>=0.34; extra == "hub"
|
|
47
|
+
Provides-Extra: viz
|
|
48
|
+
Requires-Dist: matplotlib>=3.8; extra == "viz"
|
|
49
|
+
Provides-Extra: all
|
|
50
|
+
Requires-Dist: quantik-models[arrow,dev,hub,onnx,serve,torch,viz]; extra == "all"
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# quantik-models
|
|
54
|
+
|
|
55
|
+
[](https://pypi.org/project/quantik-models/)
|
|
56
|
+
[](https://pypi.org/project/quantik-models/)
|
|
57
|
+
[](LICENSE)
|
|
58
|
+
|
|
59
|
+
Policy/value networks for **Quantik**, and the training, evaluation and play
|
|
60
|
+
tooling behind them. Four architectures, parameter-matched, trained on
|
|
61
|
+
positions labelled by an exact solver — and four sets of weights published on
|
|
62
|
+
the Hugging Face Hub.
|
|
63
|
+
|
|
64
|
+
Quantik is a 4×4 board game with a group-wise placement rule: you may not
|
|
65
|
+
place a shape in a row, column or 2×2 zone where your *opponent* already has
|
|
66
|
+
that shape, and you win by completing a line of four different shapes in
|
|
67
|
+
either colour. It is small enough to solve exactly, which is what makes it a
|
|
68
|
+
useful place to ask whether an architectural prior is worth having — the
|
|
69
|
+
ground truth is available to check the answer against.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install 'quantik-models[torch,hub]'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from quantik_models import hub
|
|
77
|
+
from quantik_models.env import fastboard as fb
|
|
78
|
+
|
|
79
|
+
evaluator = hub.load_evaluator("cpool") # downloads and verifies the weights
|
|
80
|
+
|
|
81
|
+
boards = fb.empty_boards(1) # (1, 8) uint16
|
|
82
|
+
legal = fb.legal_masks(boards) # (1, 64) bool
|
|
83
|
+
policy, value = evaluator(boards, legal) # masked priors, value in [-1, 1]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Working *on* this package rather than with it: **[DEVELOPMENT.md](DEVELOPMENT.md)**.
|
|
87
|
+
|
|
88
|
+
## Install
|
|
89
|
+
|
|
90
|
+
| you want | install |
|
|
91
|
+
|---|---|
|
|
92
|
+
| the published models, on torch | `pip install 'quantik-models[torch,hub]'` |
|
|
93
|
+
| the published models, no torch | `pip install 'quantik-models[serve,hub]'` |
|
|
94
|
+
| to train your own | `pip install 'quantik-models[torch,onnx]'` |
|
|
95
|
+
| the library only | `pip install quantik-models` |
|
|
96
|
+
|
|
97
|
+
The base install is `numpy` and `quantik-core` and nothing else. torch is a
|
|
98
|
+
529 MB dependency and onnxruntime is 80 MB; neither is imposed on someone who
|
|
99
|
+
does not need it. The full table is in
|
|
100
|
+
[DEVELOPMENT.md](DEVELOPMENT.md#environment).
|
|
101
|
+
|
|
102
|
+
Python 3.12+.
|
|
103
|
+
|
|
104
|
+
## Getting the weights
|
|
105
|
+
|
|
106
|
+
The weights are not in the wheel. They are ~7 MB each, they carry a different
|
|
107
|
+
licence from the code, and they version independently of it — so
|
|
108
|
+
`load_evaluator` fetches them from the Hub on first use and reads them from
|
|
109
|
+
the Hugging Face cache (`$HF_HOME`, default `~/.cache/huggingface`) every time
|
|
110
|
+
after. **One network call, once per model, and never again.**
|
|
111
|
+
|
|
112
|
+
To fill that cache ahead of time — a container build, a machine that is about
|
|
113
|
+
to go offline, an air-gapped copy — use the fetch command. It needs neither
|
|
114
|
+
torch nor onnxruntime, so it runs before either is installed:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
quantik-models-fetch --all # or: quantik-models-fetch cpool attn
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Once a model is cached, everything works with no network at all.
|
|
121
|
+
|
|
122
|
+
Nothing else needs special attention. Every way this can fail raises
|
|
123
|
+
`hub.HubError` with the remedy in the message rather than a traceback through
|
|
124
|
+
`huggingface_hub`:
|
|
125
|
+
|
|
126
|
+
| what went wrong | what you get |
|
|
127
|
+
|---|---|
|
|
128
|
+
| offline, model already cached | it just works — the cache is used |
|
|
129
|
+
| offline, nothing cached | the cache path, and the `quantik-models-fetch` line to run while online |
|
|
130
|
+
| truncated download | re-fetched once automatically; a second failure names the cache to clear |
|
|
131
|
+
| typo in the model name | the four names that do exist |
|
|
132
|
+
| bad `revision` | a link to the repo's commit list |
|
|
133
|
+
| rate limited | that it clears on its own, and that logging in raises the limit |
|
|
134
|
+
|
|
135
|
+
`hub.resolve()` returns the commit the download actually resolved to, which is
|
|
136
|
+
what to record when you report a number — `revision="main"` is not a pin.
|
|
137
|
+
|
|
138
|
+
## The models
|
|
139
|
+
|
|
140
|
+
Four networks answering the same question in different ways, all
|
|
141
|
+
interchangeable because they agree on one contract:
|
|
142
|
+
|
|
143
|
+
input (B, 9, 4, 4) float32 tensor-board.v1, mover-relative
|
|
144
|
+
output (B, 64) policy logits action_index = shape * 16 + position
|
|
145
|
+
(B,) value in [-1, 1] +1 = good for the side to move
|
|
146
|
+
|
|
147
|
+
**Legality masking is applied outside every model**, using the same code path
|
|
148
|
+
in training and at inference — so no engine here can return an illegal move.
|
|
149
|
+
|
|
150
|
+
| model | Hub repository | IID top-1 | vs `minimax-d2` |
|
|
151
|
+
|---|---|---|---|
|
|
152
|
+
| **`cpool`** | [`quantik-cpool-c191-b6`](https://huggingface.co/brpoplpush/quantik-cpool-c191-b6) | **0.9893** | **49.4%** |
|
|
153
|
+
| `attn` | [`quantik-attn-d192-b6`](https://huggingface.co/brpoplpush/quantik-attn-d192-b6) | 0.9879 | 43.1% |
|
|
154
|
+
| `resnet` | [`quantik-resnet-c128-b6`](https://huggingface.co/brpoplpush/quantik-resnet-c128-b6) | 0.9701 | 36.5% |
|
|
155
|
+
| `mlp` | [`quantik-mlp-h455-b4`](https://huggingface.co/brpoplpush/quantik-mlp-h455-b4) | 0.9516 | 31.9% |
|
|
156
|
+
|
|
157
|
+
`minimax-d2` is a fixed two-ply alpha-beta search — the only opponent whose
|
|
158
|
+
strength does not move with the field, and so the only column that answers
|
|
159
|
+
"is any of this good" rather than "which of these is better". `cpool` playing
|
|
160
|
+
raw policy, one forward pass per move, is even with it. **Full numbers, the
|
|
161
|
+
four measurements that disagree, and what not to conclude from them:
|
|
162
|
+
[`docs/models.md`](docs/models.md).**
|
|
163
|
+
|
|
164
|
+
> **The weights are CC BY-NC 4.0; this package is MIT.** A commercial
|
|
165
|
+
> application may use the pipeline, the rules engine and the evaluation
|
|
166
|
+
> harness freely, and may not ship these weights. Train your own and they
|
|
167
|
+
> are yours.
|
|
168
|
+
|
|
169
|
+
### `cpool` — the constraint model
|
|
170
|
+
|
|
171
|
+
Quantik's rule is group-wise, not spatial: twelve overlapping groups (4 rows,
|
|
172
|
+
4 columns, 4 zones), every cell in exactly three. Each block pools the sixteen
|
|
173
|
+
cell tokens into those groups, transforms them there, and scatters back.
|
|
174
|
+
|
|
175
|
+
```mermaid
|
|
176
|
+
flowchart LR
|
|
177
|
+
IN["board<br/>(B,9,4,4)"] --> TOK["16 cell tokens<br/>Linear 9→C"]
|
|
178
|
+
TOK --> BLK
|
|
179
|
+
subgraph BLK["constraint block × B"]
|
|
180
|
+
direction LR
|
|
181
|
+
N["LayerNorm"] --> POOL["pool to 12 groups<br/>4 rows · 4 cols · 4 zones"]
|
|
182
|
+
POOL --> KIND["+ kind embedding<br/>line | zone"]
|
|
183
|
+
KIND --> GM["group MLP"]
|
|
184
|
+
GM --> SC["scatter to member cells"]
|
|
185
|
+
SC --> MG["merge with cell features<br/>+ FFN, residual"]
|
|
186
|
+
end
|
|
187
|
+
BLK --> PH["policy head<br/>Linear C→4 per cell<br/>transpose → 64"]
|
|
188
|
+
BLK --> VH["value head<br/>mean over cells · MLP · tanh"]
|
|
189
|
+
PH --> POL["policy logits (B,64)"]
|
|
190
|
+
VH --> VAL["value (B,)"]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
[`docs/architecture-constraint-pool.md`](docs/architecture-constraint-pool.md)
|
|
194
|
+
|
|
195
|
+
### `attn` — the same bet without the prior
|
|
196
|
+
|
|
197
|
+
Transformer encoder over the sixteen cells, told *nothing* about rows,
|
|
198
|
+
columns or zones. It is the test of whether `cpool`'s explicit wiring was
|
|
199
|
+
necessary: on policy accuracy it ties, on the value head it does not.
|
|
200
|
+
|
|
201
|
+
[`docs/architectures.md`](docs/architectures.md) ·
|
|
202
|
+
[`docs/attention-negative-result.md`](docs/attention-negative-result.md)
|
|
203
|
+
|
|
204
|
+
### `resnet` — the incumbent
|
|
205
|
+
|
|
206
|
+
Convolutional residual trunk, and the architecture every hyperparameter here
|
|
207
|
+
was originally chosen for. 99.2% of its parameters are the trunk.
|
|
208
|
+
|
|
209
|
+
[`docs/architecture-resnet.md`](docs/architecture-resnet.md)
|
|
210
|
+
|
|
211
|
+
### `mlp` — the control
|
|
212
|
+
|
|
213
|
+
Throws spatial structure away entirely: 144 flat features through dense
|
|
214
|
+
residual blocks. It exists to make "convolution is worth having on a 4×4
|
|
215
|
+
board" falsifiable rather than assumed. It loses, so the spatial prior is
|
|
216
|
+
real.
|
|
217
|
+
|
|
218
|
+
[`docs/architecture-mlp.md`](docs/architecture-mlp.md)
|
|
219
|
+
|
|
220
|
+

|
|
221
|
+
|
|
222
|
+
The dashed lines are two architectures trained at `2e-3`, the rate the ResNet
|
|
223
|
+
was tuned for and everything added later inherited by silence. `attn` did not
|
|
224
|
+
learn at all at that rate; `cpool` converged perfectly well, to a lower place.
|
|
225
|
+
A single-rate comparison cannot tell either of those apart from "this
|
|
226
|
+
architecture is worse" — which is how three published conclusions here turned
|
|
227
|
+
out to be hyperparameter artifacts.
|
|
228
|
+
[`docs/learning-rate-sweep.md`](docs/learning-rate-sweep.md).
|
|
229
|
+
|
|
230
|
+
## Playing against them
|
|
231
|
+
|
|
232
|
+
The play service serves the board and the models on one port, and records
|
|
233
|
+
finished games:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
pip install 'quantik-models[serve,hub]'
|
|
237
|
+
quantik-models-play --models staging
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
It prints a LAN address to open on a phone. `--no-store` opens no database,
|
|
241
|
+
which is the configuration the public container runs.
|
|
242
|
+
[`docs/play-service.md`](docs/play-service.md).
|
|
243
|
+
|
|
244
|
+
## Training your own
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
pip install 'quantik-models[torch,onnx]'
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
# check the assumptions before a long run (~1 min/arch)
|
|
252
|
+
python -m quantik_models.train.preflight --preset medium --epochs 16
|
|
253
|
+
|
|
254
|
+
# train to convergence: --epochs is the cap, --patience the rule
|
|
255
|
+
python -m quantik_models.train.supervised --arch cpool --preset medium \
|
|
256
|
+
--corpus runs/oracle/corpus/exact-sampled.npz --name my-run \
|
|
257
|
+
--epochs 60 --patience 5
|
|
258
|
+
|
|
259
|
+
# regenerate every published number for it
|
|
260
|
+
scripts/evaluate_lineup.sh runs/eval/today cpool=runs/train/my-run/best
|
|
261
|
+
|
|
262
|
+
# stage it as a Hugging Face model repository (writes files; uploads nothing)
|
|
263
|
+
quantik-models-hf-stage runs/train/my-run/best staging/my-model
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Training writes `weights.safetensors`, `model.onnx`, a
|
|
267
|
+
`model-checkpoint.v1` `manifest.json` and a training report. Corpora, the
|
|
268
|
+
label strategy and the retrain/fine-tune path — including freezing part of a
|
|
269
|
+
network — are in [`docs/`](docs/README.md).
|
|
270
|
+
|
|
271
|
+
## Documentation
|
|
272
|
+
|
|
273
|
+
[`docs/README.md`](docs/README.md) is the reading order. The four to start
|
|
274
|
+
with:
|
|
275
|
+
|
|
276
|
+
| | |
|
|
277
|
+
|---|---|
|
|
278
|
+
| [`docs/models.md`](docs/models.md) | the published models: how to load one, what the numbers mean, what not to conclude |
|
|
279
|
+
| [`docs/decisions/0001-architecture-lineup.md`](docs/decisions/0001-architecture-lineup.md) | which architectures were trained, which six were declined, and the methodology |
|
|
280
|
+
| [`docs/benchmarks.md`](docs/benchmarks.md) | the figures, and what each does and does not establish |
|
|
281
|
+
| [`docs/oracle-benchmark.md`](docs/oracle-benchmark.md) | the field against a fixed classical engine |
|
|
282
|
+
|
|
283
|
+
## Related
|
|
284
|
+
|
|
285
|
+
- [`quantik-core`](https://pypi.org/project/quantik-core/) — the rules
|
|
286
|
+
engine, QFEN, bitboards and the exact solver. Also on
|
|
287
|
+
[crates.io](https://crates.io/crates/quantik-core).
|
|
288
|
+
- [The models on the Hub](https://huggingface.co/brpoplpush) — weights,
|
|
289
|
+
ONNX graphs and model cards.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT — see [LICENSE](LICENSE). The published **weights** are CC BY-NC 4.0 and
|
|
294
|
+
are not distributed with this package.
|