Continuous Group DRO¶
Group Distributionally Robust Optimization (Group DRO) replaces the average training risk with the worst-group risk over a small set of physical regimes. For regression on a long-tailed continuous target, the target range is split into interpretable bins, and the model is trained to equalize its error across them instead of averaging a catastrophic tail away with a well-populated bulk.
torchregress already has a CVaR loss that focuses on the worst individual samples. CVaR is the wrong tool for noisy astronomical data: the highest-loss individuals are usually corrupted spectra or outliers in the bulk, not the metal-poor tail. Group DRO first averages the individual noise inside each target regime, then equalizes the regime means, so a noisy solar-metallicity sample cannot dominate the objective.
The idea
Bin the target into \(G\) regimes. Maintain adversarial weights \(q_g\) on the simplex, update them with exponentiated-gradient ascent toward the worst-performing regime, and train on \(\sum_g q_g \mathcal L_g\).
Mathematical formulation¶
Let \(\ell(f_\theta(x), y)\) be a per-sample loss and \(P_g\) the conditional distribution of \((x,y)\) restricted to target bin \(g\). Group DRO solves the minimax problem
The inner maximization is over the simplex of group weights \(q\); the solution is found by exponentiated-gradient (EG) ascent on the group losses \(\mathcal L_g^{(t)}\) of the current batch:
and the training objective is the \(q\)-weighted mixture
where \(q\) is treated as a constant in the gradient step (the adversarial weights are updated in a separate, detached step — this is the standard two-player interpretation).
Numerical form
The implementation performs the update in log space, \(\log q_g \leftarrow \log q_g + \eta\mathcal L_g\) followed by a log-sum-exp normalization, so a badly predicted bin with a huge loss cannot overflow the weights. Groups absent from a batch keep their previous weight before renormalization. An optional per-group floor min_group_weight projects the simplex onto \(\{q_g \ge m,\ \sum_g q_g = 1\}\), trading exact worst-group optimality for lower variance when a group has very few samples.
Usage¶
End-to-end trainer¶
import torch
import torch.nn as nn
from torchregress.algorithms import GroupDROTrainer
torch.manual_seed(0)
# Three regimes with very different population sizes and scatter:
# solar-like (many, small scatter), metal-poor (few), extreme (very few).
y = torch.cat(
[
0.1 + 0.1 * torch.randn(500), # bulk
-1.5 + 0.3 * torch.randn(200), # sparse regime
-3.0 + 0.4 * torch.randn(100), # extreme regime
]
)
x = torch.stack([y, torch.sin(y)], dim=1) + 0.05 * torch.randn(y.shape[0], 2)
def make_model():
return nn.Sequential(nn.Linear(2, 32), nn.SiLU(), nn.Linear(32, 1))
# Physical regimes: sparse (-4, -2.5), (-2.5, -1), bulk (-1, 0.5).
trainer = GroupDROTrainer(
model_factory=make_model,
group_edges=[-4.0, -2.5, -1.0, 0.5],
base_loss="mse",
eta=0.01,
epochs=100,
lr=1e-3,
batch_size=64,
seed=0,
)
trainer.fit(x, y)
y_hat = trainer.predict(x)
print("group weights:", trainer.group_weights_.tolist())
print("per-regime losses:", trainer.group_losses_.tolist())
The fitted attributes are:
| Attribute | Meaning |
|---|---|
trainer.model |
Fitted model (in eval mode). |
trainer.group_weights_ |
Final simplex weights \(q\) (sum to 1). |
trainer.group_losses_ |
Per-regime final losses (data-weighted over batches; NaN for empty regimes). |
trainer.history_ |
Per-epoch {"loss": ..., "q": [...]} records. |
The loss in a custom training loop¶
ContinuousGroupDRO is a torch.nn.Module, so it composes with any optimizer:
from torchregress.algorithms import ContinuousGroupDRO
dro = ContinuousGroupDRO([-4.0, -3.0, -2.0, -1.0, 0.5], eta=0.01, base_loss="mse")
dro.fit_group_edges(y_train) # not needed when edges are isotropic/physical
model = make_model()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
for x, y in loader:
optimizer.zero_grad()
loss = dro(model(x), y) # updates q in training mode
loss.backward()
optimizer.step()
# Validation: freeze the adversarial weights.
dro.eval()
with torch.no_grad():
val_loss = dro(model(x_val), y_val)
group_losses(y_pred, target) returns the per-regime losses without updating \(q\) (useful for diagnostics), and group_weights() returns the current simplex weights.
Comparison with related objectives¶
| Objective | What is equalized / penalized | Needs target bins? | Robust to corrupted bulk samples? |
|---|---|---|---|
| Plain MSE | Mean error over the empirical mixture | No | No — bulk dominates |
| LDS / Balanced MSE | Re-weighted or distribution-corrected mean | Density estimate | No — reweights points, not regimes |
CVaR (CVaRLoss) |
Mean of the worst \(\alpha\) fraction of individual samples | No | No — corrupted bulk samples are the highest losses |
| Group DRO | Worst target-regime mean | Yes (physical bins) | Yes — noise averages out inside each bin before equalization |
| PRIME / ConR | Feature-space representation of sparse targets | No (continuous targets) | Partially |
| IRLS | Robust point-wise residual weighting | No | Yes (per-point robustness, not per-regime) |
Choosing bins
Bins should be physically meaningful and each should contain enough objects for a stable mean (tens of samples at least). For metallicity, the natural bins are [-4, -3], [-3, -2], [-2, -1], [-1, +0.5]; for photometric redshift, use redshift intervals of comparable comoving volume. If a bin is nearly empty, either merge it or set min_group_weight so it cannot be starved, and report the per-bin loss with its sample count.
Caveats¶
Assumptions and failure modes
- Group labels are needed. The bins are derived from the target; if the target is the quantity you are predicting, bins are available at training time (where labels exist). Group DRO assumes the test distribution still contains all regimes.
- Worst-group average is not worst-case robustness. A regime mean still includes corrupted samples; it just averages them. Combine with a robust base loss (
base_loss="mae"or a Huber module withreduction="none") when outliers are expected. - Sample-starved groups are high variance. With few samples per bin, EG can oscillate; lower
eta, increaseupdate_every, or set a floor on the group weights. - Adversarial weights can concentrate. With a large
eta, \(q\) can put almost all mass on one regime, sacrificing the others. Monitorgroup_weights()and capetafor stability. - Validation must not update \(q\). Call
.eval()(orGroupDROTrainer.predict) when measuring validation metrics; otherwise the adversarial weights follow the validation losses. - Not a calibration method. It changes the fitted model, not the predictive intervals or coverage; re-run conformal/post-hoc calibration after switching to Group DRO.
References¶
| # | Reference |
|---|---|
| 1 | Sagawa, S., Koh, P. W., Hashimoto, T. B., & Liang, P. (2020). Distributionally robust neural networks for group shifts: on the importance of regularization for worst-case generalization. ICLR 2020. arXiv:1911.08731 |
| 2 | Oren, Y., Sagawa, S., & Hashimoto, T. B. (2019). Distributionally robust language modeling. EMNLP 2019. arXiv:1909.02060 |
| 3 | Hashimoto, T. B., Srivastava, M., Namkoong, H., & Liang, P. (2018). Fairness without demographics in repeated loss minimization. ICML 2018. arXiv:1806.08010 |
| 4 | Rockafellar, R. T., & Uryasev, S. (2000). Optimization of conditional value-at-risk. Journal of Risk, 2, 21–42. (CVaR comparison.) |
See also¶
- Imbalanced targets — LDS, FDS, Balanced MSE, CVaR.
- PRIME & ConR — representation-level imbalanced regression.
- IRLS — robust reweighting with a different objective.
- Imbalanced / rare-target regression — task-level selection matrix.