Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Central DP (server-side adaptive clipping) #2909

Merged
merged 158 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from 154 commits
Commits
Show all changes
158 commits
Select commit Hold shift + click to select a range
6ba0507
Add central DP server side fixed clipping
mohammadnaseri Jan 15, 2024
e66e1ad
Add central DP server-side fixed clipping unit tests
mohammadnaseri Jan 15, 2024
a88f72e
Fix exceptin msg
mohammadnaseri Jan 15, 2024
b2c08ad
Add the new strategy wrapper
mohammadnaseri Jan 18, 2024
902fed8
Fix merge conflicts
mohammadnaseri Jan 18, 2024
57a2d65
WIP
mohammadnaseri Jan 21, 2024
b9aab13
WIP
mohammadnaseri Jan 21, 2024
64ef649
WIP
mohammadnaseri Jan 22, 2024
53d393e
WIP
mohammadnaseri Jan 22, 2024
888fa47
WIP
mohammadnaseri Jan 23, 2024
e7788d6
WIP
mohammadnaseri Jan 25, 2024
91e5ef7
Merge branch 'main' into central-dp-server-side-fixed-clipping
mohammadnaseri Jan 25, 2024
16c1c41
Clean code
mohammadnaseri Jan 25, 2024
497cbc9
WIP
mohammadnaseri Jan 25, 2024
4b84265
Clean code
mohammadnaseri Jan 25, 2024
93d8d75
Fix tests
mohammadnaseri Jan 25, 2024
464c3e9
Fix
mohammadnaseri Jan 25, 2024
bade827
Fix test error
mohammadnaseri Jan 25, 2024
800eac6
Clean code
mohammadnaseri Jan 25, 2024
a257d7f
Clean code
mohammadnaseri Jan 26, 2024
d1d3ff5
Fix pylint error
mohammadnaseri Jan 26, 2024
d24de45
Fix pylint error
mohammadnaseri Jan 26, 2024
ba7a00c
Add minor comment
mohammadnaseri Jan 26, 2024
b196bd7
WIP
mohammadnaseri Jan 29, 2024
58d0e49
Merge branch 'main' into central-dp-server-side-fixed-clipping
mohammadnaseri Jan 29, 2024
32a1f41
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Jan 29, 2024
6cb406c
Minor fix
mohammadnaseri Jan 29, 2024
27f4b63
Fix noise:
mohammadnaseri Jan 30, 2024
bacde18
Refactor
mohammadnaseri Jan 30, 2024
e70d9fe
Fix test
mohammadnaseri Jan 30, 2024
b482aaa
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Jan 30, 2024
885249b
WIP
mohammadnaseri Jan 31, 2024
ce8b486
Address comments
mohammadnaseri Jan 31, 2024
a9d75bb
Address comments
mohammadnaseri Jan 31, 2024
e7ba313
Address comments
mohammadnaseri Jan 31, 2024
3efa81e
Fix errors
mohammadnaseri Jan 31, 2024
05944f4
Fix errors
mohammadnaseri Jan 31, 2024
6208d51
WIP
mohammadnaseri Feb 1, 2024
b235336
Clean code
mohammadnaseri Feb 1, 2024
8cde98e
Fix errors
mohammadnaseri Feb 1, 2024
fa5a91a
WIP
mohammadnaseri Feb 1, 2024
2ed9264
WIP
mohammadnaseri Feb 1, 2024
568ab96
WIP
mohammadnaseri Feb 1, 2024
07e5146
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 1, 2024
164285a
WIP
mohammadnaseri Feb 1, 2024
da57988
WIP
mohammadnaseri Feb 1, 2024
01557c0
WIP
mohammadnaseri Feb 1, 2024
5296fc4
Format
mohammadnaseri Feb 1, 2024
469dfca
Clean code
mohammadnaseri Feb 2, 2024
00cffbd
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 2, 2024
57d940c
Clean code
mohammadnaseri Feb 2, 2024
c195fe5
Update branch
mohammadnaseri Feb 2, 2024
ce90c6a
Fix errors
mohammadnaseri Feb 2, 2024
e466f2c
Fix errors
mohammadnaseri Feb 2, 2024
633c8e7
Test lint
mohammadnaseri Feb 2, 2024
f1d40d1
Test lint
mohammadnaseri Feb 2, 2024
c49180b
Clean code
mohammadnaseri Feb 3, 2024
bbe5c5b
Improve
mohammadnaseri Feb 4, 2024
d1cfeb6
Clean code
mohammadnaseri Feb 4, 2024
f43c7a5
Fix lint error
mohammadnaseri Feb 4, 2024
c3717ee
Update
mohammadnaseri Feb 5, 2024
8dfcc20
Fix error
mohammadnaseri Feb 5, 2024
bafd6d4
Fix error
mohammadnaseri Feb 5, 2024
e7f11d5
Fix error
mohammadnaseri Feb 5, 2024
8263958
Fix error
mohammadnaseri Feb 5, 2024
5b88858
Fix error
mohammadnaseri Feb 5, 2024
01427c8
Refactor
mohammadnaseri Feb 5, 2024
c808c73
Fix error
mohammadnaseri Feb 5, 2024
afe7ccc
Fix error
mohammadnaseri Feb 5, 2024
99310cc
Fix error
mohammadnaseri Feb 5, 2024
1d6ef7d
Merge branch 'main' into central-dp-client-side-adaptive-clipping
mohammadnaseri Feb 5, 2024
ed19e42
Add serverside adaptive clipping
mohammadnaseri Feb 5, 2024
656f180
Remove function
mohammadnaseri Feb 7, 2024
55c8633
Merge branch 'main' into central-dp-server-side-fixed-clipping
mohammadnaseri Feb 8, 2024
f48b9ee
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 8, 2024
c13dec2
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 8, 2024
d026223
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 8, 2024
5fe1148
Rename to modifier
mohammadnaseri Feb 8, 2024
36947a5
Rename to modifier
mohammadnaseri Feb 8, 2024
46a6372
Add warning
mohammadnaseri Feb 9, 2024
510d6c6
Fix error
mohammadnaseri Feb 9, 2024
5eaade8
Minor
mohammadnaseri Feb 9, 2024
3ff6720
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 12, 2024
77e082e
Clean code
mohammadnaseri Feb 12, 2024
30774d9
Fix conflicts
mohammadnaseri Feb 12, 2024
5a6ec45
Fix errors
mohammadnaseri Feb 12, 2024
2a9d9c7
Fix errors
mohammadnaseri Feb 12, 2024
93bebb4
Fix conflicts
mohammadnaseri Feb 12, 2024
d5a4f0f
Fix errors
mohammadnaseri Feb 12, 2024
0b1358a
Update
mohammadnaseri Feb 12, 2024
03b147d
Update
mohammadnaseri Feb 12, 2024
57396ac
Merge branch 'main' into central-dp-server-side-fixed-clipping
mohammadnaseri Feb 13, 2024
3368e95
Merge branch 'main' into central-dp-server-side-fixed-clipping
danieljanes Feb 14, 2024
eee4833
Update src/py/flwr/common/differential_privacy.py
mohammadnaseri Feb 14, 2024
d66e6c4
Update src/py/flwr/common/differential_privacy.py
mohammadnaseri Feb 14, 2024
8ac000a
Address comments
mohammadnaseri Feb 14, 2024
fcb0c32
address reviews
mohammadnaseri Feb 15, 2024
755f9c0
Merge branch 'main' into central-dp-client-side-fixed-clipping
mohammadnaseri Feb 15, 2024
68da75d
address reviews
mohammadnaseri Feb 15, 2024
6183fd8
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 15, 2024
3b9c704
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 15, 2024
69f55dc
Minor
mohammadnaseri Feb 15, 2024
8190425
Minor
mohammadnaseri Feb 15, 2024
e4e083b
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 15, 2024
9dd584f
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 15, 2024
e27fffd
Fix errors
mohammadnaseri Feb 15, 2024
5ac0554
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 15, 2024
59ea1f2
minor
mohammadnaseri Feb 15, 2024
d31e934
Merge branch 'main' into central-dp-server-side-fixed-clipping
mohammadnaseri Feb 15, 2024
adbfd20
Add doc string example
mohammadnaseri Feb 15, 2024
cb37c9b
Merge branch 'central-dp-server-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 16, 2024
694ca01
WIP
mohammadnaseri Feb 16, 2024
aacfa0d
Use common logger
mohammadnaseri Feb 16, 2024
405aa0f
Use common logger
mohammadnaseri Feb 16, 2024
f1e0e69
Fix error
mohammadnaseri Feb 16, 2024
00e1b3e
minor
mohammadnaseri Feb 16, 2024
d4e367a
Use common logger
mohammadnaseri Feb 16, 2024
f77966c
Use common logger
mohammadnaseri Feb 16, 2024
8d39dd8
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 16, 2024
93d7721
Use common logger
mohammadnaseri Feb 16, 2024
7d69476
fix copyright year
mohammadnaseri Feb 16, 2024
1515625
Merge branch 'main' into central-dp-server-side-fixed-clipping
danieljanes Feb 20, 2024
73be298
Address comments
mohammadnaseri Feb 20, 2024
1d430bd
Address comments
mohammadnaseri Feb 20, 2024
8ce608a
Fix
mohammadnaseri Feb 20, 2024
535fe2a
Fix
mohammadnaseri Feb 20, 2024
651b0e1
Fix
mohammadnaseri Feb 20, 2024
466f3b8
Fix
mohammadnaseri Feb 20, 2024
8bdff48
Fix
mohammadnaseri Feb 20, 2024
11bde7e
Update
mohammadnaseri Feb 21, 2024
c25c4f1
Update
mohammadnaseri Feb 21, 2024
6f8f6d4
Update
mohammadnaseri Feb 21, 2024
357a7d7
Update
mohammadnaseri Feb 21, 2024
a7b483e
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 21, 2024
c7d175d
Update
mohammadnaseri Feb 21, 2024
073f61b
Update
mohammadnaseri Feb 21, 2024
abf9d41
Update
mohammadnaseri Feb 21, 2024
e1860bb
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 21, 2024
4ef469d
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 21, 2024
7d9b1d3
Update
mohammadnaseri Feb 21, 2024
d54e09a
Merge branch 'central-dp-client-side-fixed-clipping' into central-dp-…
mohammadnaseri Feb 21, 2024
d658a37
Update
mohammadnaseri Feb 21, 2024
8c2376b
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 21, 2024
dedb148
Merge branch 'main' into central-dp-server-side-adaptive-clipping
danieljanes Feb 21, 2024
ff65b64
Fix conflicts
mohammadnaseri Feb 27, 2024
01207da
Fix conflicts
mohammadnaseri Feb 27, 2024
81e6574
Improve
mohammadnaseri Feb 27, 2024
dfe8778
Improve
mohammadnaseri Feb 27, 2024
c8bf410
Improve
mohammadnaseri Feb 27, 2024
f3a5385
Improve
mohammadnaseri Feb 27, 2024
bf397ca
Improve
mohammadnaseri Feb 27, 2024
a09fd0c
Merge branch 'central-dp-client-side-adaptive-clipping' into central-…
mohammadnaseri Feb 27, 2024
a121fd0
Improve
mohammadnaseri Feb 28, 2024
e072f95
Update
mohammadnaseri Feb 28, 2024
a17bb60
Update src/py/flwr/server/strategy/dp_adaptive_clipping.py
mohammadnaseri Feb 29, 2024
7afdac3
Update
mohammadnaseri Feb 29, 2024
a9506c7
Merge branch 'main' into central-dp-server-side-adaptive-clipping
mohammadnaseri Feb 29, 2024
140ef48
Fix
mohammadnaseri Feb 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/py/flwr/server/strategy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@


