API reference

The public entry points below form the supported integration surface. Underscore-prefixed helpers and internal DP cost tables may change between releases. Use evaluator injection instead of replacing a planner’s internal engine or calling its private table builders.

Use training_cost_fn to customize only candidate training cost; use EvaluationProvider to supply complete candidate evaluations. These options are mutually exclusive on RetrainingPlanner. See cost accounting and historical state initialization.

class retrainopt.PlannerConfig(n_choices: Sequence[int | float] = <factory>, min_train_size: int = 1, time_cost_weight: float = 1.0, loss_cost_weight: float = 1.0, random_seed: int = 42, initial_loss: float | None = None, initial_model_samples: int | None = None, bayes_iterations: int = 5, bayes_initial_samples: int = 6, bayes_candidates_per_iteration: int = 1, bayes_selection_strategy: str = 'sequence', bayes_anchor_steps: Sequence[float] = <factory>, acquisition: str = 'expected', bayes_backend: str = 'lightweight', exploration_beta: float = 1.0, improvement_xi: float = 0.01, surrogate_k: int = 5, surrogate_uncertainty_floor: float = 0.05, bayes_backend_options: Dict[str, ~typing.Any]=<factory>, record_bayes_true_history: bool = False)

User-facing planner configuration.

n_choices accepts float fractions in (0, 1] or integer sample counts >= 1. Thus 1 means one sample and 1.0 means all samples.

resolve_n_choices(dataset_size: int) → List[int]

Resolve configured sample choices for a concrete train block size.

class retrainopt.RetrainingPlanner(timeline: TimelineDataset, model_adapter: ModelAdapter, config: PlannerConfig | None = None, *, evaluator: EvaluationProvider | None = None, training_cost_fn: TrainingCostFunction | None = None)

Cost-aware retraining planner for time-sliced datasets.

plan(method: str = 'exact', *, initial_model: Any | None = None) → PlanResult

Plan a retraining schedule.

Supported methods:

  • exact: exact dynamic programming over all configured candidates.

  • bayes: surrogate-guided candidate evaluation, measurement of the estimated schedule, and final DP over all measured candidates.

Bayes returns a fully measured schedule. Its estimated_total_cost evaluates that same schedule using estimates from before final measurement; it does not certify optimality over unmeasured candidates.

class retrainopt.PlanResult(method: str, decisions: ~typing.List[~retrainopt.types.Decision], total_cost: float, training_cost: float, loss_cost: float, estimated_total_cost: float | None = None, metadata: ~typing.Dict[str, ~typing.Any] = <factory>, weighted_loss_cost: float | None = None)

Structured planner output.

to_dict() → Dict[str, Any]

Serialize the result to a plain dictionary.

class retrainopt.OnlineState(step: int, current_staleness: float, accumulated_staleness: float, time_since_last_retrain: int)

The three paper features measured before the current action.

Staleness is a raw loss difference and can be negative. Accumulated staleness includes the current timestep; elapsed time counts logical steps. Model age may exceed step when it was trained before this timeline.

features() → list[float]

Return current staleness, accumulated staleness, and elapsed time.

class retrainopt.OnlineStepResult(state: OnlineState, decision: Decision, loss: float, training_seconds: float, training_cost: float, weighted_loss_cost: float, total_cost: float)

An executed action, its pre-action features, and its realized cost.

loss is the raw current-step loss of the model selected by the action. training_seconds times only the model fit. Sampling, evaluation and policy inference are excluded, just as in the offline objective.

to_dict() → dict[str, Any]

Serialize the row, including its pre-action feature values.

class retrainopt.OnlineTrainingData(plan: PlanResult, states: tuple[OnlineState, ...], decisions: tuple[Decision, ...])

A prefix-only offline plan paired with its pre-action feature rows.

class retrainopt.OnlinePolicy(*args, **kwargs)

A policy proposes an action without modifying deployment state.

The controller updates its state only after the action succeeds. Policies must therefore keep decide free of side effects to permit safe retries.

class retrainopt.BaseOnlinePolicy(period: float | None, n_samples: float | None)

Periodic retraining with the historical average interval and volume.

period=T/R and n_samples is the mean selected retraining volume. Both may be fractional. Retraining occurs once elapsed time reaches the period; volume rounds half up to an integer and clips to current data size. A policy with both parameters None never retrains.

classmethod from_plan(plan: PlanResult) → BaseOnlinePolicy

Tune from a plan computed exclusively on historical data.

decide(state: OnlineState, *, train_size: int) → Decision

Propose a retrain when elapsed time reaches the fitted period.

class retrainopt.LearnedOnlinePolicy(*, random_seed: int = 42)

Two-stage Random Forest policy fitted to historical features/actions.

The classifier uses 100 trees as in the paper. This implementation also uses a 100-tree Random Forest regressor for positive retraining volumes. Requires the sklearn extra; imports it only when fit is called.

