Python API¶
The reference for the atune package: every class, every method and every
factory, with the signatures and defaults the extension module actually
carries. It is generated from the installed module, so it cannot describe a
binding that is not there.
The same objects are documented one layer down in the Rust API —
atune.Study is a handle on atune::Study. Both surfaces share one
implementation, and the parity gate checks that
they produce bit-identical results.
The wheel uses a mixed package: the import shim and native extension sit beside
the generated typing files atune/__init__.pyi, atune/samplers.pyi,
atune/schedulers.pyi, atune/pb2.pyi, and the atune/py.typed marker.
Study.trials_dataframe() returns a column mapping: numeric columns are NumPy
arrays, while state and categorical columns are Python lists. NumPy is optional;
install atune[dataframe] for this operation. Import and optimization do not load it.
seed= on a sampler raises
atune.samplers.Random(seed=…) and atune.samplers.Tpe(seed=…) keep
Optuna's keyword in their signatures, and passing it raises AtuneError
naming the knob that does work. Determinism comes from the study seed —
atune.create_study(seed=…) — from which every per-trial sampler, scheduler
and objective seed is derived, so a per-sampler seed has nothing left to
govern. It raises rather than being ignored because a keyword that is
accepted and does nothing makes the script run and mean something else.
atune¶
atune
¶
Public Python package for the native :mod:atune.atune extension.
__version__ = '0.1.0'
module-attribute
¶
str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.
AtuneError
¶
Bases: Exception
Base class for every error raised by the atune bindings.
FrozenTrial
¶
An immutable snapshot of a finished (or in-flight) trial, as Python sees it.
Mirrors atune_facade::trial::FrozenTrial. Categoricals cross the storage
boundary by label, never by index (see Search
spaces); reading one back
resolves that label to a Python scalar of the type it was suggested as, under
the rule params documents.
categorical_labels
property
¶
Stable categorical labels as {name: (choices, selected_label)}.
Unlike params, this read keeps storage labels
rather than typed scalar payloads. Rust-created histories may use a
custom label for a scalar, or several labels for the same scalar. The
Optuna reading adapter needs these exact labels to match file exports.
Boolean distributions are not categorical label sets and are omitted.
Returns a new dict and choice lists; inconsistent records raise.
constraints
property
¶
The declared constraint values, or None when this trial has no
constraint declaration.
datetime_complete
property
¶
When the trial finished, as a timezone-aware UTC datetime.datetime.
Optuna's datetime_complete, and None while the trial is unfinished. As
with datetime_start the value is aware
UTC. A pruned or failed trial has one too — it finished, it just did
not complete.
datetime_start
property
¶
When the trial was created, as a timezone-aware UTC datetime.datetime.
Optuna's datetime_start. None for a trial that has not started —
a waiting trial created by
enqueue and never claimed has no start time.
The value is aware, with tzinfo=datetime.timezone.utc: core records
an unambiguous epoch instant, and a naive value would invite reading it as
local time. Optuna's are naive local times, so a comparison against one of
those raises rather than silently comparing two different scales.
distributions
property
¶
The distribution each parameter was sampled from, as
dict[str, dict[str, Any]].
Recorded per trial, because a define-by-run space may differ from trial to
trial, and holding exactly the parameters params
holds.
Each value is atune's own description dict rather than a distribution
object: a "kind" naming the shape, plus what that shape carries.
{"lr": {"kind": "float", "low": 1e-05, "high": 0.1, "log": True, "step": None},
"n": {"kind": "int", "low": 1, "high": 8, "log": False, "step": 1},
"opt": {"kind": "categorical", "choices": ["adam", "sgd"]},
"amp": {"kind": "bool"}}
choices entries carry the exact tagged scalar types params gives
them; labels are never parsed to guess a type.
This is not Optuna's shape. Optuna returns
dict[str, BaseDistribution] — FloatDistribution/IntDistribution/
CategoricalDistribution objects with attribute access (dist.low),
single(), to_external_repr() and pickling. atune has no Python
distribution classes and does not invent them here, so code that reaches
for an attribute needs dist["low"] instead. The keys, the parameter names
and the meaning of each bound are the same.
duration
property
¶
How long the trial took, as a datetime.timedelta, or None unless it
has both a start and a finish.
Optuna's duration. Computed as
datetime_complete - datetime_start — the subtraction of the two objects
this class hands out, so the three accessors cannot drift apart, and so no
millisecond arithmetic of ours can overflow.
error
property
¶
The failure message for a failed trial, else None. Preserved on
purpose — a failed trial keeps the most interesting data a run produces.
intermediate_values
property
¶
The intermediate reports as a dict[step, value].
Optuna's spelling, and the one to reach for when you want to look a step
up (trial.intermediate_values[10]) or ask which steps were reported
(.keys()). intermediates is the same
data as an ordered list[tuple[step, value]], kept because it preserves
report order — which a dict built from it does not promise beyond
insertion order — and because it is the shape the rest of this binding's
reports use.
A step reported twice keeps its last value here, as any dict build would; the list keeps both.
For a multi-objective trial (any report carrying more than one value) each
value is a list[float], exactly as in intermediates: the shape is
chosen once per trial, so the dict is dict[int, float] or
dict[int, list[float]] and never a mixture. Taking a single component
instead would keep the annotation shorter by silently dropping the other
objectives, which is the trade this binding does not make.
intermediates
property
¶
The intermediate reports as a list of (step, value) tuples.
For a single-objective trial each entry is (int, float); for a
multi-objective one (any report carrying more than one value) each entry
is (int, list[float]), so the list has a single, consistent shape.
This is the report-order view, and the shape the rest of this
binding's reports use;
intermediate_values is the same data
as the dict[step, value] Optuna calls by that name.
last_step
property
¶
The largest reported step, or None if the trial reported nothing.
The last step, not the last report: a trial that reported steps out of order still answers with the highest one, which is what "how far did this trial get?" asks.
number
property
¶
The per-study trial number — the determinism key.
params
property
¶
The sampled parameters as a dict.
A parameter reads back as the type it was suggested as: suggest_float
gives a float, suggest_int an int, suggest_bool a bool, and
suggest_categorical("n", [16, 32, 64]) the int 32 — the same object
type the objective received — so Model(**best_trial.params) is safe.
A categorical stores a stable label plus a tagged scalar payload. Reads use that payload without parsing the label, so mixed scalar lists retain each entry's type and numeric-looking strings remain strings. Old untagged string arrays remain readable as strings; their original source types cannot be recovered.
state
property
¶
The trial's life-cycle state, as an atune.TrialState
member.
Each member is the lowercase string this accessor has always returned
(waiting/running/paused/complete/pruned/failed), because
TrialState subclasses str — so trial.state == "complete" and
trial.state == atune.TrialState.COMPLETE are both true, and code written
either way keeps working. Returning the member rather than a bare string
is what makes the Optuna reading work at all.
user_attrs
property
¶
User-owned JSON metadata attached to this trial.
value
property
¶
The single objective value, or None if the trial has none yet or is
multi-objective (use values).
values
property
¶
Every objective value, or None if the trial has none yet.
LedgerEntry
¶
One trial's line of a ResourceLedger, an entry of
Study.resource_ledger.
age
property
¶
The resource trained since initialization or the last restart.
evaluations
property
¶
Each stored evaluation stage ("configuration", "checkpoint",
"recipe") with its replicate count.
lineage
property
¶
The resource its lineage represents: its highest reported step, where
its recipe ends (0 before it reports).
number
property
¶
The trial's per-study number.
state
property
¶
The trial's state as a TrialState member: pruned, failed, and
replaced members are charged like any other.
trained
property
¶
The resource this trial trained itself and is charged for: its highest reported step less the step of the checkpoint it started from.
LineageNode
¶
One trial's place in the fork genealogy, an entry of Study.lineage.
fork_step
property
¶
The step of the checkpoint this trial started from, or None for a
root, a fresh restart, a child that started without a checkpoint, or a
trial recorded before fork steps were.
is_fork
property
¶
Whether this trial is a plain fork of another.
is_restart
property
¶
Whether this trial is a restart child of another.
number
property
¶
The trial's per-study number.
parent
property
¶
The number of the trial this one forked or restarted from, or
None for a root.
restart
property
¶
The restart mode, "fresh" or "shrink_perturb", or None for a
trial that is not a restart child.
value
property
¶
The trial's single objective value, or None (multi-objective or
unfinished).
Mabc
¶
The clustered sliding-window UCB policy for OnlineTuner.
OnlineTuner
¶
Storage-free, deterministic tuning of clustered numeric choices.
clusters maps names to candidate float values; its insertion order is the
cluster order returned by suggest. policy accepts Mabc or PbtLite.
Use suggest() and then observe(round_return) once per round. The callback-
driven drive_round and RNG-object round_rng methods have no Python
counterpart and are intentionally not bound.
clusters
property
¶
The number of clusters this tuner manages.
direction
property
¶
The optimization direction, as a StudyDirection member.
is_flush_boundary
property
¶
True when the round just observed lands on a flush-interval boundary,
the cue to snapshot() the tuner. Always False without flush_every.
rounds
property
¶
The number of rounds observed so far.
observe(round_return)
¶
Credits a round's return to the values from the latest suggest().
restore(snapshot)
¶
Restores a snapshot into a tuner with the same clusters and policy.
The snapshot's direction, seed, flush interval and progress replace
this tuner's own. Invalid, foreign or mismatched bytes raise
AtuneError and leave the tuner unchanged.
snapshot()
¶
Compact UTF-8 JSON bytes of the Rust StateBlob, including kind/version.
suggest()
¶
Returns an owned dictionary of the next round's values in cluster order.
OutcomeUncertainError
¶
Bases: AtuneError
Raised when a mutation was submitted but whether it committed is unknown. Do not retry it blindly, which can apply it twice: read the study's durable state first and resubmit only what is missing.
Paused
¶
Bases: AtuneError
Raised when a scheduler pauses the running trial; the trial is resumable, not finished.
PbtLite
¶
The deterministic scalar-perturbation policy for OnlineTuner.
Pruned
¶
Bases: AtuneError
Raised when a scheduler prunes the running trial. See Prune and schedule.
ReevalEntry
¶
One configuration's tune-vs-test comparison, an entry of a ReevalReport.
number
property
¶
The trial's per-study number.
overfit_gap
property
¶
The signed overfit gap: positive when tuning looked better than it held up under the held-out seeds.
test_value
property
¶
Its objective aggregated over the disjoint test seeds.
tune_value
property
¶
Its objective aggregated over the tune seeds — what the sampler saw.
ReevalReport
¶
The held-out-seed re-evaluation report (Study.reevaluate).
best
property
¶
The test-seed-ranked best trial's per-study number, or None if
nothing was re-evaluated or every re-evaluation diverged.
direction
property
¶
The study's single objective direction, "minimize" or "maximize".
entries
property
¶
One ReevalEntry per re-evaluated configuration, in tune-ranked order.
ResourceLedger
¶
The study's resource ledger (Study.resource_ledger).
RetryableError
¶
Bases: AtuneError
Raised when a concurrent worker won a race or the trial's lease was lost. Re-read state and retry: the error is transient, though replaying an arbitrary operation is not guaranteed safe.
Study
¶
A Python-callable study handle.
best_params
property
¶
The best trial's parameters as a dict, or None if the study has no best
trial.
best_trial.params in one step — Optuna's quickstart accessor. The None
rather than an exception is this binding's own style, the same answer
best_trial gives for the same situation (no
completed trial yet, or a multi-objective study, where there is no single
best across a Pareto front — read best_trials).
Note that Optuna raises ValueError here instead.
A categorical reads back as the type it was suggested as, under the rule
FrozenTrial.params documents, so
Model(**study.best_params) is safe.
best_trial
property
¶
The best trial so far, or None if the study has none.
None for a multi-objective study (there is no single best across a
Pareto front — read best_trials instead).
best_trials
property
¶
The best trials as a list[FrozenTrial].
For a multi-objective study this is the Pareto front; for a
single-objective study it is [best_trial], or [] when the study has no
trial with a value yet (mirroring Optuna's best_trials).
best_value
property
¶
The best trial's single objective value, or None if the study has no
best trial.
best_trial.value in one step. None for the same three reasons that
accessor gives it — no completed trial, a multi-objective study (read
best_trials), or a best trial that carries no value
— and, as with best_params, a None rather than
the ValueError Optuna raises.
direction
property
¶
The study's single objective direction, "minimize" or "maximize", as
an atune.StudyDirection member.
Raises for a multi-objective study, naming
directions — unlike
best_value, which answers None there. The
difference is deliberate: "no best value yet" is a real answer about a
real study, while a study with two directions has no single direction at
all, and a None would let if study.direction == "minimize" read as
"maximize" for it. Optuna raises here too.
directions
property
¶
The study's objective directions as a list of
atune.StudyDirection members, one per objective.
Always at least one entry, so len(study.directions) is the objective
count. Each member is the lowercase label create_study(direction=…)
accepts, because StudyDirection subclasses str, so
study.directions[0] == "minimize" and
study.directions[0] == atune.StudyDirection.MINIMIZE are both true.
metric_names
property
¶
The objective names create_study(metric_names=…) recorded, or None if
none were.
One name per direction when present, in objective order — the labels
reports and dashboards use for the columns
trials_dataframe calls values_0, values_1,
….
name
property
¶
The study's name.
The name= create_study recorded, read back out of storage — so a
study reopened with load_study answers with the name
it was created under. Optuna spells the keyword study_name; the property
is study.study_name there and study.name here.
resource_unit
property
¶
The label of the unit Trial.report steps and the fidelity budget count
in, as create_study(resource_unit=...) recorded it: "steps"
(environment steps, the default), "episodes", "walltime_ms", or a
custom name.
trials
property
¶
Every trial the study knows about, ordered by number.
A property, as Optuna's study.trials is — len(study.trials), not
len(study.trials()). A property cannot take arguments, so the filtered
read is get_trials.
user_attrs
property
¶
User-owned JSON metadata attached to this study.
add_trial(trial)
¶
Adds terminal history without re-evaluation. Source distributions, parameters, intermediates, JSON attributes, and canonical constraints are preserved; destination numbering and timestamps are new. Only complete, pruned, and failed trials are accepted. Existing queued configurations stay queued; sampler/scheduler hooks are not invoked.
add_trials(trials)
¶
Adds terminal trials in iterable order. Like Optuna, this is not an atomic batch: a later invalid entry leaves earlier additions committed. A failed backend reconstruction leaves a diagnosable failed record.
ask()
¶
Asks for the next trial (one outstanding at a time).
The sequential, single-evaluation path: one ask/tell round-trip is
exactly one objective evaluation, with no multi-seed fan and no PBT forks
(as in Optuna's ask/tell). Use optimize when a study
configured with n_seeds > 1 or a forking scheduler must materialize its
fan or its population.
Errors if a previous trial has not been told yet.
enqueue(params)
¶
Queues a configuration to be evaluated as the next trial (warm start).
atune's spelling of Optuna's enqueue_trial: params is a dict of
name -> value, and those values outrank the sampler for the trial
that claims them — every suggest_* naming an enqueued parameter returns
the enqueued value instead of a sampled one. Templates are consumed in FIFO
order, so several enqueue calls run in the order they were made and the
sampler takes over once the queue is empty. This is how a configuration you
already trust gets evaluated first:
study.enqueue({"lr": 1e-3, "batch": 64})
study.optimize(objective, n_trials=20) # trial 0 is exactly that config
It is not the same thing as warm-starting from a prior study's history
(atune::transfer, which injects already-known values as finished trials
and re-evaluates nothing); an enqueued configuration is one the loop runs.
A bool, int or float value crosses as itself. Anything else crosses
as its str(x) label, exactly as
suggest_categorical stores it, and the label is
resolved to its index in the choice set the study already knows for that
parameter — its declared space, or a choice set an earlier trial recorded.
A study that has never seen the parameter has no choice set to resolve
against, and that raises rather than guessing an index.
Everything else about the configuration is checked when the trial that claims it suggests its parameters, and surfaces there as the core's own error: a name the objective never suggests is simply unused, a value outside the distribution the objective declares raises then, faithfully.
On determinism: an enqueued study is replayable, not pre-determined.
Which trial number a template lands on depends on which ask claims it,
and under n_jobs > 1 that is thread scheduling. The values are of
course exactly what was enqueued. Unconsumed templates remain in the
in-process core queue after a stopped or failed run.
evaluate_checkpoints(objective, top_k)
¶
The checkpoint estimand: evaluate each of the top top_k tune-ranked
trials' latest checkpoint under the held-out test seeds, without
training.
The objective sees trial.evaluation == "checkpoint", the checkpoint
as trial.parent_checkpoint (its step as trial.parent_step), and the
trial's configuration from suggest_*; it loads the checkpoint and
evaluates it. A trial that never recorded a checkpoint is reported
with a NaN test_value and the objective does not run for it. Returns
the same report as reevaluate, and needs the same single-objective
study with test seeds. Results are stored beside the trial and reused
for the same checkpoint; the trial's own values are untouched.
get_trials(states=None)
¶
Every trial in one of states, ordered by number.
states is a sequence of the lowercase state labels
FrozenTrial.state uses — "waiting",
"running", "paused", "complete", "pruned", "failed" — and
None (the default) means every state, making
study.get_trials() the same list as trials:
done = study.get_trials(states=["complete"])
done = study.get_trials(states=[atune.TrialState.COMPLETE]) # the same
The atune.TrialState members are accepted because each
one is its label — the enum subclasses str — so no separate code
path is needed for them and the two spellings cannot answer differently.
An unrecognised label raises, naming the valid ones; it does not return an empty list, because a typo that silently finds no trials reads exactly like a study that has none.
Optuna's get_trials also takes deepcopy=, which has no meaning here:
every trial this binding hands out is already an immutable snapshot.
lineage()
¶
The fork genealogy as a list[LineageNode], in trial-number order.
Each node exposes its number, its parent (the donor trial's
number, or None for a root), whether it is_fork or is_restart,
its restart mode and fork_step, and its single objective value.
Reconstructed from parent links, recorded parameters and each child's
lineage record, so a PBT study's population tree is fully recoverable
from storage.
optimize(objective, n_trials=None, timeout=None, n_jobs=1, catch=None, callbacks=None, *, max_resource=None)
¶
Optimizes objective for n_trials trials across n_jobs workers, or
until timeout seconds pass or stop is called.
Delegates to core's
optimize_with: it builds a
bounded (base + n_trials), parallelism(n_jobs) handle that resumes
this study — restoring sampler/scheduler state from storage — and runs the
Python callable through a PyObjective adapter. Everything core's loop
does then happens for free: the multi-seed tune fan (n_seeds > 1),
PBT Fork children and their lineage,
pruning, the is-pruned/is-paused consult, worker threading, and
stop-on-hard-error.
A fanned trial counts as one trial, so base + n_trials yields
exactly n_trials new trials whatever the fan width; the fan runs the
objective k times within that one trial.
The GIL is released around the whole run (py.detach) so core's worker
threads can attach; each objective call re-takes it (single-evaluation
bookkeeping is parallel, the objectives serialize on the GIL). With
n_jobs == 1 core spawns no thread and the objective runs on this thread,
so a Trial the objective stashed is later touched on the same thread and
raises AtuneError through its liveness guard rather than a cross-thread
error.
An exception the objective raises (other than atune.Pruned/Paused,
which record the trial pruned/paused) does not fail-fast: core's
contract is that one bad configuration cannot poison a study, so the run
completes all n_trials (each raising trial recorded failed) and the
first captured exception is re-raised verbatim after the run unwinds —
ahead of any core error it produced. This is Optuna-familiar but not
identical to Optuna's default fail-fast (D6: familiar, not a drop-in).
n_trials=None¶
Optional, as Optuna's is: None means "run until something else stops
the study" — timeout, stop, or a sampler that exhausts
itself (atune.samplers.Grid ends when it has handed out every point).
With n_trials=None, no timeout, no stop() and a sampler that never
ends, the call runs forever; that is allowed, exactly as it is in
Optuna, because the alternative is an invented bound that silently ends a
study the caller meant to keep running. Given an n_trials, the bound is
unchanged: base + n_trials trials, so a resumed study runs exactly
n_trials new ones.
timeout=¶
A wall-clock budget in seconds (a float, as Optuna's is), or None
for none. It means "start no new trial after the deadline", not "kill
a running objective": a trial in flight always finishes and is recorded,
which is atune's contract everywhere and is what makes the records of a
timed-out run deterministic — every trial in the study is a whole trial.
So an objective that takes a minute can overrun a one-second timeout by
most of that minute. The deadline is checked by core's loop before it
creates each trial, so it is honoured by every worker under n_jobs > 1
too. A non-positive or non-finite timeout raises rather than being read
as "stop immediately".
max_resource=¶
A keyword-only budget in the study's
resource_unit — environment steps by default —
or None for none: this call starts no new trial once the trials it ran
have been charged max_resource units. Like n_trials it counts per
call, on top of what the study had already spent when the call began.
Each trial is charged its highest
Trial.report step less the step of the
checkpoint it was forked from, so a population-based fork pays only for
the steps it trains itself, and the
resource_ledger total is the same sum.
It is a cooperative stop, checked before each trial starts, like
timeout: the trial that crosses the line finishes, so a single worker
overshoots by at most one trial's charge and n_jobs workers by at most
that many. An objective that never calls report is charged nothing and
never exhausts it, so pair it with n_trials or timeout for such
objectives. A non-positive amount raises.
callbacks=¶
A sequence of callables, invoked as callback(study, frozen_trial) after
each trial reaches a terminal state (complete, pruned or
failed), in the order given, once per trial — Optuna's shape and
arguments, so a migrated callback needs no edit. The trial is already
recorded when the callback sees it, and the callback is called before the
next trial starts, which is what lets a callback call
stop.
An exception a callback raises is treated exactly as one the objective
raises: the remaining callbacks for that trial are skipped, the run
continues, and the first exception of the run (from an objective or a
callback) is re-raised verbatim after it unwinds. It never changes what
the finished trial recorded. Optuna instead propagates it immediately and
stops the study; this binding's answer is the one its failure contract
already gives for the objective, and catch= does not apply to it.
callbacks requires n_jobs == 1 and raises otherwise. A callback runs
on the worker thread that finished the trial, and this Study handle is
not thread-safe, so study.stop() or study.best_value inside a
callback of a multi-worker run fails through the explicit owner-thread
guard rather than from inside the callback's core path.
catch=¶
A tuple of exception types whose instances are swallowed: a trial
whose objective raises one is recorded failed, the run continues, and
the exception is not re-raised when the run ends. Anything not in
catch keeps the behaviour above. A catch element that is not an
exception type raises rather than being ignored.
Two things follow, and both differ from Optuna. atune's default is
already stronger than Optuna's: catch=() there fails fast on the first
exception, while here the run always completes and re-raises afterwards,
so catch=(RuntimeError,) is a request atune already grants
unconditionally as far as finishing the study goes — all it adds is the
silence at the end. And because the loop keeps going either way, catch
cannot make a study end sooner or later than it otherwise would.
What is deliberately absent¶
gc_after_trial= has nothing to schedule: the loop is Rust and there is
no per-trial Python garbage to collect between trials, so the keyword
could only be accepted and ignored. show_progress_bar= belongs to a
program, not to a library call — atune_cli renders progress for the
study it runs, and a library that writes to your terminal by default is a
side effect a callback can implement in three lines if you want it.
param_importance(objective=0, *, normalize=True, conditional=False)
¶
Hyperparameter importance as a dict[str, float], most important first.
The in-house PED-ANOVA evaluator (D21): a closed-form, fully
deterministic score over the study's completed trials answering "which
hyperparameters mattered for reaching the good trials?". objective
selects the objective for a multi-objective study (0 = the usual
single-objective case). With normalize=True (the default) the values
sum to one and the dict is insertion-ordered most-important-first, exactly
as Optuna's get_param_importances returns; normalize=False yields the
raw PED-ANOVA values in the same order. conditional=True scores every
parameter any completed trial recorded, treating a trial without it as
its own group (conditional PED-ANOVA, Optuna 5's default); the default
False keeps the original evaluator, which drops parameters some trials
lack.
pareto_front()
¶
The Pareto front as a list[FrozenTrial].
For a multi-objective study, the feasible non-dominated trials; for a
single-objective study, [best_trial] (or []), so the accessor reads
the same whatever the objective count.
recipe(trial_number)
¶
The schedule that produced trial trial_number, as the parsed
atune.recipe version-1 JSON object.
segments run from the start of the trial's inherited training to the
trial itself, each with its trial number, start_step, end_step,
typed params and the fork or restart event that began it. Raises
AtuneError naming the trial when a trial on the path is a fork without
a lineage record or names a donor the study does not contain.
reevaluate(objective, top_k)
¶
The held-out-seed re-evaluation stage (see Re-evaluate on held-out seeds).
Re-runs objective under the disjoint test seeds for the top top_k
tune-ranked trials and returns a report whose best is the test-ranked
best (not necessarily the tune-ranked one — that gap is the point). Needs a
single-objective study whose seed protocol declares test seeds
(create_study(n_test_seeds=...)).
The Python objective is adapted into a core Objective; an exception it
raises during re-evaluation is captured and re-raised here after the stage
unwinds.
replay_recipes(objective, top_k)
¶
The recipe estimand: train each of the top top_k tune-ranked trials
afresh following its recipe under the held-out test seeds.
The objective sees trial.evaluation == "recipe" and the schedule as
trial.recipe (the Study.recipe dict); suggest_* returns the
recipe's first-segment configuration, and there is no parent
checkpoint. Returns the same report as reevaluate; a trial whose
lineage is incomplete raises AtuneError before any objective runs.
Results are stored beside the trial and reused for the same recipe.
resource_ledger()
¶
The resource ledger: per trial, the resource it was charged for
(trained), the resource its lineage represents (lineage), its
training age since initialization or the last restart, and each
stored evaluation stage's replicate count, plus the study total —
what the fidelity budget has consumed — in the study's unit.
set_user_attr(key, value)
¶
Inserts or replaces one JSON-compatible user attribute on this study.
stop()
¶
Asks the run in flight to stop: the trial in flight finishes, no new
trial starts, optimize returns normally.
Optuna's cooperative stop, with the same meaning timeout= has here —
"start no new trial after this" — and callable from the same two places:
inside an objective and inside an
optimize(callbacks=…) callback.
Like everything else on this handle it is a n_jobs == 1 facility: live
operations are owner-thread-bound, so a worker thread cannot touch the
study at all (that is true of study.best_value in an objective today,
and is not new here). The flag itself is read by every worker, so a stop raised on the
sequential path ends the run whatever the worker count of the next one.
def objective(trial):
value = train(trial)
if value < 0.01: # good enough — stop the search
study.stop()
return value
study.optimize(objective, n_trials=None) # ends at the first good trial
Calling it outside a run is harmless and does nothing: each
optimize owns a fresh run-local flag, so a stray stop() cannot make
the next run end before it starts. (Optuna raises there instead. A
no-op is this binding's answer because no active session exists, and
nothing about the study is left changed by the call.)
It is a request about new trials, not a cancellation: the objective in
flight is not interrupted, and calling stop() from an objective does not
abandon it — that trial is completed and recorded like any other, with
whatever it returns.
tell(trial, values=None, *, state=None)
¶
Tells the outstanding trial its terminal state.
The default (state=None, or the explicit state="complete")
completes the trial with values (a float or a sequence of floats).
state="pruned" records it
pruned — no values are written,
its last intermediate becomes its objective. state="failed" records it
failed, with values (if given)
used as the failure message string. This lets an ask/tell caller record a
prune or a failure, which the optimize path did implicitly through raised
sentinels.
A default (state=None) or explicit state="complete" completion is
not unconditionally recorded
Complete: the trial's context is consulted first, and a scheduler
decision is authoritative even on the manual path (the same rule core's
run_trial follows). If a scheduler
pruned or paused the trial through Trial.report,
the trial is recorded pruned/paused however the objective's values were
computed. This path is single-evaluation — it never materializes a fan.
trial must be the exact live handle returned by the outstanding
ask; passing another study's or an expired handle is an
error and leaves the real operation recoverable.
trials_dataframe()
¶
The study's trials as a dict[str, numpy.ndarray], one entry per column.
Columns, all of equal length (the number of trials, in
trials order): "number" (int64), "state" (an object
column of atune.TrialState members, which are the lowercase state
strings), "value" (float64, NaN where a trial has none)
for a single-objective study or "values_0".."values_{m-1}" for a
multi-objective one. A multi-objective trial whose value vector does not
have exactly one entry per direction is treated as missing, so every
values_* column contains NaN for that trial. There is also one
"param_<name>" per distinct parameter —
float64 (NaN for a trial missing it) for numeric parameters, 0.0/1.0
for booleans, and an object column for categoricals whose entries carry
the same recorded type FrozenTrial.params gives them
(bool/int/float/str), or None where a trial did not suggest the
parameter.
A dict of columns rather than a pandas.DataFrame, because atune does not
depend on pandas — but the dict is a DataFrame constructor argument, so
if you have pandas the frame is one line away:
import pandas as pd
df = pd.DataFrame(study.trials_dataframe())
The columns arrive flat, so there is no multi_index= to pass; group them
yourself with df.columns.str.split("_", n=1, expand=True) if you want
Optuna's two-level frame.
StudyDirection
¶
Bases: str, Enum
A study's optimization direction, as a str enum.
MINIMIZE and MAXIMIZE are the lowercase strings create_study(direction=…)
accepts, so study.direction == "minimize" and
study.direction == atune.StudyDirection.MINIMIZE are both true and either may
be used. Optuna's enum also has NOT_SET; an atune study always has at least
one direction, so there is nothing for that member to mean here.
Trial
¶
The handle a Python objective receives for the trial under evaluation.
Every method borrows the underlying TrialCtx through the guarded owner,
which raises AtuneError after the trial has ended or from another thread.
constraints
property
¶
A dict copy of this evaluation's named constraints so far. Changing the
copy does not change the trial; use set_constraint to declare a value.
evaluation
property
¶
The final-stage estimand this evaluation computes, or None.
"checkpoint" during Study.evaluate_checkpoints: load
parent_checkpoint (the trial's latest checkpoint) and evaluate it
under replicate_seed without training. "recipe" during
Study.replay_recipes: train afresh following recipe. None for a
live trial and during Study.reevaluate.
number
property
¶
The per-study trial number — the determinism key, and the identity Optuna objectives use constantly (checkpoint directories, run names, log lines).
Stable: it is assigned when the trial is created, is what every derived
seed comes from, and matches the number the finished
FrozenTrial carries. Numbering is
per-study and continues across a resume, so the first trial of a reopened
study is not 0.
params
property
¶
The parameters this trial has suggested so far, as a dict.
A mid-objective read, so it grows as the objective calls suggest_*: a
parameter not yet suggested is simply absent. Once the trial finishes, the
same dict is what FrozenTrial.params
returns — and a categorical resolves through the very same helper, so
trial.params["opt"] and best_trial.params["opt"] can never disagree
about a choice's recorded scalar type.
parent_checkpoint
property
¶
The checkpoint reference this trial should start from, if any (a forked child inherits its parent's; a resumed trial inherits its own).
parent_step
property
¶
The resource step parent_checkpoint was
recorded at, if this trial starts from one.
recipe
property
¶
The schedule a recipe replay follows, as the parsed atune.recipe
version-1 dict (Study.recipe's shape), or None unless evaluation
is "recipe". suggest_* returns its first segment's configuration;
switch to each later segment's params at its start_step.
replicate_index
property
¶
The 0-based index of the replicate under evaluation, or None outside a
multi-seed fan (an ordinary single-seed evaluation).
replicate_seed
property
¶
The CRN-aware seed the current replicate must run its environment under.
This is the payload of the multi-seed RL protocol: inside a fan
(create_study(n_seeds=k)) it is replicate j's seed — common across
trials under the default pairing="paired", so trial i and trial
i + 1 evaluate their replicate j under identical randomness
(common-random-numbers variance reduction). Outside a fan it is exactly
seed("objective"). A reproducible objective seeds its RNG
(environment, network init, …) from this, never ambient entropy.
restart
property
¶
The restart this trial was started as, or None.
A dict for the first run of a restart child: mode ("fresh", which
has no parent_checkpoint and re-initializes, or "shrink_perturb",
which loads parent_checkpoint and then shrinks and perturbs it), the
reproducible seed for that re-initialization or noise, and for
"shrink_perturb" the shrink factor and noise scale. None for an
ordinary trial, a plain fork, a resumed trial, and a re-evaluation.
user_attrs
property
¶
User-owned JSON metadata attached to this live trial.
record_checkpoint(step, reference)
¶
Records a checkpoint reference (an opaque string atune never reads)
at resource step, for a later fork or resume to start from.
report(value, step)
¶
Reports an intermediate value at resource step.
(value, step), exactly as Optuna spells it — so a migrated
objective needs no edit, which is the whole point. Rust's
TrialCtx::report keeps (step, value): the two languages differ on
purpose, each matching what its own callers already write, and the paired
examples show both forms side by side.
step is keyword-or-positional but must be given. That is the one
mitigation available for the direction this flip cannot make safe: code
written against atune's older report(step, value) still type-checks
when both arguments are integral — a reward total, a token count, a
count of correct predictions — and would silently record the pair
swapped. Nothing in the call can distinguish the two, so the honest
statement is that it is undetectable and every pre-flip report call
must be read once by a human (see Migrate from
Optuna).
Raises atune.Pruned (or atune.Paused) when the scheduler decides to
stop the trial — the sentinel is meant to propagate out of the objective
(see Prune and
schedule).
seed(stream='objective')
¶
A reproducible seed for one of this trial's random streams.
stream selects the stream: "objective" (the default — the objective's
own randomness), "sampler", or "scheduler". The seed is a pure
function of (study seed, trial number, stream), so it does not depend on
which worker ran the trial — an objective that seeds its RNG from it is
reproducible, and must never fall back to ambient entropy. Prefer
replicate_seed for the environment seed of a
multi-seed study.
set_constraint(key, value)
¶
Sets one named constraint (<= 0 feasible). Values are float-castable
and must be finite. A repeated key warns and retains its first value.
Declared key sets must agree across the study. The vector is committed
when evaluation finishes or tell runs, in numeric-then-lexical key
order matching Optuna import. Infinities are refused unlike Optuna.
set_user_attr(key, value)
¶
Inserts or replaces one JSON-compatible user attribute on this trial.
The live TrialCtx performs the write, so core's ownership fence and
reserved atune: namespace remain authoritative for both ask/tell and
objective-created trials.
should_prune()
¶
Optuna's name for should_stop, accepted so a
migrated objective needs no edit.
Identical in every respect, including answering True for a paused
trial — atune's schedulers can pause as well as prune, which is why
should_stop is the canonical spelling.
should_stop()
¶
Whether the trial should stop now (pruned or paused).
Returns a bool rather than raising, so it reads naturally in an if.
should_prune() is the same method under Optuna's name, so
if trial.should_prune(): raise atune.TrialPruned() — Optuna's idiom,
verbatim — works here. The canonical name is atune's should_stop,
because a scheduler may also pause a trial (resumable, checkpoint kept)
and this answers True for that too.
suggest_bool(name)
¶
Suggests a boolean.
suggest_categorical(name, choices)
¶
Suggests one of choices, returning the original chosen object.
Choices store a stable str(x) label plus an exact bool/int/finite-float/
string payload; the returned value remains choices[index], so a caller
gets back exactly the Python object it passed in. Empty, unsupported,
non-finite, and duplicate-label choice lists are rejected before write.
suggest_float(name, low, high, *, log=False, step=None)
¶
Suggests a float in [low, high].
log=True samples uniformly in the logarithm; step discretizes onto a
grid anchored at low. A log-and-step combination is rejected by the
core, faithfully surfaced as AtuneError.
suggest_int(name, low, high, *, log=False, step=1)
¶
Suggests an integer in [low, high].
log=True samples uniformly in the logarithm (and forces step=1);
step discretizes onto a grid anchored at low.
suggest_open_float(name, low=None, high=None, *, log=False, around=None, times=None, plus=None, sides=None, limit=None)
¶
Suggests a float whose range may exceed the seed you pass — the define-by-run declaration of an open parameter. Exactly one seed form must be given:
(low, high), withlog=Truefor a logarithmic seed; oraround=with exactly one oftimes=(multiplicative, log-scaled) orplus=(additive, linear).
sides restricts growth to "up" or "down" (both by default), and
limit=(low, high) caps growth per side — pass None for an
unbounded side, e.g. limit=(None, 1.0).
The first call for name registers the policy write-once; a later
call must pass an equal one. On a replay the recorded value is
returned unchanged. The value is drawn from the live range: the seed
on first use, then the widened range once growth has moved it.
suggest_open_int(name, low=None, high=None, *, log=False, around=None, times=None, plus=None, sides=None, limit=None)
¶
Suggests an integer whose range may exceed the seed you pass —
suggest_open_float's integer twin,
with the same seed union, write-once registration and replay rules.
TrialState
¶
Bases: str, Enum
A trial's life-cycle state, as a str enum.
Every member is the lowercase string this binding has always returned, so
trial.state == "complete" and trial.state == atune.TrialState.COMPLETE are
both true and either may be used. The members are accepted anywhere a state
label is (study.get_trials(states=[atune.TrialState.COMPLETE])).
The names are Optuna's where Optuna has the same state — WAITING, RUNNING,
COMPLETE, PRUNED, and FAIL for the state atune labels "failed". PAUSED
is atune's own: a paused trial keeps its checkpoint and can be woken again, and
Optuna has no equivalent to name it after.
MaxTrialsCallback(n_trials, states='complete')
builtin
¶
Creates a callback stopping after n_trials records in states, including
existing history. The returned callable takes (study, frozen_trial).
The default counts complete trials; states=None counts every state, and
an empty sequence counts none. As with all callbacks, n_jobs=1 is required.
A threshold already reached stops after the next callback, not before the
next evaluation, matching Optuna's callback semantics. This is a factory
for an opaque callable rather than Optuna's callback class.
create_study(direction=None, *, directions=None, search_space=None, sampler=None, scheduler=None, pruner=None, storage=None, seed=0, name=None, study_name=None, metric_names=None, load_if_exists=False, n_seeds=1, n_test_seeds=0, aggregate='mean', pairing='paired', risk_lambda=1.0, fan_sync_steps=None, target_value=None, resource_unit=None)
builtin
¶
Creates a study.
direction is "minimize" (default) or "maximize", or a list of them
for a multi-objective study; metric_names optionally names the objectives.
search_space optionally declares fixed atune distribution descriptions
(the dict shape FrozenTrial.distributions returns). Population and GP
models require a declared space; omission preserves their independent
fallback. Auto carries its explicit space into the study automatically.
sampler is an opaque handle from atune.samplers (default: uniform
Random); scheduler an opaque handle from atune.schedulers (default:
prune nothing). storage is a spec string opened through the facade's
open_storage (":memory:" by default, a *.atj journal or a *.db
SQLite file otherwise). seed is the root of every derived seed and is the
whole reproducibility story (see
Determinism).
The multi-seed
protocol is configured
inline: n_seeds tune replicates per trial, n_test_seeds disjoint held-out
seeds for reevaluate, aggregate ("mean" /
"median" / "iqm" / "mean_minus_std", the last using risk_lambda) and
pairing ("paired" common-random-numbers / "independent"). All-default
leaves the study single-seed, byte-for-byte as before.
resource_unit names what Trial.report steps count and is stored with the
study: "steps" (environment steps, the default), "episodes",
"walltime" (milliseconds, labelled "walltime_ms"), or any other
non-empty name as a custom unit. The resource ledger and
optimize(max_resource=...) count in it. A reopen
keeps the stored unit, and an explicit different one raises.
Two settings belong to the handle rather than to the stored study, so
[load_study] accepts them too and a reopened study needs them again.
fan_sync_steps makes a multi-seed fan rung-synchronous: every replicate
runs to each listed step before the scheduler decides on the aggregate, so
a pruner can cut the fan there (pass the pruner's rung steps). The objective
must then be resumable: record a checkpoint before report, let the
atune.Paused it raises at a sync step propagate, and continue from
trial.parent_checkpoint at trial.parent_step. target_value ends
optimize (and makes ask refuse) once a feasible best trial is at least
as good as it; it needs a single-objective study.
One storage spec holds exactly one study. Creating a study in a storage
that already holds one is an error, because a second study would renumber its
trials from zero and look like a resume until they were counted.
load_if_exists=True reopens the study that is there instead — the Optuna
idiom of rerunning the same script against the same file — and verifies that
its stored name is the name given here. [load_study] is the same reopen
without the create.
Three arguments accept Optuna's spelling as well as atune's.
directions= is accepted for direction=, pruner= for scheduler=,
and study_name= for name=, so
that the two most common mechanical edits in a migrated script do not have to
be made. The canonical names are atune's — scheduler (a scheduler
is the superset of a pruner: it can also pause and fork) and name — and
they are what the documentation, the stub and the error messages use.
Passing both spellings of the same argument raises rather than one of them
silently winning; passing neither keeps the default.
create_trial(*, state='complete', value=None, values=None, params=None, distributions=None, user_attrs=None, intermediate_values=None, constraints=None)
builtin
¶
Creates immutable terminal history without evaluating an objective.
value and values are mutually exclusive. Complete trials require a
nonempty, non-NaN objective vector. params and distributions must have
identical keys; distributions use atune description dicts, not Optuna
objects. Named constraints are finite and use numeric-then-lexical order.
Only complete, pruned, and failed states are supported. A pruned value is
derived from the last intermediate; explicit values on pruned/failed
records are refused. User attributes are JSON-compatible; there is no
system_attrs junk drawer. The detached number is -1; adding assigns new
destination numbers and timestamps. The returned object stays immutable.
load_study(storage, *, name=None, study_name=None, sampler=None, scheduler=None, pruner=None, fan_sync_steps=None, target_value=None)
builtin
¶
Loads the one study storage holds.
The reopen half of the one-study-per-storage-spec model: storage is a spec
string [create_study] would accept (a *.atj journal or a *.db SQLite
file), it holds exactly one study, and this
returns a handle over it. The trial numbering, the seed, the direction, the
metric names and the multi-seed protocol all come back out of storage, so
a resumed study cannot silently disagree with the one it continues:
study = atune.load_study("study.atj")
study.optimize(objective, n_trials=20) # trials 20..39, not 0..19
Which is also why the recorded knobs are not accepted here.
direction, metric_names, seed and the multi-seed arguments are part of
the stored configuration; a load_study(direction=...) could only either be
ignored or contradict the study on disk, and both are worse than not offering
it. fan_sync_steps= and target_value= are accepted as [create_study]
accepts them, because the study does not record them. sampler= and
scheduler= are accepted, and default exactly as
[create_study]'s do (uniform Random, prune nothing), because a sampler is
a live object rather than something the study records — its persisted
state is restored regardless, so a Tpe handed to a loaded study continues
its model rather than restarting it.
name is optional. When supplied, the storage catalog resolves it; when no
exact named match exists, the one-study fallback still loads the sole study
so the compatibility check can report the stored and requested names. Omit
it to load whatever the catalog says is the sole study.
study_name= is accepted for name= and pruner= for scheduler=, exactly
as [create_study] accepts them and with the same rule: the canonical names
are atune's, the Optuna spellings are accepted so a migrated script needs no
edit, and passing both spellings of one argument raises. The two entry points
take the same keywords deliberately — a study_name= that worked on one and
not the other would be worse than not offering it at all.
atune.samplers¶
Compiled submodule, generated sibling stub
atune.samplers is registered by Rust's #[pymodule]. The wheel also
carries the generated atune/samplers.pyi, so mypy and pyright discover
the factory signatures even though there is no atune/samplers.py source
file. The factories are listed below because the API page imports the
compiled module for its runtime reference.
Sampler, Random, Grid, Tpe, Qmc, Dehb, Nsga2, Nsga3,
CmaEs, GpEi, Auto, Carbs —
each returns an opaque handle for create_study(sampler=...). Their
parameters and defaults are in
crates/atune_dev/pystub_types.toml,
which cargo dev generate-all --mode check keeps in step with the module on
every push.
atune.schedulers¶
Compiled submodule, generated sibling stub
atune.schedulers is registered by Rust's #[pymodule]. The wheel also
carries the generated atune/schedulers.pyi, so mypy and pyright discover
the factory signatures even though there is no atune/schedulers.py source
file. The factories are listed below because the API page imports the
compiled module for its runtime reference.
Scheduler, Median, Percentile, Asha, Hyperband, Patient,
Wilcoxon, Pbt, Pb2 — each returns an opaque handle for
create_study(scheduler=...).
atune.pb2¶
InRunPopulation(search_space, members, *, ...) and
Ipbt(search_space, members, budget, initial_step, *, ...) are storage-free
controllers for learners owned by the host. They accept float/int distribution
description dicts and expose Rust builder defaults as keywords, including their
own seed. The generated atune/pb2.pyi carries the complete constructor and
method signatures.
InRunPopulation.report records each member's boundary progress and fitness;
decide returns exploit dicts with recipient, donor, and params.
Ipbt.round returns slots, step, and evaluate_start; report_start and
report supply fitness, and decide returns ordered action dicts with kind
(copy, reinit, retire, archive) and the corresponding fields. The host
applies learner copies, reinitializations and archives before installing the
controller's new parameters. Both expose snapshot() -> bytes and
restore(bytes) using the complete Rust StateBlob as UTF-8 JSON; save host
learners and archives separately. See Population-based
training for
the host protocol and snapshot timing.
atune.optuna¶
An optional, pure-Python adapter. Its inline annotations ship in the wheel;
the generator validates its public export and generates its API link. Calling
it requires atune[optuna]; importing the module does not load Optuna.
atune.optuna.to_optuna_study(study)
¶
Return an independent snapshot suitable for Optuna's reading interface.
The copy uses InMemoryStorage. atune storage remains the source of
truth; changing or optimizing the copy never writes back. Stop concurrent
writers before copying if study attributes and trials must describe one
instant. Reading a live study does not lock its writers.
Matches the journal/RDB converters: paused trials become RUNNING,
categorical choices and parameters become their stored string labels,
boolean distributions stay boolean categoricals, constraints use the
constraints system attribute, and multi-objective intermediate reports
retain objective zero. Per-trial ranges, trial numbers, objective values,
directions and JSON user attributes are preserved. A NaN objective becomes
FAIL with the RDB converter's degradation attributes.
Optuna assigns fresh timestamps. Worker, retry, checkpoint, lineage and per-seed payloads are outside this Python reading snapshot. Wide integer parameters share Optuna's float representation limitation above 2**53. This adapter promises no Optuna optimization or storage interoperability.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
study
|
Study
|
An atune study, read through its public Python accessors. |
required |
Returns:
| Type | Description |
|---|---|
Study
|
An in-memory Optuna study with trials in source-number order. |
Raises:
| Type | Description |
|---|---|
ImportError
|
Install |
ValueError
|
Source trial numbers are not contiguous and zero-based. |