tune design
Design goal
Auto-tuning picks a configuration (block sizes, kernel variant, layout) by
measuring candidates. Done naively it overfits: the “winner” is often the
candidate whose noise happened to be favourable, on the shapes that happened to
be measured. tune provides the policy pieces that prevent this, robust
scores, practical ties, confirmation and holdouts, while leaving the building
and running of candidates to the application, where they can be validated and
measured like any other benchmark.
Mathematical background
Scores
A candidate measured times has samples . Its score is the median of the usable samples (finite, non-negative), for the robustness reasons derived in the stats design. A secondary metric (workspace bytes, code size) breaks ties.
The winner’s curse
Let be the measured score of candidate with true cost and zero-mean noise. Choosing the minimum of the measurements is biased downward:
because for the truly best , and taking
expectations gives . With many
candidates of similar cost, the selected one is more likely to be lucky than
good. Two remedies follow, and TuningBudget names both: re-measure the
finalists with fresh confirmation_samples (the new noise is independent of
the selection, so the confirmed score is unbiased), and evaluate the winner on
a holdout it was not selected on.
Practical ties
select_best with threshold forms the tie set
and returns the element of with the best secondary value, then the smallest id. The rule is order independent: is defined by values only, and the second step is the minimum of a total order (secondary, then id) on , which is unique when ids are unique. So permuting the input cannot change the result.
Pareto dominance
With both metrics minimized, dominates () when , and . The frontier is . Sorted by primary cost, the frontier has strictly decreasing secondary cost: if and then , a contradiction, so . Points with equal primary cost on the frontier must also have equal secondary cost. Every point off the frontier is dominated by a point on it (dominance is a strict partial order on a finite set, so every chain ends in a minimal element).
Random subsets of a large space
seeded_order sorts candidates by a seeded 64-bit FNV-1a hash of their ids,
which acts as a pseudo-random permutation. Take its first candidates. If
the ids are unrelated to quality, every candidate is equally likely to land in
the prefix, and the probability that the prefix contains at least one candidate
from the best fraction of the space is
already gives for the top 5 %. This is the classical argument for random search over grids.11 J. Bergstra and Y. Bengio, “Random search for hyper-parameter optimization”, JMLR 13, 2012.
Design decisions
Policy here, effects in the application
Problem. Building a candidate may mean compiling a kernel; running it must be
validated and timed under a protocol. Choice. tune takes scores as input
and never runs anything; BuiltCandidate carries a runner.Implementation.
Why. Tuning measurements then go through the same validation, calibration
and event stream as every other benchmark, and the tuning policy is testable
with made-up numbers.
Median scores
score_samples takes the median of usable samples and marks a candidate with
no usable sample invalid, so a candidate cannot win because a broken
measurement returned 0 or NaN.
Exhaustive search over a bounded prefix
exhaustive_scores scores the first budget candidates of the enumeration
and records a BuildEvent for each, including rejected ones. Combined with
seeded_order, the prefix is a reproducible random subset; with the natural
order and a large budget, it is a full grid search. The policy string
global:<id> names a single global winner; finer policies (per shape,
Pareto) are built with select_best, pareto_frontier and
@model.DeploymentPolicy.
Adaptive confirmation
confirmation_count multiplies the base confirmation count by 1, 2 or 3 as the
relative uncertainty crosses 5 % and 20 %, clamped to the budget. Noisy
finalists get more samples, quiet ones do not waste time.
Correctness and invariants
select_bestreturnsNoneexactly when no score is usable; otherwise its result is usable, within the threshold of the fastest, and independent of input order (derived above).pareto_frontierreturns only usable, non-dominated scores, sorted by primary, secondary, id.exhaustive_scoresexamines at mostbudgetcandidates and calls the score callback only for valid ones.seeded_orderis a permutation of its input that depends only on the ids and the seed.confirmation_countlies in .
Alternatives rejected
- Bayesian optimization or evolutionary search. Effective, but needs a
model of the space and makes results harder to reproduce; the hooks
(
neighbors,seeded_order) allow a user-written search. - Mean scores. One preempted run would decide.
- Selecting the raw minimum. Subject to the winner’s curse.
Boundaries
- No candidate is built, run or validated here.
TuningBudget,TuningObjectiveandHoldoutPlanare data; no function enforces them.CandidateSpace.neighborsis not used by any function in the package.exhaustive_scoresdoes not useseeded_orderitself; reorder the space first if you want a random subset.
Footnotes
-
J. Bergstra and Y. Bengio, “Random search for hyper-parameter optimization”, JMLR 13, 2012. ↩