fit(states: Sequence[OnlineState], decisions: Sequence[Decision]) → LearnedOnlinePolicy

Fit action labels on all rows and volume labels only on RETRAIN rows.

Supply pre-action states and decisions from the same historical plan. An all-KEEP plan is valid and produces a policy that always keeps.

decide(state: OnlineState, *, train_size: int) → Decision

Predict an action and, when needed, a clipped integer volume.

class retrainopt.OnlineController(timeline: TimelineDataset, model_adapter: ModelAdapter, policy: OnlinePolicy, config: PlannerConfig | None = None, *, initial_model: Any | None = None, initial_reference_loss: float | None = None, start_step: int = 0, initial_trained_at: int = 0, initial_accumulated_staleness: float = 0.0, training_cost_fn: TrainingCostFunction | None = None)

Execute a policy one currently available timestep at a time.

Supply either a real initial_model with initial_reference_loss or config.initial_loss for a synthetic constant-loss baseline. No initial model is implicitly trained. The initial model is treated as trained at step zero unless initial_trained_at is supplied. A negative training step denotes a model trained before the supplied timeline began.

The timeline may grow between calls. step reads only the current train size/evaluation block, and samples training data only for RETRAIN. It never invokes the offline evaluation engine. Labels for the current evaluation block must be available before deciding. Model fitting must return a new artifact and evaluation must not mutate the deployed model.

property current_model: Any

Return the deployed artifact, or None for a synthetic baseline.

property next_step: int

Return the timestep that the next successful call will process.

property reference_loss: float

Return the deployed model’s loss measured at its training step.

property last_retrain_step: int

Return the training timestep of the deployed model.

property accumulated_staleness: float

Return accumulated staleness after the most recent completed action.

step() → OnlineStepResult

Observe, decide and execute one step; commit state only on success.

A RETRAIN uses the new model’s current-step loss for both its cost and its future reference baseline. Insufficient training data forces KEEP. An unavailable next step raises IndexError and can be retried once the timeline grows. Adapter exceptions propagate without advancing state.

retrainopt.collect_online_training_data(timeline: TimelineDataset, model_adapter: ModelAdapter, config: PlannerConfig | None = None, *, history_steps: int, method: str = 'exact', initial_model: Any | None = None, initial_reference_loss: float | None = None, initial_model_age: int = 0, initial_accumulated_staleness: float = 0.0, training_cost_fn: TrainingCostFunction | None = None) → OnlineTrainingData

Plan exclusively on [0, history_steps) and collect teacher rows.

The exact or Bayes planner is run anew on a bounded view of history. A full-horizon plan must never be sliced to produce causal tuning labels. Features use the deployed model before each historical action, including current signed staleness. After RETRAIN the reference becomes the selected candidate’s loss on that same step and accumulated staleness resets.

Candidate and initial losses come from the same planning evaluations; collecting features performs no extra fits or evaluations. As with the offline planner, omitting an initial model and initial_loss bootstraps a model on step zero; its step-zero loss supplies the initial reference. An explicit model requires its measured initial_reference_loss. initial_model_age counts steps since its training at the window start; initial_accumulated_staleness carries the signed sum before that start. Nonzero carry requires an explicit model or a configured constant baseline. All returned step indices remain local to the supplied timeline.

class retrainopt.Decision(action: DecisionAction, n_samples: int | None = None, trained_at: int | None = None)

A single retraining decision.

class retrainopt.DecisionAction(*values)

Supported planner actions.

class retrainopt.CandidateEvaluation(model_id: ~typing.Tuple[int, int], dataset_size: int, training_seconds: float, training_cost: float, future_losses: ~typing.Dict[int, float], observed: bool = True, metadata: ~typing.Dict[str, ~typing.Any] = <factory>)

Observed or estimated cost information for a candidate model.

to_state_cost() → Dict[str, Any]

Convert to the internal DP input format.

class retrainopt.EvaluationProvider(*args, **kwargs)

Cost evaluation seam for custom measurement or persistent caching.

Returned costs use the planner’s frozen configuration and immutable timeline. Candidate ids and complete finite losses must describe that same snapshot. Diagnostic evaluation must not add observed candidates.

class retrainopt.TrainingCostFunction(*args, **kwargs)

Price a completed fit in objective units.

Return a finite nonnegative cost. This replaces the default weighted fit time; time_cost_weight is not applied again. n_samples is the actual requested fit size after clipping to available data. model is the artifact returned by fit and may carry resource measurements.

Do not mutate the artifact or depend on earlier model choices. A failed step may retry the fit and this callback. KEEP actions and initial-model setup do not call it; cached candidates reuse their recorded cost.

__call__(*, step: int, n_samples: int, training_seconds: float, model: Any) → float

