Privacy-Preserving Experiment Design Questions
Techniques and considerations for designing experiments and data collection strategies that protect privacy. Covers methods such as differential privacy, secure aggregation, federated learning, synthetic data, data minimization, consent management, de-identification, and privacy risk assessment, with emphasis on maintaining data utility and regulatory compliance while enabling robust experimentation.
MediumTechnical
68 practiced
Describe step-by-step how to integrate DP-SGD into an existing PyTorch training pipeline using Opacus (or equivalent). Include modifications to the dataloader for privacy sampling, how Opacus handles per-sample gradients and clipping, tuning noise multiplier and clipping thresholds, and how to report and monitor cumulative epsilon during training.
Sample Answer
To integrate DP-SGD into an existing PyTorch pipeline with Opacus, follow these steps:1) Install and import Opacus- pip install opacus- from opacus import PrivacyEngine2) Modify DataLoader to use privacy-aware sampling- Use Poisson (sample-with-probability) or ensure DataLoader drop_last=False with sampler that supports per-sample sampling.- Recommended: use torch.utils.data.DataLoader(dataset, batch_size=batch_size, sampler=torch.utils.data.RandomSampler(dataset, replacement=True, num_samples=epoch_size)) or Opacus’ provided DPDataLoader wrapper for Poisson sampling.3) Wrap optimizer with PrivacyEngine- PrivacyEngine handles per-sample gradients, clipping, and noise addition. It hooks into backward to compute per-sample grads efficiently (per-layer hooks), clips each sample gradient to l2_norm_clip, then aggregates and adds Gaussian noise scaled by noise_multiplier.Example integration:4) Training loop (no changes to loss/backward except keep loss reduction='mean')- Call loss.backward(); optimizer.step(); optimizer.zero_grad()- Opacus computes per-sample gradients internally, clips, aggregates, and injects noise before step.5) Tuning noise_multiplier and clipping thresholds- Clipping (max_grad_norm): start with median per-sample grad norm observed without clipping (run a few batches to log per-sample norms) and set clip near lower percentile (e.g., 50–75th percentile).- Noise multiplier: trade-off between epsilon and utility. Use grid search: for each (clip, noise) pair train and evaluate; higher noise → higher utility loss but smaller epsilon. Use target privacy budget to pick noise.- Use larger batch_size or increase epochs rather than reduce noise to meet utility.6) Compute and monitor cumulative epsilon- Opacus provides accountant via privacy_engine.get_privacy_spent(delta) or optimizer.privacy_engine.get_privacy_spent(delta)- After each epoch or step log: eps, delta- Monitor epsilon across training and stop when budget reached.7) Edge cases & best practices- Ensure deterministic dataloader seeding if reproducible eps calculations needed.- For large models, per-sample grads can increase memory; use Opacus’ “virtual batching” / gradient accumulation to emulate larger batch without increasing memory.- Use strong default delta (<=1/num_train_examples).- Validate on non-private baseline to measure utility gap.This approach integrates DP-SGD with minimal training-loop changes while Opacus handles per-sample gradient computation, clipping, noise addition, and privacy accounting.
python
import torch
from opacus import PrivacyEngine
model = MyModel().to(device)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
privacy_engine = PrivacyEngine(
model,
sample_rate=batch_size / len(train_dataset), # if using Poisson sampling: batch_size/len
alphas=[10, 100],
noise_multiplier=noise_multiplier,
max_grad_norm=clip_norm,
)
privacy_engine.attach(optimizer)python
eps, best_delta = privacy_engine.accountant.get_privacy_spent(delta=1e-5)
print(f"After epoch {epoch}: ε = {eps:.3f}, δ = {best_delta}")HardTechnical
76 practiced
Provide a high-level implementation plan and key PyTorch or TensorFlow code snippets for training a DP-GAN that generates tabular data with mixed categorical and numeric features. Include how to implement per-example gradient clipping and noise addition for both generator and discriminator, how to integrate an RDP accountant, and which metrics to log to evaluate privacy and utility during training.
Sample Answer
High-level plan1. Clarify requirements: privacy budget (ε, δ target), dataset schema (which cols categorical vs numeric), utility targets (downstream task, distributional similarity).2. Model design: conditional GAN for mixed data (embedding layers for categorical features, continuous heads for numerics). Use architectures with small capacity to reduce required noise.3. Privacy: apply DP-SGD (per-example clipping + Gaussian noise) to both discriminator and generator updates (if generator trained with gradients that depend on real data — usually discriminator sees real data; if generator training uses discriminator output only, generator can be non-DP, but you requested DP for both so we add DP noise there too).4. Accounting: use RDP accountant each epoch to compute (ε, δ) from sigma, clipping, batch_size, dataset_size, and steps.5. Metrics: log privacy (ε for target δ), training losses, Wasserstein/JS estimates, feature-wise KS/JS, pairwise correlations, classifier AUC on real vs synthetic (propensity score), and utility on downstream tasks.6. Iterate hyperparameters (clip norm, noise multiplier, batch size) to trade privacy/utility.PyTorch (recommended: Opacus for per-sample grads; functorch for generator if needed)- Using Opacus for discriminator (handles per-sample clipping + noise + accounting).- For generator, if you require per-example clipping you can compute per-sample grads via functorch.vmap and add Gaussian noise manually before optimizer step.Example: discriminator with Opacus and RDP accountingPyTorch: generator per-sample clipping via functorch + manual noise(Implementing per-sample gradient aggregation is complex; functorch + helper utilities or Opacus extensions can simplify.)TensorFlow (using tensorflow_privacy)Key concepts / reasoning- Per-example gradient clipping bounds sensitivity so adding Gaussian noise yields DP guarantees.- RDP is preferred for composition and tight ε estimates; convert RDP -> (ε, δ) after each epoch or at end.- Larger batch sizes reduce noise per example (for same noise multiplier) but change privacy accounting (sample_rate).- Often only discriminator needs DP because generator updates depend only on discriminator outputs; however if generator directly touches real data (e.g., reconstruction loss), you must DP it too.Metrics to log (privacy + utility)- Privacy: ε at target δ using RDP accountant every epoch/step.- Training: generator & discriminator losses, gradient norms, noise multiplier, clip norm.- Distributional similarity: per-feature KS statistic, JS divergence for categorical distributions, marginal histograms.- Correlations: Pearson/Spearman and pairwise mutual information differences.- Downstream utility: classifier AUC/F1 trained on synthetic and tested on real (or vice versa), propensity score (train model to distinguish real vs synthetic; lower AUC = better).- Sample quality: nearest-neighbor distances to training set (privacy leakage check), likelihood if applicable.Practical tips- Start with strong clipping (small norm) and moderate noise multiplier; tune for utility.- Use public data or hold-out set to validate utility without consuming privacy budget.- Prefer established libraries: Opacus (PyTorch) or tensorflow_privacy to avoid subtle bugs in DP math.- Log privacy budget continuously to ensure you don't exceed target ε.
python
import torch
from opacus import PrivacyEngine
# model, dataloader, optimizer_d defined
privacy_engine = PrivacyEngine(
module=disc,
sample_rate=batch_size / len(dataset),
alphas=[1 + x/10. for x in range(1, 100)], # RDP orders
noise_multiplier=noise_multiplier,
max_grad_norm=clip_norm,
)
privacy_engine.attach(optimizer_d)
for epoch in range(epochs):
for real_batch in loader:
# standard GAN discriminator step
optimizer_d.zero_grad()
loss_d = discriminator_loss(real_batch, gen)
loss_d.backward()
optimizer_d.step()
eps, best_alpha = privacy_engine.get_privacy_spent(delta=target_delta)
print(f"Epoch {epoch} ε = {eps:.3f}, δ = {target_delta}")python
from functorch import make_functional_with_buffers, vmap, grad
# make functional for generator
f_gen, params_gen, buffers = make_functional_with_buffers(gen)
def loss_fn(params, buffers, z, real_labels):
fake = f_gen(params, buffers, z)
return generator_loss_from_disc(fake, disc)
# compute per-sample grads
per_sample_grads = vmap(grad(loss_fn), in_dims=(None, None, 0, 0))(params_gen, buffers, z_batch, real_labels_batch)
# clip per-sample grads (L2 across parameters)
def clip_and_aggregate(per_sample_grads, max_norm):
norms = torch.stack([torch.sqrt(sum((g**2).sum() for g in sample))) for sample in zip(*per_sample_grads)])
scales = (max_norm / (norms + 1e-6)).clamp(max=1.0)
# scale each sample's grads then sum and add noise
aggregated = [ (g * scales.view(-1, *([1]* (g.dim()-1)))).sum(0) for g in per_sample_grads ]
return aggregated
agg_grads = clip_and_aggregate(per_sample_grads, clip_norm)
# add Gaussian noise
for g in agg_grads:
g += torch.normal(0, noise_multiplier*clip_norm, size=g.shape, device=g.device) / batch_size
# load into optimizer & step (manual param update or set gradients then optimizer.step)python
import tensorflow as tf
from tensorflow_privacy.privacy.optimizers.dp_optimizer_keras import DPKerasAdamOptimizer
from tensorflow_privacy.privacy.analysis.rdp_accountant import compute_rdp, get_privacy_spent
optimizer_d = DPKerasAdamOptimizer(
l2_norm_clip=clip_norm,
noise_multiplier=noise_multiplier,
num_microbatches=batch_size, # or set microbatches <= batch_size
learning_rate=lr
)
# compile discriminator with optimizer_d and train via gradient tape
# compute RDP epsilon each epoch:
orders = [1 + x/10. for x in range(1, 100)]
sampling_prob = batch_size / dataset_size
rdp = compute_rdp(q=sampling_prob, noise_multiplier=noise_multiplier, steps=steps, orders=orders)
eps, opt_order = get_privacy_spent(orders, rdp, target_delta)
print(eps)MediumSystem Design
59 practiced
Design a privacy budget management system for a company where multiple product teams run experiments on shared user populations. System must enforce per-user epsilon per rolling window, allow teams to request and reserve budgets, provide immutable audit logs, and prevent accidental overspend. Describe APIs, enforcement mechanisms, user-facing controls, and conflict resolution policies between competing experiments.
Sample Answer
Requirements:- Enforce per-user epsilon over configurable rolling window (e.g., 30 days).- Teams can request/reserve budget for experiments; reservations are enforced and immutable when committed.- Prevent accidental overspend; provide immutable audit logs and alerts.- Low-latency enforcement during experiment assignment and logging; scalable to millions of users.High-level architecture:- Policy Service (central authority) + Budget Store (time-series DB) + Reservation API + Enforcement Proxy (sidecar or gateway) + Audit Log (append-only, e.g., WORM storage) + Dashboard & CLI.APIs:- POST /reserve {team, experiment_id, users/segment, epsilon_total, window, start,end} → reservation_id (validate conflicts, provisional)- POST /commit/{reservation_id} → commit reservation (immutable)- GET /balance/{user_id} → remaining epsilon for rolling window- POST /consume {experiment_id, user_id, epsilon} → synchronous call from assignment path; returns allow/deny- GET /audit?experiment_id/&team/&user_id → immutable recordsEnforcement:- Enforcement Proxy intercepts assignment/serve calls, calls Policy Service to atomically check and debit per-user budgets using a strong consistency primitive (compare-and-swap) or lightweight transactions in the Budget Store. Use token-bucket style with sliding window counters stored per user and hashed to partitions for scale. Reservations create soft locks reducing available capacity; commit turns into hard debit schedule.Audit & immutability:- All reservation, commit, consume operations append signed records to append-only storage (object store + hash chaining). Periodic Merkle root published for external verification. Retain logs per compliance SLA.User-facing controls:- Dashboard showing per-team/experiment/user segment spend, projected consumption given traffic, alerts when reach thresholds (e.g., 80%), and a “dry-run” reservation simulator.- Quotas & hard caps configurable per team.Conflict resolution:- Reservation policy: FIFO by commit time, priority tiers (safety/compliance > infra > product), and preemption rules: higher-priority reservation can preempt provisional reservations with notification and rollback window. Automated negotiation: if two reservations overlap on same user population, system proposes split by traffic or time slices; manual override requires elevated approval and is logged.Trade-offs:- Strong consistency ensures correctness but adds latency—use synchronous checks for sensitive flows and batched async debit for low-risk telemetry. Partitioning and caching reduce latency; audits ensure post-hoc verification and reconciliation.
HardTechnical
82 practiced
A third-party analytics vendor accidentally exposed raw experiment datasets containing quasi-identifiers. As the ML engineering lead, outline your incident response plan: technical containment steps, forensic investigation to determine scope, communications to legal and affected stakeholders, determining regulatory notification obligations, remediation steps for models trained on leaked data, and long-term fixes to prevent recurrence.
Sample Answer
Situation: During routine monitoring I was alerted that a third‑party analytics vendor had accidentally exposed raw experiment datasets (containing quasi‑identifiers: age, ZIP, device IDs, experiment arm). The data pipeline ingested vendor exports into a staging bucket and some models had been trained on recent batches.Task: As ML Engineering Lead I needed to contain the leak, assess scope, notify legal/PR/regulators as required, remediate any affected models and pipelines, and implement long‑term technical and contractual fixes.Action:- Immediate technical containment (first 24 hours) - Instruct platform ops to revoke vendor access keys, disable the vendor’s ingestion endpoint, and isolate the staging bucket (make it non-public, apply MFA and temporary deny‑all ACL). - Snapshot current state (immutable copy) for forensics; preserve logs, access records, S3/GCS object versions and IAM events. - Halt automated retraining jobs that consumed vendor data and quarantine model artifacts trained in the last 90 days.- Forensic investigation (24–72 hours) - Work with security/forensics to reconstruct timeline: which files were exposed, timestamps, IPs, download counts; correlate with internal ingestion logs to identify which datasets entered our systems. - Query model training metadata (dataset hashes, run IDs) to find which models used the leaked data; mark models by risk level. - Estimate re‑identification risk (k‑anonymity, uniqueness of quasi‑identifiers) with data privacy SME.- Communications & legal - Notify Legal, Privacy Officer, and CISO within 24 hours with preliminary scope and evidence. Draft holding statements for execs and PR. - Prepare targeted notifications for affected partners/customers and internal stakeholders; avoid premature public disclosure until legal advises.- Regulatory obligations - Coordinate with Legal to evaluate GDPR/CCPA obligations: if data is personal or quasi‑identifiers enable singling out, assess whether supervisory authority notification is required (72‑hour GDPR window) and whether data subject notifications are required. - Provide documented timeline and mitigation plan to regulators if necessary.- Remediation for models - For high‑risk models (directly trained on leaked records): take offline (or serve with restricted traffic), retrain from scratch on scrubbed datasets excluding leaked records, validate performance and bias metrics, run membership inference and data‑leakage tests. - For lower‑risk models: apply differential privacy finetuning or auditing; if retraining isn’t feasible immediately, add guardrails in serving (reduce confidence leakage, stricter feature exposure) and monitor for anomalous behavior. - Re‑issue model lineage and data provenance records; update model cards noting incident and remediation.- Long‑term fixes (policy + technical) - Stop future vendor direct raw data ingestion: require pseudonymization or aggregated exports; encrypt and tokenise identifiers client‑side or at vendor before transfer. - Enforce strict vendor contracts: security SLAs, breach notification timelines, right to audit, indemnity. - Implement data ingress hardening: automated scanners to detect PII/quasi‑identifiers, schema validation, mandatory data classification tags, retention policies, and immutable audit trails. - Apply role‑based access controls, short‑lived credentials, VPC service controls, and anomaly detection for unusual data egress. - Build routine privacy testing in CI: membership inference tests, k‑anonymity checks, and redaction validators.- Post‑incident review - Run blameless post‑mortem within one week, publish action items with owners and deadlines, track to closure. - Train teams and update runbooks for future vendor incidents.Result / Learning:- Containment and documented remediation minimize regulatory exposure; retraining and enhanced controls restore safe production serving. Key learning: assume third‑party data can be risky—shift to privacy‑first ingestion, stricter contracts, and automated pre‑ingest checks to prevent recurrence.
HardTechnical
63 practiced
Implement in Python an RDP accountant that supports the subsampled Gaussian mechanism under Poisson subsampling. The function must accept noise multiplier sigma, sampling probability q, number of steps T, and target delta, and return minimal epsilon. Outline numerical methods used (log-space sums, optimization over Renyi orders) and include a short test validating results against small brute-force calculations.
Sample Answer
To compute epsilon for the subsampled Gaussian mechanism under Poisson subsampling we use the Rényi Differential Privacy (RDP) accountant. For integer order α ≥ 2 the RDP can be computed exactly via the moment-generating expression:RDP(α) = (1/(α-1)) * log( sum_{j=0}^{α} C(α,j) q^j (1-q)^{α-j} exp((j^2 - j) / (2 sigma^2)) )We implement this in log-space to avoid overflow/underflow (use gammaln for log binomials and log-sum-exp). Then we search a grid of Renyi orders (integers + some fractional) and return eps = min_alpha (RDP(α) - log(delta)) / (α-1). Numerical care: compute log terms, use scipy.special.gammaln if available or math.lgamma.Code (with inline comments) and a small test comparing log-space result to a direct double-precision brute-force for small α:Key points and numerical methods:- Use log-space for all binomial-weighted sums (log_comb + log-sum-exp) to avoid overflow.- Compute RDP for integer α using the closed-form summation; compose additively across T steps.- Optimize epsilon over a grid of Renyi orders (integers 2..max_alpha). For production, extend to non-integer orders (via continuous formulas or interpolation) and increase max_alpha adaptively.- Complexity: computing RDP at alpha costs O(alpha) work; scanning alphas up to M costs O(M^2) in worst case (sum of 1..M). For typical M~200 this is fast.This implementation is intentionally concise and numerically stable; for high-precision or non-integer-orders, incorporate scipy.special and higher-precision libraries.
python
import math
import numpy as np
def log_comb(n, k):
# log binomial using log gamma
return math.lgamma(n+1) - math.lgamma(k+1) - math.lgamma(n-k+1)
def logsumexp(arr):
a = max(arr)
return a + math.log(sum(math.exp(x - a) for x in arr))
def rdp_poisson_subsampled_gaussian(alpha, q, sigma):
"""
Compute RDP at integer alpha >= 2 for Poisson subsampling + Gaussian noise.
Uses log-space sums for stability.
Formula: RDP = 1/(alpha-1) * log( sum_{j=0}^alpha C(alpha,j) q^j (1-q)^{alpha-j} exp((j^2 - j)/(2 sigma^2)) )
"""
if alpha < 2 or int(alpha) != alpha:
raise ValueError("This implementation supports integer alpha >= 2")
alpha = int(alpha)
log_terms = []
log_q = math.log(q) if q > 0 else float("-inf")
log_1_q = math.log(1 - q) if q < 1 else float("-inf")
coeff = 1.0 # placeholder
for j in range(0, alpha+1):
# log C(alpha, j) + j*log q + (alpha-j)*log(1-q) + ((j^2 - j)/(2 sigma^2))
log_p = log_comb(alpha, j)
log_p += j * log_q if log_q != float("-inf") else (0.0 if j == 0 else float("-inf"))
log_p += (alpha - j) * log_1_q if log_1_q != float("-inf") else (0.0 if alpha - j == 0 else float("-inf"))
log_p += (j*j - j) / (2.0 * sigma * sigma)
log_terms.append(log_p)
log_A = logsumexp(log_terms)
return (log_A) / (alpha - 1.0)
def get_epsilon(q, sigma, T, delta, max_alpha=200):
"""
Compose RDP over T steps (additive) and convert to (epsilon, delta).
Search over integer alphas from 2..max_alpha and a small set of fractional orders near minima.
"""
best_eps = float("inf")
best_alpha = None
# precompute RDP per step
for alpha in range(2, max_alpha+1):
rdp = rdp_poisson_subsampled_gaussian(alpha, q, sigma)
rdp_total = rdp * T
eps = (rdp_total - math.log(delta)) / (alpha - 1.0)
if eps < best_eps:
best_eps = eps
best_alpha = alpha
return best_eps, best_alpha
# Small brute-force test to validate log-space calculation for small alphas
def brute_rdp_integer(alpha, q, sigma):
# direct arithmetic (no log-sum-exp) to compare
s = 0.0
for j in range(0, alpha+1):
comb = math.comb(alpha, j)
p = comb * (q**j) * ((1 - q)**(alpha - j)) * math.exp((j*j - j) / (2.0 * sigma * sigma))
s += p
return math.log(s) / (alpha - 1.0)
def test():
for alpha in [2,3,4,5,10]:
q = 0.1
sigma = 1.0
v1 = rdp_poisson_subsampled_gaussian(alpha, q, sigma)
v2 = brute_rdp_integer(alpha, q, sigma)
assert abs(v1 - v2) < 1e-10, (alpha, v1, v2)
# small composition test vs naive: one step T=1
eps, a = get_epsilon(q=0.1, sigma=1.0, T=1, delta=1e-5, max_alpha=50)
print("Test passed. Example epsilon:", eps, "best alpha:", a)
if __name__ == "__main__":
test()Unlock Full Question Bank
Get access to hundreds of Privacy-Preserving Experiment Design interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.