Fitting and objectives
See Fitting hyperparameters for an end-to-end MLE
and MAP example. Fitting functions optimize explicit Parameter leaves in a
model PyTree. To fit both GP and observation-noise parameters, include both
objects, for example (gp, dataset), in the fitted model.
Optimizers and results
| Function | Use |
|---|---|
fit_lbfgs(model, objective, ...) |
Deterministic objective with line search and gradient convergence |
fit(model, objective, optimizer, ...) |
A fixed number of updates using a supplied Optax optimizer |
fit_multistart(starts, fit_one) |
Independent fits from several initial parameter settings |
Single fits return the final model, loss, gradient_norm, and update and
evaluation counts. fit_lbfgs sets converged=True when it meets its gradient
tolerance. Reaching its iteration limit returns converged=False. Fixed-step
fit always reports converged=False.
losses includes the initial loss. L-BFGS allocates max_steps + 1 entries
and fills unused entries with NaN. Outside JIT, use
result.losses[:int(result.step_count) + 1] for the completed history.
A failed line search raises, as does an accepted iterate with non-finite
parameters, objective, or gradients.
Multistart inputs may differ in trainable parameter values. Their shapes,
transforms, priors, names, and fixed data must agree. result.model selects
the smallest final objective, and plural diagnostic fields report each start
in input order. Any failed run raises. See the
multistart example.
The fitting loops are compiled. Changing optimizer configuration, model
structure, shapes, or iteration budgets may recompile them. fit supports
reverse differentiation through its updates. fit_lbfgs differentiates the
objective but does not support reverse differentiation through the entire fit.
Call multistart helpers outside an outer JIT because best-start selection
returns a Python index. See JAX and observation capacity
for data shape reuse.
gpex.fitting
Explicit Optax fitting, L-BFGS, and independent multistart orchestration.
FitResult
Bases: Module
Final model and its diagnostics.
losses includes the initial objective. L-BFGS fills unused entries with
NaN; use the first step_count + 1 entries when plotting. converged
reports L-BFGS's gradient criterion and is always false for fixed-step fits.
evaluation_count includes line-search trials. optimizer_state belongs
to the final iterate. Reaching the iteration limit returns a finite model;
encountering a non-finite accepted iterate raises instead.
MultiStartFitResult
dataclass
MultiStartFitResult(
models: tuple[Model, ...],
losses: MultiStartLossHistory,
optimizer_state: Any,
final_losses: StartScalars,
gradient_norms: StartScalars,
step_counts: StartIntegers,
evaluation_counts: StartIntegers,
converged: StartBooleans,
best_index: int,
)
Independent fits in input order, selected by their final objective.
final_losses holds one value per start; losses holds their histories.
model and loss select the start at best_index. Optimizer state
and all diagnostic arrays have a leading start dimension.
fit
fit(
model: Model,
objective: Objective[Model],
optimizer: GradientTransformation,
*,
step_count: int,
) -> FitResult[Model]
Minimize a scalar objective for exactly step_count updates.
Only explicit Parameter leaves are trained. Supply an Optax optimizer
such as optax.adam(0.01) or a composed transformation whose update needs
only gradients, state, and parameters. Use fit_lbfgs for L-BFGS.
The result contains the final iterate, its optimizer state, and a loss trace
of length step_count + 1. There is no early stopping. The compiled scan
supports reverse-mode differentiation through the optimization trajectory.
Every iterate is checked for finite parameters, objective, and gradient.
Any failure raises after the loop completes, even if later iterates are finite.
Source code in src/gpex/fitting/optax.py
fit_lbfgs
fit_lbfgs(
model: Model,
objective: Objective[Model],
*,
max_steps: int = 100,
gradient_tolerance: float = 1e-05,
memory_size: int = 10,
max_linesearch_steps: int = 20,
) -> FitResult[Model]
Fit a deterministic objective with Optax L-BFGS and a zoom line search.
Stop when the gradient norm is at most gradient_tolerance or after
max_steps updates. Only explicit Parameter leaves are trained.
Cached line-search values and gradients avoid reevaluating accepted points.
Non-finite accepted iterates and failed line searches raise an error.
The result contains the final iterate. Its loss trace has length
max_steps + 1, with NaN after step_count + 1 valid entries. Check
converged to distinguish gradient convergence from the iteration limit.
This dynamic loop cannot be reverse-mode differentiated through; the
objective itself is differentiated normally.
Source code in src/gpex/fitting/lbfgs.py
fit_multistart
fit_multistart(
starts: Sequence[Model],
fit_one: Callable[[Model], FitResult[Model]],
) -> MultiStartFitResult[Model]
Vectorize a fitting callable over informed parameter starts.
For example, fit_multistart(starts, lambda m: fit_lbfgs(m, objective)).
Starts may differ only in their explicit parameter arrays: structure,
shapes, parameter metadata, and fixed leaves must agree. Each run owns its
optimizer state. Any failed run raises; finite final objectives determine
the selected model. This function selects best_index on the host; use
the single-fit functions when nesting fitting inside another JIT.
Source code in src/gpex/fitting/multistart.py
Subset objectives
fit_random_subsets draws a fresh subset without replacement from each
observation block at every Optax update. An integer subset_size applies to
every block, or a mapping gives counts by block name. All output components
at a selected location stay together, along with the block's shared noise.
Each selected count must be between one and the active location count.
A GP marginal likelihood couples observations through its covariance. A
subset objective is therefore an approximation, even after likelihood scaling.
For MAP, scale only the likelihood and include the prior once. Use a full-data
reference_objective to evaluate the final model. The
subset fitting example
shows the complete objective and its scaling.
subset_losses records each update's proxy objective. Values from different
subsets are not directly comparable. reference_loss is evaluated once at
the final model. Multistart subset fits select by their final full-data
reference_losses. Use a first-order Optax optimizer for the changing subset
objective.
gpex.fitting
Explicit Optax fitting, L-BFGS, and independent multistart orchestration.
RandomSubsetFitResult
Bases: Module
Final subset iterate, assessed once on the full reference objective.
subset_losses records the objective before each update. Values from
different subsets are not directly comparable. reference_loss and
reference_gradient_norm describe the returned model on the full data.
MultiStartRandomSubsetFitResult
dataclass
MultiStartRandomSubsetFitResult(
models: tuple[Model, ...],
subset_losses: MultiStartLossHistory,
optimizer_state: Any,
reference_losses: StartScalars,
reference_gradient_norms: StartScalars,
step_counts: StartIntegers,
evaluation_counts: StartIntegers,
best_index: int,
)
Independent subset fits, selected by their final reference objective.
fit_random_subsets
fit_random_subsets(
model: GPModel,
subset_objective: Objective[GPModel],
optimizer: GradientTransformation,
*,
step_count: int,
subset_size: SubsetSize,
reference_objective: Objective[GPModel],
key: PRNGKeyArray,
) -> RandomSubsetFitResult[GPModel]
Fit (gp, dataset) with a fresh subset per Optax update.
Supply a first-order optimizer such as optax.adam(0.01). subset_size
is an active location count per block, or a mapping from every block name to
its count. Sampling is uniform without replacement over active locations and
reproducible from key. Every block needs at least that many active rows.
A subset GP likelihood is an approximation, not an unbiased estimate of the
full likelihood. The caller defines any scaling in subset_objective.
Run exactly step_count updates, then evaluate reference_objective
and its gradient once on the full data. Return the final model; non-finite
iterates, subset diagnostics, or reference diagnostics raise an error.
Source code in src/gpex/fitting/subsets.py
fit_multistart_random_subsets
fit_multistart_random_subsets(
starts: Sequence[GPModel],
subset_objective: Objective[GPModel],
optimizer: GradientTransformation,
*,
step_count: int,
subset_size: SubsetSize,
reference_objective: Objective[GPModel],
key: PRNGKeyArray,
) -> MultiStartRandomSubsetFitResult[GPModel]
Run fit_random_subsets with an independent key per start.
Arguments and failure behavior match fit_random_subsets. Starts must
satisfy the same structure and fixed-leaf requirements as fit_multistart.
Select the final model with the lowest full-data reference objective.
Source code in src/gpex/fitting/multistart.py
Exact objectives
gpex.fitting.objectives
Differentiable exact GP objectives.
negative_log_marginal_likelihood
negative_log_marginal_likelihood(
gp: GaussianProcess,
dataset: FunctionalDataset,
*,
jitter: float = 1e-06,
) -> ScalarObjective
Return the exact Gaussian negative log marginal likelihood.
Invalid factorizations produce non-finite trials for optimizers to reject. Padding contributes neither observations nor likelihood normalization.
Source code in src/gpex/fitting/objectives.py
negative_log_posterior
negative_log_posterior(
gp: GaussianProcess,
dataset: FunctionalDataset,
*,
jitter: float = 1e-06,
) -> ScalarObjective
Add explicitly declared GP and noise priors to the exact likelihood.