SnapJudge

Non-autoregressive System-1 decision model for games. Give it a game state (tic-tac-toe board, snake grid, or temple-run obstacle as text or JSON) and typed questions; it returns typed answers with calibrated probabilities in a single forward pass on T4 (see Speed below). Inspired by convaiinnovations/laya: same architecture family (encoder + option-marker scorer + act head) and same training principle (RLCD — reinforcement learning against strictly proper scoring rules, so honest probabilities maximise reward). It never generates text, so there is nothing to parse and nothing to hallucinate.

Quickstart

pip install torch transformers safetensors huggingface_hub numpy
git clone https://huggingface.co/Brutalsky111/Snapjudge
export PYTHONPATH=$PYTHONPATH:$(pwd)/Snapjudge   # repo root (provides `snapjudge/` package)
from huggingface_hub import snapshot_download
from snapjudge.agent import load
from snapjudge.router import GameRouter
from snapjudge.data_gen import questions_for

local = snapshot_download("Brutalsky111/Snapjudge")  # or git-clone path ./Snapjudge
router = GameRouter(agent=load(local))

# 1. tic-tac-toe: X can win immediately with cell2
state = {"game": "tictactoe",
         "board": ["X", "X", " ", "O", "O", " ", " ", " ", " "],
         "player": "X", "board_str": "XX.OO...."}
res = router.predict(state, questions_for("tictactoe"))
print(res["answers"]["next_move"]["choice"])   # -> cell2
print(res["routing"])                          # -> {'model': 'joint', 'reason': 'game=tictactoe ...'}

# 2. snake: head (5,5), food to the right
res = router.predict(
    {"game": "snake", "head": [5, 5], "body": [[5, 5], [5, 6]], "food": [7, 5], "grid": [10, 10]},
    questions_for("snake"))
print(res["answers"]["direction"]["choice"])   # -> right

# 3. temple-run: gap, near, fast -> jump, urgency 2.0, crash imminent
res = router.predict(
    {"game": "templerun", "obstacle": "gap", "lane": "mid", "distance": "near", "speed": "fast"},
    questions_for("templerun"))
print(res["answers"]["action"]["choice"])      # -> jump

Every result carries routing metadata (res["routing"]) explaining which game was detected and why.

Decision primitives

Primitive Output Game use
choice Top label + per-option probs + confidence next_move (9 cells), direction (4), action (5)
score Expected ordinal level + distribution danger / risk / urgency (3 levels each)
noul Calibrated P(true) must_block, will_die, game_over_soon

Architecture

  • Backbone: ModernBERT-base (149M, bidirectional, fully fine-tuned) + decision head trained from scratch: 2 transformer layers, option-marker scorer, act head. ~165M total.
  • Option markers: every option is scored at its own [MASK] token, softmaxed per question. New schemas need no retraining.
  • Format: [CLS] <type> instructions [SEP] [MASK] opt0 [MASK] opt1 … [SEP] state [SEP].
  • Budget: 256 tokens (head_max_len = 128); all questions in one call answered in one forward pass.

Training (RLCD, like Laya)

  1. Supervised CE pretrain (3 epochs) on 5,400 synthetic games (16,200 typed decisions) with exact-solver labels: minimax (tic-tac-toe), collision + Manhattan-to-food (snake), obstacle table (temple-run).
  2. RLCD fine-tune (2 epochs): zero-mean Gaussian noise on logits (exploration), reward = log score + 0.5·spherical + RPS for ordinal questions; direct proper-score ascent with CE anchor.
  3. Calibration: one temperature per (question type, option-count bucket) refit on held-out data.

Benchmarks (held-out 600 games / 1,800 decisions, T4)

SnapJudge performance

Game Accuracy (strict) Fresh re-check, tie-aware*
temple-run (action/urgency/over) 1.000 1.000
snake (direction/risk/trapped) 0.939 0.998
tic-tac-toe (move/danger/block) 0.772 0.848
overall 0.905, ECE 0.049 0.949, ECE 0.096

* Strict = argmax must equal the single stored label. Tie-aware = any optimal move counts (9-way tic-tac-toe and tied snake positions share target mass across all minimax-optimal moves). Strict choice acc on fresh seeds is 0.79; tie-aware is 0.95. Chart above shows seed 999/123.

Training curve: 0.824 → 0.862 → 0.876 (CE) → 0.882 → 0.905 (RLCD); ECE 0.060 → 0.042 after first RLCD epoch.

Speed (Tesla T4, fp16)

Call Latency
3 questions, one state (warm, T4 fp16) ~36–38 ms (p50)
10 states batched (30 questions, one forward pass) 141 ms total (14 ms/state)
First call (cold, CUDA warmup) ~700 ms, one-time

Reproduce: python3 bench.py --model . --n 200 --seed 999 (see bench.py).

Batch, validation, server, play

# batch: argmax-identical to predict(), probs within fp16 rounding
outs = router._agents["joint"].predict_batch([s1, s2, s3], [q1, q2, q3])
outs = router.predict_batch([{"state": s1, "questions": q1}, {"state": s2, "questions": q2}])

Malformed questions raise ValueError naming the question (unknown type, empty instructions, choice with <2 options, score criteria not a list, noul keys not true/false). Serve: python3 serve.py --model . --port 8000 → POST /v1/systemone {state, questions}. Play: python3 play_ttt.py --human O.

Honest limits

  • Labels come from exact solvers on synthetic positions — human play distributions will differ; fine-tune on your own logs before trusting deployment.
  • 9-way tic-tac-toe choice (0.77) is the weakest head; narrow-board endgames dominate errors.
  • Single joint checkpoint for all three games; no per-game experts yet (GameRouter supports attaching them).
  • Probabilities are temperature-fitted on synthetic held-out data — refit on your domain before using confidence gating.

Files

README.md               # this model card
snapjudge_perf.png      # performance chart (see Benchmarks)
snapjudge_config.json   # encoder, head, context budgets, temperatures
model.safetensors       # 656 MB weights
tokenizer/              # ModernBERT tokenizer snapshot
metrics.json            # held-out metrics (original split)
snapjudge/              # runtime: common.py, agent.py, router.py, data_gen.py, train.py
example.py              # runnable quickstart
bench.py                # fresh-data accuracy/ECE/latency check
serve.py                # stdlib POST /v1/systemone server
play_ttt.py             # human vs model tic-tac-toe
make_chart.py           # regenerates snapjudge_perf.png
requirements.txt

License & credit

Apache 2.0. Architecture and RLCD methodology inspired by Laya (Convai Innovations, Apache 2.0). Backbone: ModernBERT-base.

Downloads last month

-

Downloads are not tracked for this model. How to track
Safetensors
Model size
0.2B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for Seedyai/Snapjudge

Finetuned
(1492)
this model