from .bulyan import Bulyan as Bulyan
from .dp_adaptive_clipping import DifferentialPrivacyClientSideAdaptiveClipping
from .dp_adaptive_clipping import (
DifferentialPrivacyClientSideAdaptiveClipping,
DifferentialPrivacyServerSideAdaptiveClipping,
)
from .dp_fixed_clipping import (
DifferentialPrivacyClientSideFixedClipping,
DifferentialPrivacyServerSideFixedClipping,
mohammadnaseri marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -46,6 +49,7 @@
"DPFedAvgAdaptive",
"DPFedAvgFixed",
"DifferentialPrivacyClientSideAdaptiveClipping",
"DifferentialPrivacyServerSideAdaptiveClipping",
"DifferentialPrivacyClientSideFixedClipping",
"DifferentialPrivacyServerSideFixedClipping",
"FedAdagrad",
Expand Down
206 changes: 205 additions & 1 deletion src/py/flwr/server/strategy/dp_adaptive_clipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,19 @@

import numpy as np

from flwr.common import EvaluateIns, EvaluateRes, FitIns, FitRes, Parameters, Scalar
from flwr.common import (
EvaluateIns,
EvaluateRes,
FitIns,
FitRes,
NDArrays,
Parameters,
Scalar,
ndarrays_to_parameters,
parameters_to_ndarrays,
)
from flwr.common.differential_privacy import (
adaptive_clip_inputs_inplace,
add_gaussian_noise_to_params,
compute_adaptive_noise_params,
)
Expand All @@ -40,6 +51,199 @@
from flwr.server.strategy.strategy import Strategy


class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
"""Strategy wrapper for central DP with server-side adaptive clipping.

Parameters
----------
strategy: Strategy
The strategy to which DP functionalities will be added by this wrapper.
noise_multiplier : float
The noise multiplier for the Gaussian mechanism for model updates.
num_sampled_clients : int
The number of clients that are sampled on each round.
initial_clipping_norm : float
The initial value of clipping norm. Deafults to 0.1.
Andrew et al. recommends to set to 0.1.
target_clipped_quantile : float
The desired quantile of updates which should be clipped. Defaults to 0.5.
clip_norm_lr : float
The learning rate for the clipping norm adaptation. Defaults to 0.2.
Andrew et al. recommends to set to 0.2.
clipped_count_stddev : float
The stddev of the noise added to the count of updates currently below the estimate.
mohammadnaseri marked this conversation as resolved.
Show resolved Hide resolved
Andrew et al. recommends to set to `expected_num_records/20`

Examples
--------
Create a strategy:

>>> strategy = fl.server.strategy.FedAvg( ... )

Wrap the strategy with the DifferentialPrivacyServerSideAdaptiveClipping wrapper

>>> dp_strategy = DifferentialPrivacyServerSideAdaptiveClipping(
>>> strategy, cfg.noise_multiplier, cfg.num_sampled_clients, ...
>>> )
"""

# pylint: disable=too-many-arguments,too-many-instance-attributes
def __init__(
self,
strategy: Strategy,
noise_multiplier: float,
num_sampled_clients: int,
initial_clipping_norm: float = 0.1,
target_clipped_quantile: float = 0.5,
clip_norm_lr: float = 0.2,
clipped_count_stddev: Optional[float] = None,
) -> None:
super().__init__()

if strategy is None:
raise ValueError("The passed strategy is None.")

if noise_multiplier < 0:
raise ValueError("The noise multiplier should be a non-negative value.")

if num_sampled_clients <= 0:
raise ValueError(
"The number of sampled clients should be a positive value."
)

if initial_clipping_norm <= 0:
raise ValueError("The initial clipping norm should be a positive value.")

if not 0 <= target_clipped_quantile <= 1:
raise ValueError(
"The target clipped quantile must be between 0 and 1 (inclusive)."
)

if clip_norm_lr <= 0:
raise ValueError("The learning rate must be positive.")

if clipped_count_stddev is not None:
if clipped_count_stddev < 0:
raise ValueError("The `clipped_count_stddev` must be non-negative.")

self.strategy = strategy
self.num_sampled_clients = num_sampled_clients
self.clipping_norm = initial_clipping_norm
self.target_clipped_quantile = target_clipped_quantile
self.clip_norm_lr = clip_norm_lr
(
self.clipped_count_stddev,
self.noise_multiplier,
) = compute_adaptive_noise_params(
noise_multiplier,
num_sampled_clients,
clipped_count_stddev,
)

self.current_round_params: NDArrays = []

def __repr__(self) -> str:
"""Compute a string representation of the strategy."""
rep = "Differential Privacy Strategy Wrapper (Server-Side Adaptive Clipping)"
return rep

def initialize_parameters(
self, client_manager: ClientManager
) -> Optional[Parameters]:
"""Initialize global model parameters using given strategy."""
return self.strategy.initialize_parameters(client_manager)

def configure_fit(
self, server_round: int, parameters: Parameters, client_manager: ClientManager
) -> List[Tuple[ClientProxy, FitIns]]:
"""Configure the next round of training."""
self.current_round_params = parameters_to_ndarrays(parameters)
return self.strategy.configure_fit(server_round, parameters, client_manager)

def configure_evaluate(
self, server_round: int, parameters: Parameters, client_manager: ClientManager
) -> List[Tuple[ClientProxy, EvaluateIns]]:
"""Configure the next round of evaluation."""
return self.strategy.configure_evaluate(
server_round, parameters, client_manager
)

def aggregate_fit(
self,
server_round: int,
results: List[Tuple[ClientProxy, FitRes]],
failures: List[Union[Tuple[ClientProxy, FitRes], BaseException]],
) -> Tuple[Optional[Parameters], Dict[str, Scalar]]:
"""Aggregate training results and update clip norms."""
if failures:
return None, {}

if len(results) != self.num_sampled_clients:
log(
WARNING,
CLIENTS_DISCREPANCY_WARNING,
len(results),
self.num_sampled_clients,
)

norm_bit_set_count = 0
for _, res in results:
param = parameters_to_ndarrays(res.parameters)
# Compute and clip update
model_update = [
np.subtract(x, y) for (x, y) in zip(param, self.current_round_params)
]

norm_bit = adaptive_clip_inputs_inplace(model_update, self.clipping_norm)
norm_bit_set_count += norm_bit

for i, _ in enumerate(self.current_round_params):
param[i] = self.current_round_params[i] + model_update[i]
# Convert back to parameters
res.parameters = ndarrays_to_parameters(param)

# Noising the count
noised_norm_bit_set_count = float(
np.random.normal(norm_bit_set_count, self.clipped_count_stddev)
)
noised_norm_bit_set_fraction = noised_norm_bit_set_count / len(results)
# Geometric update
self.clipping_norm *= math.exp(
-self.clip_norm_lr
* (noised_norm_bit_set_fraction - self.target_clipped_quantile)
)

aggregated_params, metrics = self.strategy.aggregate_fit(
server_round, results, failures
)

# Add Gaussian noise to the aggregated parameters
if aggregated_params:
aggregated_params = add_gaussian_noise_to_params(
aggregated_params,
self.noise_multiplier,
self.clipping_norm,
self.num_sampled_clients,
)

return aggregated_params, metrics

def aggregate_evaluate(
self,
server_round: int,
results: List[Tuple[ClientProxy, EvaluateRes]],
failures: List[Union[Tuple[ClientProxy, EvaluateRes], BaseException]],
) -> Tuple[Optional[float], Dict[str, Scalar]]:
"""Aggregate evaluation losses using the given strategy."""
return self.strategy.aggregate_evaluate(server_round, results, failures)

def evaluate(
self, server_round: int, parameters: Parameters
) -> Optional[Tuple[float, Dict[str, Scalar]]]:
"""Evaluate model parameters using an evaluation function from the strategy."""
return self.strategy.evaluate(server_round, parameters)


class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
"""Strategy wrapper for central DP with client-side adaptive clipping.

Expand Down