What’s one thing you learned? What’s still confusing?
DICOM & Medical Imaging Standards
DICOM file format, PACS protocols, HU conversion, photometric interpretation, anonymization for ML, and HIPAA-aligned clinical imaging pipelines.
AI Ops History & Future
Two AI winters killed careers and companies.
Welcome to AI
What is AI? What is machine learning? Start your journey here — no experience needed.
Interactive Labs for This Track
DNS Flow
You type google.com — trace the journey from your browser through DNS servers to the actual website
Load Balancer
10 million users hit your app — watch how traffic is distributed across servers
Rate Limiter
An API getting hammered — build a rate limiter that protects it without blocking real users
Ask questions, share insights
Machine learning models aren't just statistical summaries — they can memorize and reproduce training data in ways that directly violate user privacy.
| Regulation | Scope | Privacy Obligation | Max Fine |
|---|---|---|---|
| GDPR (EU) | Any EU data subject | Right to erasure, data minimization, lawful basis | 4% global revenue |
| HIPAA (US) | Healthcare data (PHI) | De-identification required for ML training | $1.9M/year per violation category |
| CCPA (California) | CA residents | Right to deletion, opt-out of sale | $7,500 per intentional violation |
| EU AI Act | High-risk AI systems | Transparency, data governance, human oversight | 35M euros or 7% global revenue |
The EU AI Act specifically classifies models trained on biometric, health, and financial data as high-risk, requiring documented privacy controls — which in practice means DP or FL certification for training pipelines.
Differential privacy provides a mathematical guarantee: the output of a computation is approximately the same whether or not any single individual's data is included. This prevents inference attacks because the model genuinely doesn't "know" whether any specific record existed.
A randomized mechanism M satisfies (ε, δ)-differential privacy if, for all pairs of adjacent datasets D and D' (differing by exactly one record), and all possible outputs S:
Pr[M(D) ∈ S] ≤ exp(ε) · Pr[M(D') ∈ S] + δ
The Gaussian mechanism adds calibrated noise to a function's output to achieve DP. For a function f: D → ℝᵈ with L2 sensitivity Δf (maximum change in output when one record changes):
M(D) = f(D) + N(0, σ² · Iᵈ)
σ ≥ Δf · √(2 ln(1.25/δ)) / εThis is the basis of all practical DP mechanisms. The key tradeoff: smaller ε → larger σ → more noise → lower model quality.
Standard SGD leaks privacy through gradients — even a single gradient update can reveal whether a specific record was in the batch. DP-SGD (Abadi et al., 2016) makes each SGD step differentially private through two modifications:
Compute per-sample gradients gᵢ (not the batch average). Clip each to L2 norm C:
g̃ᵢ = gᵢ / max(1, |gᵢ|₂/C)
This bounds the sensitivity: no single sample can move the gradient by more than C.
Add noise calibrated to the clipping bound:
g_noisy = (1/B) · (Σᵢ g̃ᵢ + N(0, σ²C²I))
Where B is the batch size and σ is the noise multiplier.
Composing T DP-SGD steps doesn't multiply the cost linearly. The moments accountant (Rényi DP framework) tracks the exact privacy cost of composition, yielding tighter bounds than naive composition. For a dataset of size n, sampling probability q = B/n, noise multiplier σ, and T steps:
ε_total ≈ q · √(2T · ln(1/δ)) / σ (simplified Gaussian DP bound)
DP adds real accuracy cost. Typical impact on image classification:
| ε | Accuracy Drop (CIFAR-10) | Accuracy Drop (Medical Imaging) |
|---|---|---|
| 10 | -1.5% | -3% |
| 3 | -3% | -6% |
| 1 | -6% | -12% |
| 0.3 | -15% | -25% |
The 2–5% accuracy cost at ε=3–8 is generally acceptable for high-value regulated applications. Below ε=1, the utility penalty becomes prohibitive for most production use cases.
DP budget depletes every time you query the data — training, validation, hyperparameter tuning, and evaluation all consume budget. Best practices:
Federated learning (FL) trains a shared model across many clients (phones, hospitals, bank branches) without centralizing raw data. Each client trains locally and shares only model updates (gradients or weight deltas).
Most production FL deployments are horizontal.
FedAvg (McMahan et al., 2017) is the standard FL algorithm. Each round:
W_t+1 = W_t + Σₖ (nₖ/n) · ΔWₖ
Where n = Σₖ nₖ. This is identical to full-batch gradient descent when E=1 and all clients participate — the power of FedAvg is that E > 1 (multiple local steps) dramatically reduces communication rounds.
In practice, client data is non-IID — each hospital's patient population, each phone's user behavior, each branch's customer demographics are all different. This breaks FedAvg's convergence assumptions:
FL's main bottleneck is communication: a 7B model sends 28 GB of weight updates each round. With 1,000 hospital clients each round, that's 28 TB of data transfer per global step. Compression is mandatory:
| Technique | Compression Ratio | Accuracy Impact |
|---|---|---|
| Gradient sparsification (top-k) | 100–1,000× | Minimal (k≥0.1%) |
| Quantization (fp16) | 2× | None |
| Quantization (int8) | 4× | <0.5% |
| Quantization (int4) | 8× | 1–2% |
| Structured pruning of deltas | 10–50× | Moderate |
| Error feedback + sparsification | 100–1,000× | Minimal |
In practice, FL pipelines combine top-k sparsification (send only the largest k% of gradient elements) with error feedback (accumulate the dropped gradients locally for the next round).
Choosing the right privacy tool depends on the threat model, data location, and regulatory requirement:
A model for rare pediatric cancers needs data from 50 hospitals, each with 200–1,000 patient records. Centralizing data violates HIPAA BAAs and individual hospital governance rules. Solution stack:
GDPR Article 17 gives EU citizens the "right to erasure" — the right to have their data deleted. For traditional databases, this is simple: delete the row. For ML models, it's not. A model trained on a deleted user's data still "contains" information about them.
ΔW ≈ H⁻¹ · ∇L(xᵢ, W)
Where H is the Hessian of the loss. Computing H⁻¹ exactly is intractable for large models, but Kronecker-factored approximations (K-FAC) make it feasible for models up to ~1B parameters.
Regulators have not yet defined what "sufficient" unlearning means for ML models. Current best practice for GDPR compliance:
A healthcare startup trains a patient readmission model with ε=8, δ=1e-5. Their legal team says this needs to be ε=1 to meet their HIPAA data governance policy. What does lowering ε from 8 to 1 require, and what's the expected cost?
"""
DP-SGD training with Facebook Opacus.
Opacus wraps a standard PyTorch training loop and handles:
- Per-sample gradient computation
- Gradient clipping
- Noise injection
- Privacy accounting (Rényi DP / moments accountant)
"""
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
from opacus import PrivacyEngine
from opacus.validators import ModuleValidator
# ── 1. Define a simple classifier ──────────────────────────────────────────
class TabularClassifier(nn.Module):
def __init__(self, input_dim: int, num_classes: int):
super().__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, num_classes),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.net(x)
# ── 2. Prepare synthetic data ───────────────────────────────────────────────
n_samples, n_features, n_classes = 10_000, 32, 2
X = torch.randn(n_samples, n_features)
y = torch.randint(0, n_classes, (n_samples,))
dataset = TensorDataset(X, y)
# Opacus requires that batch_size is fixed (no drop_last=False with non-uniform batches)
loader = DataLoader(dataset, batch_size=256, shuffle=True, drop_last=True)
# ── 3. Initialize model and optimizer ──────────────────────────────────────
model = TabularClassifier(input_dim=n_features, num_classes=n_classes)
# Opacus validates that the model has no unsupported layers (e.g., BatchNorm).
# Replace BatchNorm with GroupNorm if needed.
errors = ModuleValidator.validate(model, strict=False)
if errors:
model = ModuleValidator.fix(model) # auto-replace incompatible layers
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()
# ── 4. Attach Opacus PrivacyEngine ────────────────────────────────────────
# Key hyperparameters:
# max_grad_norm (C): clipping threshold per sample
# noise_multiplier (σ): noise added per step, relative to C
# target_epsilon: desired final privacy budget (computed post-hoc or pre-committed)
# target_delta: failure probability (set << 1/n_samples)
privacy_engine = PrivacyEngine()
model, optimizer, loader = privacy_engine.make_private_with_epsilon(
module=model,
optimizer=optimizer,
data_loader=loader,
epochs=10,
target_epsilon=3.0, # ε = 3: strong privacy guarantee
target_delta=1e-5, # δ < 1/n_samples = 1/10,000
max_grad_norm=1.0, # C: clip per-sample gradient L2 norm to 1.0
)
print(f"Noise multiplier σ = {optimizer.noise_multiplier:.3f}")
# ── 5. Training loop ───────────────────────────────────────────────────────
def train_epoch(model, loader, optimizer, criterion, device="cpu"):
model.train()
total_loss = 0.0
total_correct = 0
for X_batch, y_batch in loader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
optimizer.zero_grad()
logits = model(X_batch)
loss = criterion(logits, y_batch)
loss.backward()
optimizer.step() # Opacus handles clipping + noise injection here
total_loss += loss.item() * len(y_batch)
total_correct += (logits.argmax(dim=1) == y_batch).sum().item()
return total_loss / len(loader.dataset), total_correct / len(loader.dataset)
for epoch in range(1, 11):
loss, acc = train_epoch(model, loader, optimizer, criterion)
# Query the privacy accountant — ε grows each epoch
epsilon = privacy_engine.get_epsilon(delta=1e-5)
print(f"Epoch {epoch:2d} | Loss: {loss:.4f} | Acc: {acc:.3f} | ε = {epsilon:.3f}")
# ── 6. Privacy budget summary ─────────────────────────────────────────────
final_epsilon = privacy_engine.get_epsilon(delta=1e-5)
print(f"\nFinal privacy guarantee: (ε={final_epsilon:.3f}, δ=1e-5)-DP")
print("Interpretation: an adversary cannot determine if any individual")
print(f"was in the training set with better than e^{final_epsilon:.1f}≈{torch.exp(torch.tensor(final_epsilon)):.1f}x prior odds.")
# ── 7. Non-private baseline for comparison ────────────────────────────────
# To quantify the privacy-utility tradeoff, train the same model without DP:
# model_base = TabularClassifier(n_features, n_classes)
# optimizer_base = torch.optim.Adam(model_base.parameters(), lr=1e-3)
# loader_base = DataLoader(dataset, batch_size=256, shuffle=True)
# ... standard training loop ...
# Compare accuracy_base vs accuracy_dp — typically 2-5% gap at ε=3