flwr-nightly 1.5.0.dev20230608__py3-none-any.whl → 1.5.0.dev20230615__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|