Bias, Fairness and Differential Privacy
Measure bias, pick a fairness criterion, train with DP-SGD and audit the privacy claim. Stdlib Python toys.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Comparisons
- Defaults and numbers
- Troubleshooting
- Questions and tips
Three fairness families side by side#
| Factor | Group fairness | Individual fairness | Counterfactual fairness |
|---|---|---|---|
| Rule | Equal rates across protected groups | Similar individuals get similar decisions | Decision unchanged when sensitive attributes change |
| Source | Demographic parity, equalized odds, CUAE | Dwork et al. 2012 | Kusner et al. 2017 |
| Needs | Group labels and outcomes | A similarity metric d | A causal DAG |
| Formal test | Equal rates per group | Lipschitz constant L | Counterfactual alteration |
| Weak point | Criteria conflict under unequal base rates | Defining d is a policy question | Only as justified as the DAG |
Use each criterion when#
- Use demographic parity when the claim is equal acceptance rates.
- Use equalized odds when the claim is equal TPR and FPR across groups.
- Use conditional use accuracy equality when the claim is equal predictive value.
- Use individual fairness when you can define a task-specific metric d.
- Use counterfactual fairness when you have a causal DAG of the population.
- Use backtracking counterfactuals when the law forbids interventions on protected attributes.
Formulas#
- Demographic parity
- P(Y=1 | A=a) = P(Y=1 | A=a') for all groups.
- Equalized odds
- P(Y=1 | Y=y, A=a) = P(Y=1 | Y=y, A=a').
- Conditional use accuracy
- P(Y=y | Y=y, A=a) = P(Y=y | Y=y, A=a').
- Individual fairness
- |f(x) - f(x')| <= L * d(x, x')
- (ε, δ)-DP
- P(M(D) \in S) \le e^{\varepsilon} \cdot P(M(D') \in S) + \delta
- WEAT term
- s(w, X, Y) = mean cosine(w, X) - mean cosine(w, Y)
- WEAT effect
- mean_a(s) - mean_b(s) over identity groups.
DP-SGD recipe#
Where bias is measured#
Toy WEAT probe#
A = ["he", "his", "man"]identity group AB = ["she", "her", "woman"]identity group BX = ["engineer", "programmer", "scientist"]tech / careerY = ["nurse", "teacher", "caregiver"]care / familypre = weat_score(A, B, X, Y)positive: A closer to XEMB = debias(EMB)project out the gender directiongender_dir = [1.0, -1.0, 0.0, 0.0]axis 1 minus axis 0post = weat_score(A, B, X, Y)drops, not to zeroCall the toy code#
| Task | Code |
|---|---|
| Score a WEAT probe | weat_score(<identity_a>, |
| Project out a bias direction | debias(<emb>) |
| Train with reweighting | train(data, |
| Demographic parity per group | demographic_parity(preds) |
| Equalized odds per group | equalized_odds(preds) |
| Clip one gradient | clip(<g>, |
| Train with DP-SGD | dp_sgd(data, |
| Epsilon for a run | analytical_epsilon(sigma, |
Group metrics and DP reweighting#
train_data = gen(1000)A=0 base 0.3, A=1 base 0.6test_data = gen(500)baseline = train(train_data)steps 200, lr 0.1preds = predict(baseline, test_data)(pred, label, group)demographic_parity(preds)rate0, rate1equalized_odds(preds)(TPR, FPR) per groupconditional_use(preds)(PPV, NPV) per groupdp_reweighted = train(train_data, sample_weights=weights)a=0 y=1: 2.0, a=1 y=1: 0.5DP-SGD toy#
grad_w = clip(grad_w, C)scale to norm Cgrad_b = max(-C, min(C, grad_b))clip the bias gradientnoise_b = random.gauss(0.0, sigma * C)noise std sigma * Cb -= lr * (grad_b + noise_b)noisy update per examplefor sigma in (0.0, 0.5, 1.0, 2.0, 4.0):sweep the noise multiplier model = dp_sgd(train_data, epochs=epochs, lr=0.05, sigma=sigma, C=C) acc = accuracy(model, test_data)eps = analytical_epsilon(max(sigma, 0.01), steps=epochs * len(train_data), delta=delta)Toy defaults#
| Setting | Default | Note |
|---|---|---|
Clip norm C | 1.0 | Lesson 22 toy |
delta | 1e-5 | Default of analytical_epsilon |
epochs | 10 | DP-SGD toy, 500 train rows |
DP-SGD lr | 0.05 | Fixed in the sweep |
sigma | 0.0 | Standard SGD, infinite epsilon |
| Published ε | [1, 10] | Illustrative, not a recommended default |
Fairness train | steps: int = | lr: float = |
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| WEAT effect does not drop to zero | Debiasing reduces but does not eliminate it | Add probability and generated-text metrics |
| Diverse portrayals, unequal decisions | Only representational harm measured | Measure allocational harm too |
| Gender eval passes, bias remains | Bias fires on (gender, race) pairs | Run intersectional tests |
| DP gap shrinks, EO and CUAE worsen | Unequal base rates | State the chosen criterion as policy |
| Canary MIA shows little leakage | Canaries are not "most extractable" data | Add training-data extraction tests |
| Outputs safe, individuals re-identified | Confidence scores leak | Do not expose, or truncate/quantize them |
Questions#
- Can one model meet all three group criteria?
- No. Unequal base rates prevent it (Chouldechova, KMR 2017).
- Why backtracking counterfactuals?
- They reason from actual features. They do not intervene on the attribute.
- Why do MIA and extraction disagree?
- They measure different things: inserted canaries vs "most extractable" data.
- What does LoRA + DP-SGD protect?
- The adapter. The base model is held fixed.
- Why uncertainty in WinoIdentity?
- Equal error with unequal uncertainty still changes allocation.