"examples/vscode:/vscode.git/clone" did not exist on "cac7adab11a6fcbd592f5b8c7fa48ce194758bde"
Unverified Commit 44fa4b9a authored by Ilya Mironov's avatar Ilya Mironov Committed by GitHub
Browse files

Merge pull request #4221 from ilyamironov/master

Addressing reviewers' comments. Added correct handling of order=np.inf.
parents 1d76d3ae 2de7692d
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
Functionality for computing Renyi differential privacy of an additive Gaussian Functionality for computing Renyi differential privacy of an additive Gaussian
mechanism with sampling. Its public interface consists of two methods: mechanism with sampling. Its public interface consists of two methods:
compute_rdp(q, sigma, T, order) computes RDP with sampling probability q, compute_rdp(q, sigma, T, orders) computes RDP with the sampling rate q,
noise sigma, T steps at a given order. noise sigma, T steps at the list of orders.
get_privacy_spent computes delta (or eps) given RDP and eps (or delta). get_privacy_spent(orders, rdp, target_eps, target_delta) computes delta
(or eps) given RDP at multiple orders and
a target value for eps (or delta).
Example use: Example use:
...@@ -26,22 +28,22 @@ Suppose that we have run an algorithm with parameters, an array of ...@@ -26,22 +28,22 @@ Suppose that we have run an algorithm with parameters, an array of
(q1, sigma1, T1) ... (qk, sigma_k, Tk), and we wish to compute eps for a given (q1, sigma1, T1) ... (qk, sigma_k, Tk), and we wish to compute eps for a given
delta. The example code would be: delta. The example code would be:
max_order = 32 max_order = 32
orders = range(2, max_order + 1) orders = range(2, max_order + 1)
rdp = np.zeros_like(orders, dtype=float) rdp = np.zeros_like(orders, dtype=float)
for q, sigma, T in parameters: for q, sigma, T in parameters:
rdp += rdp_accountant.compute_rdp(q, sigma, T, orders) rdp += rdp_accountant.compute_rdp(q, sigma, T, orders)
eps, _, opt_order = rdp_accountant.get_privacy_spent(rdp, target_delta=delta) eps, _, opt_order = rdp_accountant.get_privacy_spent(rdp, target_delta=delta)
""" """
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
import math
import sys import sys
from absl import app from absl import app
from absl import flags from absl import flags
import math
import numpy as np import numpy as np
from scipy import special from scipy import special
...@@ -168,6 +170,7 @@ def _compute_log_a_frac(q, sigma, alpha): ...@@ -168,6 +170,7 @@ def _compute_log_a_frac(q, sigma, alpha):
def _compute_log_a(q, sigma, alpha): def _compute_log_a(q, sigma, alpha):
"""Compute log(A_alpha) for any positive finite alpha."""
if float(alpha).is_integer(): if float(alpha).is_integer():
return _compute_log_a_int(q, sigma, int(alpha)) return _compute_log_a_int(q, sigma, int(alpha))
else: else:
...@@ -196,7 +199,7 @@ def _compute_zs(sigma, q): ...@@ -196,7 +199,7 @@ def _compute_zs(sigma, q):
def _compute_log_b0(sigma, q, alpha, z1): def _compute_log_b0(sigma, q, alpha, z1):
"""Return an approximation to B0 or None if failed to converge.""" """Return an approximation to log(B0) or None if failed to converge."""
z0, _ = _compute_zs(sigma, q) z0, _ = _compute_zs(sigma, q)
s, log_term, log_b0, k, sign, max_log_term = 0, 1., 0, 0, 1, -np.inf s, log_term, log_b0, k, sign, max_log_term = 0, 1., 0, 0, 1, -np.inf
# Keep adding new terms until precision is no longer preserved. # Keep adding new terms until precision is no longer preserved.
...@@ -315,7 +318,20 @@ def _compute_eps(orders, rdp, delta): ...@@ -315,7 +318,20 @@ def _compute_eps(orders, rdp, delta):
return eps[idx_opt], orders_vec[idx_opt] return eps[idx_opt], orders_vec[idx_opt]
def _compute_rdp(q, sigma, steps, alpha): def _compute_rdp(q, sigma, alpha):
"""Compute RDP of the Gaussian mechanism with sampling at order alpha.
Args:
q: The sampling rate.
sigma: The std of the additive Gaussian noise.
alpha: The order at which RDP is computed.
Returns:
RDP at alpha, can be np.inf.
"""
if np.isinf(alpha):
return np.inf
log_moment_a = _compute_log_a(q, sigma, alpha - 1) log_moment_a = _compute_log_a(q, sigma, alpha - 1)
log_bound_b = _log_bound_b_elementary(q, alpha - 1) # does not require sigma 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,15 +351,15 @@ def _compute_rdp(q, sigma, steps, alpha):
_log_print(log_bound_b2), _log_print(log_bound_b))) _log_print(log_bound_b2), _log_print(log_bound_b)))
log_bound_b = min(log_bound_b, log_bound_b2) log_bound_b = min(log_bound_b, log_bound_b2)
return max(log_moment_a, log_bound_b) * steps / (alpha - 1) return max(log_moment_a, log_bound_b) / (alpha - 1)
def compute_rdp(q, sigma, steps, orders): def compute_rdp(q, sigma, steps, orders):
"""Compute RDP of Gaussian mechanism with sampling for given parameters. """Compute RDP of Gaussian mechanism with sampling for given parameters.
Args: Args:
q: The sampling ratio. q: The sampling rate.
sigma: The noise sigma. sigma: The std of the additive Gaussian noise.
steps: The number of steps. steps: The number of steps.
orders: An array (or a scalar) of RDP orders. orders: An array (or a scalar) of RDP orders.
...@@ -352,12 +368,11 @@ def compute_rdp(q, sigma, steps, orders): ...@@ -352,12 +368,11 @@ def compute_rdp(q, sigma, steps, orders):
""" """
if np.isscalar(orders): if np.isscalar(orders):
return _compute_rdp(q, sigma, steps, orders) rdp = _compute_rdp(q, sigma, orders)
else: else:
rdp = np.zeros_like(orders, dtype=float) rdp = np.array([_compute_rdp(q, sigma, order) for order in orders])
for i, order in enumerate(orders):
rdp[i] = _compute_rdp(q, sigma, steps, order) return rdp * steps
return rdp
def get_privacy_spent(orders, rdp, target_eps=None, target_delta=None): def get_privacy_spent(orders, rdp, target_eps=None, target_delta=None):
...@@ -365,7 +380,7 @@ def get_privacy_spent(orders, rdp, target_eps=None, target_delta=None): ...@@ -365,7 +380,7 @@ def get_privacy_spent(orders, rdp, target_eps=None, target_delta=None):
Args: Args:
orders: An array (or a scalar) of RDP orders. orders: An array (or a scalar) of RDP orders.
rdp: An array of RDP values. rdp: An array of RDP values. Must be of the same length as the orders list.
target_eps: If not None, the epsilon for which we compute the corresponding target_eps: If not None, the epsilon for which we compute the corresponding
delta. delta.
target_delta: If not None, the delta for which we compute the corresponding target_delta: If not None, the delta for which we compute the corresponding
......
# Copyright 2016 The TensorFlow Authors. All Rights Reserved. # Copyright 2016 The TensorFlow Authors. All Rights Reserved.
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
...@@ -95,7 +94,7 @@ class TestGaussianMoments(absltest.TestCase): ...@@ -95,7 +94,7 @@ class TestGaussianMoments(absltest.TestCase):
return log_a_mp, log_b_mp return log_a_mp, log_b_mp
# TEST ROUTINES # TEST ROUTINES
def _almost_equal(self, a, b, rtol, atol=0): def _almost_equal(self, a, b, rtol, atol=0.):
# Analogue of np.testing.assert_allclose(a, b, rtol, atol). # Analogue of np.testing.assert_allclose(a, b, rtol, atol).
self.assertBetween(a, b * (1 - rtol) - atol, b * (1 + rtol) + atol) self.assertBetween(a, b * (1 - rtol) - atol, b * (1 + rtol) + atol)
...@@ -123,9 +122,10 @@ class TestGaussianMoments(absltest.TestCase): ...@@ -123,9 +122,10 @@ class TestGaussianMoments(absltest.TestCase):
rdp_scalar = rdp_accountant.compute_rdp(0.1, 2, 10, 5) rdp_scalar = rdp_accountant.compute_rdp(0.1, 2, 10, 5)
self.assertAlmostEqual(rdp_scalar, 0.07737, places=5) self.assertAlmostEqual(rdp_scalar, 0.07737, places=5)
rdp_vec = rdp_accountant.compute_rdp(0.01, 2.5, 50, [1.5, 2.5, 5, 50, 100]) rdp_vec = rdp_accountant.compute_rdp(0.01, 2.5, 50, [1.5, 2.5, 5, 50, 100,
np.inf])
correct = [0.00065, 0.001085, 0.00218075, 0.023846, 167.416307] correct = [0.00065, 0.001085, 0.00218075, 0.023846, 167.416307, np.inf]
for i in range(len(rdp_vec)): for i in range(len(rdp_vec)):
self.assertAlmostEqual(rdp_vec[i], correct[i], places=5) self.assertAlmostEqual(rdp_vec[i], correct[i], places=5)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment