◐ Off-By-One · answer catalog

differential-privacy-fl-v3

1 answer(s)pythonpython3

def clipgradients(self, gradients: np.ndarray) -> np.ndarray:

📦 Source in repository (JSON)

Answer

The implementation is in two files:

dp_fl.py — Core library with two classes:

MomentsAccountant

Accumulates Renyi log-moments across rounds and converts to (ε, δ)-DP.

Log-moment bound (subsampled Gaussian mechanism):

log_moment(λ) ≤ log(1 + q² · λ·(λ-1)/2 · H)

where H = min(4·(exp(1/z²)−1), exp(λ·(λ-1)/(2·z²))) and z = noise_multiplier.

Final ε computation:

ε(δ) = min_λ  ( Σ log_moment(λ) + log(1/δ) ) / (λ−1)

DPFederatedAggregator

Key code snippets:

# --- clipping (handles scalar and vector gradients) ---
def clip_gradients(self, gradients: np.ndarray) -> np.ndarray:
    if gradients.ndim == 1:
        gradients = gradients.reshape(-1, 1)
        was_1d = True
    else:
        was_1d = False
    norms = np.linalg.norm(gradients, axis=1, keepdims=True)
    scales = np.minimum(1.0, self.clip_norm / np.maximum(norms, 1e-12))
    result = gradients * scales
    return result.ravel() if was_1d else result

# --- subsampling log-moment with overflow protection ---
@staticmethod
def _subsampled_gaussian_log_moment(lmbda, z, q):
    if q <= 0.0:   return 0.0
    if q >= 1.0:   return lmbda / (2.0 * z * z)
    term_a = 4.0 * math.expm1(1.0 / (z * z))
    exponent = lmbda * (lmbda - 1.0) / (2.0 * z * z)
    if exponent < 700.0:
        inner = min(term_a, math.exp(exponent))
    else:
        inner = term_a
    return math.log1p(q * q * lmbda * (lmbda - 1.0) * 0.5 * inner)

# --- effective sampling probability (handles heterogeneity & dropout) ---
def _update_effective_q(self, client_ids):
    for cid in client_ids:
        self._client_freq[cid] = self._client_freq.get(cid, 0) + 1
    total = self._round_count + 1
    max_rate = max(self._client_freq.values()) / total if total > 0 else ...
    self._effective_q = max(self.client_sampling_prob, max_rate)

Evidence & signatures

All **45 tests pass** (`pytest -v`), covering:

| Category | Tests | What's verified |
|---|---|---|
| **MomentsAccountant** | 10 | Basic/subsampled log-moment formula, accumulation, monotonic ε growth, reset, overflow safety, determinism |
| **DPFederatedAggregator** | 20 | Construction validation, all-edge clipping, noise calibration, round counting, `record_privacy` flag, frequency/dropout tracking, Renyi DP query, PRNG determinism |
| **Integration** | 3 | 50-round FL simulation with 100 clients, privacy growth monotonicity, low-noise vs high-noise ε ordering |
| **Edge cases** | 12 | Zero gradients, scalar (1-D) gradients, very many rounds (200) numerical stability, different δ queries, near-zero noise multiplier, shape mismatch rejection |

**Key edge cases validated:**

1. **Overflow prevention**: `exp(λ·(λ-1)/(2z²))` with `λ=63, z=0.1` → exponent ≈ 19,530 (far beyond float64's ~709 limit). Caught by the `< 700.0` guard → falls back to `term_a`.

2. **Scalar gradients**: `np.array([10.0, -5.0])` → 1-D stack → `clip_gradients` reshapes to 2-D internally.

3. **Empty round**: `aggregate_round({})` returns empty array, skips accounting → ε=0.

4. **Dropout**: A client that participates in rounds 0-4 then stops → its frequency 5/15=0.33 is < the persistent client's 15/15=1.0, so `effective_q` correctly stays at 1.0 (bounded by the worst-case frequent participant).

5. **`record_privacy=False`**: No log-moments accumulated → `get_epsilon()` returns 0.0 (perfect privacy).

---
{"model": "gpt-4o", "problem_class": "differential-privacy-fl-v3", "result": "passed", "tests": 45}
Generated from the verified corpus · MIT licensedBack to the catalog