flwr-nightly 1.7.0.dev20240130__py3-none-any.whl → 1.7.0.dev20240201__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 CHANGED
@@ -18,7 +18,7 @@
18
18
  import argparse
19
19
  import sys
20
20
  import time
21
- from logging import INFO, WARN
21
+ from logging import DEBUG, INFO, WARN
22
22
  from pathlib import Path
23
23
  from typing import Callable, ContextManager, Optional, Tuple, Union
24
24
 
@@ -62,7 +62,12 @@ def run_client() -> None:
62
62
  "the '--root-certificates' option when running in insecure mode, "
63
63
  "or omit '--insecure' to use HTTPS."
64
64
  )
65
- log(WARN, "Option `--insecure` was set. Starting insecure HTTP client.")
65
+ log(
66
+ WARN,
67
+ "Option `--insecure` was set. "
68
+ "Starting insecure HTTP client connected to %s.",
69
+ args.server,
70
+ )
66
71
  root_certificates = None
67
72
  else:
68
73
  # Load the certificates if provided, or load the system certificates
@@ -71,11 +76,19 @@ def run_client() -> None:
71
76
  root_certificates = None
72
77
  else:
73
78
  root_certificates = Path(cert_path).read_bytes()
79
+ log(
80
+ DEBUG,
81
+ "Starting secure HTTPS client connected to %s "
82
+ "with the following certificates: %s.",
83
+ args.server,
84
+ cert_path,
85
+ )
74
86
 
75
- print(args.root_certificates)
76
- print(args.server)
77
- print(args.dir)
78
- print(args.callable)
87
+ log(
88
+ DEBUG,
89
+ "The Flower client uses `%s` to execute tasks",
90
+ args.callable,
91
+ )
79
92
 
80
93
  callable_dir = args.dir
81
94
  if callable_dir is not None:
@@ -88,7 +101,7 @@ def run_client() -> None:
88
101
  _start_client_internal(
89
102
  server_address=args.server,
90
103
  load_flower_callable_fn=_load,
91
- transport="grpc-rere", # Only
104
+ transport="rest" if args.rest else "grpc-rere",
92
105
  root_certificates=root_certificates,
93
106
  insecure=args.insecure,
94
107
  )
@@ -111,6 +124,11 @@ def _parse_args_client() -> argparse.ArgumentParser:
111
124
  help="Run the client without HTTPS. By default, the client runs with "
112
125
  "HTTPS enabled. Use this flag only if you understand the risks.",
113
126
  )
