Hivemind — Bughouse TwinBoard-S
A small, fast network for Hivemind, a UCI engine for Bughouse chess — the four-player variant played on two boards, where captured pieces are passed to your partner. The network drives a Monte Carlo Graph Search (MCGS) that evaluates both boards jointly.
It was distilled from the 13.6 M-parameter RISEv3.3 network and then improved by self-play reinforcement learning. At 0.97 M parameters it searches about 3x as many nodes per second, and was stronger at 100 ms per move in our matches.
Files
| File | Purpose |
|---|---|
twin-s-noattn.onnx |
Latest promoted network — use this one |
twin-s-noattn-itN.onnx |
Every RL iteration's network (it0 = distilled, before RL), promoted or not |
Architecture
A small network that runs the same trunk on each board separately, with shared weights, and lets the
boards exchange information explicitly. RISE-style networks stack both boards as channels of one 8x8 image,
so every convolution mixes squares that have no spatial relationship. The twin design also makes the network
exactly symmetric under swapping the two boards (which is a symmetry of the game): swapping the input boards
swaps pi_a and pi_b and leaves value, WDL and moves-left unchanged.
| Architecture | TwinBoardNet, size twin-s, no attention, no ECA, value head sees A + B and |A − B| |
| Trunk | 8 bottleneck residual blocks per board, 128 channels (operating width 256) |
| Cross-board exchange | 2 pooled scale-and-shift exchanges (after blocks 3 and 6) |
| Parameters | 0.97 M (ONNX, BatchNorm folded) · 1.25 M (checkpoint) |
| ONNX | opset 18 · IR version 8 · dynamic batch · FP32 weights (the engine builds FP16 TensorRT plans) |
| Input representation | version 3 (same planes as bughouse-rise-v3) |
How it was trained
- Distillation (iteration 0): trained on 30 M positions labelled by the RISEv3.3 network (policy over all legal moves, value, WDL, moves-left), with targets averaged over both board orders because the teacher is not swap-symmetric. Dropping the cross-board attention layer gave about +32 % engine search speed, and this variant beat the attention versions at equal time.
- Self-play reinforcement learning: each iteration plays 100,000 games with the current network (800 nodes ±5 % per move, Dirichlet noise and temperature for exploration, no resignation), then trains from the previous iteration's weights on the visit-count policies, game results (WDL) and moves-left. From iteration 2 on, training replays the previous three iterations' games alongside the new ones (1.5 passes over new games, 0.5 over each older iteration) to avoid forgetting. A new network replaces the current one if it scores at least 50 % in a 160-game match at 100 ms per move.
Strength
160-game matches at 100 ms per move on an RTX 4070, both sides at about 72–77 k nodes per second. Each network is compared with the previous one and with the fixed distilled network (iteration 0), whose results are on the same scale across iterations.
| Iteration | vs previous | vs iteration 0 (Elo, 95 % CI) |
|---|---|---|
| 1 | 90–64–6 (+57) | +57 (+22 to +93) |
| 2 | 79–78–3 (+2) | +46 (+9 to +83) |
| 3 | 80–76–4 (+9) | +68 (+31 to +107) |
twin-s-noattn.onnx is always the latest promoted iteration (see Files); each upload's commit
message names the iteration and its match result.
ONNX signature
The same inputs and outputs as bughouse-rise-v3, so Hivemind loads either network with --model. Opset 18 · IR version 8 · dynamic batch dimension.
Input
| Name | Shape | Notes |
|---|---|---|
data |
[batch, 74, 8, 8] |
74 input planes encoding both boards, pockets, and side-to-move context |
Outputs
| Name | Shape | Notes |
|---|---|---|
value |
[batch, 1] |
Scalar position evaluation |
pi_a |
[batch, 4672] |
Policy logits, board A |
pi_b |
[batch, 4672] |
Policy logits, board B |
wdl_out |
[batch, 3] |
Win / draw / loss head |
moves_left |
[batch, 1] |
Plies-to-end head |
The two policy heads are what make this a bughouse network rather than two independent chess networks:
the body reasons over both boards at once and emits a move distribution for each. The 4672 policy size is
the standard AlphaZero chess move encoding.
Usage
./engine/build-ninja/hivemind --model models/twin-s-noattn.onnx
import numpy as np, onnxruntime as ort
sess = ort.InferenceSession("twin-s-noattn.onnx")
planes = np.zeros((1, 74, 8, 8), dtype=np.float32) # your encoded position (version 3 planes)
value, pi_a, pi_b, wdl, moves_left = sess.run(None, {"data": planes})
The engine builds FP16 TensorRT plans from the ONNX at runtime; prebuilt plans are not published because they are specific to a GPU, TensorRT version and batch size.
License
MIT, matching the Hivemind repository.