Answer To: Differential Privacy Blog Series | NISTThis link has multiple examples of demonstrations for...
Banasree answered on Nov 12 2022
Privacy budget accountant for differential privacy
1. from numbers import Integral
import numpy as np
from diffprivlib.utils import Budget, BudgetError
from diffprivlib.validation import check_epsilon_delta
class BudgetAccountant:
2. _default = None
def __init__(self, epsilon=float("inf"), delta=1.0, slack=0.0, spent_budget=None):
check_epsilon_delta(epsilon, delta)
self.__epsilon = epsilon
self.__min_epsilon = 0 if epsilon == float("inf") else epsilon * 1e-14
self.__delta = delta
self.__spent_budget = []
self.slack = slack
if spent_budget is not None:
if not isinstance(spent_budget, list):
raise TypeError("spent_budget must be a list")
for _epsilon, _delta in spent_budget:
self.spend(_epsilon, _delta)
def __repr__(self, n_budget_max=5):
params = []
if self.epsilon != float("inf"):
params.append(f"epsilon={self.epsilon}")
if self.delta != 1:
params.append(f"delta={self.delta}")
if self.slack > 0:
params.append(f"slack={self.slack}")
if self.spent_budget:
if len(self.spent_budget) > n_budget_max:
params.append("spent_budget=" + str(self.spent_budget[:n_budget_max] + ["..."]).replace("'", ""))
else:
params.append("spent_budget=" + str(self.spent_budget))
return "BudgetAccountant(" + ", ".join(params) + ")"
def __enter__(self):
self.old_default = self.pop_default()
self.set_default()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.pop_default()
if self.old_default is not None:
self.old_default.set_default()
del self.old_default
def __len__(self):
return len(self.spent_budget)
@property
def slack(self):
"""Slack parameter for composition.
"""
return self.__slack
@slack.setter
def slack(self, slack):
if not 0 <= slack <= self.delta:
raise ValueError(f"Slack must be between 0 and delta ({self.delta}), inclusive. Got {slack}.")
epsilon_spent, delta_spent = self.total(slack=slack)
if self.epsilon < epsilon_spent or self.delta < delta_spent:
raise BudgetError(f"Privacy budget will be exceeded by changing slack to {slack}.")
self.__slack = slack
@property
def spent_budget(self):
return self.__spent_budget.copy()
@property
def epsilon(self):
"""Epsilon privacy ceiling of the accountant.
"""
return self.__epsilon
@property
def delta(self):
"""Delta privacy ceiling of the accountant.
"""
return self.__delta
[def total(self, spent_budget=None, slack=None):
3. if spent_budget is None:
spent_budget = self.spent_budget
else:
for epsilon, delta in spent_budget:
check_epsilon_delta(epsilon, delta)
if slack is None:
slack = self.slack
elif not 0 <= slack <= self.delta:
raise ValueError(f"Slack must be between 0 and delta ({self.delta}), inclusive. Got {slack}.")
epsilon_sum, epsilon_exp_sum, epsilon_sq_sum = 0, 0, 0
for epsilon, _ in spent_budget:
epsilon_sum += epsilon
epsilon_exp_sum += (1 - np.exp(-epsilon)) * epsilon / (1 + np.exp(-epsilon))
epsilon_sq_sum += epsilon ** 2
total_epsilon_naive = epsilon_sum
total_delta = self.__total_delta_safe(spent_budget, slack)
if slack == 0:
return Budget(total_epsilon_naive, total_delta)
total_epsilon_drv = epsilon_exp_sum + np.sqrt(2 * epsilon_sq_sum * np.log(1 / slack))
total_epsilon_kov = epsilon_exp_sum + np.sqrt(2 * epsilon_sq_sum *
np.log(np.exp(1) + np.sqrt(epsilon_sq_sum) / slack))
return Budget(min(total_epsilon_naive, total_epsilon_drv, total_epsilon_kov), total_delta)
def check(self, epsilon, delta):
4. check_epsilon_delta(epsilon, delta)
if self.epsilon == float("inf") and self.delta == 1:
return True
if 0 < epsilon < self.__min_epsilon:
raise ValueError(f"Epsilon must be at least {self.__min_epsilon} if...