Other NN DRO

This notebook demonstrates how to call the neural-network implementations of chi-square DRO, CVaR-DRO, Wasserstein DRO, and Holistic Robust DRO. All four examples use the same binary classification data, MLP architecture, and training settings so that the API differences are easy to compare. The focus here is code usage rather than mathematical formulations.

Shared setup

The Wasserstein and Holistic Robust estimators create bounded adversarial perturbations, so the synthetic features are scaled to the interval [0, 1]. Set verbose=False to keep progress-bar output out of the generated documentation.

[ ]:
import numpy as np
import torch
from sklearn.datasets import make_classification
from sklearn.preprocessing import MinMaxScaler

from dro.neural_model import Chi2NNDRO, CVaRNNDRO, HRNNDRO, WNNDRO

np.random.seed(42)
torch.manual_seed(42)

X, y = make_classification(
    n_samples=200,
    n_features=10,
    n_informative=6,
    n_redundant=2,
    weights=[0.7, 0.3],
    random_state=42,
)
X = MinMaxScaler().fit_transform(X).astype(np.float32)
y = y.astype(np.int64)

fit_options = {
    "train_ratio": 0.8,
    "lr": 1e-3,
    "batch_size": 32,
    "epochs": 3,
    "verbose": False,
}

print(f"X shape: {X.shape}; class counts: {np.bincount(y)}")

Chi-square neural DRO

size controls the uncertainty-set radius and reg controls regularization of the sample weights. Training uses the standard neural fit() interface.

[ ]:
torch.manual_seed(42)
chi2_model = Chi2NNDRO(
    input_dim=X.shape[1],
    num_classes=2,
    task_type="classification",
    model_type="mlp",
    size=0.1,
    reg=0.1,
    max_iter=100,
)
chi2_metrics = chi2_model.fit(X, y, **fit_options)
print("Chi-square DRO:", chi2_metrics)

CVaR neural DRO

For CVaRNNDRO, size is the CVaR fraction and must be between zero and one. The remaining training call is identical to the chi-square example.

[ ]:
torch.manual_seed(42)
cvar_model = CVaRNNDRO(
    input_dim=X.shape[1],
    num_classes=2,
    task_type="classification",
    model_type="mlp",
    size=0.2,
    reg=0.1,
    max_iter=100,
)
cvar_metrics = cvar_model.fit(X, y, **fit_options)
print("CVaR-DRO:", cvar_metrics)

Wasserstein neural DRO

WNNDRO exposes the perturbation radius, attack step count, step size, norm, and attack method in its constructor. This compact example uses three projected-gradient steps.

[ ]:
torch.manual_seed(42)
wasserstein_model = WNNDRO(
    input_dim=X.shape[1],
    num_classes=2,
    task_type="classification",
    model_type="mlp",
    epsilon=0.1,
    adversarial_steps=3,
    adversarial_step_size=0.02,
    adversarial_norm="l2",
    adversarial_method="PGD",
)
wasserstein_metrics = wasserstein_model.fit(X, y, **fit_options)
print("Wasserstein DRO:", wasserstein_metrics)

Holistic Robust neural DRO

HRNNDRO combines its robustness settings with an adversarial-training configuration. train_batch_size is kept consistent with the batch size passed to fit().

[ ]:
torch.manual_seed(42)
holistic_model = HRNNDRO(
    input_dim=X.shape[1],
    num_classes=2,
    task_type="classification",
    model_type="mlp",
    alpha=0.1,
    r=0.01,
    epsilon=0.05,
    learning_approach="HD",
    adversarial_params={
        "steps": 3,
        "step_size": 0.02,
        "norm": "l2",
        "method": "PGD",
    },
    train_batch_size=32,
)
holistic_metrics = holistic_model.fit(X, y, **fit_options)
print("Holistic Robust DRO:", holistic_metrics)

Compare the returned metrics

Every estimator returns the same validation-metric dictionary for this classification example, which makes downstream comparison straightforward.

[ ]:
results = {
    "Chi-square DRO": chi2_metrics,
    "CVaR-DRO": cvar_metrics,
    "Wasserstein DRO": wasserstein_metrics,
    "Holistic Robust DRO": holistic_metrics,
}

for method, metrics in results.items():
    print(f"{method:24s} accuracy={metrics['acc']:.3f}, f1={metrics['f1']:.3f}")