Source code for opacus.accountants.rdp
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import List, Optional, Tuple, Union
from .accountant import IAccountant
from .analysis import rdp as privacy_analysis
[docs]
class RDPAccountant(IAccountant):
DEFAULT_ALPHAS = [1 + x / 10.0 for x in range(1, 100)] + list(range(12, 64))
def __init__(self):
super().__init__()
[docs]
def step(self, *, noise_multiplier: float, sample_rate: float):
if len(self.history) >= 1:
last_noise_multiplier, last_sample_rate, num_steps = self.history.pop()
if (
last_noise_multiplier == noise_multiplier
and last_sample_rate == sample_rate
):
self.history.append(
(last_noise_multiplier, last_sample_rate, num_steps + 1)
)
else:
self.history.append(
(last_noise_multiplier, last_sample_rate, num_steps)
)
self.history.append((noise_multiplier, sample_rate, 1))
else:
self.history.append((noise_multiplier, sample_rate, 1))
def get_privacy_spent(
self, *, delta: float, alphas: Optional[List[Union[float, int]]] = None
) -> Tuple[float, float]:
if not self.history:
return 0, 0
if alphas is None:
alphas = self.DEFAULT_ALPHAS
rdp = sum(
[
privacy_analysis.compute_rdp(
q=sample_rate,
noise_multiplier=noise_multiplier,
steps=num_steps,
orders=alphas,
)
for (noise_multiplier, sample_rate, num_steps) in self.history
]
)
eps, best_alpha = privacy_analysis.get_privacy_spent(
orders=alphas, rdp=rdp, delta=delta
)
return float(eps), float(best_alpha)
[docs]
def get_epsilon(
self, delta: float, alphas: Optional[List[Union[float, int]]] = None
):
"""
Return privacy budget (epsilon) expended so far.
Args:
delta: target delta
alphas: List of RDP orders (alphas) used to search for the optimal conversion
between RDP and (epd, delta)-DP
"""
eps, _ = self.get_privacy_spent(delta=delta, alphas=alphas)
return eps
def __len__(self):
return len(self.history)
[docs]
@classmethod
def mechanism(cls) -> str:
return "rdp"