whestbench.

Validate, run, and package

Sourced from whest-starterkit @ 96e308c.

Validate, run, and package

โ† Documentation

๐ŸŽฏ When to use this page

Use this page for the standard local participant loop.

๐Ÿš€ Do this now

Validate estimator loading and output contract:

whest validate is a fast sanity check using a small fixed MLP (width=4, depth=2). It verifies loading, that setup(context) finishes inside the graded 5 s cap, output shape, and value finiteness, not full behavioral or performance correctness. Always follow with whest run for realistic tests.

uv run whest validate --estimator estimator.py

Run local scoring (recommended default runner):

uv run whest run --estimator estimator.py

whest run defaults to --runner local for fast iteration.

Run against the published evaluation dataset on HuggingFace (skips sampling; much faster for repeated runs, no local bake needed):

uv run whest run \
    --estimator estimator.py \
    --dataset hf://aicrowd/arc-whestbench-public-2026@v2-phase2
# auto-resolves to the `mini` split (100 MLPs, cached after the first call)

โš  Check the current revision tag before relying on this command; see Use Evaluation Datasets for the current coordinates. whest run without --dataset generates MLPs locally and needs none.

Or bake a custom local dataset once and reuse it:

uv run whest dataset bake --output ./my-eval --n-mlps 10 --n-samples 100_000 --width 1024 --depth 16
# ~80 s and ~670 MB for 10 MLPs at 1024x16 on a laptop; sampling time scales
# linearly in --n-samples
uv run whest run --estimator estimator.py --dataset ./my-eval

See Use Evaluation Datasets for details.

Run the way the grader does, with an isolated subprocess and the memory cap enforced:

uv run whest run --estimator estimator.py --runner subprocess

Under the default --runner local the 8 GB limit is advisory only; the CLI says so.

Run with machine-readable output:

uv run whest run --estimator estimator.py --format json

--json still works as an alias, but --format rich|plain|json is the canonical output selector across the CLI.

Package submission artifact (single file, the common case):

uv run whest package --estimator estimator.py --output ./submission.tar.gz

A file argument ships only that file; a folder argument (--estimator .) ships every file in that folder. Either way whest package previews exactly what will be submitted and (in folder mode) asks for confirmation before writing; to skip the prompt in CI or scripts, pass --yes / -y. Credential files (.env, *.pem, keys, โ€ฆ) are never included. The 50 MiB / 50-file caps apply; use .whestignore to exclude scratch or large artefacts.

Shipping helper modules or precomputed weights? Keep them in the folder and package the folder; they ship by being present, no extra flags. Data files (weights, lookup tables, precomputed artifacts) are explicitly permitted; third-party packages are not. Vendoring numpy, scipy, a BLAS build, or any compiled kernel into your folder is prohibited by the Phase 2 rules and disqualifiable (not merely unavailable), so do that work offline and ship the result as data. See Allowed Code and Ship Weights and Multi-File Submissions.

Useful whest run flags

These all appear in whest run --help. Reach for them when:

