Use calibrate_dp_mechanism from differential_privacy library instead of custom binary search.
PiperOrigin-RevId: 466798182
This commit is contained in:
parent
857fe8f482
commit
ca077a5b12
1 changed files with 15 additions and 28 deletions
|
@ -18,19 +18,6 @@ import math
|
||||||
|
|
||||||
from absl import app
|
from absl import app
|
||||||
import dp_accounting
|
import dp_accounting
|
||||||
from scipy import optimize
|
|
||||||
|
|
||||||
|
|
||||||
def apply_dp_sgd_analysis(q, sigma, steps, orders, delta):
|
|
||||||
"""Compute and print results of DP-SGD analysis."""
|
|
||||||
|
|
||||||
accountant = dp_accounting.rdp.RdpAccountant(orders)
|
|
||||||
event = dp_accounting.SelfComposedDpEvent(
|
|
||||||
dp_accounting.PoissonSampledDpEvent(q,
|
|
||||||
dp_accounting.GaussianDpEvent(sigma)),
|
|
||||||
steps)
|
|
||||||
accountant.compose(event)
|
|
||||||
return accountant.get_epsilon_and_optimal_order(delta)
|
|
||||||
|
|
||||||
|
|
||||||
def compute_noise(n, batch_size, target_epsilon, epochs, delta, noise_lbd):
|
def compute_noise(n, batch_size, target_epsilon, epochs, delta, noise_lbd):
|
||||||
|
@ -42,26 +29,26 @@ def compute_noise(n, batch_size, target_epsilon, epochs, delta, noise_lbd):
|
||||||
list(range(5, 64)) + [128, 256, 512])
|
list(range(5, 64)) + [128, 256, 512])
|
||||||
steps = int(math.ceil(epochs * n / batch_size))
|
steps = int(math.ceil(epochs * n / batch_size))
|
||||||
|
|
||||||
init_noise = noise_lbd # minimum possible noise
|
def make_event_from_noise(sigma):
|
||||||
init_epsilon, _ = apply_dp_sgd_analysis(q, init_noise, steps, orders, delta)
|
return dp_accounting.SelfComposedDpEvent(
|
||||||
|
dp_accounting.PoissonSampledDpEvent(
|
||||||
|
q, dp_accounting.GaussianDpEvent(sigma)), steps)
|
||||||
|
|
||||||
|
def make_accountant():
|
||||||
|
return dp_accounting.rdp.RdpAccountant(orders)
|
||||||
|
|
||||||
|
accountant = make_accountant()
|
||||||
|
accountant.compose(make_event_from_noise(noise_lbd))
|
||||||
|
init_epsilon = accountant.get_epsilon(delta)
|
||||||
|
|
||||||
if init_epsilon < target_epsilon: # noise_lbd was an overestimate
|
if init_epsilon < target_epsilon: # noise_lbd was an overestimate
|
||||||
print('min_noise too large for target epsilon.')
|
print('noise_lbd too large for target epsilon.')
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
cur_epsilon = init_epsilon
|
target_noise = dp_accounting.calibrate_dp_mechanism(
|
||||||
max_noise, min_noise = init_noise, 0
|
make_accountant, make_event_from_noise, target_epsilon, delta,
|
||||||
|
dp_accounting.LowerEndpointAndGuess(noise_lbd, noise_lbd * 2))
|
||||||
|
|
||||||
# doubling to find the right range
|
|
||||||
while cur_epsilon > target_epsilon: # until noise is large enough
|
|
||||||
max_noise, min_noise = max_noise * 2, max_noise
|
|
||||||
cur_epsilon, _ = apply_dp_sgd_analysis(q, max_noise, steps, orders, delta)
|
|
||||||
|
|
||||||
def epsilon_fn(noise): # should return 0 if guess_epsilon==target_epsilon
|
|
||||||
guess_epsilon = apply_dp_sgd_analysis(q, noise, steps, orders, delta)[0]
|
|
||||||
return guess_epsilon - target_epsilon
|
|
||||||
|
|
||||||
target_noise = optimize.bisect(epsilon_fn, min_noise, max_noise)
|
|
||||||
print(
|
print(
|
||||||
'DP-SGD with sampling rate = {:.3g}% and noise_multiplier = {} iterated'
|
'DP-SGD with sampling rate = {:.3g}% and noise_multiplier = {} iterated'
|
||||||
' over {} steps satisfies'.format(100 * q, target_noise, steps),
|
' over {} steps satisfies'.format(100 * q, target_noise, steps),
|
||||||
|
|
Loading…
Reference in a new issue