flwr-nightly 1.12.0.dev20240907__py3-none-any.whl → 1.12.0.dev20240913__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/build.py +1 -2
- flwr/cli/config_utils.py +10 -10
- flwr/cli/install.py +1 -2
- flwr/cli/new/new.py +26 -40
- flwr/cli/new/templates/app/code/client.huggingface.py.tpl +19 -29
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -3
- flwr/cli/new/templates/app/code/server.huggingface.py.tpl +18 -3
- flwr/cli/new/templates/app/code/task.huggingface.py.tpl +16 -13
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +9 -1
- flwr/cli/run/run.py +6 -7
- flwr/cli/utils.py +2 -2
- flwr/client/app.py +14 -14
- flwr/client/client_app.py +5 -5
- flwr/client/clientapp/app.py +2 -2
- flwr/client/dpfedavg_numpy_client.py +6 -7
- flwr/client/grpc_adapter_client/connection.py +4 -3
- flwr/client/grpc_client/connection.py +4 -3
- flwr/client/grpc_rere_client/client_interceptor.py +5 -5
- flwr/client/grpc_rere_client/connection.py +5 -4
- flwr/client/grpc_rere_client/grpc_adapter.py +2 -2
- flwr/client/message_handler/message_handler.py +3 -3
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +25 -25
- flwr/client/mod/utils.py +1 -3
- flwr/client/node_state.py +2 -2
- flwr/client/numpy_client.py +8 -8
- flwr/client/rest_client/connection.py +5 -4
- flwr/client/supernode/app.py +7 -8
- flwr/common/address.py +2 -2
- flwr/common/config.py +8 -8
- flwr/common/constant.py +12 -1
- flwr/common/differential_privacy.py +2 -2
- flwr/common/dp.py +1 -3
- flwr/common/exit_handlers.py +3 -3
- flwr/common/grpc.py +2 -1
- flwr/common/logger.py +3 -3
- flwr/common/object_ref.py +3 -3
- flwr/common/record/configsrecord.py +3 -3
- flwr/common/record/metricsrecord.py +3 -3
- flwr/common/record/parametersrecord.py +3 -2
- flwr/common/record/recordset.py +1 -1
- flwr/common/record/typeddict.py +23 -10
- flwr/common/recordset_compat.py +7 -5
- flwr/common/retry_invoker.py +6 -17
- flwr/common/secure_aggregation/crypto/shamir.py +10 -10
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +2 -2
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +16 -16
- flwr/common/secure_aggregation/quantization.py +7 -7
- flwr/common/secure_aggregation/secaggplus_utils.py +3 -5
- flwr/common/serde.py +11 -9
- flwr/common/telemetry.py +5 -5
- flwr/common/typing.py +19 -19
- flwr/common/version.py +2 -3
- flwr/server/app.py +18 -18
- flwr/server/client_manager.py +6 -6
- flwr/server/compat/app_utils.py +2 -3
- flwr/server/driver/driver.py +3 -2
- flwr/server/driver/grpc_driver.py +7 -7
- flwr/server/driver/inmemory_driver.py +5 -4
- flwr/server/history.py +8 -9
- flwr/server/run_serverapp.py +5 -6
- flwr/server/server.py +36 -36
- flwr/server/strategy/aggregate.py +13 -13
- flwr/server/strategy/bulyan.py +8 -8
- flwr/server/strategy/dp_adaptive_clipping.py +20 -20
- flwr/server/strategy/dp_fixed_clipping.py +19 -19
- flwr/server/strategy/dpfedavg_adaptive.py +6 -6
- flwr/server/strategy/dpfedavg_fixed.py +10 -10
- flwr/server/strategy/fault_tolerant_fedavg.py +11 -11
- flwr/server/strategy/fedadagrad.py +8 -8
- flwr/server/strategy/fedadam.py +8 -8
- flwr/server/strategy/fedavg.py +16 -16
- flwr/server/strategy/fedavg_android.py +16 -16
- flwr/server/strategy/fedavgm.py +8 -8
- flwr/server/strategy/fedmedian.py +4 -4
- flwr/server/strategy/fedopt.py +5 -5
- flwr/server/strategy/fedprox.py +6 -6
- flwr/server/strategy/fedtrimmedavg.py +8 -8
- flwr/server/strategy/fedxgb_bagging.py +11 -11
- flwr/server/strategy/fedxgb_cyclic.py +9 -9
- flwr/server/strategy/fedxgb_nn_avg.py +5 -5
- flwr/server/strategy/fedyogi.py +8 -8
- flwr/server/strategy/krum.py +8 -8
- flwr/server/strategy/qfedavg.py +15 -15
- flwr/server/strategy/strategy.py +10 -10
- flwr/server/superlink/driver/driver_grpc.py +2 -2
- flwr/server/superlink/driver/driver_servicer.py +6 -6
- flwr/server/superlink/ffs/disk_ffs.py +4 -4
- flwr/server/superlink/ffs/ffs.py +4 -4
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +2 -2
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +2 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +2 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +9 -8
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +5 -3
- flwr/server/superlink/fleet/message_handler/message_handler.py +2 -2
- flwr/server/superlink/fleet/rest_rere/rest_api.py +2 -1
- flwr/server/superlink/fleet/vce/backend/__init__.py +2 -3
- flwr/server/superlink/fleet/vce/backend/backend.py +3 -3
- flwr/server/superlink/fleet/vce/backend/raybackend.py +26 -17
- flwr/server/superlink/fleet/vce/vce_api.py +6 -6
- flwr/server/superlink/state/in_memory_state.py +18 -18
- flwr/server/superlink/state/sqlite_state.py +22 -21
- flwr/server/superlink/state/state.py +7 -7
- flwr/server/utils/tensorboard.py +4 -4
- flwr/server/utils/validator.py +2 -2
- flwr/server/workflow/default_workflows.py +5 -5
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +22 -22
- flwr/simulation/app.py +8 -8
- flwr/simulation/ray_transport/ray_actor.py +23 -23
- flwr/simulation/run_simulation.py +16 -4
- flwr/superexec/app.py +4 -4
- flwr/superexec/deployment.py +2 -2
- flwr/superexec/exec_grpc.py +2 -2
- flwr/superexec/exec_servicer.py +3 -2
- {flwr_nightly-1.12.0.dev20240907.dist-info → flwr_nightly-1.12.0.dev20240913.dist-info}/METADATA +4 -6
- {flwr_nightly-1.12.0.dev20240907.dist-info → flwr_nightly-1.12.0.dev20240913.dist-info}/RECORD +118 -118
- {flwr_nightly-1.12.0.dev20240907.dist-info → flwr_nightly-1.12.0.dev20240913.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.12.0.dev20240907.dist-info → flwr_nightly-1.12.0.dev20240913.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.12.0.dev20240907.dist-info → flwr_nightly-1.12.0.dev20240913.dist-info}/entry_points.txt +0 -0
flwr/server/server.py
CHANGED
|
@@ -19,7 +19,7 @@ import concurrent.futures
|
|
|
19
19
|
import io
|
|
20
20
|
import timeit
|
|
21
21
|
from logging import INFO, WARN
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import Optional, Union
|
|
23
23
|
|
|
24
24
|
from flwr.common import (
|
|
25
25
|
Code,
|
|
@@ -41,17 +41,17 @@ from flwr.server.strategy import FedAvg, Strategy
|
|
|
41
41
|
|
|
42
42
|
from .server_config import ServerConfig
|
|
43
43
|
|
|
44
|
-
FitResultsAndFailures =
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
FitResultsAndFailures = tuple[
|
|
45
|
+
list[tuple[ClientProxy, FitRes]],
|
|
46
|
+
list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
47
47
|
]
|
|
48
|
-
EvaluateResultsAndFailures =
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
EvaluateResultsAndFailures = tuple[
|
|
49
|
+
list[tuple[ClientProxy, EvaluateRes]],
|
|
50
|
+
list[Union[tuple[ClientProxy, EvaluateRes], BaseException]],
|
|
51
51
|
]
|
|
52
|
-
ReconnectResultsAndFailures =
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
ReconnectResultsAndFailures = tuple[
|
|
53
|
+
list[tuple[ClientProxy, DisconnectRes]],
|
|
54
|
+
list[Union[tuple[ClientProxy, DisconnectRes], BaseException]],
|
|
55
55
|
]
|
|
56
56
|
|
|
57
57
|
|
|
@@ -84,7 +84,7 @@ class Server:
|
|
|
84
84
|
return self._client_manager
|
|
85
85
|
|
|
86
86
|
# pylint: disable=too-many-locals
|
|
87
|
-
def fit(self, num_rounds: int, timeout: Optional[float]) ->
|
|
87
|
+
def fit(self, num_rounds: int, timeout: Optional[float]) -> tuple[History, float]:
|
|
88
88
|
"""Run federated averaging for a number of rounds."""
|
|
89
89
|
history = History()
|
|
90
90
|
|
|
@@ -163,7 +163,7 @@ class Server:
|
|
|
163
163
|
server_round: int,
|
|
164
164
|
timeout: Optional[float],
|
|
165
165
|
) -> Optional[
|
|
166
|
-
|
|
166
|
+
tuple[Optional[float], dict[str, Scalar], EvaluateResultsAndFailures]
|
|
167
167
|
]:
|
|
168
168
|
"""Validate current global model on a number of clients."""
|
|
169
169
|
# Get clients and their respective instructions from strategy
|
|
@@ -197,9 +197,9 @@ class Server:
|
|
|
197
197
|
)
|
|
198
198
|
|
|
199
199
|
# Aggregate the evaluation results
|
|
200
|
-
aggregated_result:
|
|
200
|
+
aggregated_result: tuple[
|
|
201
201
|
Optional[float],
|
|
202
|
-
|
|
202
|
+
dict[str, Scalar],
|
|
203
203
|
] = self.strategy.aggregate_evaluate(server_round, results, failures)
|
|
204
204
|
|
|
205
205
|
loss_aggregated, metrics_aggregated = aggregated_result
|
|
@@ -210,7 +210,7 @@ class Server:
|
|
|
210
210
|
server_round: int,
|
|
211
211
|
timeout: Optional[float],
|
|
212
212
|
) -> Optional[
|
|
213
|
-
|
|
213
|
+
tuple[Optional[Parameters], dict[str, Scalar], FitResultsAndFailures]
|
|
214
214
|
]:
|
|
215
215
|
"""Perform a single round of federated averaging."""
|
|
216
216
|
# Get clients and their respective instructions from strategy
|
|
@@ -245,9 +245,9 @@ class Server:
|
|
|
245
245
|
)
|
|
246
246
|
|
|
247
247
|
# Aggregate training results
|
|
248
|
-
aggregated_result:
|
|
248
|
+
aggregated_result: tuple[
|
|
249
249
|
Optional[Parameters],
|
|
250
|
-
|
|
250
|
+
dict[str, Scalar],
|
|
251
251
|
] = self.strategy.aggregate_fit(server_round, results, failures)
|
|
252
252
|
|
|
253
253
|
parameters_aggregated, metrics_aggregated = aggregated_result
|
|
@@ -296,7 +296,7 @@ class Server:
|
|
|
296
296
|
|
|
297
297
|
|
|
298
298
|
def reconnect_clients(
|
|
299
|
-
client_instructions:
|
|
299
|
+
client_instructions: list[tuple[ClientProxy, ReconnectIns]],
|
|
300
300
|
max_workers: Optional[int],
|
|
301
301
|
timeout: Optional[float],
|
|
302
302
|
) -> ReconnectResultsAndFailures:
|
|
@@ -312,8 +312,8 @@ def reconnect_clients(
|
|
|
312
312
|
)
|
|
313
313
|
|
|
314
314
|
# Gather results
|
|
315
|
-
results:
|
|
316
|
-
failures:
|
|
315
|
+
results: list[tuple[ClientProxy, DisconnectRes]] = []
|
|
316
|
+
failures: list[Union[tuple[ClientProxy, DisconnectRes], BaseException]] = []
|
|
317
317
|
for future in finished_fs:
|
|
318
318
|
failure = future.exception()
|
|
319
319
|
if failure is not None:
|
|
@@ -328,7 +328,7 @@ def reconnect_client(
|
|
|
328
328
|
client: ClientProxy,
|
|
329
329
|
reconnect: ReconnectIns,
|
|
330
330
|
timeout: Optional[float],
|
|
331
|
-
) ->
|
|
331
|
+
) -> tuple[ClientProxy, DisconnectRes]:
|
|
332
332
|
"""Instruct client to disconnect and (optionally) reconnect later."""
|
|
333
333
|
disconnect = client.reconnect(
|
|
334
334
|
reconnect,
|
|
@@ -339,7 +339,7 @@ def reconnect_client(
|
|
|
339
339
|
|
|
340
340
|
|
|
341
341
|
def fit_clients(
|
|
342
|
-
client_instructions:
|
|
342
|
+
client_instructions: list[tuple[ClientProxy, FitIns]],
|
|
343
343
|
max_workers: Optional[int],
|
|
344
344
|
timeout: Optional[float],
|
|
345
345
|
group_id: int,
|
|
@@ -356,8 +356,8 @@ def fit_clients(
|
|
|
356
356
|
)
|
|
357
357
|
|
|
358
358
|
# Gather results
|
|
359
|
-
results:
|
|
360
|
-
failures:
|
|
359
|
+
results: list[tuple[ClientProxy, FitRes]] = []
|
|
360
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]] = []
|
|
361
361
|
for future in finished_fs:
|
|
362
362
|
_handle_finished_future_after_fit(
|
|
363
363
|
future=future, results=results, failures=failures
|
|
@@ -367,7 +367,7 @@ def fit_clients(
|
|
|
367
367
|
|
|
368
368
|
def fit_client(
|
|
369
369
|
client: ClientProxy, ins: FitIns, timeout: Optional[float], group_id: int
|
|
370
|
-
) ->
|
|
370
|
+
) -> tuple[ClientProxy, FitRes]:
|
|
371
371
|
"""Refine parameters on a single client."""
|
|
372
372
|
fit_res = client.fit(ins, timeout=timeout, group_id=group_id)
|
|
373
373
|
return client, fit_res
|
|
@@ -375,8 +375,8 @@ def fit_client(
|
|
|
375
375
|
|
|
376
376
|
def _handle_finished_future_after_fit(
|
|
377
377
|
future: concurrent.futures.Future, # type: ignore
|
|
378
|
-
results:
|
|
379
|
-
failures:
|
|
378
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
379
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
380
380
|
) -> None:
|
|
381
381
|
"""Convert finished future into either a result or a failure."""
|
|
382
382
|
# Check if there was an exception
|
|
@@ -386,7 +386,7 @@ def _handle_finished_future_after_fit(
|
|
|
386
386
|
return
|
|
387
387
|
|
|
388
388
|
# Successfully received a result from a client
|
|
389
|
-
result:
|
|
389
|
+
result: tuple[ClientProxy, FitRes] = future.result()
|
|
390
390
|
_, res = result
|
|
391
391
|
|
|
392
392
|
# Check result status code
|
|
@@ -399,7 +399,7 @@ def _handle_finished_future_after_fit(
|
|
|
399
399
|
|
|
400
400
|
|
|
401
401
|
def evaluate_clients(
|
|
402
|
-
client_instructions:
|
|
402
|
+
client_instructions: list[tuple[ClientProxy, EvaluateIns]],
|
|
403
403
|
max_workers: Optional[int],
|
|
404
404
|
timeout: Optional[float],
|
|
405
405
|
group_id: int,
|
|
@@ -416,8 +416,8 @@ def evaluate_clients(
|
|
|
416
416
|
)
|
|
417
417
|
|
|
418
418
|
# Gather results
|
|
419
|
-
results:
|
|
420
|
-
failures:
|
|
419
|
+
results: list[tuple[ClientProxy, EvaluateRes]] = []
|
|
420
|
+
failures: list[Union[tuple[ClientProxy, EvaluateRes], BaseException]] = []
|
|
421
421
|
for future in finished_fs:
|
|
422
422
|
_handle_finished_future_after_evaluate(
|
|
423
423
|
future=future, results=results, failures=failures
|
|
@@ -430,7 +430,7 @@ def evaluate_client(
|
|
|
430
430
|
ins: EvaluateIns,
|
|
431
431
|
timeout: Optional[float],
|
|
432
432
|
group_id: int,
|
|
433
|
-
) ->
|
|
433
|
+
) -> tuple[ClientProxy, EvaluateRes]:
|
|
434
434
|
"""Evaluate parameters on a single client."""
|
|
435
435
|
evaluate_res = client.evaluate(ins, timeout=timeout, group_id=group_id)
|
|
436
436
|
return client, evaluate_res
|
|
@@ -438,8 +438,8 @@ def evaluate_client(
|
|
|
438
438
|
|
|
439
439
|
def _handle_finished_future_after_evaluate(
|
|
440
440
|
future: concurrent.futures.Future, # type: ignore
|
|
441
|
-
results:
|
|
442
|
-
failures:
|
|
441
|
+
results: list[tuple[ClientProxy, EvaluateRes]],
|
|
442
|
+
failures: list[Union[tuple[ClientProxy, EvaluateRes], BaseException]],
|
|
443
443
|
) -> None:
|
|
444
444
|
"""Convert finished future into either a result or a failure."""
|
|
445
445
|
# Check if there was an exception
|
|
@@ -449,7 +449,7 @@ def _handle_finished_future_after_evaluate(
|
|
|
449
449
|
return
|
|
450
450
|
|
|
451
451
|
# Successfully received a result from a client
|
|
452
|
-
result:
|
|
452
|
+
result: tuple[ClientProxy, EvaluateRes] = future.result()
|
|
453
453
|
_, res = result
|
|
454
454
|
|
|
455
455
|
# Check result status code
|
|
@@ -466,7 +466,7 @@ def init_defaults(
|
|
|
466
466
|
config: Optional[ServerConfig],
|
|
467
467
|
strategy: Optional[Strategy],
|
|
468
468
|
client_manager: Optional[ClientManager],
|
|
469
|
-
) ->
|
|
469
|
+
) -> tuple[Server, ServerConfig]:
|
|
470
470
|
"""Create server instance if none was given."""
|
|
471
471
|
if server is None:
|
|
472
472
|
if client_manager is None:
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
# mypy: disallow_untyped_calls=False
|
|
17
17
|
|
|
18
18
|
from functools import reduce
|
|
19
|
-
from typing import Any, Callable
|
|
19
|
+
from typing import Any, Callable
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
|
|
@@ -24,7 +24,7 @@ from flwr.common import FitRes, NDArray, NDArrays, parameters_to_ndarrays
|
|
|
24
24
|
from flwr.server.client_proxy import ClientProxy
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def aggregate(results:
|
|
27
|
+
def aggregate(results: list[tuple[NDArrays, int]]) -> NDArrays:
|
|
28
28
|
"""Compute weighted average."""
|
|
29
29
|
# Calculate the total number of examples used during training
|
|
30
30
|
num_examples_total = sum(num_examples for (_, num_examples) in results)
|
|
@@ -42,7 +42,7 @@ def aggregate(results: List[Tuple[NDArrays, int]]) -> NDArrays:
|
|
|
42
42
|
return weights_prime
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def aggregate_inplace(results:
|
|
45
|
+
def aggregate_inplace(results: list[tuple[ClientProxy, FitRes]]) -> NDArrays:
|
|
46
46
|
"""Compute in-place weighted average."""
|
|
47
47
|
# Count total examples
|
|
48
48
|
num_examples_total = sum(fit_res.num_examples for (_, fit_res) in results)
|
|
@@ -67,7 +67,7 @@ def aggregate_inplace(results: List[Tuple[ClientProxy, FitRes]]) -> NDArrays:
|
|
|
67
67
|
return params
|
|
68
68
|
|
|
69
69
|
|
|
70
|
-
def aggregate_median(results:
|
|
70
|
+
def aggregate_median(results: list[tuple[NDArrays, int]]) -> NDArrays:
|
|
71
71
|
"""Compute median."""
|
|
72
72
|
# Create a list of weights and ignore the number of examples
|
|
73
73
|
weights = [weights for weights, _ in results]
|
|
@@ -80,7 +80,7 @@ def aggregate_median(results: List[Tuple[NDArrays, int]]) -> NDArrays:
|
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def aggregate_krum(
|
|
83
|
-
results:
|
|
83
|
+
results: list[tuple[NDArrays, int]], num_malicious: int, to_keep: int
|
|
84
84
|
) -> NDArrays:
|
|
85
85
|
"""Choose one parameter vector according to the Krum function.
|
|
86
86
|
|
|
@@ -119,7 +119,7 @@ def aggregate_krum(
|
|
|
119
119
|
|
|
120
120
|
# pylint: disable=too-many-locals
|
|
121
121
|
def aggregate_bulyan(
|
|
122
|
-
results:
|
|
122
|
+
results: list[tuple[NDArrays, int]],
|
|
123
123
|
num_malicious: int,
|
|
124
124
|
aggregation_rule: Callable, # type: ignore
|
|
125
125
|
**aggregation_rule_kwargs: Any,
|
|
@@ -155,7 +155,7 @@ def aggregate_bulyan(
|
|
|
155
155
|
"It is needed to ensure that the method reduces the attacker's leeway to "
|
|
156
156
|
"the one proved in the paper."
|
|
157
157
|
)
|
|
158
|
-
selected_models_set:
|
|
158
|
+
selected_models_set: list[tuple[NDArrays, int]] = []
|
|
159
159
|
|
|
160
160
|
theta = len(results) - 2 * num_malicious
|
|
161
161
|
beta = theta - 2 * num_malicious
|
|
@@ -200,7 +200,7 @@ def aggregate_bulyan(
|
|
|
200
200
|
return parameters_aggregated
|
|
201
201
|
|
|
202
202
|
|
|
203
|
-
def weighted_loss_avg(results:
|
|
203
|
+
def weighted_loss_avg(results: list[tuple[int, float]]) -> float:
|
|
204
204
|
"""Aggregate evaluation results obtained from multiple clients."""
|
|
205
205
|
num_total_evaluation_examples = sum(num_examples for (num_examples, _) in results)
|
|
206
206
|
weighted_losses = [num_examples * loss for num_examples, loss in results]
|
|
@@ -208,7 +208,7 @@ def weighted_loss_avg(results: List[Tuple[int, float]]) -> float:
|
|
|
208
208
|
|
|
209
209
|
|
|
210
210
|
def aggregate_qffl(
|
|
211
|
-
parameters: NDArrays, deltas:
|
|
211
|
+
parameters: NDArrays, deltas: list[NDArrays], hs_fll: list[NDArrays]
|
|
212
212
|
) -> NDArrays:
|
|
213
213
|
"""Compute weighted average based on Q-FFL paper."""
|
|
214
214
|
demominator: float = np.sum(np.asarray(hs_fll))
|
|
@@ -225,7 +225,7 @@ def aggregate_qffl(
|
|
|
225
225
|
return new_parameters
|
|
226
226
|
|
|
227
227
|
|
|
228
|
-
def _compute_distances(weights:
|
|
228
|
+
def _compute_distances(weights: list[NDArrays]) -> NDArray:
|
|
229
229
|
"""Compute distances between vectors.
|
|
230
230
|
|
|
231
231
|
Input: weights - list of weights vectors
|
|
@@ -265,7 +265,7 @@ def _trim_mean(array: NDArray, proportiontocut: float) -> NDArray:
|
|
|
265
265
|
|
|
266
266
|
|
|
267
267
|
def aggregate_trimmed_avg(
|
|
268
|
-
results:
|
|
268
|
+
results: list[tuple[NDArrays, int]], proportiontocut: float
|
|
269
269
|
) -> NDArrays:
|
|
270
270
|
"""Compute trimmed average."""
|
|
271
271
|
# Create a list of weights and ignore the number of examples
|
|
@@ -290,7 +290,7 @@ def _check_weights_equality(weights1: NDArrays, weights2: NDArrays) -> bool:
|
|
|
290
290
|
|
|
291
291
|
|
|
292
292
|
def _find_reference_weights(
|
|
293
|
-
reference_weights: NDArrays, list_of_weights:
|
|
293
|
+
reference_weights: NDArrays, list_of_weights: list[NDArrays]
|
|
294
294
|
) -> int:
|
|
295
295
|
"""Find the reference weights by looping through the `list_of_weights`.
|
|
296
296
|
|
|
@@ -320,7 +320,7 @@ def _find_reference_weights(
|
|
|
320
320
|
|
|
321
321
|
|
|
322
322
|
def _aggregate_n_closest_weights(
|
|
323
|
-
reference_weights: NDArrays, results:
|
|
323
|
+
reference_weights: NDArrays, results: list[tuple[NDArrays, int]], beta_closest: int
|
|
324
324
|
) -> NDArrays:
|
|
325
325
|
"""Calculate element-wise mean of the `N` closest values.
|
|
326
326
|
|
flwr/server/strategy/bulyan.py
CHANGED
|
@@ -19,7 +19,7 @@ Paper: arxiv.org/abs/1802.07927
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
from logging import WARNING
|
|
22
|
-
from typing import Any, Callable,
|
|
22
|
+
from typing import Any, Callable, Optional, Union
|
|
23
23
|
|
|
24
24
|
from flwr.common import (
|
|
25
25
|
FitRes,
|
|
@@ -86,12 +86,12 @@ class Bulyan(FedAvg):
|
|
|
86
86
|
num_malicious_clients: int = 0,
|
|
87
87
|
evaluate_fn: Optional[
|
|
88
88
|
Callable[
|
|
89
|
-
[int, NDArrays,
|
|
90
|
-
Optional[
|
|
89
|
+
[int, NDArrays, dict[str, Scalar]],
|
|
90
|
+
Optional[tuple[float, dict[str, Scalar]]],
|
|
91
91
|
]
|
|
92
92
|
] = None,
|
|
93
|
-
on_fit_config_fn: Optional[Callable[[int],
|
|
94
|
-
on_evaluate_config_fn: Optional[Callable[[int],
|
|
93
|
+
on_fit_config_fn: Optional[Callable[[int], dict[str, Scalar]]] = None,
|
|
94
|
+
on_evaluate_config_fn: Optional[Callable[[int], dict[str, Scalar]]] = None,
|
|
95
95
|
accept_failures: bool = True,
|
|
96
96
|
initial_parameters: Optional[Parameters] = None,
|
|
97
97
|
fit_metrics_aggregation_fn: Optional[MetricsAggregationFn] = None,
|
|
@@ -125,9 +125,9 @@ class Bulyan(FedAvg):
|
|
|
125
125
|
def aggregate_fit(
|
|
126
126
|
self,
|
|
127
127
|
server_round: int,
|
|
128
|
-
results:
|
|
129
|
-
failures:
|
|
130
|
-
) ->
|
|
128
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
129
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
130
|
+
) -> tuple[Optional[Parameters], dict[str, Scalar]]:
|
|
131
131
|
"""Aggregate fit results using Bulyan."""
|
|
132
132
|
if not results:
|
|
133
133
|
return None, {}
|
|
@@ -20,7 +20,7 @@ Paper (Andrew et al.): https://arxiv.org/abs/1905.03871
|
|
|
20
20
|
|
|
21
21
|
import math
|
|
22
22
|
from logging import INFO, WARNING
|
|
23
|
-
from typing import
|
|
23
|
+
from typing import Optional, Union
|
|
24
24
|
|
|
25
25
|
import numpy as np
|
|
26
26
|
|
|
@@ -156,14 +156,14 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
|
|
|
156
156
|
|
|
157
157
|
def configure_fit(
|
|
158
158
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
159
|
-
) ->
|
|
159
|
+
) -> list[tuple[ClientProxy, FitIns]]:
|
|
160
160
|
"""Configure the next round of training."""
|
|
161
161
|
self.current_round_params = parameters_to_ndarrays(parameters)
|
|
162
162
|
return self.strategy.configure_fit(server_round, parameters, client_manager)
|
|
163
163
|
|
|
164
164
|
def configure_evaluate(
|
|
165
165
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
166
|
-
) ->
|
|
166
|
+
) -> list[tuple[ClientProxy, EvaluateIns]]:
|
|
167
167
|
"""Configure the next round of evaluation."""
|
|
168
168
|
return self.strategy.configure_evaluate(
|
|
169
169
|
server_round, parameters, client_manager
|
|
@@ -172,9 +172,9 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
|
|
|
172
172
|
def aggregate_fit(
|
|
173
173
|
self,
|
|
174
174
|
server_round: int,
|
|
175
|
-
results:
|
|
176
|
-
failures:
|
|
177
|
-
) ->
|
|
175
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
176
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
177
|
+
) -> tuple[Optional[Parameters], dict[str, Scalar]]:
|
|
178
178
|
"""Aggregate training results and update clip norms."""
|
|
179
179
|
if failures:
|
|
180
180
|
return None, {}
|
|
@@ -245,15 +245,15 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
|
|
|
245
245
|
def aggregate_evaluate(
|
|
246
246
|
self,
|
|
247
247
|
server_round: int,
|
|
248
|
-
results:
|
|
249
|
-
failures:
|
|
250
|
-
) ->
|
|
248
|
+
results: list[tuple[ClientProxy, EvaluateRes]],
|
|
249
|
+
failures: list[Union[tuple[ClientProxy, EvaluateRes], BaseException]],
|
|
250
|
+
) -> tuple[Optional[float], dict[str, Scalar]]:
|
|
251
251
|
"""Aggregate evaluation losses using the given strategy."""
|
|
252
252
|
return self.strategy.aggregate_evaluate(server_round, results, failures)
|
|
253
253
|
|
|
254
254
|
def evaluate(
|
|
255
255
|
self, server_round: int, parameters: Parameters
|
|
256
|
-
) -> Optional[
|
|
256
|
+
) -> Optional[tuple[float, dict[str, Scalar]]]:
|
|
257
257
|
"""Evaluate model parameters using an evaluation function from the strategy."""
|
|
258
258
|
return self.strategy.evaluate(server_round, parameters)
|
|
259
259
|
|
|
@@ -372,7 +372,7 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
|
|
|
372
372
|
|
|
373
373
|
def configure_fit(
|
|
374
374
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
375
|
-
) ->
|
|
375
|
+
) -> list[tuple[ClientProxy, FitIns]]:
|
|
376
376
|
"""Configure the next round of training."""
|
|
377
377
|
additional_config = {KEY_CLIPPING_NORM: self.clipping_norm}
|
|
378
378
|
inner_strategy_config_result = self.strategy.configure_fit(
|
|
@@ -385,7 +385,7 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
|
|
|
385
385
|
|
|
386
386
|
def configure_evaluate(
|
|
387
387
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
388
|
-
) ->
|
|
388
|
+
) -> list[tuple[ClientProxy, EvaluateIns]]:
|
|
389
389
|
"""Configure the next round of evaluation."""
|
|
390
390
|
return self.strategy.configure_evaluate(
|
|
391
391
|
server_round, parameters, client_manager
|
|
@@ -394,9 +394,9 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
|
|
|
394
394
|
def aggregate_fit(
|
|
395
395
|
self,
|
|
396
396
|
server_round: int,
|
|
397
|
-
results:
|
|
398
|
-
failures:
|
|
399
|
-
) ->
|
|
397
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
398
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
399
|
+
) -> tuple[Optional[Parameters], dict[str, Scalar]]:
|
|
400
400
|
"""Aggregate training results and update clip norms."""
|
|
401
401
|
if failures:
|
|
402
402
|
return None, {}
|
|
@@ -432,7 +432,7 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
|
|
|
432
432
|
|
|
433
433
|
return aggregated_params, metrics
|
|
434
434
|
|
|
435
|
-
def _update_clip_norm(self, results:
|
|
435
|
+
def _update_clip_norm(self, results: list[tuple[ClientProxy, FitRes]]) -> None:
|
|
436
436
|
# Calculate the number of clients which set the norm indicator bit
|
|
437
437
|
norm_bit_set_count = 0
|
|
438
438
|
for client_proxy, fit_res in results:
|
|
@@ -457,14 +457,14 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
|
|
|
457
457
|
def aggregate_evaluate(
|
|
458
458
|
self,
|
|
459
459
|
server_round: int,
|
|
460
|
-
results:
|
|
461
|
-
failures:
|
|
462
|
-
) ->
|
|
460
|
+
results: list[tuple[ClientProxy, EvaluateRes]],
|
|
461
|
+
failures: list[Union[tuple[ClientProxy, EvaluateRes], BaseException]],
|
|
462
|
+
) -> tuple[Optional[float], dict[str, Scalar]]:
|
|
463
463
|
"""Aggregate evaluation losses using the given strategy."""
|
|
464
464
|
return self.strategy.aggregate_evaluate(server_round, results, failures)
|
|
465
465
|
|
|
466
466
|
def evaluate(
|
|
467
467
|
self, server_round: int, parameters: Parameters
|
|
468
|
-
) -> Optional[
|
|
468
|
+
) -> Optional[tuple[float, dict[str, Scalar]]]:
|
|
469
469
|
"""Evaluate model parameters using an evaluation function from the strategy."""
|
|
470
470
|
return self.strategy.evaluate(server_round, parameters)
|
|
@@ -19,7 +19,7 @@ Papers: https://arxiv.org/abs/1712.07557, https://arxiv.org/abs/1710.06963
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
from logging import INFO, WARNING
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import Optional, Union
|
|
23
23
|
|
|
24
24
|
from flwr.common import (
|
|
25
25
|
EvaluateIns,
|
|
@@ -117,14 +117,14 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
|
|
117
117
|
|
|
118
118
|
def configure_fit(
|
|
119
119
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
120
|
-
) ->
|
|
120
|
+
) -> list[tuple[ClientProxy, FitIns]]:
|
|
121
121
|
"""Configure the next round of training."""
|
|
122
122
|
self.current_round_params = parameters_to_ndarrays(parameters)
|
|
123
123
|
return self.strategy.configure_fit(server_round, parameters, client_manager)
|
|
124
124
|
|
|
125
125
|
def configure_evaluate(
|
|
126
126
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
127
|
-
) ->
|
|
127
|
+
) -> list[tuple[ClientProxy, EvaluateIns]]:
|
|
128
128
|
"""Configure the next round of evaluation."""
|
|
129
129
|
return self.strategy.configure_evaluate(
|
|
130
130
|
server_round, parameters, client_manager
|
|
@@ -133,9 +133,9 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
|
|
133
133
|
def aggregate_fit(
|
|
134
134
|
self,
|
|
135
135
|
server_round: int,
|
|
136
|
-
results:
|
|
137
|
-
failures:
|
|
138
|
-
) ->
|
|
136
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
137
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
138
|
+
) -> tuple[Optional[Parameters], dict[str, Scalar]]:
|
|
139
139
|
"""Compute the updates, clip, and pass them for aggregation.
|
|
140
140
|
|
|
141
141
|
Afterward, add noise to the aggregated parameters.
|
|
@@ -191,15 +191,15 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
|
|
191
191
|
def aggregate_evaluate(
|
|
192
192
|
self,
|
|
193
193
|
server_round: int,
|
|
194
|
-
results:
|
|
195
|
-
failures:
|
|
196
|
-
) ->
|
|
194
|
+
results: list[tuple[ClientProxy, EvaluateRes]],
|
|
195
|
+
failures: list[Union[tuple[ClientProxy, EvaluateRes], BaseException]],
|
|
196
|
+
) -> tuple[Optional[float], dict[str, Scalar]]:
|
|
197
197
|
"""Aggregate evaluation losses using the given strategy."""
|
|
198
198
|
return self.strategy.aggregate_evaluate(server_round, results, failures)
|
|
199
199
|
|
|
200
200
|
def evaluate(
|
|
201
201
|
self, server_round: int, parameters: Parameters
|
|
202
|
-
) -> Optional[
|
|
202
|
+
) -> Optional[tuple[float, dict[str, Scalar]]]:
|
|
203
203
|
"""Evaluate model parameters using an evaluation function from the strategy."""
|
|
204
204
|
return self.strategy.evaluate(server_round, parameters)
|
|
205
205
|
|
|
@@ -285,7 +285,7 @@ class DifferentialPrivacyClientSideFixedClipping(Strategy):
|
|
|
285
285
|
|
|
286
286
|
def configure_fit(
|
|
287
287
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
288
|
-
) ->
|
|
288
|
+
) -> list[tuple[ClientProxy, FitIns]]:
|
|
289
289
|
"""Configure the next round of training."""
|
|
290
290
|
additional_config = {KEY_CLIPPING_NORM: self.clipping_norm}
|
|
291
291
|
inner_strategy_config_result = self.strategy.configure_fit(
|
|
@@ -298,7 +298,7 @@ class DifferentialPrivacyClientSideFixedClipping(Strategy):
|
|
|
298
298
|
|
|
299
299
|
def configure_evaluate(
|
|
300
300
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
301
|
-
) ->
|
|
301
|
+
) -> list[tuple[ClientProxy, EvaluateIns]]:
|
|
302
302
|
"""Configure the next round of evaluation."""
|
|
303
303
|
return self.strategy.configure_evaluate(
|
|
304
304
|
server_round, parameters, client_manager
|
|
@@ -307,9 +307,9 @@ class DifferentialPrivacyClientSideFixedClipping(Strategy):
|
|
|
307
307
|
def aggregate_fit(
|
|
308
308
|
self,
|
|
309
309
|
server_round: int,
|
|
310
|
-
results:
|
|
311
|
-
failures:
|
|
312
|
-
) ->
|
|
310
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
311
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
312
|
+
) -> tuple[Optional[Parameters], dict[str, Scalar]]:
|
|
313
313
|
"""Add noise to the aggregated parameters."""
|
|
314
314
|
if failures:
|
|
315
315
|
return None, {}
|
|
@@ -348,14 +348,14 @@ class DifferentialPrivacyClientSideFixedClipping(Strategy):
|
|
|
348
348
|
def aggregate_evaluate(
|
|
349
349
|
self,
|
|
350
350
|
server_round: int,
|
|
351
|
-
results:
|
|
352
|
-
failures:
|
|
353
|
-
) ->
|
|
351
|
+
results: list[tuple[ClientProxy, EvaluateRes]],
|
|
352
|
+
failures: list[Union[tuple[ClientProxy, EvaluateRes], BaseException]],
|
|
353
|
+
) -> tuple[Optional[float], dict[str, Scalar]]:
|
|
354
354
|
"""Aggregate evaluation losses using the given strategy."""
|
|
355
355
|
return self.strategy.aggregate_evaluate(server_round, results, failures)
|
|
356
356
|
|
|
357
357
|
def evaluate(
|
|
358
358
|
self, server_round: int, parameters: Parameters
|
|
359
|
-
) -> Optional[
|
|
359
|
+
) -> Optional[tuple[float, dict[str, Scalar]]]:
|
|
360
360
|
"""Evaluate model parameters using an evaluation function from the strategy."""
|
|
361
361
|
return self.strategy.evaluate(server_round, parameters)
|
|
@@ -19,7 +19,7 @@ Paper: arxiv.org/pdf/1905.03871.pdf
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
import math
|
|
22
|
-
from typing import
|
|
22
|
+
from typing import Optional, Union
|
|
23
23
|
|
|
24
24
|
import numpy as np
|
|
25
25
|
|
|
@@ -80,7 +80,7 @@ class DPFedAvgAdaptive(DPFedAvgFixed):
|
|
|
80
80
|
|
|
81
81
|
def configure_fit(
|
|
82
82
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
|
83
|
-
) ->
|
|
83
|
+
) -> list[tuple[ClientProxy, FitIns]]:
|
|
84
84
|
"""Configure the next round of training."""
|
|
85
85
|
additional_config = {"dpfedavg_adaptive_clip_enabled": True}
|
|
86
86
|
|
|
@@ -93,7 +93,7 @@ class DPFedAvgAdaptive(DPFedAvgFixed):
|
|
|
93
93
|
|
|
94
94
|
return client_instructions
|
|
95
95
|
|
|
96
|
-
def _update_clip_norm(self, results:
|
|
96
|
+
def _update_clip_norm(self, results: list[tuple[ClientProxy, FitRes]]) -> None:
|
|
97
97
|
# Calculating number of clients which set the norm indicator bit
|
|
98
98
|
norm_bit_set_count = 0
|
|
99
99
|
for client_proxy, fit_res in results:
|
|
@@ -118,9 +118,9 @@ class DPFedAvgAdaptive(DPFedAvgFixed):
|
|
|
118
118
|
def aggregate_fit(
|
|
119
119
|
self,
|
|
120
120
|
server_round: int,
|
|
121
|
-
results:
|
|
122
|
-
failures:
|
|
123
|
-
) ->
|
|
121
|
+
results: list[tuple[ClientProxy, FitRes]],
|
|
122
|
+
failures: list[Union[tuple[ClientProxy, FitRes], BaseException]],
|
|
123
|
+
) -> tuple[Optional[Parameters], dict[str, Scalar]]:
|
|
124
124
|
"""Aggregate training results as in DPFedAvgFixed and update clip norms."""
|
|
125
125
|
if failures:
|
|
126
126
|
return None, {}
|