FlagReach for it whenโ€ฆ
--seed NDeterministic comparison between two estimator versions. Pin the seed and the same MLPs, the same per-MLP mlp.seed values, and the same SetupContext.seed are used across runs. Also accepted by whest validate (seeds the validation setup(ctx) call). With --dataset, the dataset supplies the per-MLP seeds and --seed controls ctx.seed only.
--n-samples NGround-truth Monte-Carlo samples per MLP, used only for --dataset-less runs; the default is 200,000 (whestbench.cli._default_contest_spec). With --dataset the flag is ignored: the published Phase 2 dataset bakes n_samples = 1_000_000_000 per MLP. Drop to --n-samples 5000 for a ~9x faster local sanity check (measured 12.9 s โ†’ 1.4 s for --n-mlps 1 at 1024ร—16); raise back up before drawing real conclusions. whest dataset bake has no --n-samples default: it is a required flag; see Use Evaluation Datasets.
--n-mlps NDefault 10 without --dataset. With --dataset it defaults to the whole split (100 for mini, 1000 for full) and is clamped to the split size, so pass it explicitly when you want a short dataset run. Drop to 3 while iterating to cut runtime to about a third; raise to 20+ when you're trying to reduce noise on a close score.
--flop-budget NDeliberately not matching the grader. Phase 2 grades each MLP against B_m = 2,199,023,255,552 FLOPs (2^41), and what the budget caps is C_m = F_m: your analytical FLOP count, nothing else. Default 2199023255552, the Phase 2 budget, so a plain run applies it without this flag. Bump it to 1e13 to confirm an algorithm idea isn't budget-starved before you optimize for budget, or drop it to an earlier round's value (2.72e11 for Phase 1, 6.8e10 for v1-warmup; see Competition Rounds). The value you were actually scored under is run_config.flop_budget in the run's own report.
--profileEmits a per-namespace FLOP/time breakdown so you can see where your estimator spends the budget.
--show-diagnostic-plotsRenders convergence and per-layer error plots inline (terminal-friendly). Pairs well with --profile.
--max-threads NPin the BLAS thread pool size so wall_time_s is comparable across machines. Useful when triaging a "fast on my laptop, slow in CI" report. Reach for --max-threads 1 as your conservative check: the rules guarantee no particular evaluation hardware, so anything that finishes inside the 120 s per-MLP cap locally only because it is multi-threaded can exceed the cap on the grader. (This pins the flopscope backend's threads, which is a timing knob only. Your own estimator may not start threads at all; see the Phase 2 allowed-code rules in the Pre-Submission Checklist. On the grader the solution process gets 2 pinned vCPUs and the flopscope backend 14.) See Is scoring hardware-dependent?.
--detail {raw,full}raw strips Rich formatting (handy for tee-ing logs); full adds the per-MLP raw arrays.
--wall-time-limit SCap each predict() call's wall time. Default 120.0, the Phase 2 cap, so you do not pass this to apply it; pass it only to go stricter while chasing a numerical edge case that hangs. Confirm the value you ran under in run_config.wall_time_limit_s.
--setup-timeout STesting that setup() fits the graded budget. Default 5.0, the graded cap, and the only limit whose breach fails the entire submission rather than one MLP. whest validate times setup() against the same 5 s cap, though it has no flag of its own. Lower it (--setup-timeout 2) to leave headroom for a slower grader if you load weights in setup(). Confirm the value you ran under in run_config.setup_timeout_s. See Ship Weights.
--residual-wall-time-limit SCap time spent outside flopscope ops (Python plumbing, loops, control flow). Default 0.4, already the graded cap, so a plain whest run already gates you exactly as the live round does; exceed it and that MLP's prediction is replaced with zeros. Residual time is not priced into your score any more, and it is not a place to compute: meaningful work outside flopscope ops is disqualifiable.
--debug + --fail-fastFirst exception โ†’ halt + raw traceback. Combine for the fastest "what broke?" loop.

โœ… Expected outcome

  • validate passes,
  • run produces a score report,
  • package creates a .tar.gz artifact.

โš ๏ธ Common first failure

Symptom: run fails after validate passed.

A plain whest run keeps going after a per-MLP failure and collects the messages into one table at the end:

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Estimator Errors โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ 2 of 2 MLP(s) raised during predict.                                         โ”‚
โ”‚ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ โ”‚
โ”‚ โ”ƒ MLP                โ”ƒ Code          โ”ƒ Message                             โ”ƒ โ”‚
โ”‚ โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ โ”‚
โ”‚ โ”‚ megan-chang (#0)   โ”‚ PREDICT_ERROR โ”‚ index 17 is out of bounds for axis  โ”‚ โ”‚
โ”‚ โ”‚                    โ”‚               โ”‚ 0 with size 16                      โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚ Rerun with --debug to include full tracebacks; --fail-fast to stop on first  โ”‚
โ”‚ error.                                                                       โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Use this escalation flow:

  1. Stop at the first failure and get the raw traceback:
uv run whest run --estimator estimator.py --fail-fast --debug
  1. If it only breaks under isolation, reproduce it the way the grader runs it:
uv run whest run --estimator estimator.py --runner subprocess --fail-fast --debug

For runner modes, see Stage 3: Run Locally, Stage 4: Subprocess Runner, and the Debugging Checklist.

โžก๏ธ Next step

On this page