Call self as a function.

class retrainopt.evaluation.EvaluationEngine(timeline: TimelineDataset, model_adapter: ModelAdapter, config: PlannerConfig, *, training_cost_fn: TrainingCostFunction | None = None)

Train and evaluate candidates with an in-memory result cache.

evaluate_initial_model(initial_model: Any | None = None) → CandidateEvaluation

Evaluate the initial deployed model.

Use a supplied model or the configured constant initial_loss. If neither is supplied, train on the first timestep using initial_model_samples or the full first train block.

evaluate_candidate(step: int, n_samples: int) → CandidateEvaluation

Evaluate a concrete (step, n_samples) candidate.

evaluate_candidate_uncached(step: int, n_samples: int) → CandidateEvaluation

Evaluate a candidate for diagnostics without adding it to the observed cache.

class retrainopt.TimelineDataset

Time-sliced train/eval dataset interface.

abstract property num_steps: int

Return the number of logical timesteps.

abstractmethod get_train_block(step: int) → Any

Return the full train block for step.

abstractmethod get_eval_block(step: int) → Any

Return the full eval block for step.

abstractmethod train_size(step: int) → int

Return the train-set size for step.

sample_train_block(step: int, n_samples: int, *, seed: int) → Any

Return a sampled train block for candidate evaluation.

class retrainopt.ModelAdapter

Model fitting/evaluation abstraction.

abstractmethod fit(train_data: Any, *, step: int, n_samples: int, random_seed: int) → Any

Fit a candidate model and return a model artifact.

abstractmethod evaluate(model: Any, eval_data: Any, *, step: int) → float

Evaluate a model artifact and return a scalar loss.

Built-in timeline and model adapters.

class retrainopt.adapters.ArrayTimelineAdapter(train_blocks: Sequence[Sequence[Any]], eval_blocks: Sequence[Sequence[Any]])

Timeline adapter backed by in-memory Python sequences.

property num_steps: int

Return the number of logical timesteps.

get_train_block(step: int) → List[Any]

Return the full train block for step.

get_eval_block(step: int) → List[Any]

Return the full eval block for step.

train_size(step: int) → int

Return the train-set size for step.

sample_train_block(step: int, n_samples: int, *, seed: int) → List[Any]

Return a sampled train block for candidate evaluation.

class retrainopt.adapters.BinaryTimelineAdapter(root_dir: str | Path, *, num_features: int | None = None)

Load a train/*.bin and test/*.bin timeline directory.

class retrainopt.adapters.PrototypeModelAdapter

Dependency-free prototype classifier with integer class labels.

Labels follow the same numeric contract as SklearnModelAdapter. Features are finite real scalars or nonempty flat lists/tuples of finite real values. Every train/evaluation sample must have the trained feature dimension. Boolean feature values remain valid numeric indicators.

fit(train_data: Any, *, step: int, n_samples: int, random_seed: int) → Any

Fit a candidate model and return a model artifact.

evaluate(model: Any, eval_data: Any, *, step: int) → float

Evaluate a model artifact and return a scalar loss.

class retrainopt.adapters.SklearnModelAdapter(model_factory: Callable[[], Any] | Any, *, classes: Sequence[int] | None = None)

ModelAdapter for sklearn classifiers with integer class labels.

Finite integer-valued real labels, such as 1.0, are also accepted. Fractional labels, booleans and strings are rejected rather than coerced. classes declares the task’s complete class space before evaluation. Missing fitted classes receive zero probability when computing log loss.

fit(train_data: Any, *, step: int, n_samples: int, random_seed: int) → Any

Fit a candidate model and return a model artifact.

evaluate(model: Any, eval_data: Any, *, step: int) → float

Evaluate a model artifact and return a scalar loss.

class retrainopt.adapters.TorchModelAdapter(model_factory: Callable[[], Any], *, optimizer_factory: Callable[[Iterable[Any]], Any] | None = None, epochs: int = 5, batch_size: int = 64, device: str = 'cpu')

ModelAdapter for PyTorch classifiers.

fit(train_data: Any, *, step: int, n_samples: int, random_seed: int) → Any

Fit a candidate model and return a model artifact.

evaluate(model: Any, eval_data: Any, *, step: int) → float

Evaluate a model artifact and return a scalar loss.

class retrainopt.adapters.TorchTimelineAdapter(train_blocks: Sequence[Any], eval_blocks: Sequence[Any])

Timeline adapter for PyTorch datasets or lists of tensor/label pairs.

property num_steps: int

Return the number of logical timesteps.

get_train_block(step: int) → Any

Return the full train block for step.

get_eval_block(step: int) → Any

Return the full eval block for step.

train_size(step: int) → int

Return the train-set size for step.

sample_train_block(step: int, n_samples: int, *, seed: int) → Any

Return a sampled train block for candidate evaluation.