pyepo.func.perturbed¶
Perturbed optimization function
Classes¶
Differentiable Perturbed Optimizer (DPO) -- additive-Gaussian variant. |
|
An autograd function for perturbed optimizer |
|
Multiplicative-perturbation variant of |
|
Perturbed Fenchel-Young loss (PFYL) -- additive-Gaussian variant. |
|
An autograd function for Fenchel-Young loss using perturbation techniques. |
|
Multiplicative-perturbation variant of |
|
Implicit Maximum Likelihood Estimator (I-MLE) via perturb-and-MAP. |
|
An autograd function for Implicit Maximum Likelihood Estimator |
|
Adaptive Implicit MLE (AI-MLE): I-MLE with an adaptive interpolation step. |
|
An autograd function for Adaptive Implicit Maximum Likelihood Estimator |
Module Contents¶
- class pyepo.func.perturbed.perturbedOpt(optmodel: pyepo.model.opt.optModel, n_samples: int = 10, sigma: float = 1.0, processes: int = 1, seed: int = 135, variance_reduction: bool = True, solve_ratio: float = 1.0, dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
pyepo.func.abcmodule.optModuleDifferentiable Perturbed Optimizer (DPO) – additive-Gaussian variant.
Estimates the expected solution \(\mathbb{E}_{\boldsymbol{\xi}}[\mathbf{w}^*(\hat{\mathbf{c}} + \sigma\boldsymbol{\xi})]\) by Monte Carlo averaging over
n_samplesGaussian perturbations of the predicted cost vector. The smoothed map varies continuously with \(\hat{\mathbf{c}}\) – small perturbations only re-weight the distribution over active vertices – giving an informative gradient where the bare LP solver gives zero.Returns a solution, not a loss: the user supplies a task loss (MSE against \(\mathbf{w}^*(\mathbf{c})\) is the standard choice). For sign-sensitive oracles, use
perturbedOptMulinstead.Reference: Berthet et al. (2020) https://papers.nips.cc/paper/2020/hash/6bb56208f672af0dd65451f869fedfd9-Abstract.html
- n_samples = 10¶
- sigma = 1.0¶
- seed = 135¶
- variance_reduction = True¶
- forward(pred_cost: torch.Tensor) torch.Tensor¶
Forward pass
- class pyepo.func.perturbed.perturbedOptFunc(*args, **kwargs)¶
Bases:
torch.autograd.FunctionAn autograd function for perturbed optimizer
- static forward(ctx, pred_cost: torch.Tensor, module: perturbedOpt) torch.Tensor¶
Forward pass for perturbed
- Parameters:
pred_cost – a batch of predicted values of the cost
module – perturbedOpt module
- Returns:
solution expectations with perturbation
- Return type:
torch.tensor
- static backward(ctx, grad_output: torch.Tensor) tuple[torch.Tensor | None, Ellipsis]¶
Backward pass for perturbed
- class pyepo.func.perturbed.perturbedOptMul(optmodel: pyepo.model.opt.optModel, n_samples: int = 10, sigma: float = 1.0, processes: int = 1, seed: int = 135, variance_reduction: bool = True, solve_ratio: float = 1.0, dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
perturbedOptMultiplicative-perturbation variant of
perturbedOptfor sign-sensitive oracles.Replaces additive noise with the multiplicative perturbation \(\hat{\mathbf{c}} \odot \exp(\sigma\boldsymbol{\xi} - \tfrac{1}{2}\sigma^2)\), which preserves the sign of each cost entry – required when the solver expects, e.g., strictly nonnegative edge costs. Predicted costs must already carry the intended nonzero sign; for nonnegative problems pair this module with a positive-output prediction layer (e.g.
nn.Softplus()plus a small epsilon).Reference: Dalle et al. (2022) https://arxiv.org/abs/2207.13513
- class pyepo.func.perturbed.perturbedFenchelYoung(optmodel: pyepo.model.opt.optModel, n_samples: int = 10, sigma: float = 1.0, processes: int = 1, seed: int = 135, solve_ratio: float = 1.0, reduction: pyepo.func.abcmodule.Reduction = 'mean', dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
pyepo.func.abcmodule.optModulePerturbed Fenchel-Young loss (PFYL) – additive-Gaussian variant.
Pairs the same Monte-Carlo expected perturbed solution as
perturbedOptwith the Fenchel-Young loss against the true optimum \(\mathbf{w}^*(\mathbf{c})\), returning a scalar loss directly – no user-defined task loss needed. The gradient collapses to the simple residual \(\mathbf{w}^*(\mathbf{c}) - \mathbb{E}_{\boldsymbol{\xi}} [\mathbf{w}^*(\hat{\mathbf{c}} + \sigma\boldsymbol{\xi})]\), so no explicit Jacobian through the solver is required. For sign-sensitive oracles, useperturbedFenchelYoungMul.Reference: Berthet et al. (2020) https://papers.nips.cc/paper/2020/hash/6bb56208f672af0dd65451f869fedfd9-Abstract.html
- n_samples = 10¶
- sigma = 1.0¶
- seed = 135¶
- forward(pred_cost: torch.Tensor, true_sol: torch.Tensor) torch.Tensor¶
Forward pass
- class pyepo.func.perturbed.perturbedFenchelYoungFunc(*args, **kwargs)¶
Bases:
torch.autograd.FunctionAn autograd function for Fenchel-Young loss using perturbation techniques.
- static forward(ctx, pred_cost: torch.Tensor, true_sol: torch.Tensor, module: perturbedFenchelYoung) torch.Tensor¶
Forward pass for perturbed Fenchel-Young loss
- Parameters:
pred_cost – a batch of predicted values of the cost
true_sol – a batch of true optimal solutions
module – perturbedFenchelYoung module
- Returns:
solution expectations with perturbation
- Return type:
torch.tensor
- static backward(ctx, grad_output: torch.Tensor) tuple[torch.Tensor | None, Ellipsis]¶
Backward pass for perturbed Fenchel-Young loss
- class pyepo.func.perturbed.perturbedFenchelYoungMul(optmodel: pyepo.model.opt.optModel, n_samples: int = 10, sigma: float = 1.0, processes: int = 1, seed: int = 135, solve_ratio: float = 1.0, reduction: pyepo.func.abcmodule.Reduction = 'mean', dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
perturbedFenchelYoungMultiplicative-perturbation variant of
perturbedFenchelYoungfor sign-sensitive oracles.Uses the same sign-preserving multiplicative perturbation \(\hat{\mathbf{c}} \odot \exp(\sigma\boldsymbol{\xi} - \tfrac{1}{2}\sigma^2)\) as
perturbedOptMul. Predicted costs must carry the intended nonzero sign; for nonnegative problems pair this module with a positive-output prediction layer (e.g.nn.Softplus()plus a small epsilon).Reference: Dalle et al. (2022) https://arxiv.org/abs/2207.13513
- class pyepo.func.perturbed.implicitMLE(optmodel: pyepo.model.opt.optModel, n_samples: int = 10, sigma: float = 1.0, lambd: float = 10, distribution: pyepo.func.utils.sumGammaDistribution | None = None, two_sides: bool = False, processes: int = 1, solve_ratio: float = 1.0, dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
pyepo.func.abcmodule.optModuleImplicit Maximum Likelihood Estimator (I-MLE) via perturb-and-MAP.
Frames decision-focused learning as imitation: an upstream task gradient \(\mathbf{d}\) induces a virtual update \(\hat{\mathbf{c}}' = \hat{\mathbf{c}} + \lambda \mathbf{d}\), and the gradient is estimated by a directional finite difference between smoothed solutions at \(\hat{\mathbf{c}}'\) and \(\hat{\mathbf{c}}\), sharing the same Sum-of-Gamma noise realization across the two evaluations to reduce variance.
Returns the (perturbation-smoothed) predicted solution; the user supplies a task loss (L1 against \(\mathbf{w}^*(\mathbf{c})\) is standard).
Reference: Niepert, Minervini & Franceschi (2021) https://proceedings.neurips.cc/paper_files/paper/2021/hash/7a430339c10c642c4b2251756fd1b484-Abstract.html
- n_samples = 10¶
- sigma = 1.0¶
- lambd = 10¶
- distribution = None¶
- two_sides = False¶
- forward(pred_cost: torch.Tensor) torch.Tensor¶
Forward pass
- class pyepo.func.perturbed.implicitMLEFunc(*args, **kwargs)¶
Bases:
torch.autograd.FunctionAn autograd function for Implicit Maximum Likelihood Estimator
- static forward(ctx, pred_cost: torch.Tensor, module: implicitMLE) torch.Tensor¶
Forward pass for IMLE
- Parameters:
pred_cost – a batch of predicted values of the cost
module – implicitMLE module
- Returns:
predicted solutions
- Return type:
torch.tensor
- static backward(ctx, grad_output: torch.Tensor) tuple[torch.Tensor | None, Ellipsis]¶
Backward pass for IMLE
- class pyepo.func.perturbed.adaptiveImplicitMLE(optmodel: pyepo.model.opt.optModel, n_samples: int = 10, sigma: float = 1.0, distribution: pyepo.func.utils.sumGammaDistribution | None = None, two_sides: bool = False, processes: int = 1, solve_ratio: float = 1.0, dataset: pyepo.data.dataset.optDataset | None = None)¶
Bases:
pyepo.func.abcmodule.optModuleAdaptive Implicit MLE (AI-MLE): I-MLE with an adaptive interpolation step.
Replaces I-MLE’s fixed finite-difference step \(\lambda\) with the data-dependent choice \(\lambda_t = \alpha_t \cdot \|\hat{\mathbf{c}}\| / \|\mathbf{d}\|\), where the magnitude \(\alpha_t\) is tuned online from a moving average of gradient sparsity. The rescaling keeps the perturbation commensurate with \(\hat{\mathbf{c}}\) and removes the need to tune \(\lambda\) by hand, while the rest of the forward / backward path is identical to
implicitMLE.Reference: Minervini, Franceschi & Niepert (2023) https://ojs.aaai.org/index.php/AAAI/article/view/26103
- n_samples = 10¶
- sigma = 1.0¶
- distribution = None¶
- two_sides = False¶
- alpha = 1.0¶
- grad_norm_avg = 1¶
- step = 0.001¶
- forward(pred_cost: torch.Tensor) torch.Tensor¶
Forward pass
- class pyepo.func.perturbed.adaptiveImplicitMLEFunc(*args, **kwargs)¶
Bases:
implicitMLEFuncAn autograd function for Adaptive Implicit Maximum Likelihood Estimator
- static backward(ctx, grad_output: torch.Tensor) tuple[torch.Tensor | None, Ellipsis]¶
Backward pass for IMLE