flwr-nightly 1.5.0.dev20230608__py3-none-any.whl → 1.5.0.dev20230615__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.
- flwr/client/app.py +0 -3
- flwr/client/client.py +0 -4
- flwr/client/dpfedavg_numpy_client.py +97 -0
- flwr/client/grpc_rere_client/connection.py +0 -2
- flwr/client/message_handler/task_handler.py +0 -1
- flwr/client/numpy_client.py +1 -1
- flwr/client/rest_client/connection.py +0 -3
- flwr/common/address.py +1 -1
- flwr/common/dp.py +1 -2
- flwr/common/grpc.py +0 -1
- flwr/common/logger.py +0 -1
- flwr/common/serde.py +0 -1
- flwr/driver/driver.py +0 -3
- flwr/driver/driver_client_manager.py +9 -0
- flwr/driver/driver_client_proxy.py +1 -1
- flwr/proto/task_pb2.py +94 -6
- flwr/proto/task_pb2.pyi +137 -2
- flwr/server/app.py +4 -11
- flwr/server/client_manager.py +7 -0
- flwr/server/client_proxy.py +1 -1
- flwr/server/criterion.py +1 -2
- flwr/server/fleet/grpc_bidi/flower_service_servicer.py +3 -1
- flwr/server/fleet/grpc_bidi/grpc_bridge.py +1 -2
- flwr/server/fleet/grpc_bidi/grpc_client_proxy.py +1 -1
- flwr/server/fleet/grpc_bidi/grpc_server.py +1 -3
- flwr/server/fleet/grpc_bidi/ins_scheduler.py +0 -1
- flwr/server/fleet/message_handler/message_handler.py +0 -2
- flwr/server/history.py +15 -0
- flwr/server/server.py +0 -5
- flwr/server/state/in_memory_state.py +8 -5
- flwr/server/state/sqlite_state.py +4 -5
- flwr/server/state/state.py +2 -2
- flwr/server/state/state_factory.py +0 -1
- flwr/server/strategy/dpfedavg_adaptive.py +1 -1
- flwr/server/strategy/dpfedavg_fixed.py +46 -2
- flwr/server/strategy/fedadagrad.py +4 -4
- flwr/server/strategy/fedadam.py +3 -4
- flwr/server/strategy/fedavg.py +1 -2
- flwr/server/strategy/fedavg_android.py +1 -2
- flwr/server/strategy/fedopt.py +1 -2
- flwr/server/strategy/fedxgb_nn_avg.py +2 -2
- flwr/server/strategy/fedyogi.py +3 -4
- flwr/server/strategy/qfedavg.py +1 -2
- flwr/server/utils/tensorboard.py +2 -4
- flwr/server/utils/validator.py +0 -1
- flwr/simulation/app.py +4 -5
- flwr/simulation/ray_transport/ray_client_proxy.py +13 -13
- {flwr_nightly-1.5.0.dev20230608.dist-info → flwr_nightly-1.5.0.dev20230615.dist-info}/METADATA +1 -1
- {flwr_nightly-1.5.0.dev20230608.dist-info → flwr_nightly-1.5.0.dev20230615.dist-info}/RECORD +52 -52
- {flwr_nightly-1.5.0.dev20230608.dist-info → flwr_nightly-1.5.0.dev20230615.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.5.0.dev20230608.dist-info → flwr_nightly-1.5.0.dev20230615.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.5.0.dev20230608.dist-info → flwr_nightly-1.5.0.dev20230615.dist-info}/entry_points.txt +0 -0
flwr/server/app.py
CHANGED
@@ -66,8 +66,8 @@ DATABASE = ":flwr-in-memory-state:"
|
|
66
66
|
class ServerConfig:
|
67
67
|
"""Flower server config.
|
68
68
|
|
69
|
-
All attributes have default values which allows users to configure
|
70
|
-
|
69
|
+
All attributes have default values which allows users to configure just the ones
|
70
|
+
they care about.
|
71
71
|
"""
|
72
72
|
|
73
73
|
num_rounds: int = 1
|
@@ -236,7 +236,6 @@ def run_fl(
|
|
236
236
|
|
237
237
|
def run_driver_api() -> None:
|
238
238
|
"""Run Flower server (Driver API)."""
|
239
|
-
|
240
239
|
log(INFO, "Starting Flower server (Driver API)")
|
241
240
|
event(EventType.RUN_DRIVER_API_ENTER)
|
242
241
|
args = _parse_args_driver().parse_args()
|
@@ -270,7 +269,6 @@ def run_driver_api() -> None:
|
|
270
269
|
|
271
270
|
def run_fleet_api() -> None:
|
272
271
|
"""Run Flower server (Fleet API)."""
|
273
|
-
|
274
272
|
log(INFO, "Starting Flower server (Fleet API)")
|
275
273
|
event(EventType.RUN_FLEET_API_ENTER)
|
276
274
|
args = _parse_args_fleet().parse_args()
|
@@ -352,7 +350,6 @@ def run_fleet_api() -> None:
|
|
352
350
|
# pylint: disable=too-many-branches
|
353
351
|
def run_server() -> None:
|
354
352
|
"""Run Flower server (Driver API and Fleet API)."""
|
355
|
-
|
356
353
|
log(INFO, "Starting Flower server")
|
357
354
|
event(EventType.RUN_SERVER_ENTER)
|
358
355
|
args = _parse_args_server().parse_args()
|
@@ -462,10 +459,9 @@ def _register_exit_handlers(
|
|
462
459
|
) -> None:
|
463
460
|
"""Exit handler to be registered with signal.signal.
|
464
461
|
|
465
|
-
When called will reset signal handler to original signal handler
|
466
|
-
|
462
|
+
When called will reset signal handler to original signal handler from
|
463
|
+
default_handlers.
|
467
464
|
"""
|
468
|
-
|
469
465
|
# Reset to default handler
|
470
466
|
signal(signalnum, default_handlers[signalnum])
|
471
467
|
|
@@ -498,7 +494,6 @@ def _run_driver_api_grpc(
|
|
498
494
|
state_factory: StateFactory,
|
499
495
|
) -> grpc.Server:
|
500
496
|
"""Run Driver API (gRPC, request-response)."""
|
501
|
-
|
502
497
|
# Create Driver API gRPC server
|
503
498
|
driver_servicer: grpc.Server = DriverServicer(
|
504
499
|
state_factory=state_factory,
|
@@ -522,7 +517,6 @@ def _run_fleet_api_grpc_bidi(
|
|
522
517
|
state_factory: StateFactory,
|
523
518
|
) -> grpc.Server:
|
524
519
|
"""Run Fleet API (gRPC, bidirectional streaming)."""
|
525
|
-
|
526
520
|
# DriverClientManager
|
527
521
|
driver_client_manager = DriverClientManager(
|
528
522
|
state_factory=state_factory,
|
@@ -551,7 +545,6 @@ def _run_fleet_api_grpc_rere(
|
|
551
545
|
state_factory: StateFactory,
|
552
546
|
) -> grpc.Server:
|
553
547
|
"""Run Fleet API (gRPC, request-response)."""
|
554
|
-
|
555
548
|
# Create Fleet API gRPC server
|
556
549
|
fleet_servicer = FleetServicer(
|
557
550
|
state=state_factory.state(),
|
flwr/server/client_manager.py
CHANGED
@@ -92,6 +92,13 @@ class SimpleClientManager(ClientManager):
|
|
92
92
|
self._cv = threading.Condition()
|
93
93
|
|
94
94
|
def __len__(self) -> int:
|
95
|
+
"""Return the number of available clients.
|
96
|
+
|
97
|
+
Returns
|
98
|
+
-------
|
99
|
+
num_available : int
|
100
|
+
The number of currently available clients.
|
101
|
+
"""
|
95
102
|
return len(self.clients)
|
96
103
|
|
97
104
|
def num_available(self) -> int:
|
flwr/server/client_proxy.py
CHANGED
flwr/server/criterion.py
CHANGED
@@ -21,8 +21,7 @@ from .client_proxy import ClientProxy
|
|
21
21
|
|
22
22
|
|
23
23
|
class Criterion(ABC):
|
24
|
-
"""Abstract class which allows subclasses to implement criterion
|
25
|
-
sampling."""
|
24
|
+
"""Abstract class which allows subclasses to implement criterion sampling."""
|
26
25
|
|
27
26
|
@abstractmethod
|
28
27
|
def select(self, client: ClientProxy) -> bool:
|
@@ -78,7 +78,9 @@ class FlowerServiceServicer(transport_pb2_grpc.FlowerServiceServicer):
|
|
78
78
|
request_iterator: Iterator[ClientMessage],
|
79
79
|
context: grpc.ServicerContext,
|
80
80
|
) -> Iterator[ServerMessage]:
|
81
|
-
"""
|
81
|
+
"""Facilitate bi-directional streaming of messages between server and client.
|
82
|
+
|
83
|
+
Invoked by each gRPC client which participates in the network.
|
82
84
|
|
83
85
|
Protocol:
|
84
86
|
- The first message is sent from the server to the client
|
@@ -80,8 +80,7 @@ class GrpcBridge:
|
|
80
80
|
def _transition(self, next_status: Status) -> None:
|
81
81
|
"""Validate status transition and set next status.
|
82
82
|
|
83
|
-
The caller of the transition method will have to aquire
|
84
|
-
conditional variable.
|
83
|
+
The caller of the transition method will have to aquire conditional variable.
|
85
84
|
"""
|
86
85
|
if next_status == Status.CLOSED:
|
87
86
|
self._status = next_status
|
@@ -40,7 +40,7 @@ class GrpcClientProxy(ClientProxy):
|
|
40
40
|
ins: common.GetPropertiesIns,
|
41
41
|
timeout: Optional[float],
|
42
42
|
) -> common.GetPropertiesRes:
|
43
|
-
"""
|
43
|
+
"""Request client's set of internal properties."""
|
44
44
|
get_properties_msg = serde.get_properties_ins_to_proto(ins)
|
45
45
|
res_wrapper: ResWrapper = self.bridge.request(
|
46
46
|
ins_wrapper=InsWrapper(
|
@@ -130,7 +130,6 @@ def start_grpc_server( # pylint: disable=too-many-arguments
|
|
130
130
|
>>> ),
|
131
131
|
>>> )
|
132
132
|
"""
|
133
|
-
|
134
133
|
servicer = FlowerServiceServicer(client_manager)
|
135
134
|
add_servicer_to_server_fn = add_FlowerServiceServicer_to_server
|
136
135
|
|
@@ -160,7 +159,7 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments
|
|
160
159
|
keepalive_time_ms: int = 210000,
|
161
160
|
certificates: Optional[Tuple[bytes, bytes, bytes]] = None,
|
162
161
|
) -> grpc.Server:
|
163
|
-
"""
|
162
|
+
"""Create a gRPC server with a single servicer.
|
164
163
|
|
165
164
|
Parameters
|
166
165
|
----------
|
@@ -210,7 +209,6 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments
|
|
210
209
|
server : grpc.Server
|
211
210
|
A non-running instance of a gRPC server.
|
212
211
|
"""
|
213
|
-
|
214
212
|
# Deconstruct tuple into servicer and function
|
215
213
|
servicer, add_servicer_to_server_fn = servicer_and_add_fn
|
216
214
|
|
@@ -31,7 +31,6 @@ from flwr.server.state import State
|
|
31
31
|
|
32
32
|
def pull_task_ins(request: PullTaskInsRequest, state: State) -> PullTaskInsResponse:
|
33
33
|
"""Pull TaskIns handler."""
|
34
|
-
|
35
34
|
# Get node_id if client node is not anonymous
|
36
35
|
node = request.node # pylint: disable=no-member
|
37
36
|
node_id: Optional[int] = None if node.anonymous else node.node_id
|
@@ -48,7 +47,6 @@ def pull_task_ins(request: PullTaskInsRequest, state: State) -> PullTaskInsRespo
|
|
48
47
|
|
49
48
|
def push_task_res(request: PushTaskResRequest, state: State) -> PushTaskResResponse:
|
50
49
|
"""Push TaskRes handler."""
|
51
|
-
|
52
50
|
# pylint: disable=no-member
|
53
51
|
task_res: TaskRes = request.task_res_list[0]
|
54
52
|
# pylint: enable=no-member
|
flwr/server/history.py
CHANGED
@@ -73,6 +73,21 @@ class History:
|
|
73
73
|
self.metrics_centralized[key].append((server_round, metrics[key]))
|
74
74
|
|
75
75
|
def __repr__(self) -> str:
|
76
|
+
"""Create a representation of History.
|
77
|
+
|
78
|
+
The representation consists of the following data (for each round) if present:
|
79
|
+
|
80
|
+
* distributed loss.
|
81
|
+
* centralized loss.
|
82
|
+
* distributed training metrics.
|
83
|
+
* distributed evaluation metrics.
|
84
|
+
* centralized metrics.
|
85
|
+
|
86
|
+
Returns
|
87
|
+
-------
|
88
|
+
representation : str
|
89
|
+
The string representation of the history object.
|
90
|
+
"""
|
76
91
|
rep = ""
|
77
92
|
if self.losses_distributed:
|
78
93
|
rep += "History (loss, distributed):\n" + reduce(
|
flwr/server/server.py
CHANGED
@@ -161,7 +161,6 @@ class Server:
|
|
161
161
|
Tuple[Optional[float], Dict[str, Scalar], EvaluateResultsAndFailures]
|
162
162
|
]:
|
163
163
|
"""Validate current global model on a number of clients."""
|
164
|
-
|
165
164
|
# Get clients and their respective instructions from strategy
|
166
165
|
client_instructions = self.strategy.configure_evaluate(
|
167
166
|
server_round=server_round,
|
@@ -210,7 +209,6 @@ class Server:
|
|
210
209
|
Tuple[Optional[Parameters], Dict[str, Scalar], FitResultsAndFailures]
|
211
210
|
]:
|
212
211
|
"""Perform a single round of federated averaging."""
|
213
|
-
|
214
212
|
# Get clients and their respective instructions from strategy
|
215
213
|
client_instructions = self.strategy.configure_fit(
|
216
214
|
server_round=server_round,
|
@@ -266,7 +264,6 @@ class Server:
|
|
266
264
|
|
267
265
|
def _get_initial_parameters(self, timeout: Optional[float]) -> Parameters:
|
268
266
|
"""Get initial parameters from one of the available clients."""
|
269
|
-
|
270
267
|
# Server-side parameter initialization
|
271
268
|
parameters: Optional[Parameters] = self.strategy.initialize_parameters(
|
272
269
|
client_manager=self._client_manager
|
@@ -366,7 +363,6 @@ def _handle_finished_future_after_fit(
|
|
366
363
|
failures: List[Union[Tuple[ClientProxy, FitRes], BaseException]],
|
367
364
|
) -> None:
|
368
365
|
"""Convert finished future into either a result or a failure."""
|
369
|
-
|
370
366
|
# Check if there was an exception
|
371
367
|
failure = future.exception()
|
372
368
|
if failure is not None:
|
@@ -428,7 +424,6 @@ def _handle_finished_future_after_evaluate(
|
|
428
424
|
failures: List[Union[Tuple[ClientProxy, EvaluateRes], BaseException]],
|
429
425
|
) -> None:
|
430
426
|
"""Convert finished future into either a result or a failure."""
|
431
|
-
|
432
427
|
# Check if there was an exception
|
433
428
|
failure = future.exception()
|
434
429
|
if failure is not None:
|
@@ -36,7 +36,6 @@ class InMemoryState(State):
|
|
36
36
|
|
37
37
|
def store_task_ins(self, task_ins: TaskIns) -> Optional[UUID]:
|
38
38
|
"""Store one TaskIns."""
|
39
|
-
|
40
39
|
# Validate task
|
41
40
|
errors = validate_task_ins_or_res(task_ins)
|
42
41
|
if any(errors):
|
@@ -61,7 +60,6 @@ class InMemoryState(State):
|
|
61
60
|
self, node_id: Optional[int], limit: Optional[int]
|
62
61
|
) -> List[TaskIns]:
|
63
62
|
"""Get all TaskIns that have not been delivered yet."""
|
64
|
-
|
65
63
|
if limit is not None and limit < 1:
|
66
64
|
raise AssertionError("`limit` must be >= 1")
|
67
65
|
|
@@ -94,7 +92,6 @@ class InMemoryState(State):
|
|
94
92
|
|
95
93
|
def store_task_res(self, task_res: TaskRes) -> Optional[UUID]:
|
96
94
|
"""Store one TaskRes."""
|
97
|
-
|
98
95
|
# Validate task
|
99
96
|
errors = validate_task_ins_or_res(task_res)
|
100
97
|
if any(errors):
|
@@ -117,7 +114,6 @@ class InMemoryState(State):
|
|
117
114
|
|
118
115
|
def get_task_res(self, task_ids: Set[UUID], limit: Optional[int]) -> List[TaskRes]:
|
119
116
|
"""Get all TaskRes that have not been delivered yet."""
|
120
|
-
|
121
117
|
if limit is not None and limit < 1:
|
122
118
|
raise AssertionError("`limit` must be >= 1")
|
123
119
|
|
@@ -142,7 +138,6 @@ class InMemoryState(State):
|
|
142
138
|
|
143
139
|
def delete_tasks(self, task_ids: Set[UUID]) -> None:
|
144
140
|
"""Delete all delivered TaskIns/TaskRes pairs."""
|
145
|
-
|
146
141
|
task_ins_to_be_deleted: Set[UUID] = set()
|
147
142
|
task_res_to_be_deleted: Set[UUID] = set()
|
148
143
|
|
@@ -163,9 +158,17 @@ class InMemoryState(State):
|
|
163
158
|
del self.task_res_store[task_id]
|
164
159
|
|
165
160
|
def num_task_ins(self) -> int:
|
161
|
+
"""Calculate the number of task_ins in store.
|
162
|
+
|
163
|
+
This includes delivered but not yet deleted task_ins.
|
164
|
+
"""
|
166
165
|
return len(self.task_ins_store)
|
167
166
|
|
168
167
|
def num_task_res(self) -> int:
|
168
|
+
"""Calculate the number of task_res in store.
|
169
|
+
|
170
|
+
This includes delivered but not yet deleted task_res.
|
171
|
+
"""
|
169
172
|
return len(self.task_res_store)
|
170
173
|
|
171
174
|
def register_node(self, node_id: int) -> None:
|
@@ -390,7 +390,7 @@ class SqliteState(State):
|
|
390
390
|
return result
|
391
391
|
|
392
392
|
def num_task_ins(self) -> int:
|
393
|
-
"""
|
393
|
+
"""Calculate the number of task_ins in store.
|
394
394
|
|
395
395
|
This includes delivered but not yet deleted task_ins.
|
396
396
|
"""
|
@@ -401,7 +401,7 @@ class SqliteState(State):
|
|
401
401
|
return num
|
402
402
|
|
403
403
|
def num_task_res(self) -> int:
|
404
|
-
"""
|
404
|
+
"""Calculate the number of task_res in store.
|
405
405
|
|
406
406
|
This includes delivered but not yet deleted task_res.
|
407
407
|
"""
|
@@ -469,10 +469,9 @@ def dict_factory(
|
|
469
469
|
cursor: sqlite3.Cursor,
|
470
470
|
row: sqlite3.Row,
|
471
471
|
) -> Dict[str, Any]:
|
472
|
-
"""
|
472
|
+
"""Turn SQLite results into dicts.
|
473
473
|
|
474
|
-
Less efficent for retrival of large amounts of data but easier to
|
475
|
-
use.
|
474
|
+
Less efficent for retrival of large amounts of data but easier to use.
|
476
475
|
"""
|
477
476
|
fields = [column[0] for column in cursor.description]
|
478
477
|
return dict(zip(fields, row))
|
flwr/server/state/state.py
CHANGED
@@ -109,14 +109,14 @@ class State(abc.ABC):
|
|
109
109
|
|
110
110
|
@abc.abstractmethod
|
111
111
|
def num_task_ins(self) -> int:
|
112
|
-
"""
|
112
|
+
"""Calculate the number of task_ins in store.
|
113
113
|
|
114
114
|
This includes delivered but not yet deleted task_ins.
|
115
115
|
"""
|
116
116
|
|
117
117
|
@abc.abstractmethod
|
118
118
|
def num_task_res(self) -> int:
|
119
|
-
"""
|
119
|
+
"""Calculate the number of task_res in store.
|
120
120
|
|
121
121
|
This includes delivered but not yet deleted task_res.
|
122
122
|
"""
|
@@ -74,7 +74,6 @@ class DPFedAvgAdaptive(DPFedAvgFixed):
|
|
74
74
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
75
75
|
) -> List[Tuple[ClientProxy, FitIns]]:
|
76
76
|
"""Configure the next round of training."""
|
77
|
-
|
78
77
|
additional_config = {"dpfedavg_adaptive_clip_enabled": True}
|
79
78
|
|
80
79
|
client_instructions = super().configure_fit(
|
@@ -114,6 +113,7 @@ class DPFedAvgAdaptive(DPFedAvgFixed):
|
|
114
113
|
results: List[Tuple[ClientProxy, FitRes]],
|
115
114
|
failures: List[Union[Tuple[ClientProxy, FitRes], BaseException]],
|
116
115
|
) -> Tuple[Optional[Parameters], Dict[str, Scalar]]:
|
116
|
+
"""Aggregate training results as in DPFedAvgFixed and update clip norms."""
|
117
117
|
if failures:
|
118
118
|
return None, {}
|
119
119
|
new_global_model = super().aggregate_fit(server_round, results, failures)
|
@@ -67,13 +67,34 @@ class DPFedAvgFixed(Strategy):
|
|
67
67
|
def initialize_parameters(
|
68
68
|
self, client_manager: ClientManager
|
69
69
|
) -> Optional[Parameters]:
|
70
|
+
"""Initialize global model parameters using given strategy."""
|
70
71
|
return self.strategy.initialize_parameters(client_manager)
|
71
72
|
|
72
73
|
def configure_fit(
|
73
74
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
74
75
|
) -> List[Tuple[ClientProxy, FitIns]]:
|
75
|
-
"""Configure the next round of training.
|
76
|
-
|
76
|
+
"""Configure the next round of training incorporating Differential Privacy (DP).
|
77
|
+
|
78
|
+
Configuration of the next training round includes information related to DP,
|
79
|
+
such as clip norm and noise stddev.
|
80
|
+
|
81
|
+
Parameters
|
82
|
+
----------
|
83
|
+
server_round : int
|
84
|
+
The current round of federated learning.
|
85
|
+
parameters : Parameters
|
86
|
+
The current (global) model parameters.
|
87
|
+
client_manager : ClientManager
|
88
|
+
The client manager which holds all currently connected clients.
|
89
|
+
|
90
|
+
Returns
|
91
|
+
-------
|
92
|
+
fit_configuration : List[Tuple[ClientProxy, FitIns]]
|
93
|
+
A list of tuples. Each tuple in the list identifies a `ClientProxy` and the
|
94
|
+
`FitIns` for this particular `ClientProxy`. If a particular `ClientProxy`
|
95
|
+
is not included in this list, it means that this `ClientProxy`
|
96
|
+
will not participate in the next round of federated learning.
|
97
|
+
"""
|
77
98
|
additional_config = {"dpfedavg_clip_norm": self.clip_norm}
|
78
99
|
if not self.server_side_noising:
|
79
100
|
additional_config[
|
@@ -92,6 +113,26 @@ class DPFedAvgFixed(Strategy):
|
|
92
113
|
def configure_evaluate(
|
93
114
|
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
94
115
|
) -> List[Tuple[ClientProxy, EvaluateIns]]:
|
116
|
+
"""Configure the next round of evaluation using the specified strategy.
|
117
|
+
|
118
|
+
Parameters
|
119
|
+
----------
|
120
|
+
server_round : int
|
121
|
+
The current round of federated learning.
|
122
|
+
parameters : Parameters
|
123
|
+
The current (global) model parameters.
|
124
|
+
client_manager : ClientManager
|
125
|
+
The client manager which holds all currently connected clients.
|
126
|
+
|
127
|
+
Returns
|
128
|
+
-------
|
129
|
+
evaluate_configuration : List[Tuple[ClientProxy, EvaluateIns]]
|
130
|
+
A list of tuples. Each tuple in the list identifies a `ClientProxy` and the
|
131
|
+
`EvaluateIns` for this particular `ClientProxy`. If a particular
|
132
|
+
`ClientProxy` is not included in this list, it means that this
|
133
|
+
`ClientProxy` will not participate in the next round of federated
|
134
|
+
evaluation.
|
135
|
+
"""
|
95
136
|
return self.strategy.configure_evaluate(
|
96
137
|
server_round, parameters, client_manager
|
97
138
|
)
|
@@ -102,6 +143,7 @@ class DPFedAvgFixed(Strategy):
|
|
102
143
|
results: List[Tuple[ClientProxy, FitRes]],
|
103
144
|
failures: List[Union[Tuple[ClientProxy, FitRes], BaseException]],
|
104
145
|
) -> Tuple[Optional[Parameters], Dict[str, Scalar]]:
|
146
|
+
"""Aggregate training results using unweighted aggregation."""
|
105
147
|
if failures:
|
106
148
|
return None, {}
|
107
149
|
# Forcing unweighted aggregation, as in https://arxiv.org/abs/1905.03871.
|
@@ -122,9 +164,11 @@ class DPFedAvgFixed(Strategy):
|
|
122
164
|
results: List[Tuple[ClientProxy, EvaluateRes]],
|
123
165
|
failures: List[Union[Tuple[ClientProxy, EvaluateRes], BaseException]],
|
124
166
|
) -> Tuple[Optional[float], Dict[str, Scalar]]:
|
167
|
+
"""Aggregate evaluation losses using the given strategy."""
|
125
168
|
return self.strategy.aggregate_evaluate(server_round, results, failures)
|
126
169
|
|
127
170
|
def evaluate(
|
128
171
|
self, server_round: int, parameters: Parameters
|
129
172
|
) -> Optional[Tuple[float, Dict[str, Scalar]]]:
|
173
|
+
"""Evaluate model parameters using an evaluation function from the strategy."""
|
130
174
|
return self.strategy.evaluate(server_round, parameters)
|
@@ -12,8 +12,8 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""Adaptive Federated Optimization using Adagrad (FedAdagrad) [Reddi et al.,
|
16
|
-
|
15
|
+
"""Adaptive Federated Optimization using Adagrad (FedAdagrad) [Reddi et al., 2020]
|
16
|
+
strategy.
|
17
17
|
|
18
18
|
Paper: arxiv.org/abs/2003.00295
|
19
19
|
"""
|
@@ -39,8 +39,8 @@ from .fedopt import FedOpt
|
|
39
39
|
|
40
40
|
# flake8: noqa: E501
|
41
41
|
class FedAdagrad(FedOpt):
|
42
|
-
"""Adaptive Federated Optimization using Adagrad (FedAdagrad) [Reddi et
|
43
|
-
|
42
|
+
"""Adaptive Federated Optimization using Adagrad (FedAdagrad) [Reddi et al., 2020]
|
43
|
+
strategy.
|
44
44
|
|
45
45
|
Paper: https://arxiv.org/abs/2003.00295
|
46
46
|
"""
|
flwr/server/strategy/fedadam.py
CHANGED
@@ -12,8 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""Adaptive Federated Optimization using Adam (FedAdam) [Reddi et al., 2020]
|
16
|
-
strategy.
|
15
|
+
"""Adaptive Federated Optimization using Adam (FedAdam) [Reddi et al., 2020] strategy.
|
17
16
|
|
18
17
|
Paper: arxiv.org/abs/2003.00295
|
19
18
|
"""
|
@@ -39,8 +38,8 @@ from .fedopt import FedOpt
|
|
39
38
|
|
40
39
|
# flake8: noqa: E501
|
41
40
|
class FedAdam(FedOpt):
|
42
|
-
"""Adaptive Federated Optimization using Adam (FedAdam) [Reddi et al.,
|
43
|
-
|
41
|
+
"""Adaptive Federated Optimization using Adam (FedAdam) [Reddi et al., 2020]
|
42
|
+
strategy.
|
44
43
|
|
45
44
|
Paper: https://arxiv.org/abs/2003.00295
|
46
45
|
"""
|
flwr/server/strategy/fedavg.py
CHANGED
@@ -135,8 +135,7 @@ class FedAvg(Strategy):
|
|
135
135
|
return rep
|
136
136
|
|
137
137
|
def num_fit_clients(self, num_available_clients: int) -> Tuple[int, int]:
|
138
|
-
"""Return the sample size and the required number of available
|
139
|
-
clients."""
|
138
|
+
"""Return the sample size and the required number of available clients."""
|
140
139
|
num_clients = int(num_available_clients * self.fraction_fit)
|
141
140
|
return max(num_clients, self.min_fit_clients), self.min_available_clients
|
142
141
|
|
@@ -109,8 +109,7 @@ class FedAvgAndroid(Strategy):
|
|
109
109
|
return rep
|
110
110
|
|
111
111
|
def num_fit_clients(self, num_available_clients: int) -> Tuple[int, int]:
|
112
|
-
"""Return the sample size and the required number of available
|
113
|
-
clients."""
|
112
|
+
"""Return the sample size and the required number of available clients."""
|
114
113
|
num_clients = int(num_available_clients * self.fraction_fit)
|
115
114
|
return max(num_clients, self.min_fit_clients), self.min_available_clients
|
116
115
|
|
flwr/server/strategy/fedopt.py
CHANGED
@@ -12,8 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""Adaptive Federated Optimization (FedOpt) [Reddi et al., 2020] abstract
|
16
|
-
strategy.
|
15
|
+
"""Adaptive Federated Optimization (FedOpt) [Reddi et al., 2020] abstract strategy.
|
17
16
|
|
18
17
|
Paper: arxiv.org/abs/2003.00295
|
19
18
|
"""
|
@@ -12,8 +12,8 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""Federated XGBoost in the horizontal setting based on building Neural Network
|
16
|
-
|
15
|
+
"""Federated XGBoost in the horizontal setting based on building Neural Network and
|
16
|
+
averaging on prediction outcomes [Ma et al., 2023].
|
17
17
|
|
18
18
|
Paper: Coming
|
19
19
|
"""
|
flwr/server/strategy/fedyogi.py
CHANGED
@@ -12,8 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
|
-
"""Adaptive Federated Optimization using Yogi (FedYogi) [Reddi et al., 2020]
|
16
|
-
strategy.
|
15
|
+
"""Adaptive Federated Optimization using Yogi (FedYogi) [Reddi et al., 2020] strategy.
|
17
16
|
|
18
17
|
Paper: arxiv.org/abs/2003.00295
|
19
18
|
"""
|
@@ -39,8 +38,8 @@ from .fedopt import FedOpt
|
|
39
38
|
|
40
39
|
# flake8: noqa: E501
|
41
40
|
class FedYogi(FedOpt):
|
42
|
-
"""Adaptive Federated Optimization using Yogi (FedYogi) [Reddi et al.,
|
43
|
-
|
41
|
+
"""Adaptive Federated Optimization using Yogi (FedYogi) [Reddi et al., 2020]
|
42
|
+
strategy.
|
44
43
|
|
45
44
|
Paper: https://arxiv.org/abs/2003.00295
|
46
45
|
"""
|
flwr/server/strategy/qfedavg.py
CHANGED
@@ -96,8 +96,7 @@ class QFedAvg(FedAvg):
|
|
96
96
|
return rep
|
97
97
|
|
98
98
|
def num_fit_clients(self, num_available_clients: int) -> Tuple[int, int]:
|
99
|
-
"""Return the sample size and the required number of available
|
100
|
-
clients."""
|
99
|
+
"""Return the sample size and the required number of available clients."""
|
101
100
|
num_clients = int(num_available_clients * self.fraction_fit)
|
102
101
|
return max(num_clients, self.min_fit_clients), self.min_available_clients
|
103
102
|
|
flwr/server/utils/tensorboard.py
CHANGED
@@ -73,8 +73,7 @@ def tensorboard(logdir: str) -> Callable[[Strategy], Strategy]:
|
|
73
73
|
"""Return overloaded Strategy Wrapper."""
|
74
74
|
|
75
75
|
class TBWrapper(strategy_class): # type: ignore
|
76
|
-
"""Strategy wrapper
|
77
|
-
logging."""
|
76
|
+
"""Strategy wrapper that hooks into some methods for TensorBoard logging."""
|
78
77
|
|
79
78
|
def aggregate_evaluate(
|
80
79
|
self,
|
@@ -82,8 +81,7 @@ def tensorboard(logdir: str) -> Callable[[Strategy], Strategy]:
|
|
82
81
|
results: List[Tuple[ClientProxy, EvaluateRes]],
|
83
82
|
failures: List[Union[Tuple[ClientProxy, EvaluateRes], BaseException]],
|
84
83
|
) -> Tuple[Optional[float], Dict[str, Scalar]]:
|
85
|
-
"""Hooks into aggregate_evaluate for TensorBoard logging
|
86
|
-
purpose."""
|
84
|
+
"""Hooks into aggregate_evaluate for TensorBoard logging purpose."""
|
87
85
|
# Execute decorated function and extract results for logging
|
88
86
|
# They will be returned at the end of this function but also
|
89
87
|
# used for logging
|
flwr/server/utils/validator.py
CHANGED
@@ -23,7 +23,6 @@ from flwr.proto.task_pb2 import TaskIns, TaskRes
|
|
23
23
|
# pylint: disable-next=too-many-branches
|
24
24
|
def validate_task_ins_or_res(tasks_ins_res: Union[TaskIns, TaskRes]) -> List[str]:
|
25
25
|
"""Validate a TaskIns or TaskRes."""
|
26
|
-
|
27
26
|
validation_errors = []
|
28
27
|
|
29
28
|
if tasks_ins_res.task_id != "":
|
flwr/simulation/app.py
CHANGED
@@ -129,7 +129,6 @@ def start_simulation( # pylint: disable=too-many-arguments
|
|
129
129
|
hist : flwr.server.history.History
|
130
130
|
Object containing metrics from training.
|
131
131
|
"""
|
132
|
-
|
133
132
|
# pylint: disable-msg=too-many-locals
|
134
133
|
event(
|
135
134
|
EventType.START_SIMULATION_ENTER,
|
@@ -172,15 +171,15 @@ def start_simulation( # pylint: disable=too-many-arguments
|
|
172
171
|
}
|
173
172
|
|
174
173
|
# Shut down Ray if it has already been initialized (unless asked not to)
|
175
|
-
if ray.is_initialized() and not keep_initialised:
|
176
|
-
ray.shutdown()
|
174
|
+
if ray.is_initialized() and not keep_initialised: # type: ignore
|
175
|
+
ray.shutdown() # type: ignore
|
177
176
|
|
178
177
|
# Initialize Ray
|
179
|
-
ray.init(**ray_init_args)
|
178
|
+
ray.init(**ray_init_args) # type: ignore
|
180
179
|
log(
|
181
180
|
INFO,
|
182
181
|
"Flower VCE: Ray initialized with resources: %s",
|
183
|
-
ray.cluster_resources(),
|
182
|
+
ray.cluster_resources(), # type: ignore
|
184
183
|
)
|
185
184
|
|
186
185
|
# Register one RayClientProxy object for each client with the ClientManager
|