16
16
17
17
Functionality for computing Renyi differential privacy of an additive Gaussian
18
18
mechanism with sampling. Its public interface consists of two methods:
19
- compute_rdp(q, sigma, T, order) computes RDP with sampling probability q,
20
- noise sigma, T steps at a given order.
21
- get_privacy_spent computes delta (or eps) given RDP and eps (or delta).
19
+ compute_rdp(q, sigma, T, orders) computes RDP with the sampling rate q,
20
+ noise sigma, T steps at the list of orders.
21
+ get_privacy_spent(orders, rdp, target_eps, target_delta) computes delta
22
+ (or eps) given RDP at multiple orders and
23
+ a target value for eps (or delta).
22
24
23
25
Example use:
24
26
25
27
Suppose that we have run an algorithm with parameters, an array of
26
28
(q1, sigma1, T1) ... (qk, sigma_k, Tk), and we wish to compute eps for a given
27
29
delta. The example code would be:
28
30
29
- max_order = 32
30
- orders = range(2, max_order + 1)
31
- rdp = np.zeros_like(orders, dtype=float)
32
- for q, sigma, T in parameters:
33
- rdp += rdp_accountant.compute_rdp(q, sigma, T, orders)
34
- eps, _, opt_order = rdp_accountant.get_privacy_spent(rdp, target_delta=delta)
31
+ max_order = 32
32
+ orders = range(2, max_order + 1)
33
+ rdp = np.zeros_like(orders, dtype=float)
34
+ for q, sigma, T in parameters:
35
+ rdp += rdp_accountant.compute_rdp(q, sigma, T, orders)
36
+ eps, _, opt_order = rdp_accountant.get_privacy_spent(rdp, target_delta=delta)
35
37
"""
36
38
from __future__ import absolute_import
37
39
from __future__ import division
38
40
from __future__ import print_function
39
41
40
- import math
41
42
import sys
42
43
43
44
from absl import app
44
45
from absl import flags
46
+ import math
45
47
import numpy as np
46
48
from scipy import special
47
49
@@ -168,6 +170,7 @@ def _compute_log_a_frac(q, sigma, alpha):
168
170
169
171
170
172
def _compute_log_a (q , sigma , alpha ):
173
+ """Compute log(A_alpha) for any positive finite alpha."""
171
174
if float (alpha ).is_integer ():
172
175
return _compute_log_a_int (q , sigma , int (alpha ))
173
176
else :
@@ -196,7 +199,7 @@ def _compute_zs(sigma, q):
196
199
197
200
198
201
def _compute_log_b0 (sigma , q , alpha , z1 ):
199
- """Return an approximation to B0 or None if failed to converge."""
202
+ """Return an approximation to log(B0) or None if failed to converge."""
200
203
z0 , _ = _compute_zs (sigma , q )
201
204
s , log_term , log_b0 , k , sign , max_log_term = 0 , 1. , 0 , 0 , 1 , - np .inf
202
205
# Keep adding new terms until precision is no longer preserved.
@@ -315,7 +318,20 @@ def _compute_eps(orders, rdp, delta):
315
318
return eps [idx_opt ], orders_vec [idx_opt ]
316
319
317
320
318
- def _compute_rdp (q , sigma , steps , alpha ):
321
+ def _compute_rdp (q , sigma , alpha ):
322
+ """Compute RDP of the Gaussian mechanism with sampling at order alpha.
323
+
324
+ Args:
325
+ q: The sampling rate.
326
+ sigma: The std of the additive Gaussian noise.
327
+ alpha: The order at which RDP is computed.
328
+
329
+ Returns:
330
+ RDP at alpha, can be np.inf.
331
+ """
332
+ if np .isinf (alpha ):
333
+ return np .inf
334
+
319
335
log_moment_a = _compute_log_a (q , sigma , alpha - 1 )
320
336
321
337
log_bound_b = _log_bound_b_elementary (q , alpha - 1 ) # does not require sigma
@@ -335,15 +351,15 @@ def _compute_rdp(q, sigma, steps, alpha):
335
351
_log_print (log_bound_b2 ), _log_print (log_bound_b )))
336
352
log_bound_b = min (log_bound_b , log_bound_b2 )
337
353
338
- return max (log_moment_a , log_bound_b ) * steps / (alpha - 1 )
354
+ return max (log_moment_a , log_bound_b ) / (alpha - 1 )
339
355
340
356
341
357
def compute_rdp (q , sigma , steps , orders ):
342
358
"""Compute RDP of Gaussian mechanism with sampling for given parameters.
343
359
344
360
Args:
345
- q: The sampling ratio .
346
- sigma: The noise sigma .
361
+ q: The sampling rate .
362
+ sigma: The std of the additive Gaussian noise .
347
363
steps: The number of steps.
348
364
orders: An array (or a scalar) of RDP orders.
349
365
@@ -352,20 +368,19 @@ def compute_rdp(q, sigma, steps, orders):
352
368
"""
353
369
354
370
if np .isscalar (orders ):
355
- return _compute_rdp (q , sigma , steps , orders )
371
+ rdp = _compute_rdp (q , sigma , orders )
356
372
else :
357
- rdp = np .zeros_like (orders , dtype = float )
358
- for i , order in enumerate (orders ):
359
- rdp [i ] = _compute_rdp (q , sigma , steps , order )
360
- return rdp
373
+ rdp = np .array ([_compute_rdp (q , sigma , order ) for order in orders ])
374
+
375
+ return rdp * steps
361
376
362
377
363
378
def get_privacy_spent (orders , rdp , target_eps = None , target_delta = None ):
364
379
"""Compute delta (or eps) for given eps (or delta) from the RDP curve.
365
380
366
381
Args:
367
382
orders: An array (or a scalar) of RDP orders.
368
- rdp: An array of RDP values.
383
+ rdp: An array of RDP values. Must be of the same length as the orders list.
369
384
target_eps: If not None, the epsilon for which we compute the corresponding
370
385
delta.
371
386
target_delta: If not None, the delta for which we compute the corresponding
0 commit comments