Personalization¶
In general, when rewritting the function for a new class, one way is to apply the following protocol code:
from types import MethodType
def _loss(self, X, y):
xxx
def _cvx_loss(self, X, y, theta, b):
xxx
model = XXDRO(...)
model._loss = MethodType(_loss, model)
model._cvx_loss = MethodType(_cvx_loss, model)
if we want to modify the self._cvx_loss and _loss functions in the model class.
1. Linear (Exact) DRO Methods¶
In DRO models that are solved exactly, for each particular DRO type, we change _loss and _cvx_loss in each class.
As a general high-level example, consider a convex piecewise-affine loss of the prediction residual
The arrays of slopes a and offsets c specify the loss. This family is
broader than a single newsvendor loss: absolute, pinball, and
epsilon-insensitive losses are all special cases. The
personalized-loss notebook
implements this parameterization for both \(f\)-DRO and Wasserstein DRO.
\(f\)-DRO¶
In KLDRO, Chi2DRO, CVaRDRO, TVDRO (and corresponding BayesianDRO), the
ambiguity set reweights the per-sample losses. Therefore, implementing the
piecewise-affine example only requires overriding _loss and
_cvx_loss.
Wasserstein DRO¶
For Wasserstein DRO, also override _penalization so that it matches the
Lipschitz modulus of the personalized loss. For the loss above and transport
cost
the notebook uses
with the second term omitted when labels cannot move
(kappa='inf'). This follows the tractable piecewise-affine regression
formulation in Theorem 4 of
Regularization via Mass Transportation.
Remark¶
We remark that for more complicated losses, e.g., losses with a mixture of distances, we have not implemented the personalize loss yet.
Note that we have not implemented the personalized constraint module yet \((e.g., for \)\theta$). Stay tuned for that.
2. NN-Based DRO Methods¶
2.1 Personalized Loss¶
For f-DRO and WDRO methods, our package supports personalized loss functions.
For example, a decision-aware regression model can use the unbalanced L1 loss
where the two coefficients encode the different downstream costs of under-predicting and over-predicting. The final section of the personalized-loss notebook shows how to use this per-sample loss in both the neural \(f\)-DRO and neural Wasserstein hooks.
\(f\)-DRO¶
To integrate a custom loss function:
Create a new
RobustLossinstance (fromfdro_utils.py), and re-write theself._compute_individual_loss()function to user-specified forms.Create a new
Chi2NNDROorCVaRNNDROinstance (fromfdro_nn.py), and re-write theself._criterion()function with the newly-modifiedRobustLossinstance above.
WDRO¶
When personalizing the loss function for WDRO, please:
Create a new
WNNDROinstance (fromwdro_nn.py).Re-write the
self._loss()function.
2.2 Personalized Model Architecture¶
Users could pass their own model via self.update() function. Note that the personalized model must be written via PyTorch and is a sub-class of torch.nn.Module.
3. Tree-Based DRO Methods¶
For tree-based DRO methods, users can rewrite the self.loss() function to change loss functions. To change the DRO type, adjust self._kl_dro_loss() (or self._cvar_dro_loss()) if the base model is KLDRO_XX (or CVaRDRO_XX), respectively.
See the personalized-loss notebook for end-to-end linear and neural customization examples.