127
+ parser.add_argument(
128
+ "--rest",
129
+ action="store_true",
130
+ help="Use REST as a transport layer for the client.",
131
+ )
114
132
  parser.add_argument(
115
133
  "--root-certificates",
116
134
  metavar="ROOT_CERT",
@@ -22,13 +22,20 @@ import numpy as np
22
22
 
23
23
  from flwr.client.numpy_client import NumPyClient
24
24
  from flwr.common.dp import add_gaussian_noise, clip_by_l2
25
+ from flwr.common.logger import warn_deprecated_feature
25
26
  from flwr.common.typing import Config, NDArrays, Scalar
26
27
 
27
28
 
28
29
  class DPFedAvgNumPyClient(NumPyClient):
29
- """Wrapper for configuring a Flower client for DP."""
30
+ """Wrapper for configuring a Flower client for DP.
31
+
32
+ Warning
33
+ -------
34
+ This class is deprecated and will be removed in a future release.
35
+ """
30
36
 
31
37
  def __init__(self, client: NumPyClient) -> None:
38
+ warn_deprecated_feature("`DPFedAvgNumPyClient` wrapper")
32
39
  super().__init__()
33
40
  self.client = client
34
41
 
@@ -15,8 +15,10 @@
15
15
  """Middleware layers."""
16
16
 
17
17
 
18
+ from .secure_aggregation.secaggplus_middleware import secaggplus_middleware
18
19
  from .utils import make_ffn
19
20
 
20
21
  __all__ = [
21
22
  "make_ffn",
23
+ "secaggplus_middleware",
22
24
  ]
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -13,12 +13,8 @@
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
15
  """Secure Aggregation handlers."""
16
-
17
-
18
- from .handler import SecureAggregationHandler
19
- from .secaggplus_handler import SecAggPlusHandler
16
+ from .secaggplus_middleware import secaggplus_middleware
20
17
 
21
18
  __all__ = [
22
- "SecAggPlusHandler",
23
- "SecureAggregationHandler",
19
+ "secaggplus_middleware",
24
20
  ]
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -17,18 +17,18 @@
17
17
 
18
18
  import os
19
19
  from dataclasses import dataclass, field
20
- from logging import ERROR, INFO, WARNING
21
- from typing import Any, Dict, List, Optional, Tuple, Union, cast
22
-
23
- from flwr.client.client import Client
24
- from flwr.client.numpy_client import NumPyClient
25
- from flwr.common import (
26
- bytes_to_ndarray,
27
- ndarray_to_bytes,
28
- ndarrays_to_parameters,
29
- parameters_to_ndarrays,
30
- )
20
+ from logging import INFO, WARNING
21
+ from typing import Any, Callable, Dict, List, Tuple, cast
22
+
23
+ from flwr.client.typing import FlowerCallable
24
+ from flwr.common import ndarray_to_bytes, parameters_to_ndarrays
25
+ from flwr.common import recordset_compat as compat
26
+ from flwr.common.configsrecord import ConfigsRecord
27
+ from flwr.common.constant import TASK_TYPE_FIT
28
+ from flwr.common.context import Context
31
29
  from flwr.common.logger import log
30
+ from flwr.common.message import Message, Metadata
31
+ from flwr.common.recordset import RecordSet
32
32
  from flwr.common.secure_aggregation.crypto.shamir import create_shares
33
33
  from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
34
34
  bytes_to_private_key,
@@ -56,7 +56,6 @@ from flwr.common.secure_aggregation.secaggplus_constants import (
56
56
  KEY_DESTINATION_LIST,
57
57
  KEY_MASKED_PARAMETERS,
58
58
  KEY_MOD_RANGE,
59
- KEY_PARAMETERS,
60
59
  KEY_PUBLIC_KEY_1,
61
60
  KEY_PUBLIC_KEY_2,
62
61
  KEY_SAMPLE_NUMBER,
@@ -68,6 +67,8 @@ from flwr.common.secure_aggregation.secaggplus_constants import (
68
67
  KEY_STAGE,
69
68
  KEY_TARGET_RANGE,
70
69
  KEY_THRESHOLD,
70
+ RECORD_KEY_CONFIGS,
71
+ RECORD_KEY_STATE,
71
72
  STAGE_COLLECT_MASKED_INPUT,
72
73
  STAGE_SETUP,
73
74
  STAGE_SHARE_KEYS,
@@ -79,9 +80,7 @@ from flwr.common.secure_aggregation.secaggplus_utils import (
79
80
  share_keys_plaintext_concat,
80
81
  share_keys_plaintext_separate,
81
82
  )
82
- from flwr.common.typing import FitIns, Value
83
-
84
- from .handler import SecureAggregationHandler
83
+ from flwr.common.typing import ConfigsRecordValues, FitRes
85
84
 
86
85
 
87
86
  @dataclass
@@ -89,6 +88,8 @@ from .handler import SecureAggregationHandler
89
88
  class SecAggPlusState:
90
89
  """State of the SecAgg+ protocol."""
91
90
 
91
+ current_stage: str = STAGE_UNMASK
92
+
92
93
  sid: int = 0
93
94
  sample_num: int = 0
94
95
  share_num: int = 0
@@ -112,70 +113,115 @@ class SecAggPlusState:
112
113
  ss2_dict: Dict[int, bytes] = field(default_factory=dict)
113
114
  public_keys_dict: Dict[int, Tuple[bytes, bytes]] = field(default_factory=dict)
114
115
 
115
- client: Optional[Union[Client, NumPyClient]] = None
116
-
117
-
118
- class SecAggPlusHandler(SecureAggregationHandler):
119
- """Message handler for the SecAgg+ protocol."""
120
-
121
- _shared_state = SecAggPlusState()
122
- _current_stage = STAGE_UNMASK
123
-
124
- def handle_secure_aggregation(
125
- self, named_values: Dict[str, Value]
126
- ) -> Dict[str, Value]:
127
- """Handle incoming message and return results, following the SecAgg+ protocol.
128
-
129
- Parameters
130
- ----------
131
- named_values : Dict[str, Value]
132
- The named values retrieved from the SecureAggregation sub-message
133
- of Task message in the server's TaskIns.
116
+ def __init__(self, **kwargs: ConfigsRecordValues) -> None:
117
+ for k, v in kwargs.items():
118
+ if k.endswith(":V"):
119
+ continue
120
+ new_v: Any = v
121
+ if k.endswith(":K"):
122
+ k = k[:-2]
123
+ keys = cast(List[int], v)
124
+ values = cast(List[bytes], kwargs[f"{k}:V"])
125
+ if len(values) > len(keys):
126
+ updated_values = [
127
+ tuple(values[i : i + 2]) for i in range(0, len(values), 2)
128
+ ]
129
+ new_v = dict(zip(keys, updated_values))
130
+ else:
131
+ new_v = dict(zip(keys, values))
132
+ self.__setattr__(k, new_v)
133
+
134
+ def to_dict(self) -> Dict[str, ConfigsRecordValues]:
135
+ """Convert the state to a dictionary."""
136
+ ret = vars(self)
137
+ for k in list(ret.keys()):
138
+ if isinstance(ret[k], dict):
139
+ # Replace dict with two lists
140
+ v = cast(Dict[str, Any], ret.pop(k))
141
+ ret[f"{k}:K"] = list(v.keys())
142
+ if k == "public_keys_dict":
143
+ v_list: List[bytes] = []
144
+ for b1_b2 in cast(List[Tuple[bytes, bytes]], v.values()):
145
+ v_list.extend(b1_b2)
146
+ ret[f"{k}:V"] = v_list
147
+ else:
148
+ ret[f"{k}:V"] = list(v.values())
149
+ return ret
150
+
151
+
152
+ def _get_fit_fn(
153
+ msg: Message, ctxt: Context, call_next: FlowerCallable
154
+ ) -> Callable[[], FitRes]:
155
+ """Get the fit function."""
156
+
157
+ def fit() -> FitRes:
158
+ out_msg = call_next(msg, ctxt)
159
+ return compat.recordset_to_fitres(out_msg.message, keep_input=False)
160
+
161
+ return fit
162
+
163
+
164
+ def secaggplus_middleware(
165
+ msg: Message,
166
+ ctxt: Context,
167
+ call_next: FlowerCallable,
168
+ ) -> Message:
169
+ """Handle incoming message and return results, following the SecAgg+ protocol."""
170
+ # Ignore non-fit messages
171
+ if msg.metadata.task_type != TASK_TYPE_FIT:
172
+ return call_next(msg, ctxt)
173
+
174
+ # Retrieve local state
175
+ if RECORD_KEY_STATE not in ctxt.state.configs:
176
+ ctxt.state.set_configs(RECORD_KEY_STATE, ConfigsRecord({}))
177
+ state_dict = ctxt.state.get_configs(RECORD_KEY_STATE).data
178
+ state = SecAggPlusState(**state_dict)
179
+
180
+ # Retrieve incoming configs
181
+ configs = msg.message.get_configs(RECORD_KEY_CONFIGS).data
134
182
 
135
- Returns
136
- -------
137
- Dict[str, Value]
138
- The final/intermediate results of the SecAgg+ protocol.
139
- """
140
- # Check if self is a client
141
- if not isinstance(self, (Client, NumPyClient)):
142
- raise TypeError(
143
- "The subclass of SecAggPlusHandler must be "
144
- "the subclass of Client or NumPyClient."
145
- )
146
-
147
- # Check the validity of the next stage
148
- check_stage(self._current_stage, named_values)
149
-
150
- # Update the current stage
151
- self._current_stage = cast(str, named_values.pop(KEY_STAGE))
183
+ # Check the validity of the next stage
184
+ check_stage(state.current_stage, configs)
185
+
186
+ # Update the current stage
187
+ state.current_stage = cast(str, configs.pop(KEY_STAGE))
188
+
189
+ # Check the validity of the configs based on the current stage
190
+ check_configs(state.current_stage, configs)
191
+
192
+ # Execute
193
+ if state.current_stage == STAGE_SETUP:
194
+ res = _setup(state, configs)
195
+ elif state.current_stage == STAGE_SHARE_KEYS:
196
+ res = _share_keys(state, configs)
197
+ elif state.current_stage == STAGE_COLLECT_MASKED_INPUT:
198
+ fit = _get_fit_fn(msg, ctxt, call_next)
199
+ res = _collect_masked_input(state, configs, fit)
200
+ elif state.current_stage == STAGE_UNMASK:
201
+ res = _unmask(state, configs)
202
+ else:
203
+ raise ValueError(f"Unknown secagg stage: {state.current_stage}")
152
204
 
153
- # Check the validity of the `named_values` based on the current stage
154
- check_named_values(self._current_stage, named_values)
205
+ # Save state
206
+ ctxt.state.set_configs(RECORD_KEY_STATE, ConfigsRecord(state.to_dict()))
155
207
 
156
- # Execute
157
- if self._current_stage == STAGE_SETUP:
158
- self._shared_state = SecAggPlusState(client=self)
159
- return _setup(self._shared_state, named_values)
160
- if self._current_stage == STAGE_SHARE_KEYS:
161
- return _share_keys(self._shared_state, named_values)
162
- if self._current_stage == STAGE_COLLECT_MASKED_INPUT:
163
- return _collect_masked_input(self._shared_state, named_values)
164
- if self._current_stage == STAGE_UNMASK:
165
- return _unmask(self._shared_state, named_values)
166
- raise ValueError(f"Unknown secagg stage: {self._current_stage}")
208
+ # Return message
209
+ return Message(
210
+ metadata=Metadata(0, "", "", "", TASK_TYPE_FIT),
211
+ message=RecordSet(configs={RECORD_KEY_CONFIGS: ConfigsRecord(res, False)}),
212
+ )
167
213
 
168
214
 
169
- def check_stage(current_stage: str, named_values: Dict[str, Value]) -> None:
215
+ def check_stage(current_stage: str, configs: Dict[str, ConfigsRecordValues]) -> None:
170
216
  """Check the validity of the next stage."""
171
217
  # Check the existence of KEY_STAGE
172
- if KEY_STAGE not in named_values:
218
+ if KEY_STAGE not in configs:
173
219
  raise KeyError(
174
220
  f"The required key '{KEY_STAGE}' is missing from the input `named_values`."
175
221
  )
176
222
 
177
223
  # Check the value type of the KEY_STAGE
178
- next_stage = named_values[KEY_STAGE]
224
+ next_stage = configs[KEY_STAGE]
179
225
  if not isinstance(next_stage, str):
180
226
  raise TypeError(
181
227
  f"The value for the key '{KEY_STAGE}' must be of type {str}, "
@@ -198,8 +244,8 @@ def check_stage(current_stage: str, named_values: Dict[str, Value]) -> None:
198
244
 
199
245
 
200
246
  # pylint: disable-next=too-many-branches
201
- def check_named_values(stage: str, named_values: Dict[str, Value]) -> None:
202
- """Check the validity of the input `named_values`."""
247
+ def check_configs(stage: str, configs: Dict[str, ConfigsRecordValues]) -> None:
248
+ """Check the validity of the configs."""
203
249
  # Check `named_values` for the setup stage
204
250
  if stage == STAGE_SETUP:
205
251
  key_type_pairs = [
@@ -212,7 +258,7 @@ def check_named_values(stage: str, named_values: Dict[str, Value]) -> None:
212
258
  (KEY_MOD_RANGE, int),
213
259
  ]
214
260
  for key, expected_type in key_type_pairs:
215
- if key not in named_values:
261
+ if key not in configs:
216
262
  raise KeyError(
217
263
  f"Stage {STAGE_SETUP}: the required key '{key}' is "
218
264
  "missing from the input `named_values`."
@@ -220,14 +266,14 @@ def check_named_values(stage: str, named_values: Dict[str, Value]) -> None:
220
266
  # Bool is a subclass of int in Python,
221
267
  # so `isinstance(v, int)` will return True even if v is a boolean.
222
268
  # pylint: disable-next=unidiomatic-typecheck
223
- if type(named_values[key]) is not expected_type:
269
+ if type(configs[key]) is not expected_type:
224
270
  raise TypeError(
225
271
  f"Stage {STAGE_SETUP}: The value for the key '{key}' "
226
272
  f"must be of type {expected_type}, "
227
- f"but got {type(named_values[key])} instead."
273
+ f"but got {type(configs[key])} instead."
228
274
  )
229
275
  elif stage == STAGE_SHARE_KEYS:
230
- for key, value in named_values.items():
276
+ for key, value in configs.items():
231
277
  if (
232
278
  not isinstance(value, list)
233
279
  or len(value) != 2
@@ -242,18 +288,17 @@ def check_named_values(stage: str, named_values: Dict[str, Value]) -> None:
242
288
  key_type_pairs = [
243
289
  (KEY_CIPHERTEXT_LIST, bytes),
244
290
  (KEY_SOURCE_LIST, int),
245
- (KEY_PARAMETERS, bytes),
246
291
  ]
247
292
  for key, expected_type in key_type_pairs:
248
- if key not in named_values:
293
+ if key not in configs:
249
294
  raise KeyError(
250
295
  f"Stage {STAGE_COLLECT_MASKED_INPUT}: "
251
296
  f"the required key '{key}' is "
252
297
  "missing from the input `named_values`."
253
298
  )
254
- if not isinstance(named_values[key], list) or any(
299
+ if not isinstance(configs[key], list) or any(
255
300
  elm
256
- for elm in cast(List[Any], named_values[key])
301
+ for elm in cast(List[Any], configs[key])
257
302
  # pylint: disable-next=unidiomatic-typecheck
258
303
  if type(elm) is not expected_type
259
304
  ):
@@ -268,15 +313,15 @@ def check_named_values(stage: str, named_values: Dict[str, Value]) -> None:
268
313
  (KEY_DEAD_SECURE_ID_LIST, int),
269
314
  ]
270
315
  for key, expected_type in key_type_pairs:
271
- if key not in named_values:
316
+ if key not in configs:
272
317
  raise KeyError(
273
318
  f"Stage {STAGE_UNMASK}: "
274
319
  f"the required key '{key}' is "
275
320
  "missing from the input `named_values`."
276
321
  )
277
- if not isinstance(named_values[key], list) or any(
322
+ if not isinstance(configs[key], list) or any(
278
323
  elm
279
- for elm in cast(List[Any], named_values[key])
324
+ for elm in cast(List[Any], configs[key])
280
325
  # pylint: disable-next=unidiomatic-typecheck
281
326
  if type(elm) is not expected_type
282
327
  ):
@@ -289,9 +334,11 @@ def check_named_values(stage: str, named_values: Dict[str, Value]) -> None:
289
334
  raise ValueError(f"Unknown secagg stage: {stage}")
290
335
 
291
336
 
292
- def _setup(state: SecAggPlusState, named_values: Dict[str, Value]) -> Dict[str, Value]:
337
+ def _setup(
338
+ state: SecAggPlusState, configs: Dict[str, ConfigsRecordValues]
339
+ ) -> Dict[str, ConfigsRecordValues]:
293
340
  # Assigning parameter values to object fields
294
- sec_agg_param_dict = named_values
341
+ sec_agg_param_dict = configs
295
342
  state.sample_num = cast(int, sec_agg_param_dict[KEY_SAMPLE_NUMBER])
296
343
  state.sid = cast(int, sec_agg_param_dict[KEY_SECURE_ID])
297
344
  log(INFO, "Client %d: starting stage 0...", state.sid)
@@ -324,9 +371,9 @@ def _setup(state: SecAggPlusState, named_values: Dict[str, Value]) -> Dict[str,
324
371
 
325
372
  # pylint: disable-next=too-many-locals
326
373
  def _share_keys(
327
- state: SecAggPlusState, named_values: Dict[str, Value]
328
- ) -> Dict[str, Value]:
329
- named_bytes_tuples = cast(Dict[str, Tuple[bytes, bytes]], named_values)
374
+ state: SecAggPlusState, configs: Dict[str, ConfigsRecordValues]
375
+ ) -> Dict[str, ConfigsRecordValues]:
376
+ named_bytes_tuples = cast(Dict[str, Tuple[bytes, bytes]], configs)
330
377
  key_dict = {int(sid): (pk1, pk2) for sid, (pk1, pk2) in named_bytes_tuples.items()}
331
378
  log(INFO, "Client %d: starting stage 1...", state.sid)
332
379
  state.public_keys_dict = key_dict
@@ -386,12 +433,14 @@ def _share_keys(
386
433
 
387
434
  # pylint: disable-next=too-many-locals
388
435
  def _collect_masked_input(
389
- state: SecAggPlusState, named_values: Dict[str, Value]
390
- ) -> Dict[str, Value]:
436
+ state: SecAggPlusState,
437
+ configs: Dict[str, ConfigsRecordValues],
438
+ fit: Callable[[], FitRes],
439
+ ) -> Dict[str, ConfigsRecordValues]:
391
440
  log(INFO, "Client %d: starting stage 2...", state.sid)
392
441
  available_clients: List[int] = []
393
- ciphertexts = cast(List[bytes], named_values[KEY_CIPHERTEXT_LIST])
394
- srcs = cast(List[int], named_values[KEY_SOURCE_LIST])
442
+ ciphertexts = cast(List[bytes], configs[KEY_CIPHERTEXT_LIST])
443
+ srcs = cast(List[int], configs[KEY_SOURCE_LIST])
395
444
  if len(ciphertexts) + 1 < state.threshold:
396
445
  raise ValueError("Not enough available neighbour clients.")
397
446
 
@@ -417,18 +466,9 @@ def _collect_masked_input(
417
466
  state.sk1_share_dict[src] = sk1_share
418
467
 
419
468
  # Fit client
420
- parameters_bytes = cast(List[bytes], named_values[KEY_PARAMETERS])
421
- parameters = [bytes_to_ndarray(w) for w in parameters_bytes]
422
- if isinstance(state.client, Client):
423
- fit_res = state.client.fit(
424
- FitIns(parameters=ndarrays_to_parameters(parameters), config={})
425
- )
426
- parameters_factor = fit_res.num_examples
427
- parameters = parameters_to_ndarrays(fit_res.parameters)
428
- elif isinstance(state.client, NumPyClient):
429
- parameters, parameters_factor, _ = state.client.fit(parameters, {})
430
- else:
431
- log(ERROR, "Client %d: fit function is missing.", state.sid)
469
+ fit_res = fit()
470
+ parameters_factor = fit_res.num_examples
471
+ parameters = parameters_to_ndarrays(fit_res.parameters)
432
472
 
433
473
  # Quantize parameter update (vector)
434
474
  quantized_parameters = quantize(
@@ -468,11 +508,13 @@ def _collect_masked_input(
468
508
  }
469
509
 
470
510
 
471
- def _unmask(state: SecAggPlusState, named_values: Dict[str, Value]) -> Dict[str, Value]:
511
+ def _unmask(
512
+ state: SecAggPlusState, configs: Dict[str, ConfigsRecordValues]
513
+ ) -> Dict[str, ConfigsRecordValues]:
472
514
  log(INFO, "Client %d: starting stage 3...", state.sid)
473
515
 
474
- active_sids = cast(List[int], named_values[KEY_ACTIVE_SECURE_ID_LIST])
475
- dead_sids = cast(List[int], named_values[KEY_DEAD_SECURE_ID_LIST])
516
+ active_sids = cast(List[int], configs[KEY_ACTIVE_SECURE_ID_LIST])
517
+ dead_sids = cast(List[int], configs[KEY_DEAD_SECURE_ID_LIST])
476
518
  # Send private mask seed share for every avaliable client (including itclient)
477
519
  # Send first private key share for building pairwise mask for every dropped client
478
520
  if len(active_sids) < state.threshold:
flwr/common/dp.py CHANGED
@@ -19,11 +19,13 @@ from typing import Tuple
19
19
 
20
20
  import numpy as np
21
21
 
22
+ from flwr.common.logger import warn_deprecated_feature
22
23
  from flwr.common.typing import NDArrays
23
24
 
24
25
 
25
26
  # Calculates the L2-norm of a potentially ragged array
26
27
  def _get_update_norm(update: NDArrays) -> float:
28
+ warn_deprecated_feature("`_get_update_norm` method")
27
29
  flattened_update = update[0]
28
30
  for i in range(1, len(update)):
29
31
  flattened_update = np.append(flattened_update, update[i])
@@ -32,6 +34,7 @@ def _get_update_norm(update: NDArrays) -> float:
32
34
 
33
35
  def add_gaussian_noise(update: NDArrays, std_dev: float) -> NDArrays:
34
36
  """Add iid Gaussian noise to each floating point value in the update."""
37
+ warn_deprecated_feature("`add_gaussian_noise` method")
35
38
  update_noised = [
36
39
  layer + np.random.normal(0, std_dev, layer.shape) for layer in update
37
40
  ]
@@ -40,6 +43,7 @@ def add_gaussian_noise(update: NDArrays, std_dev: float) -> NDArrays:
40
43
 
41
44
  def clip_by_l2(update: NDArrays, threshold: float) -> Tuple[NDArrays, bool]:
42
45
  """Scales the update so thats its L2 norm is upper-bound to threshold."""
46
+ warn_deprecated_feature("`clip_by_l2` method")
43
47
  update_norm = _get_update_norm(update)
44
48
  scaling_factor = min(1, threshold / update_norm)
45
49
  update_clipped: NDArrays = [layer * scaling_factor for layer in update]
@@ -14,6 +14,8 @@
14
14
  # ==============================================================================
15
15
  """Constants for the SecAgg/SecAgg+ protocol."""
16
16
 
17
+ RECORD_KEY_STATE = "secaggplus_state"
18
+ RECORD_KEY_CONFIGS = "secaggplus_configs"
17
19
 
18
20
  # Names of stages
19
21
  STAGE_SETUP = "setup"
flwr/driver/app.py CHANGED
@@ -110,7 +110,9 @@ def start_driver( # pylint: disable=too-many-arguments, too-many-locals
110
110
  # Create the Driver
111
111
  if isinstance(root_certificates, str):
112
112
  root_certificates = Path(root_certificates).read_bytes()
113
- driver = GrpcDriver(driver_service_address=address, certificates=root_certificates)
113
+ driver = GrpcDriver(
114
+ driver_service_address=address, root_certificates=root_certificates
115
+ )
114
116
  driver.connect()
115
117
  lock = threading.Lock()
116
118
 
flwr/driver/driver.py CHANGED
@@ -49,10 +49,10 @@ class Driver:
49
49
  def __init__(
50
50
  self,
51
51
  driver_service_address: str = DEFAULT_SERVER_ADDRESS_DRIVER,
52
- certificates: Optional[bytes] = None,
52
+ root_certificates: Optional[bytes] = None,
53
53
  ) -> None:
54
54
  self.addr = driver_service_address
55
- self.certificates = certificates
55
+ self.root_certificates = root_certificates
56
56
  self.grpc_driver: Optional[GrpcDriver] = None
57
57
  self.run_id: Optional[int] = None
58
58
  self.node = Node(node_id=0, anonymous=True)
@@ -62,7 +62,8 @@ class Driver:
62
62
  if self.grpc_driver is None or self.run_id is None:
63
63
  # Connect and create run
64
64
  self.grpc_driver = GrpcDriver(
65
- driver_service_address=self.addr, certificates=self.certificates
65
+ driver_service_address=self.addr,
66
+ root_certificates=self.root_certificates,
66
67
  )
67
68
  self.grpc_driver.connect()
68
69
  res = self.grpc_driver.create_run(CreateRunRequest())
@@ -51,10 +51,10 @@ class GrpcDriver:
51
51
  def __init__(
52
52
  self,
53
53
  driver_service_address: str = DEFAULT_SERVER_ADDRESS_DRIVER,
54
- certificates: Optional[bytes] = None,
54
+ root_certificates: Optional[bytes] = None,
55
55
  ) -> None:
56
56
  self.driver_service_address = driver_service_address
57
- self.certificates = certificates
57
+ self.root_certificates = root_certificates
58
58
  self.channel: Optional[grpc.Channel] = None
59
59
  self.stub: Optional[DriverStub] = None
60
60
 
@@ -66,8 +66,8 @@ class GrpcDriver:
66
66
  return
67
67
  self.channel = create_channel(
68
68
  server_address=self.driver_service_address,
69
- insecure=(self.certificates is None),
70
- root_certificates=self.certificates,
69
+ insecure=(self.root_certificates is None),
70
+ root_certificates=self.root_certificates,
71
71
  )
72
72
  self.stub = DriverStub(self.channel)
73
73
  log(INFO, "[Driver] Connected to %s", self.driver_service_address)
flwr/server/app.py CHANGED
@@ -532,7 +532,7 @@ def _run_fleet_api_grpc_rere(
532
532
  """Run Fleet API (gRPC, request-response)."""
533
533
  # Create Fleet API gRPC server
534
534
  fleet_servicer = FleetServicer(
535
- state=state_factory.state(),
535
+ state_factory=state_factory,
536
536
  )
537
537
  fleet_add_servicer_to_server_fn = add_FleetServicer_to_server
538
538
  fleet_grpc_server = generic_create_grpc_server(
@@ -18,7 +18,7 @@ Relevant knowledge for reading this modules code:
18
18
  - https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
19
19
  """
20
20
 
21
-
21
+ import uuid
22
22
  from typing import Callable, Iterator
23
23
 
24
24
  import grpc
@@ -91,9 +91,12 @@ class FlowerServiceServicer(transport_pb2_grpc.FlowerServiceServicer):
91
91
  wrapping the actual message
92
92
  - The `Join` method is (pretty much) unaware of the protocol
93
93
  """
94
- peer: str = context.peer()
94
+ # When running Flower behind a proxy, the peer can be the same for
95
+ # different clients, so instead of `cid: str = context.peer()` we
96
+ # use a `UUID4` that is unique.
97
+ cid: str = uuid.uuid4().hex
95
98
  bridge = self.grpc_bridge_factory()
96
- client_proxy = self.client_proxy_factory(peer, bridge)
99
+ client_proxy = self.client_proxy_factory(cid, bridge)
97
100
  is_success = register_client_proxy(self.client_manager, client_proxy, context)
98
101
 
99
102
  if is_success:
@@ -32,14 +32,14 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
32
32
  PushTaskResResponse,
33
33
  )
34
34
  from flwr.server.fleet.message_handler import message_handler
35
- from flwr.server.state import State
35
+ from flwr.server.state import StateFactory
36
36
 
37
37
 
38
38
  class FleetServicer(fleet_pb2_grpc.FleetServicer):
39
39
  """Fleet API servicer."""
40
40
 
41
- def __init__(self, state: State) -> None:
42
- self.state = state
41
+ def __init__(self, state_factory: StateFactory) -> None:
42
+ self.state_factory = state_factory
43
43
 
44
44
  def CreateNode(
45
45
  self, request: CreateNodeRequest, context: grpc.ServicerContext
@@ -48,7 +48,7 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
48
48
  log(INFO, "FleetServicer.CreateNode")
49
49
  return message_handler.create_node(
50
50
  request=request,
51
- state=self.state,
51
+ state=self.state_factory.state(),
52
52
  )
53
53
 
54
54
  def DeleteNode(
@@ -58,7 +58,7 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
58
58
  log(INFO, "FleetServicer.DeleteNode")
59
59
  return message_handler.delete_node(
60
60
  request=request,
61
- state=self.state,
61
+ state=self.state_factory.state(),
62
62
  )
63
63
 
64
64
  def PullTaskIns(
@@ -68,7 +68,7 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
68
68
  log(INFO, "FleetServicer.PullTaskIns")
69
69
  return message_handler.pull_task_ins(
70
70
  request=request,
71
- state=self.state,
71
+ state=self.state_factory.state(),
72
72
  )
73
73
 
74
74
  def PushTaskRes(
@@ -78,5 +78,5 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
78
78
  log(INFO, "FleetServicer.PushTaskRes")
79
79
  return message_handler.push_task_res(
80
80
  request=request,
81
- state=self.state,
81
+ state=self.state_factory.state(),
82
82
  )
@@ -24,6 +24,7 @@ from typing import Dict, List, Optional, Tuple, Union
24
24
  import numpy as np
25
25
 
26
26
  from flwr.common import FitIns, FitRes, Parameters, Scalar
27
+ from flwr.common.logger import warn_deprecated_feature
27
28
  from flwr.server.client_manager import ClientManager
28
29
  from flwr.server.client_proxy import ClientProxy
29
30
  from flwr.server.strategy.dpfedavg_fixed import DPFedAvgFixed
@@ -31,7 +32,12 @@ from flwr.server.strategy.strategy import Strategy
31
32
 
32
33
 
33
34
  class DPFedAvgAdaptive(DPFedAvgFixed):
34
- """Wrapper for configuring a Strategy for DP with Adaptive Clipping."""
35
+ """Wrapper for configuring a Strategy for DP with Adaptive Clipping.
36
+
37
+ Warning
38
+ -------
39
+ This class is deprecated and will be removed in a future release.
40
+ """
35
41
 
36
42
  # pylint: disable=too-many-arguments,too-many-instance-attributes
37
43
  def __init__(
@@ -45,6 +51,7 @@ class DPFedAvgAdaptive(DPFedAvgFixed):
45
51
  clip_norm_target_quantile: float = 0.5,
46
52
  clip_count_stddev: Optional[float] = None,
47
53
  ) -> None:
54
+ warn_deprecated_feature("`DPFedAvgAdaptive` wrapper")
48
55
  super().__init__(
49
56
  strategy=strategy,
50
57
  num_sampled_clients=num_sampled_clients,
@@ -17,11 +17,11 @@
17
17
  Paper: arxiv.org/pdf/1710.06963.pdf
18
18
  """
19
19
 
20
-
21
20
  from typing import Dict, List, Optional, Tuple, Union
22
21
 
23
22
  from flwr.common import EvaluateIns, EvaluateRes, FitIns, FitRes, Parameters, Scalar
24
23
  from flwr.common.dp import add_gaussian_noise
24
+ from flwr.common.logger import warn_deprecated_feature
25
25
  from flwr.common.parameter import ndarrays_to_parameters, parameters_to_ndarrays
26
26
  from flwr.server.client_manager import ClientManager
27
27
  from flwr.server.client_proxy import ClientProxy
@@ -29,7 +29,12 @@ from flwr.server.strategy.strategy import Strategy
29
29
 
30
30
 
31
31
  class DPFedAvgFixed(Strategy):
32
- """Wrapper for configuring a Strategy for DP with Fixed Clipping."""
32
+ """Wrapper for configuring a Strategy for DP with Fixed Clipping.
33
+
34
+ Warning
35
+ -------
36
+ This class is deprecated and will be removed in a future release.
37
+ """
33
38
 
34
39
  # pylint: disable=too-many-arguments,too-many-instance-attributes
35
40
  def __init__(
@@ -40,6 +45,7 @@ class DPFedAvgFixed(Strategy):
40
45
  noise_multiplier: float = 1,
41
46
  server_side_noising: bool = True,
42
47
  ) -> None:
48
+ warn_deprecated_feature("`DPFedAvgFixed` wrapper")
43
49
  super().__init__()
44
50
  self.strategy = strategy
45
51
  # Doing fixed-size subsampling as in https://arxiv.org/abs/1905.03871.
@@ -44,6 +44,11 @@ class FedXgbBagging(FedAvg):
44
44
  self.global_model: Optional[bytes] = None
45
45
  super().__init__(**kwargs)
46
46
 
47
+ def __repr__(self) -> str:
48
+ """Compute a string representation of the strategy."""
49
+ rep = f"FedXgbBagging(accept_failures={self.accept_failures})"
50
+ return rep
51
+
47
52
  def aggregate_fit(
48
53
  self,
49
54
  server_round: int,
@@ -37,6 +37,11 @@ class FedXgbCyclic(FedAvg):
37
37
  self.global_model: Optional[bytes] = None
38
38
  super().__init__(**kwargs)
39
39
 
40
+ def __repr__(self) -> str:
41
+ """Compute a string representation of the strategy."""
42
+ rep = f"FedXgbCyclic(accept_failures={self.accept_failures})"
43
+ return rep
44
+
40
45
  def aggregate_fit(
41
46
  self,
42
47
  server_round: int,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.7.0.dev20240130
3
+ Version: 1.7.0.dev20240201
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.dev
6
6
  License: Apache-2.0
@@ -82,8 +82,7 @@ design of Flower is based on a few guiding principles:
82
82
 
83
83
  - **Framework-agnostic**: Different machine learning frameworks have different
84
84
  strengths. Flower can be used with any machine learning framework, for
85
- example, [PyTorch](https://pytorch.org),
86
- [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [fastai](https://www.fast.ai/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
85
+ example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
87
86
  for users who enjoy computing gradients by hand.
88
87
 
89
88
  - **Understandable**: Flower is written with maintainability in mind. The
@@ -129,7 +128,7 @@ Stay tuned, more tutorials are coming soon. Topics include **Privacy and Securit
129
128
  - [Quickstart (TensorFlow)](https://flower.dev/docs/framework/tutorial-quickstart-tensorflow.html)
130
129
  - [Quickstart (PyTorch)](https://flower.dev/docs/framework/tutorial-quickstart-pytorch.html)
131
130
  - [Quickstart (Hugging Face)](https://flower.dev/docs/framework/tutorial-quickstart-huggingface.html)
132
- - [Quickstart (PyTorch Lightning [code example])](https://flower.dev/docs/framework/tutorial-quickstart-pytorch-lightning.html)
131
+ - [Quickstart (PyTorch Lightning)](https://flower.dev/docs/framework/tutorial-quickstart-pytorch-lightning.html)
133
132
  - [Quickstart (Pandas)](https://flower.dev/docs/framework/tutorial-quickstart-pandas.html)
134
133
  - [Quickstart (fastai)](https://flower.dev/docs/framework/tutorial-quickstart-fastai.html)
135
134
  - [Quickstart (JAX)](https://flower.dev/docs/framework/tutorial-quickstart-jax.html)
@@ -148,11 +147,17 @@ Flower Baselines is a collection of community-contributed projects that reproduc
148
147
  - [FedMLB](https://github.com/adap/flower/tree/main/baselines/fedmlb)
149
148
  - [FedPer](https://github.com/adap/flower/tree/main/baselines/fedper)
150
149
  - [FedProx](https://github.com/adap/flower/tree/main/baselines/fedprox)
150
+ - [FedNova](https://github.com/adap/flower/tree/main/baselines/fednova)
151
+ - [HeteroFL](https://github.com/adap/flower/tree/main/baselines/heterofl)
152
+ - [FedAvgM](https://github.com/adap/flower/tree/main/baselines/fedavgm)
151
153
  - [FedWav2vec2](https://github.com/adap/flower/tree/main/baselines/fedwav2vec2)
152
154
  - [FjORD](https://github.com/adap/flower/tree/main/baselines/fjord)
153
155
  - [MOON](https://github.com/adap/flower/tree/main/baselines/moon)
154
156
  - [niid-Bench](https://github.com/adap/flower/tree/main/baselines/niid_bench)
155
157
  - [TAMUNA](https://github.com/adap/flower/tree/main/baselines/tamuna)
158
+ - [FedVSSL](https://github.com/adap/flower/tree/main/baselines/fedvssl)
159
+ - [FedXGBoost](https://github.com/adap/flower/tree/main/baselines/hfedxgboost)
160
+ - [FedPara](https://github.com/adap/flower/tree/main/baselines/fedpara)
156
161
  - [FedAvg](https://github.com/adap/flower/tree/main/baselines/flwr_baselines/flwr_baselines/publications/fedavg_mnist)
157
162
  - [FedOpt](https://github.com/adap/flower/tree/main/baselines/flwr_baselines/flwr_baselines/publications/adaptive_federated_optimization)
158
163
 
@@ -174,16 +179,23 @@ Quickstart examples:
174
179
  - [Quickstart (Pandas)](https://github.com/adap/flower/tree/main/examples/quickstart-pandas)
175
180
  - [Quickstart (JAX)](https://github.com/adap/flower/tree/main/examples/quickstart-jax)
176
181
  - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/sklearn-logreg-mnist)
182
+ - [Quickstart (XGBoost)](https://github.com/adap/flower/tree/main/examples/xgboost-quickstart)
177
183
  - [Quickstart (Android [TFLite])](https://github.com/adap/flower/tree/main/examples/android)
178
184
  - [Quickstart (iOS [CoreML])](https://github.com/adap/flower/tree/main/examples/ios)
185
+ - [Quickstart (MLX)](https://github.com/adap/flower/tree/main/examples/quickstart-mlx)
186
+ - [Quickstart (XGBoost)](https://github.com/adap/flower/tree/main/examples/xgboost-quickstart)
179
187
 
180
188
  Other [examples](https://github.com/adap/flower/tree/main/examples):
181
189
 
182
190
  - [Raspberry Pi & Nvidia Jetson Tutorial](https://github.com/adap/flower/tree/main/examples/embedded-devices)
183
191
  - [PyTorch: From Centralized to Federated](https://github.com/adap/flower/tree/main/examples/pytorch-from-centralized-to-federated)
192
+ - [Vertical FL](https://github.com/adap/flower/tree/main/examples/vertical-fl)
193
+ - [Federated Finetuning of OpenAI's Whisper](https://github.com/adap/flower/tree/main/examples/whisper-federated-finetuning)
194
+ - [Comprehensive XGBoost](https://github.com/adap/flower/tree/main/examples/xgboost-comprehensive)
184
195
  - [Advanced Flower with TensorFlow/Keras](https://github.com/adap/flower/tree/main/examples/advanced-tensorflow)
185
196
  - [Advanced Flower with PyTorch](https://github.com/adap/flower/tree/main/examples/advanced-pytorch)
186
- - Single-Machine Simulation of Federated Learning Systems ([PyTorch](https://github.com/adap/flower/tree/main/examples/simulation_pytorch)) ([Tensorflow](https://github.com/adap/flower/tree/main/examples/simulation_tensorflow))
197
+ - Single-Machine Simulation of Federated Learning Systems ([PyTorch](https://github.com/adap/flower/tree/main/examples/simulation-pytorch)) ([Tensorflow](https://github.com/adap/flower/tree/main/examples/simulation-tensorflow))
198
+ - [Comprehensive Flower+XGBoost](https://github.com/adap/flower/tree/main/examples/xgboost-comprehensive)
187
199
  - [Flower through Docker Compose and with Grafana dashboard](https://github.com/adap/flower/tree/main/examples/flower-via-docker-compose)
188
200
 
189
201
  ## Community
@@ -1,8 +1,8 @@
1
1
  flwr/__init__.py,sha256=6zbcS7z2q-VUdmpFppLH6BacsE-ZFmfq6OvtKNOyYE0,981
2
2
  flwr/client/__init__.py,sha256=2T4enmlE4PsoKiGTvXwBKSlhOjZ7MXRy5oCGNf0UH9Y,1111
3
- flwr/client/app.py,sha256=eBZocV3uFm1w0H6Vp6DmelojSzIHKlcXHVOZzHowE7c,19483
3
+ flwr/client/app.py,sha256=EMN_gRPn6Jn9sDUaDRHFHVR7p4a9a1VWq358-7ToZmg,19947
4
4
  flwr/client/client.py,sha256=ATcsqAMS9zpMBJ9ZUbBeB7BEPWX_VWISONy0p6Wxl5g,8210
5
- flwr/client/dpfedavg_numpy_client.py,sha256=0XryFdCMM_RLiNLCr6evLp-6R7ZjeMmRUROIgzRmtmc,7215
5
+ flwr/client/dpfedavg_numpy_client.py,sha256=9Tnig4iml2J88HBKNahegjXjbfvIQyBtaIQaqjbeqsA,7435
6
6
  flwr/client/flower.py,sha256=QKWBjB8YbzlKfC1EPVpxLfiYRL078C7BL5hPaX_rUMY,4211
7
7
  flwr/client/grpc_client/__init__.py,sha256=LsnbqXiJhgQcB0XzAlUQgPx011Uf7Y7yabIC1HxivJ8,735
8
8
  flwr/client/grpc_client/connection.py,sha256=x50raKKVKVNjNNOr2u1gOS2Ts6ohs2cAGrRXZw6sgLE,8226
@@ -11,16 +11,15 @@ flwr/client/grpc_rere_client/connection.py,sha256=Ey1xN0a69nv59MV8-BC8BpYwPqhufU
11
11
  flwr/client/message_handler/__init__.py,sha256=abHvBRJJiiaAMNgeILQbMOa6h8WqMK2BcnvxwQZFpic,719
12
12
  flwr/client/message_handler/message_handler.py,sha256=cknnjvgmNdBZOcPfJ4bBjcIK8ZDqXZMiXK69-toumNs,5900
13
13
  flwr/client/message_handler/task_handler.py,sha256=_mmUiMKlnO196Jqw9sEgTevkWQm7ra-Vf3JzQD-Cx_A,4128
14
- flwr/client/middleware/__init__.py,sha256=Eo3JvAV5XqmyRySNqeiw93YNETmmP5ixEOMeBA6ah4w,769
14
+ flwr/client/middleware/__init__.py,sha256=mYWAt8YUy2aiL-kK7LDASgMpbsYxfRoE4iptf1zene4,874
15
+ flwr/client/middleware/secure_aggregation/__init__.py,sha256=3GinEPdTOULN5D9BD2ujX0uEEUHytlKoCT81rErw6sw,819
16
+ flwr/client/middleware/secure_aggregation/secaggplus_middleware.py,sha256=A6fpS3uQEP_vMeRZ688GK7LJ13WlP1TQksyMapvHGHU,20111
15
17
  flwr/client/middleware/utils.py,sha256=8fWgKhDr_HV7ZawcgcPKqfwdDUpDfAtLItxtTi3oC5Q,1281
16
18
  flwr/client/node_state.py,sha256=0hk1RZuFZ3_S7Y8Q0BCP60NljxnT9vqPmIflvCCGxnQ,1819
17
19
  flwr/client/node_state_tests.py,sha256=H3sO526boAlDS491fO5xvZhl5XNDzzl-I8DiaVmnsXM,2195
18
20
  flwr/client/numpy_client.py,sha256=42e8_gZU5gwzpvVXQr6LEWEGfpWYTcQ0MY0F0owNlAc,10310
19
21
  flwr/client/rest_client/__init__.py,sha256=ThwOnkMdzxo_UuyTI47Q7y9oSpuTgNT2OuFvJCfuDiw,735
20
22
  flwr/client/rest_client/connection.py,sha256=NK3PFGJvOwh3bUNSp5nfkfLHa6T5kzQ0XN9ire9F4tk,11964
21
- flwr/client/secure_aggregation/__init__.py,sha256=XCDycteBTivym0zwkwqXhFMCAoDoHBZQg5GxdMnFCfA,888
22
- flwr/client/secure_aggregation/handler.py,sha256=oRyGCerz92aED7UydYwJ7OFVxUwHqedG3PshHrdZq-Y,1522
23
- flwr/client/secure_aggregation/secaggplus_handler.py,sha256=2jKtRhoJaVRmMJgJ2v8VRUCw2ko7uhTL2_h8CZVFwZA,18928
24
23
  flwr/client/typing.py,sha256=pk0eIYcLUXRic_rRxQxW7Vdp7b6cRjlRiagpMs7HicQ,1023
25
24
  flwr/common/__init__.py,sha256=qttep0POwoigzB5pcraZa4YMt9jsCSfeibcrTQMUjIc,2884
26
25
  flwr/common/address.py,sha256=iTAN9jtmIGMrWFnx9XZQl45ZEtQJVZZLYPRBSNVARGI,1882
@@ -28,7 +27,7 @@ flwr/common/configsrecord.py,sha256=i41syiXeG4CyWr4ujOCxTDBZKiClNnNgR4xbufxThh0,
28
27
  flwr/common/constant.py,sha256=tQxp9yXKXVajh6obsUlFs4UYIiTBxl4bGHnj9ds7NLQ,1263
29
28
  flwr/common/context.py,sha256=OP4mTxsCdU2LS63TegdLHaEDpxULZ4AQ4ybZl7jEdDU,1329
30
29
  flwr/common/date.py,sha256=UWhBZj49yX9LD4BmatS_ZFZu_-kweGh0KQJ1djyWWH4,891
31
- flwr/common/dp.py,sha256=hF45cPElXxcQsh4AoquAyaTrNi0xCrIcKx7xOcV_1XU,1782
30
+ flwr/common/dp.py,sha256=Hc3lLHihjexbJaD_ft31gdv9XRcwOTgDBwJzICuok3A,2004
32
31
  flwr/common/grpc.py,sha256=qVLB0d6bCuaBRW5YB0vEZXsR7Bo3R2lh4ONiCocqwRI,2270
33
32
  flwr/common/logger.py,sha256=qX_gqEyrmGOH0x_r8uQ1Vskz4fGvEij9asdo4DUOPY8,4135
34
33
  flwr/common/message.py,sha256=GQuhFmvJIrCG6h4L-jQMsn6KYh-nmNqNNo5qVe7ye5w,1847
@@ -44,17 +43,17 @@ flwr/common/secure_aggregation/crypto/shamir.py,sha256=yY35ZgHlB4YyGW_buG-1X-0M-
44
43
  flwr/common/secure_aggregation/crypto/symmetric_encryption.py,sha256=-zDyQoTsHHQjR7o-92FNIikg1zM_Ke9yynaD5u2BXbQ,3546
45
44
  flwr/common/secure_aggregation/ndarrays_arithmetic.py,sha256=KAHCEHGSTJ6mCgnC8dTpIx6URk11s5XxWTHI_7ToGIg,2979
46
45
  flwr/common/secure_aggregation/quantization.py,sha256=appui7GGrkRPsupF59TkapeV4Na_CyPi73JtJ1pimdI,2310
47
- flwr/common/secure_aggregation/secaggplus_constants.py,sha256=m5UDo7IgRkMS3yixhzz7DhhAv6VAQMCghglMygSPU_k,1606
46
+ flwr/common/secure_aggregation/secaggplus_constants.py,sha256=pITi-nuzrNvKWR42XwVFBuejv1RdGLwmuErLp0X0t_Y,1686
48
47
  flwr/common/secure_aggregation/secaggplus_utils.py,sha256=PleDyDu7jHNAfbRoEaoQiOjxG6iMl9yA8rNKYTfnyFw,3155
49
48
  flwr/common/serde.py,sha256=rXUSH9TNFsRDBTdr9bGCKGLyjNuzagUOQVynS_luWkI,19643
50
49
  flwr/common/telemetry.py,sha256=se_-pHgEWcmN09ChSpTeek72l1UJHf7GbwXBB1KXBjQ,7683
51
50
  flwr/common/typing.py,sha256=3Wu6Ol1Ja6Gb0WdlcXVEn1EHYJbc4oRRJA81vEegxBo,4382
52
51
  flwr/common/version.py,sha256=A0MKvyKPrV8wLg0YCAODTqM71v26NEH36c6JYtfgg0o,667
53
52
  flwr/driver/__init__.py,sha256=NQ4KeZ5fP9wdxGjcr2cP41_7TLuuYQ3u4J7GwYtQ488,870
54
- flwr/driver/app.py,sha256=rTBmbDt3kUN9-j3I-HwZE43Y1oSjVb3DR3R2ntt4f5c,7249
55
- flwr/driver/driver.py,sha256=S9KsRlpf7j3y6jGaAgu4TwM_AyHlZFhJV-HgfwJKxks,3967
53
+ flwr/driver/app.py,sha256=rhACazH0J06Tnqy5aU0DoJlx5ZksK4b0NgHkM1bAE38,7268
54
+ flwr/driver/driver.py,sha256=BhCXx55Lk9WdpcfjlHhKyLbGdiIvawIvMWYPewIaI8I,4009
56
55
  flwr/driver/driver_client_proxy.py,sha256=wKC3R-293dOqxNytzf78z6tuDCXORbuJAdICyZ5jeK8,6126
57
- flwr/driver/grpc_driver.py,sha256=KlJT_wWVm9xx2xapzC0Kgn1UDnBBem514aaTtzJSlkw,4560
56
+ flwr/driver/grpc_driver.py,sha256=Ekcxx4Miqume02fiBjBRJhItaOFNpn120WT3uRIPWIc,4585
58
57
  flwr/flower/__init__.py,sha256=aUO5V7ovBwDoXuS9Dqlpzq_m_VGRpYiRgR2jpokRPy8,786
59
58
  flwr/proto/__init__.py,sha256=hbY7JYakwZwCkYgCNlmHdc8rtvfoJbAZLalMdc--CGc,683
60
59
  flwr/proto/driver_pb2.py,sha256=JHIdjNPTgp6YHD-_lz5ZZFB0VIOR3_GmcaOTN4jndc4,3115
@@ -83,7 +82,7 @@ flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPc
83
82
  flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
84
83
  flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
84
  flwr/server/__init__.py,sha256=SG7XJWnskPZu30VfY5WmXbfYKeb8UFrths4qprAb0yg,1377
86
- flwr/server/app.py,sha256=KeRcABvbNnTXHdsz-WPMjNcgLRrdZR6MLNTX8bIK83Y,25619
85
+ flwr/server/app.py,sha256=WYAyWQZksetbzR8Gos_LSQOTzzhzapuRhjXdks6K9xM,25619
87
86
  flwr/server/client_manager.py,sha256=T8UDSRJBVD3fyIDI7NTAA-NA7GPrMNNgH2OAF54RRxE,6127
88
87
  flwr/server/client_proxy.py,sha256=8ScGDvP3jHbl8DV3hyFID5N5VEVlXn8ZTQXtkdOfssI,2234
89
88
  flwr/server/criterion.py,sha256=ypbAexbztzGUxNen9RCHF91QeqiEQix4t4Ih3E-42MM,1061
@@ -91,12 +90,12 @@ flwr/server/driver/__init__.py,sha256=STB1_DASVEg7Cu6L7VYxTzV7UMkgtBkFim09Z82Dh8
91
90
  flwr/server/driver/driver_servicer.py,sha256=8JwftxoMMqHPAEgvE2TDDvm4zW2-7xaHYoji5kb6k8k,4553
92
91
  flwr/server/fleet/__init__.py,sha256=C6GCSD5eP5Of6_dIeSe1jx9HnV0icsvWyQ5EKAUHJRU,711
93
92
  flwr/server/fleet/grpc_bidi/__init__.py,sha256=mgGJGjwT6VU7ovC1gdnnqttjyBPlNIcZnYRqx4K3IBQ,735
94
- flwr/server/fleet/grpc_bidi/flower_service_servicer.py,sha256=v1oDksCIphGoTCMbz68DjaTk7Pw89wjGTJUw4rezV1Q,5756
93
+ flwr/server/fleet/grpc_bidi/flower_service_servicer.py,sha256=DVYlKxOVHwdQVux9XKJTomWwoLLlhhPhvvluU50hO4E,5956
95
94
  flwr/server/fleet/grpc_bidi/grpc_bridge.py,sha256=LSOmabFXAQxKycQOliplKmigbmVwdm-D4CI-hJ0Pav0,6458
96
95
  flwr/server/fleet/grpc_bidi/grpc_client_proxy.py,sha256=MubuEEAZAcKzx9LYAB87B2sjvZWWyQS3RPAJJm1GS4I,4695
97
96
  flwr/server/fleet/grpc_bidi/grpc_server.py,sha256=TY_Z8ComreNNOOKveeUO6eE5hoSuTvx_EWqQl0zRADQ,11779
98
97
  flwr/server/fleet/grpc_rere/__init__.py,sha256=bEJOMWbSlqkw-y5ZHtEXczhoSlAxErcRYffmTMQAV8M,758
99
- flwr/server/fleet/grpc_rere/fleet_servicer.py,sha256=tG_t9_Fpbs-K1uT5B6GeLdrQCVcOXAdtqBGg_f7ZVVw,2603
98
+ flwr/server/fleet/grpc_rere/fleet_servicer.py,sha256=I6-mfOIKjxiGgHuL2AeiKqYnXDY_qBN1YXDJw1cttcA,2705
100
99
  flwr/server/fleet/message_handler/__init__.py,sha256=hEY0l61ojH8Iz30_K1btm1HJ6J49iZJSFUsVYqUTw3A,731
101
100
  flwr/server/fleet/message_handler/message_handler.py,sha256=_SauWQUO6VCMRRNXDfg3gv2h1FKG7e7p8F-Nj4aY6OM,2823
102
101
  flwr/server/fleet/rest_rere/__init__.py,sha256=VKDvDq5H8koOUztpmQacVzGJXPLEEkL1Vmolxt3mvnY,735
@@ -111,8 +110,8 @@ flwr/server/state/state_factory.py,sha256=91cSB-KOAFM37z7T098WxTkVeKNaAZ_mTI75sn
111
110
  flwr/server/strategy/__init__.py,sha256=EDTv_lU67VmZ8pRqy5fabQDhq5x4oRiD-KHoXhOIWMs,2096
112
111
  flwr/server/strategy/aggregate.py,sha256=QyRIJtI5gnuY1NbgrcrOvkHxGIxBvApq7d9Y4xl-6W4,13468
113
112
  flwr/server/strategy/bulyan.py,sha256=8GsSVJzRSoSWE2zQUKqC3Z795grdN9xpmc3MSGGXnzM,6532
114
- flwr/server/strategy/dpfedavg_adaptive.py,sha256=Wu0StMixNy-1fIJ3Bo2HcytoDQv5Xe5dCZcrsMTOBdg,4660
115
- flwr/server/strategy/dpfedavg_fixed.py,sha256=roWpIRhup30P1tEgijsJGBAPqtLIuJZ9etFeukwKpjU,7004
113
+ flwr/server/strategy/dpfedavg_adaptive.py,sha256=hLJkPQJl1bHjwrBNg3PSRFKf3no0hg5EHiFaWhHlWqw,4877
114
+ flwr/server/strategy/dpfedavg_fixed.py,sha256=mV_UimlGigUJjc2a9dmUig5EuVZ4yGIb9pkq31bKG1A,7217
116
115
  flwr/server/strategy/fault_tolerant_fedavg.py,sha256=veGcehB6rXT_MihNDrD1v5JY-TxJi7fybdDl-OZooDQ,5900
117
116
  flwr/server/strategy/fedadagrad.py,sha256=9yoVdZOFTjQ7DpaVrYLH9ca88WgJVWepld6UXybGQMY,6505
118
117
  flwr/server/strategy/fedadam.py,sha256=Zvqo6oChwB2aDGHeLXHNE74nHGwkFAWODLZ8f6Dtq1g,6763
@@ -123,8 +122,8 @@ flwr/server/strategy/fedmedian.py,sha256=HpmUkLLXWgmMgQiEK2cG1l5nOd99ykAWdUxV5uU
123
122
  flwr/server/strategy/fedopt.py,sha256=xqu-7513C8bFBw2qrzvduk9o2mT0sPHNVLKmVbJ3V4U,5242
124
123
  flwr/server/strategy/fedprox.py,sha256=BBmIDoRtDeb3TpigO1beBZ79wIVy2UsVDIDnxktoyas,6862
125
124
  flwr/server/strategy/fedtrimmedavg.py,sha256=p12uA7EN0k_CfYeh513P3m8mH3h14SmR3C_MQ9vw6Sc,5890
126
- flwr/server/strategy/fedxgb_bagging.py,sha256=BqtHfdRrLW5AhnBiN_aiECWcgIvgFEzku_76D98vMXg,5895
127
- flwr/server/strategy/fedxgb_cyclic.py,sha256=CjlFdy-0lxM4m1O6lYL2498lImPHhxiTkiOvPTXKj24,5423
125
+ flwr/server/strategy/fedxgb_bagging.py,sha256=Fm6bkulhPkes2k5lyG7oxgwtdJrXeNWDa-FCc_5AGVY,6080
126
+ flwr/server/strategy/fedxgb_cyclic.py,sha256=keiPOtd843-5uWWpRqJkEhvoNqTEB4zSIr51F6soosQ,5607
128
127
  flwr/server/strategy/fedxgb_nn_avg.py,sha256=tA6X43juce0ShfRgfeNxRIcpSUlgVNwGB8vYoUuNFhI,4047
129
128
  flwr/server/strategy/fedyogi.py,sha256=fG9i1WEdUXTYh5mTmagGLHqc12OogEsj3s3IopwM4ZA,6801
130
129
  flwr/server/strategy/krum.py,sha256=yaYAZw4KOL84nc_PZAp43rBl0pXC0dT6y46sEuZrirA,6285
@@ -139,8 +138,8 @@ flwr/simulation/ray_transport/__init__.py,sha256=FsaAnzC4cw4DqoouBCix6496k29jACk
139
138
  flwr/simulation/ray_transport/ray_actor.py,sha256=G_g50ISt3Knf0zuX1wmw39gsDXSoMI5f3rmYZWGrUh4,17062
140
139
  flwr/simulation/ray_transport/ray_client_proxy.py,sha256=UxQEzWmklp3WO2V7LH5vNyAgYL7KYFFZQa1HTUSgEqY,9429
141
140
  flwr/simulation/ray_transport/utils.py,sha256=5dwzUppfJP8lrpBU1rvhzfPZqAeGo8wx-hOm8wy_HmA,3376
142
- flwr_nightly-1.7.0.dev20240130.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
143
- flwr_nightly-1.7.0.dev20240130.dist-info/METADATA,sha256=clCdgXSkrZfi3u8GQhP0L2Hf3uuxexRQCfU5WPAWwAk,13584
144
- flwr_nightly-1.7.0.dev20240130.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
145
- flwr_nightly-1.7.0.dev20240130.dist-info/entry_points.txt,sha256=1uLlD5tIunkzALMfMWnqjdE_D5hRUX_I1iMmOMv6tZI,181
146
- flwr_nightly-1.7.0.dev20240130.dist-info/RECORD,,
141
+ flwr_nightly-1.7.0.dev20240201.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
142
+ flwr_nightly-1.7.0.dev20240201.dist-info/METADATA,sha256=9Dy5grkrz2m-B-DQV_fT1We-X7-wXAEhYB5dyEH181c,14811
143
+ flwr_nightly-1.7.0.dev20240201.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
144
+ flwr_nightly-1.7.0.dev20240201.dist-info/entry_points.txt,sha256=1uLlD5tIunkzALMfMWnqjdE_D5hRUX_I1iMmOMv6tZI,181
145
+ flwr_nightly-1.7.0.dev20240201.dist-info/RECORD,,
@@ -1,43 +0,0 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- # ==============================================================================
15
- """Message Handler for Secure Aggregation (abstract base class)."""
16
-
17
-
18
- from abc import ABC, abstractmethod
19
- from typing import Dict
20
-
21
- from flwr.common.typing import Value
22
-
23
-
24
- class SecureAggregationHandler(ABC):
25
- """Abstract base class for secure aggregation message handlers."""
26
-
27
- @abstractmethod
28
- def handle_secure_aggregation(
29
- self, named_values: Dict[str, Value]
30
- ) -> Dict[str, Value]:
31
- """Handle incoming Secure Aggregation message and return results.
32
-
33
- Parameters
34
- ----------
35
- named_values : Dict[str, Value]
36
- The named values retrieved from the SecureAggregation sub-message
37
- of Task message in the server's TaskIns.
38
-
39
- Returns
40
- -------
41
- Dict[str, Value]
42
- The final/intermediate results of the Secure Aggregation protocol.
43
- """