pyepo.func.surrogate¶
Surrogate Loss function
Classes¶
SPO+ loss: a convex surrogate for the SPO regret of a linear-objective LP. |
|
An autograd function for SPO+ Loss |
|
Perturbation Gradient (PG): zeroth-order surrogate of the objective-value loss. |
Module Contents¶
- class pyepo.func.surrogate.SPOPlus(optmodel: pyepo.model.opt.optModel, processes: int = 1, solve_ratio: float = 1.0, reduction: pyepo.func.abcmodule.Reduction = 'mean', dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
pyepo.func.abcmodule.optModuleSPO+ loss: a convex surrogate for the SPO regret of a linear-objective LP.
SPO+ upper-bounds the SPO regret with a convex function of the predicted cost vector and provides an informative subgradient (via Danskin’s theorem) for end-to-end training. It is the strong default for predict-then-optimize when true optimal solutions \(\mathbf{w}^*(\mathbf{c})\) are available as supervision.
The forward pass solves the perturbed problem with cost \(2\hat{\mathbf{c}} - \mathbf{c}\) once per training instance and returns a scalar loss; the backward pass uses the cached solution to form the subgradient \(2(\mathbf{w}^*(\mathbf{c}) - \mathbf{w}^*(2\hat{\mathbf{c}} - \mathbf{c}))\) without any extra solver call.
Reference: Elmachtoub & Grigas (2022) https://doi.org/10.1287/mnsc.2020.3922
- forward(pred_cost: torch.Tensor, true_cost: torch.Tensor, true_sol: torch.Tensor, true_obj: torch.Tensor) torch.Tensor¶
Forward pass
- class pyepo.func.surrogate.SPOPlusFunc(*args, **kwargs)¶
Bases:
torch.autograd.FunctionAn autograd function for SPO+ Loss
- static forward(ctx, pred_cost: torch.Tensor, true_cost: torch.Tensor, true_sol: torch.Tensor, true_obj: torch.Tensor, module: SPOPlus) torch.Tensor¶
Forward pass for SPO+
- Parameters:
pred_cost – a batch of predicted values of the cost
true_cost – a batch of true values of the cost
true_sol – a batch of true optimal solutions
true_obj – a batch of true optimal objective values
module – SPOPlus module
- Returns:
SPO+ loss
- Return type:
torch.tensor
- static backward(ctx, grad_output: torch.Tensor) tuple[torch.Tensor | None, Ellipsis]¶
Backward pass for SPO+
- class pyepo.func.surrogate.perturbationGradient(optmodel: pyepo.model.opt.optModel, sigma: float = 0.1, two_sides: bool = False, processes: int = 1, solve_ratio: float = 1.0, reduction: pyepo.func.abcmodule.Reduction = 'mean', dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
pyepo.func.abcmodule.optModulePerturbation Gradient (PG): zeroth-order surrogate of the objective-value loss.
PG approximates the directional derivative of \(z^*(\hat{\mathbf{c}})\) along the true cost \(\mathbf{c}\) with a finite difference, yielding an informative gradient through the otherwise piecewise-constant solver layer. Two variants are exposed via
two_sides: backward differencing (False, one extra solve per step) and central differencing (True, two extra solves but more accurate gradients).Unlike SPO+, PG does not require true optimal solutions – it only needs the true cost vector \(\mathbf{c}\).
Reference: Gupta & Huang (2024) https://arxiv.org/abs/2402.03256
- sigma = 0.1¶
- two_sides = False¶
- forward(pred_cost: torch.Tensor, true_cost: torch.Tensor) torch.Tensor¶
Forward pass