Imbalanced Regression¶
Imbalanced regression addresses problems where the target distribution is highly non-uniform — some regions (e.g., extreme values) are severely underrepresented. Standard MSE optimises average performance, causing the model to ignore rare-but-important regions.
The Problem¶
Reweighting changes the target distribution
Target-dependent weights change the population optimum. For a weighted log score the optimizer converges to
which is not the naturally occurring \(p(y\mid x)\) unless \(w(y)\) is
constant. DensityWeightedLoss and other inverse-density schemes therefore
optimize a tail-balanced objective, not population density estimation.
This can be useful for rare-value performance, but must be reported
separately from calibration; it is not "calibration preserving".
Available Losses¶
| Loss | Method | Calibration | Pre-fitting | API |
|---|---|---|---|---|
BalancedMSELoss |
Inverse bin frequency (fixed edges) | ⚠️ Check | fit(y) |
Losses API (imbalanced) |
BalancedMSEBMC |
True noise-adaptive Balanced MSE (BMC) | Batch-coupled; tune/learn \(\sigma\) | fit(y) |
BMC guide |
RankSimLoss |
Feature ranking-similarity regularizer | Add to task loss | — | RankSim guide |
BinReweightedMSELoss |
Inverse bin frequency + count smoothing | ⚠️ Check | fit(y) |
Losses API (imbalanced) |
DensityWeightedLoss |
Inverse kernel-density weights | ⚠️ Tail objective (changes target density) | fit_density(y) |
Losses API (imbalanced) |
LDSLoss |
Smoothed label distribution | ⚠️ May break | fit(y) |
Losses API (imbalanced) |
PropensityWeightedLoss |
Inverse propensity scores | ✅ With correct scores | None | Losses API (imbalanced) |
FocalRLoss |
Sigmoid-scaled error emphasis | ✅ Mostly | None | Losses API (imbalanced) |
FeatureDistributionSmoother |
Feature-statistics (FDS) layer: smooths feature mean/variance across neighbouring target bins with a kernel, then recalibrates batch features | Representation-level; used inside the model | EMA per epoch (epoch counter) |
PRIME & ConR |
BalancedMSELoss and BinReweightedMSELoss¶
Inverse bin-frequency weighting (historically called BalancedMSELoss): partition the target range into histogram bins on training data, then weight each sample by roughly 1 / (bin count) (with optional additive smoothing). Bin weights are normalised so that their average over the training samples is 1 (the training loss stays on the MSE scale); empty bins (zero smoothed count) get weight 0 instead of a huge 1/eps that would collapse every populated bin's weight. BalancedMSELoss uses your bin_edges; BinReweightedMSELoss builds equal-width or quantile edges from num_bins and uses noise_sigma as a pseudocount when inverting counts (Laplace-style).
Name vs. method
Despite its historical name, BalancedMSELoss is inverse bin-frequency weighting, not the noise-adaptive Balanced MSE (BMC) of Ren et al. (CVPR 2022, arXiv:2203.16427). BMC models the target-noise distribution and is a different estimator; do not cite this class as a Ren et al. implementation. Use BalancedMSEBMC for the true batch-coupled BMC loss.
from torchregress.losses import BalancedMSELoss, BinReweightedMSELoss
edges = torch.linspace(y_train.min(), y_train.max(), 11) # 10 bins
loss_bal = BalancedMSELoss(bin_edges=edges).fit(y_train)
loss_binrew = BinReweightedMSELoss(num_bins=10, noise_sigma=1.0, binning="equal").fit(y_train)
loss = loss_bal(model(x), y_batch)
Multi-output targets use the mean coordinate for bin assignment; the weighted squared error still applies elementwise to y_pred - target.
Out-of-range targets
If test targets fall outside the bin edges estimated from fit(y_train), the weights for those samples are undefined. Always ensure y_train covers the full expected range of test targets, or use DensityWeightedLoss which handles out-of-range values gracefully via KDE.
KDE scaling
DensityWeightedLoss.fit_density() uses kernel density estimation (KDE).
The query axis is chunked, so memory is bounded rather than \(\mathcal{O}(N^2)\);
the time cost still grows with \(N \times N_{\text{train}}\). For very large
training sets, subsample for density estimation or use a bin-based method.
Calibration
Like other reweighting schemes, these losses change the training objective. Validate calibration on held-out data before relying on variance or interval outputs.
Sample weights vs. imbalance weights
For BalancedMSELoss, BinReweightedMSELoss, DensityWeightedLoss, LDSLoss, FocalRLoss and PropensityWeightedLoss, the imbalance (bin / density / focal / propensity) weights are part of the loss, while the user weights= argument follows the shared reduction contract: reduction="mean" returns \(\sum_i w_i \ell_i / \sum_i w_i\), so constant weights never change the loss scale. DensityWeightedLoss without sample_indices normalises the on-the-fly KDE weights by the training-set mean stored by fit_density(), so a target's weight does not depend on the rest of its mini-batch; the KDE reference uses only finite training targets, and masked (possibly NaN) targets are ignored.
DensityWeightedLoss¶
Weights samples inversely proportional to local target density via KDE:
from torchregress.losses import DensityWeightedLoss
loss_fn = DensityWeightedLoss(kernel_width=0.5, base_loss="mse", reweight_factor=1.0)
loss_fn.fit_density(y_train) # estimate density once
# Training loop
loss = loss_fn(model(x), y)
| Parameter | Type | Default | Description |
|---|---|---|---|
kernel_width |
float |
0.5 |
KDE bandwidth (smaller → more local) |
base_loss |
str |
"mse" |
"mse", "mae", or "huber" |
reweight_factor |
float |
1.0 |
Interpolation: 0 = uniform, 1 = full inverse density |
Recommended first choice
DensityWeightedLoss is a tail-balanced objective: it changes the
effective target density. Do not use it as a drop-in population density
estimator; evaluate calibration and rare-slice performance separately.
LDSLoss¶
Label Distribution Smoothing — smoother, more aggressive reweighting using kernel-smoothed bin frequencies:
from torchregress.losses import LDSLoss
loss_fn = LDSLoss(kernel="gaussian", kernel_width=2.0, reweight_factor=0.8)
loss_fn.fit(y_train, n_bins=100)
loss = loss_fn(model(x), y)
| Parameter | Type | Default | Description |
|---|---|---|---|
kernel |
str |
"gaussian" |
"gaussian", "triang", or "laplace" |
kernel_width |
float |
2.0 |
Smoothing bandwidth |
reweight_factor |
float |
1.0 |
Reweight interpolation |
base_loss |
str |
"mse" |
"mse", "mae", or "huber" |
Calibration
LDS modifies the effective training distribution through smoothing. Apply post-hoc calibration (e.g., isotonic regression, temperature scaling) before deployment.
PropensityWeightedLoss¶
Inverse-propensity weighting for selection bias correction — re-weights observed samples by estimated probability of being observed:
from torchregress.losses import PropensityWeightedLoss
loss_fn = PropensityWeightedLoss(
base_loss="mse",
clip_min=0.01, # floor propensity to avoid extreme weights
clip_max=0.99,
normalize_weights=True,
)
# propensity: P(observed | x) estimated externally (e.g., logistic regression)
loss = loss_fn(model(x), y, propensity=p_scores, observed=obs_mask)
| Parameter | Type | Default | Description |
|---|---|---|---|
base_loss |
str |
"mse" |
"mse", "mae", or "huber" |
clip_min |
float |
0.01 |
Minimum propensity (prevents extreme weights) |
clip_max |
float |
0.99 |
Maximum propensity |
normalize_weights |
bool |
True |
Normalise IPW weights to sum to batch size |
When to use
Use when you have selection bias — not all targets are equally likely to be observed (e.g., censored data, missing-not-at-random, survey sampling).
FocalRLoss¶
Focal loss for regression — adaptively upweights samples with larger prediction errors:
from torchregress.losses import FocalRLoss
loss_fn = FocalRLoss(beta=0.2, gamma=1.0, base_loss="mse")
loss = loss_fn(model(x), y)
| Parameter | Type | Default | Description |
|---|---|---|---|
beta |
float |
0.2 |
Error scaling in sigmoid |
gamma |
float |
1.0 |
Focus strength (higher → more emphasis on hard samples) |
base_loss |
str |
"mse" |
"mse", "mae", or "huber" |
No pre-fitting needed
Unlike density-based methods, FocalRLoss doesn't require a separate fit step — it adapts automatically during training.
Decision Guide¶
graph TD
A["Is target distribution imbalanced?"] -->|No| B["Use standard loss"]
A -->|Yes| C["Is calibration critical?"]
C -->|Yes| D["DensityWeightedLoss"]
C -->|No| E["How severe?"]
E -->|Moderate| F["FocalRLoss"]
E -->|Extreme| G["LDSLoss + post-hoc calibration"]
A -->|"Selection bias"| H["PropensityWeightedLoss"]
Limitations¶
- Calibration risk: Any target-dependent weight changes the population optimum.
DensityWeightedLossandLDSLossboth target a reweighted distribution unless corrected; validate calibration and report the weighting objective. Use sampling-selection corrections for population inference instead. - Out-of-range targets: If test targets fall outside the bin edges estimated from
fit(y_train)forBalancedMSELoss/BinReweightedMSELoss, weights are undefined. Ensure training targets cover the full expected test range. - KDE scaling:
DensityWeightedLoss.fit_density()scales as \(\mathcal{O}(N^2)\) with training set size. For \(N > 10^4\), subsample for density estimation or switch to a bin-based method. - FocalRLoss does not rebalance: Unlike density-based methods,
FocalRLossupweights hard samples regardless of their target value. It helps with difficult examples but does not address target-distribution imbalance. - Propensity scores must be accurate:
PropensityWeightedLossrequires well-calibrated propensity estimates. Poor propensity scores can amplify rather than correct selection bias.
Recommendations¶
- Default choice:
DensityWeightedLossis a reasonable tail-focused starting point; it handles out-of-range values via KDE, but it changes the target density. For population density estimation use the unweighted likelihood plus an explicit sampling-selection model. - For large datasets: Use
BalancedMSELossorBinReweightedMSELosswith pre-computed bin edges to avoid \(\mathcal{O}(N^2)\) density estimation. - For extreme imbalance:
LDSLosswith post-hoc calibration (temperature scaling) is the most aggressive option. See the imbalanced regression demo. - No pre-fitting needed:
FocalRLossrequires no separatefit()step — use when you want a quick, adaptive reweighting during training.
Next steps¶
- Noisy labels — another form of data quality issue
- Robust losses — bounded-influence alternatives for tail-focused evaluation
- Tail metrics — evaluate accuracy specifically on tail quantiles
- Imbalanced example — runnable comparison of all methods
References¶
| # | Reference |
|---|---|
| 1 | Y. Yang et al. "Delving into Deep Imbalanced Regression." ICML, 2021. |
| 2 | T.-Y. Lin et al. "Focal Loss for Dense Object Detection." ICCV, 2017. |