pyepo.func.surrogate ==================== .. py:module:: pyepo.func.surrogate .. autoapi-nested-parse:: Surrogate Loss function Attributes ---------- .. autoapisummary:: pyepo.func.surrogate.smartPredictThenOptimizePlus pyepo.func.surrogate.PG Classes ------- .. autoapisummary:: pyepo.func.surrogate.SPOPlus pyepo.func.surrogate.SPOPlusFunc pyepo.func.surrogate.perturbationGradient Module Contents --------------- .. py:class:: 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: :py:obj:`pyepo.func.abcmodule.optModule` SPO+ 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 :math:`\mathbf{w}^*(\mathbf{c})` are available as supervision. The forward pass solves the perturbed problem with cost :math:`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 :math:`2(\mathbf{w}^*(\mathbf{c}) - \mathbf{w}^*(2\hat{\mathbf{c}} - \mathbf{c}))` without any extra solver call. Reference: Elmachtoub & Grigas (2022) ``_ .. py:method:: forward(pred_cost: torch.Tensor, true_cost: torch.Tensor, true_sol: torch.Tensor, true_obj: torch.Tensor) -> torch.Tensor Forward pass .. py:class:: SPOPlusFunc(*args, **kwargs) Bases: :py:obj:`torch.autograd.Function` An autograd function for SPO+ Loss .. py:method:: forward(ctx, pred_cost: torch.Tensor, true_cost: torch.Tensor, true_sol: torch.Tensor, true_obj: torch.Tensor, module: SPOPlus) -> torch.Tensor :staticmethod: Forward pass for SPO+ :param pred_cost: a batch of predicted values of the cost :param true_cost: a batch of true values of the cost :param true_sol: a batch of true optimal solutions :param true_obj: a batch of true optimal objective values :param module: SPOPlus module :returns: SPO+ loss :rtype: torch.tensor .. py:method:: backward(ctx, grad_output: torch.Tensor) -> tuple[torch.Tensor | None, Ellipsis] :staticmethod: Backward pass for SPO+ .. py:class:: 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: :py:obj:`pyepo.func.abcmodule.optModule` Perturbation Gradient (PG): zeroth-order surrogate of the objective-value loss. PG approximates the directional derivative of :math:`z^*(\hat{\mathbf{c}})` along the true cost :math:`\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 :math:`\mathbf{c}`. Reference: Gupta & Huang (2024) ``_ .. py:attribute:: sigma :value: 0.1 .. py:attribute:: two_sides :value: False .. py:method:: forward(pred_cost: torch.Tensor, true_cost: torch.Tensor) -> torch.Tensor Forward pass .. py:data:: smartPredictThenOptimizePlus .. py:data:: PG