flwr-nightly 1.8.0.dev20240315__py3-none-any.whl → 1.11.0.dev20240813__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/app.py +7 -0
- flwr/cli/build.py +150 -0
- flwr/cli/config_utils.py +219 -0
- flwr/cli/example.py +3 -1
- flwr/cli/install.py +227 -0
- flwr/cli/new/new.py +179 -48
- flwr/cli/new/templates/app/.gitignore.tpl +160 -0
- flwr/cli/new/templates/app/README.flowertune.md.tpl +56 -0
- flwr/cli/new/templates/app/README.md.tpl +1 -5
- flwr/cli/new/templates/app/code/__init__.py.tpl +1 -1
- flwr/cli/new/templates/app/code/client.huggingface.py.tpl +65 -0
- flwr/cli/new/templates/app/code/client.jax.py.tpl +56 -0
- flwr/cli/new/templates/app/code/client.mlx.py.tpl +93 -0
- flwr/cli/new/templates/app/code/client.numpy.py.tpl +3 -2
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl +23 -11
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl +97 -0
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +60 -1
- flwr/cli/new/templates/app/code/flwr_tune/__init__.py +15 -0
- flwr/cli/new/templates/app/code/flwr_tune/app.py.tpl +89 -0
- flwr/cli/new/templates/app/code/flwr_tune/client.py.tpl +126 -0
- flwr/cli/new/templates/app/code/flwr_tune/config.yaml.tpl +34 -0
- flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +57 -0
- flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +59 -0
- flwr/cli/new/templates/app/code/flwr_tune/server.py.tpl +48 -0
- flwr/cli/new/templates/app/code/flwr_tune/static_config.yaml.tpl +11 -0
- flwr/cli/new/templates/app/code/server.huggingface.py.tpl +23 -0
- flwr/cli/new/templates/app/code/server.jax.py.tpl +20 -0
- flwr/cli/new/templates/app/code/server.mlx.py.tpl +20 -0
- flwr/cli/new/templates/app/code/server.numpy.py.tpl +17 -9
- flwr/cli/new/templates/app/code/server.pytorch.py.tpl +21 -18
- flwr/cli/new/templates/app/code/server.sklearn.py.tpl +24 -0
- flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +29 -1
- flwr/cli/new/templates/app/code/task.huggingface.py.tpl +99 -0
- flwr/cli/new/templates/app/code/task.jax.py.tpl +57 -0
- flwr/cli/new/templates/app/code/task.mlx.py.tpl +102 -0
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +28 -23
- flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +53 -0
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +39 -0
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +38 -0
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +34 -0
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +39 -0
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +25 -12
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +29 -14
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +33 -0
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +29 -14
- flwr/cli/run/run.py +168 -17
- flwr/cli/utils.py +75 -4
- flwr/client/__init__.py +6 -1
- flwr/client/app.py +239 -248
- flwr/client/client_app.py +70 -9
- flwr/client/dpfedavg_numpy_client.py +1 -1
- flwr/client/grpc_adapter_client/__init__.py +15 -0
- flwr/client/grpc_adapter_client/connection.py +97 -0
- flwr/client/grpc_client/connection.py +18 -5
- flwr/client/grpc_rere_client/__init__.py +1 -1
- flwr/client/grpc_rere_client/client_interceptor.py +158 -0
- flwr/client/grpc_rere_client/connection.py +127 -33
- flwr/client/grpc_rere_client/grpc_adapter.py +140 -0
- flwr/client/heartbeat.py +74 -0
- flwr/client/message_handler/__init__.py +1 -1
- flwr/client/message_handler/message_handler.py +7 -7
- flwr/client/mod/__init__.py +5 -5
- flwr/client/mod/centraldp_mods.py +4 -2
- flwr/client/mod/comms_mods.py +4 -4
- flwr/client/mod/localdp_mod.py +9 -4
- flwr/client/mod/secure_aggregation/__init__.py +1 -1
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +1 -1
- flwr/client/mod/utils.py +1 -1
- flwr/client/node_state.py +60 -10
- flwr/client/node_state_tests.py +4 -3
- flwr/client/rest_client/__init__.py +1 -1
- flwr/client/rest_client/connection.py +177 -157
- flwr/client/supernode/__init__.py +26 -0
- flwr/client/supernode/app.py +464 -0
- flwr/client/typing.py +1 -0
- flwr/common/__init__.py +13 -11
- flwr/common/address.py +1 -1
- flwr/common/config.py +193 -0
- flwr/common/constant.py +42 -1
- flwr/common/context.py +26 -1
- flwr/common/date.py +1 -1
- flwr/common/dp.py +1 -1
- flwr/common/grpc.py +6 -2
- flwr/common/logger.py +79 -8
- flwr/common/message.py +167 -105
- flwr/common/object_ref.py +126 -25
- flwr/common/record/__init__.py +1 -1
- flwr/common/record/parametersrecord.py +0 -1
- flwr/common/record/recordset.py +78 -27
- flwr/common/recordset_compat.py +8 -1
- flwr/common/retry_invoker.py +25 -13
- flwr/common/secure_aggregation/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/shamir.py +1 -1
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +21 -2
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +1 -1
- flwr/common/secure_aggregation/quantization.py +1 -1
- flwr/common/secure_aggregation/secaggplus_constants.py +1 -1
- flwr/common/secure_aggregation/secaggplus_utils.py +1 -1
- flwr/common/serde.py +209 -3
- flwr/common/telemetry.py +25 -0
- flwr/common/typing.py +38 -0
- flwr/common/version.py +14 -0
- flwr/proto/clientappio_pb2.py +41 -0
- flwr/proto/clientappio_pb2.pyi +110 -0
- flwr/proto/clientappio_pb2_grpc.py +101 -0
- flwr/proto/clientappio_pb2_grpc.pyi +40 -0
- flwr/proto/common_pb2.py +36 -0
- flwr/proto/common_pb2.pyi +121 -0
- flwr/proto/common_pb2_grpc.py +4 -0
- flwr/proto/common_pb2_grpc.pyi +4 -0
- flwr/proto/driver_pb2.py +26 -19
- flwr/proto/driver_pb2.pyi +34 -0
- flwr/proto/driver_pb2_grpc.py +70 -0
- flwr/proto/driver_pb2_grpc.pyi +28 -0
- flwr/proto/exec_pb2.py +43 -0
- flwr/proto/exec_pb2.pyi +95 -0
- flwr/proto/exec_pb2_grpc.py +101 -0
- flwr/proto/exec_pb2_grpc.pyi +41 -0
- flwr/proto/fab_pb2.py +30 -0
- flwr/proto/fab_pb2.pyi +56 -0
- flwr/proto/fab_pb2_grpc.py +4 -0
- flwr/proto/fab_pb2_grpc.pyi +4 -0
- flwr/proto/fleet_pb2.py +29 -23
- flwr/proto/fleet_pb2.pyi +33 -0
- flwr/proto/fleet_pb2_grpc.py +102 -0
- flwr/proto/fleet_pb2_grpc.pyi +35 -0
- flwr/proto/grpcadapter_pb2.py +32 -0
- flwr/proto/grpcadapter_pb2.pyi +43 -0
- flwr/proto/grpcadapter_pb2_grpc.py +66 -0
- flwr/proto/grpcadapter_pb2_grpc.pyi +24 -0
- flwr/proto/message_pb2.py +41 -0
- flwr/proto/message_pb2.pyi +122 -0
- flwr/proto/message_pb2_grpc.py +4 -0
- flwr/proto/message_pb2_grpc.pyi +4 -0
- flwr/proto/run_pb2.py +35 -0
- flwr/proto/run_pb2.pyi +76 -0
- flwr/proto/run_pb2_grpc.py +4 -0
- flwr/proto/run_pb2_grpc.pyi +4 -0
- flwr/proto/task_pb2.py +7 -8
- flwr/proto/task_pb2.pyi +8 -5
- flwr/server/__init__.py +4 -8
- flwr/server/app.py +298 -350
- flwr/server/compat/app.py +6 -57
- flwr/server/compat/app_utils.py +5 -4
- flwr/server/compat/driver_client_proxy.py +29 -48
- flwr/server/compat/legacy_context.py +5 -4
- flwr/server/driver/__init__.py +2 -0
- flwr/server/driver/driver.py +22 -132
- flwr/server/driver/grpc_driver.py +224 -74
- flwr/server/driver/inmemory_driver.py +183 -0
- flwr/server/history.py +20 -20
- flwr/server/run_serverapp.py +121 -34
- flwr/server/server.py +11 -7
- flwr/server/server_app.py +59 -10
- flwr/server/serverapp_components.py +52 -0
- flwr/server/strategy/__init__.py +2 -2
- flwr/server/strategy/bulyan.py +1 -1
- flwr/server/strategy/dp_adaptive_clipping.py +3 -3
- flwr/server/strategy/dp_fixed_clipping.py +4 -3
- flwr/server/strategy/dpfedavg_adaptive.py +1 -1
- flwr/server/strategy/dpfedavg_fixed.py +1 -1
- flwr/server/strategy/fedadagrad.py +1 -1
- flwr/server/strategy/fedadam.py +1 -1
- flwr/server/strategy/fedavg_android.py +1 -1
- flwr/server/strategy/fedavgm.py +1 -1
- flwr/server/strategy/fedmedian.py +1 -1
- flwr/server/strategy/fedopt.py +1 -1
- flwr/server/strategy/fedprox.py +1 -1
- flwr/server/strategy/fedxgb_bagging.py +1 -1
- flwr/server/strategy/fedxgb_cyclic.py +1 -1
- flwr/server/strategy/fedxgb_nn_avg.py +1 -1
- flwr/server/strategy/fedyogi.py +1 -1
- flwr/server/strategy/krum.py +1 -1
- flwr/server/strategy/qfedavg.py +1 -1
- flwr/server/superlink/driver/__init__.py +1 -1
- flwr/server/superlink/driver/driver_grpc.py +1 -1
- flwr/server/superlink/driver/driver_servicer.py +51 -4
- flwr/server/superlink/ffs/__init__.py +24 -0
- flwr/server/superlink/ffs/disk_ffs.py +104 -0
- flwr/server/superlink/ffs/ffs.py +79 -0
- flwr/server/superlink/fleet/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_adapter/__init__.py +15 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +131 -0
- flwr/server/superlink/fleet/grpc_bidi/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +8 -2
- flwr/server/superlink/fleet/grpc_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +30 -2
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +214 -0
- flwr/server/superlink/fleet/message_handler/__init__.py +1 -1
- flwr/server/superlink/fleet/message_handler/message_handler.py +42 -2
- flwr/server/superlink/fleet/rest_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/rest_rere/rest_api.py +59 -1
- flwr/server/superlink/fleet/vce/backend/__init__.py +1 -1
- flwr/server/superlink/fleet/vce/backend/backend.py +5 -5
- flwr/server/superlink/fleet/vce/backend/raybackend.py +53 -56
- flwr/server/superlink/fleet/vce/vce_api.py +190 -127
- flwr/server/superlink/state/__init__.py +1 -1
- flwr/server/superlink/state/in_memory_state.py +159 -42
- flwr/server/superlink/state/sqlite_state.py +243 -39
- flwr/server/superlink/state/state.py +81 -6
- flwr/server/superlink/state/state_factory.py +11 -2
- flwr/server/superlink/state/utils.py +62 -0
- flwr/server/typing.py +2 -0
- flwr/server/utils/__init__.py +1 -1
- flwr/server/utils/tensorboard.py +1 -1
- flwr/server/utils/validator.py +23 -9
- flwr/server/workflow/default_workflows.py +67 -25
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +18 -6
- flwr/simulation/__init__.py +7 -4
- flwr/simulation/app.py +67 -36
- flwr/simulation/ray_transport/__init__.py +1 -1
- flwr/simulation/ray_transport/ray_actor.py +20 -46
- flwr/simulation/ray_transport/ray_client_proxy.py +36 -16
- flwr/simulation/run_simulation.py +308 -92
- flwr/superexec/__init__.py +21 -0
- flwr/superexec/app.py +184 -0
- flwr/superexec/deployment.py +185 -0
- flwr/superexec/exec_grpc.py +55 -0
- flwr/superexec/exec_servicer.py +70 -0
- flwr/superexec/executor.py +75 -0
- flwr/superexec/simulation.py +193 -0
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/METADATA +10 -6
- flwr_nightly-1.11.0.dev20240813.dist-info/RECORD +288 -0
- flwr_nightly-1.11.0.dev20240813.dist-info/entry_points.txt +10 -0
- flwr/cli/flower_toml.py +0 -140
- flwr/cli/new/templates/app/flower.toml.tpl +0 -13
- flwr/cli/new/templates/app/requirements.numpy.txt.tpl +0 -2
- flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -4
- flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -4
- flwr_nightly-1.8.0.dev20240315.dist-info/RECORD +0 -211
- flwr_nightly-1.8.0.dev20240315.dist-info/entry_points.txt +0 -9
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/WHEEL +0 -0
flwr/server/run_serverapp.py
CHANGED
|
@@ -22,16 +22,32 @@ from pathlib import Path
|
|
|
22
22
|
from typing import Optional
|
|
23
23
|
|
|
24
24
|
from flwr.common import Context, EventType, RecordSet, event
|
|
25
|
-
from flwr.common.
|
|
25
|
+
from flwr.common.config import (
|
|
26
|
+
get_flwr_dir,
|
|
27
|
+
get_fused_config_from_dir,
|
|
28
|
+
get_metadata_from_config,
|
|
29
|
+
get_project_config,
|
|
30
|
+
get_project_dir,
|
|
31
|
+
)
|
|
32
|
+
from flwr.common.logger import log, update_console_handler, warn_deprecated_feature
|
|
26
33
|
from flwr.common.object_ref import load_app
|
|
34
|
+
from flwr.common.typing import UserConfig
|
|
35
|
+
from flwr.proto.driver_pb2 import ( # pylint: disable=E0611
|
|
36
|
+
CreateRunRequest,
|
|
37
|
+
CreateRunResponse,
|
|
38
|
+
)
|
|
27
39
|
|
|
28
|
-
from .driver
|
|
40
|
+
from .driver import Driver
|
|
41
|
+
from .driver.grpc_driver import GrpcDriver
|
|
29
42
|
from .server_app import LoadServerAppError, ServerApp
|
|
30
43
|
|
|
44
|
+
ADDRESS_DRIVER_API = "0.0.0.0:9091"
|
|
45
|
+
|
|
31
46
|
|
|
32
47
|
def run(
|
|
33
48
|
driver: Driver,
|
|
34
49
|
server_app_dir: str,
|
|
50
|
+
server_app_run_config: UserConfig,
|
|
35
51
|
server_app_attr: Optional[str] = None,
|
|
36
52
|
loaded_server_app: Optional[ServerApp] = None,
|
|
37
53
|
) -> None:
|
|
@@ -39,16 +55,15 @@ def run(
|
|
|
39
55
|
if not (server_app_attr is None) ^ (loaded_server_app is None):
|
|
40
56
|
raise ValueError(
|
|
41
57
|
"Either `server_app_attr` or `loaded_server_app` should be set "
|
|
42
|
-
"but not both.
|
|
58
|
+
"but not both."
|
|
43
59
|
)
|
|
44
60
|
|
|
45
|
-
if server_app_dir is not None:
|
|
46
|
-
sys.path.insert(0, server_app_dir)
|
|
47
|
-
|
|
48
61
|
# Load ServerApp if needed
|
|
49
62
|
def _load() -> ServerApp:
|
|
50
63
|
if server_app_attr:
|
|
51
|
-
server_app: ServerApp = load_app(
|
|
64
|
+
server_app: ServerApp = load_app(
|
|
65
|
+
server_app_attr, LoadServerAppError, server_app_dir
|
|
66
|
+
)
|
|
52
67
|
|
|
53
68
|
if not isinstance(server_app, ServerApp):
|
|
54
69
|
raise LoadServerAppError(
|
|
@@ -62,7 +77,9 @@ def run(
|
|
|
62
77
|
server_app = _load()
|
|
63
78
|
|
|
64
79
|
# Initialize Context
|
|
65
|
-
context = Context(
|
|
80
|
+
context = Context(
|
|
81
|
+
node_id=0, node_config={}, state=RecordSet(), run_config=server_app_run_config
|
|
82
|
+
)
|
|
66
83
|
|
|
67
84
|
# Call ServerApp
|
|
68
85
|
server_app(driver=driver, context=context)
|
|
@@ -70,12 +87,29 @@ def run(
|
|
|
70
87
|
log(DEBUG, "ServerApp finished running.")
|
|
71
88
|
|
|
72
89
|
|
|
73
|
-
def run_server_app() -> None:
|
|
90
|
+
def run_server_app() -> None: # pylint: disable=too-many-branches
|
|
74
91
|
"""Run Flower server app."""
|
|
75
92
|
event(EventType.RUN_SERVER_APP_ENTER)
|
|
76
93
|
|
|
77
94
|
args = _parse_args_run_server_app().parse_args()
|
|
78
95
|
|
|
96
|
+
if args.server != ADDRESS_DRIVER_API:
|
|
97
|
+
warn = "Passing flag --server is deprecated. Use --superlink instead."
|
|
98
|
+
warn_deprecated_feature(warn)
|
|
99
|
+
|
|
100
|
+
if args.superlink != ADDRESS_DRIVER_API:
|
|
101
|
+
# if `--superlink` also passed, then
|
|
102
|
+
# warn user that this argument overrides what was passed with `--server`
|
|
103
|
+
log(
|
|
104
|
+
WARN,
|
|
105
|
+
"Both `--server` and `--superlink` were passed. "
|
|
106
|
+
"`--server` will be ignored. Connecting to the Superlink Driver API "
|
|
107
|
+
"at %s.",
|
|
108
|
+
args.superlink,
|
|
109
|
+
)
|
|
110
|
+
else:
|
|
111
|
+
args.superlink = args.server
|
|
112
|
+
|
|
79
113
|
update_console_handler(
|
|
80
114
|
level=DEBUG if args.verbose else INFO,
|
|
81
115
|
timestamps=args.verbose,
|
|
@@ -95,7 +129,7 @@ def run_server_app() -> None:
|
|
|
95
129
|
WARN,
|
|
96
130
|
"Option `--insecure` was set. "
|
|
97
131
|
"Starting insecure HTTP client connected to %s.",
|
|
98
|
-
args.
|
|
132
|
+
args.superlink,
|
|
99
133
|
)
|
|
100
134
|
root_certificates = None
|
|
101
135
|
else:
|
|
@@ -109,34 +143,69 @@ def run_server_app() -> None:
|
|
|
109
143
|
DEBUG,
|
|
110
144
|
"Starting secure HTTPS client connected to %s "
|
|
111
145
|
"with the following certificates: %s.",
|
|
112
|
-
args.
|
|
146
|
+
args.superlink,
|
|
113
147
|
cert_path,
|
|
114
148
|
)
|
|
115
149
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
150
|
+
app_path: Optional[str] = args.app
|
|
151
|
+
if not (app_path is None) ^ (args.run_id is None):
|
|
152
|
+
raise sys.exit(
|
|
153
|
+
"Please provide either a Flower App path or a Run ID, but not both. "
|
|
154
|
+
"For more details, use: ``flower-server-app -h``"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Initialize GrpcDriver
|
|
158
|
+
if app_path is None:
|
|
159
|
+
# User provided `--run-id`, but not `app_dir`
|
|
160
|
+
driver = GrpcDriver(
|
|
161
|
+
run_id=args.run_id,
|
|
162
|
+
driver_service_address=args.superlink,
|
|
163
|
+
root_certificates=root_certificates,
|
|
164
|
+
)
|
|
165
|
+
flwr_dir = get_flwr_dir(args.flwr_dir)
|
|
166
|
+
run_ = driver.run
|
|
167
|
+
app_path = str(get_project_dir(run_.fab_id, run_.fab_version, flwr_dir))
|
|
168
|
+
config = get_project_config(app_path)
|
|
169
|
+
else:
|
|
170
|
+
# User provided `app_dir`, but not `--run-id`
|
|
171
|
+
# Create run if run_id is not provided
|
|
172
|
+
driver = GrpcDriver(
|
|
173
|
+
run_id=0, # Will be overwritten
|
|
174
|
+
driver_service_address=args.superlink,
|
|
175
|
+
root_certificates=root_certificates,
|
|
176
|
+
)
|
|
177
|
+
# Load config from the project directory
|
|
178
|
+
config = get_project_config(app_path)
|
|
179
|
+
fab_version, fab_id = get_metadata_from_config(config)
|
|
180
|
+
|
|
181
|
+
# Create run
|
|
182
|
+
req = CreateRunRequest(fab_id=fab_id, fab_version=fab_version)
|
|
183
|
+
res: CreateRunResponse = driver._stub.CreateRun(req) # pylint: disable=W0212
|
|
184
|
+
# Overwrite driver._run_id
|
|
185
|
+
driver._run_id = res.run_id # pylint: disable=W0212
|
|
186
|
+
|
|
187
|
+
# Obtain server app reference and the run config
|
|
188
|
+
server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
|
|
189
|
+
server_app_run_config = get_fused_config_from_dir(
|
|
190
|
+
Path(app_path), driver.run.override_config
|
|
120
191
|
)
|
|
121
192
|
|
|
193
|
+
log(DEBUG, "Flower will load ServerApp `%s` in %s", server_app_attr, app_path)
|
|
194
|
+
|
|
122
195
|
log(
|
|
123
196
|
DEBUG,
|
|
124
197
|
"root_certificates: `%s`",
|
|
125
198
|
root_certificates,
|
|
126
199
|
)
|
|
127
200
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
root_certificates=root_certificates,
|
|
201
|
+
# Run the ServerApp with the Driver
|
|
202
|
+
run(
|
|
203
|
+
driver=driver,
|
|
204
|
+
server_app_dir=app_path,
|
|
205
|
+
server_app_run_config=server_app_run_config,
|
|
206
|
+
server_app_attr=server_app_attr,
|
|
135
207
|
)
|
|
136
208
|
|
|
137
|
-
# Run the Server App with the Driver
|
|
138
|
-
run(driver=driver, server_app_dir=server_app_dir, server_app_attr=server_app_attr)
|
|
139
|
-
|
|
140
209
|
# Clean up
|
|
141
210
|
driver.close()
|
|
142
211
|
|
|
@@ -150,13 +219,16 @@ def _parse_args_run_server_app() -> argparse.ArgumentParser:
|
|
|
150
219
|
)
|
|
151
220
|
|
|
152
221
|
parser.add_argument(
|
|
153
|
-
"
|
|
154
|
-
|
|
222
|
+
"app",
|
|
223
|
+
nargs="?",
|
|
224
|
+
default=None,
|
|
225
|
+
help="Load and run the `ServerApp` from the specified Flower App path. "
|
|
226
|
+
"The `pyproject.toml` file must be located in the root of this path.",
|
|
155
227
|
)
|
|
156
228
|
parser.add_argument(
|
|
157
229
|
"--insecure",
|
|
158
230
|
action="store_true",
|
|
159
|
-
help="Run the
|
|
231
|
+
help="Run the `ServerApp` without HTTPS. By default, the app runs with "
|
|
160
232
|
"HTTPS enabled. Use this flag only if you understand the risks.",
|
|
161
233
|
)
|
|
162
234
|
parser.add_argument(
|
|
@@ -173,15 +245,30 @@ def _parse_args_run_server_app() -> argparse.ArgumentParser:
|
|
|
173
245
|
)
|
|
174
246
|
parser.add_argument(
|
|
175
247
|
"--server",
|
|
176
|
-
default=
|
|
248
|
+
default=ADDRESS_DRIVER_API,
|
|
177
249
|
help="Server address",
|
|
178
250
|
)
|
|
179
251
|
parser.add_argument(
|
|
180
|
-
"--
|
|
181
|
-
default=
|
|
182
|
-
help="
|
|
183
|
-
|
|
184
|
-
|
|
252
|
+
"--superlink",
|
|
253
|
+
default=ADDRESS_DRIVER_API,
|
|
254
|
+
help="SuperLink Driver API (gRPC-rere) address (IPv4, IPv6, or a domain name)",
|
|
255
|
+
)
|
|
256
|
+
parser.add_argument(
|
|
257
|
+
"--run-id",
|
|
258
|
+
default=None,
|
|
259
|
+
type=int,
|
|
260
|
+
help="The identifier of the run.",
|
|
261
|
+
)
|
|
262
|
+
parser.add_argument(
|
|
263
|
+
"--flwr-dir",
|
|
264
|
+
default=None,
|
|
265
|
+
help="""The path containing installed Flower Apps.
|
|
266
|
+
By default, this value is equal to:
|
|
267
|
+
|
|
268
|
+
- `$FLWR_HOME/` if `$FLWR_HOME` is defined
|
|
269
|
+
- `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
|
|
270
|
+
- `$HOME/.flwr/` in all other cases
|
|
271
|
+
""",
|
|
185
272
|
)
|
|
186
273
|
|
|
187
274
|
return parser
|
flwr/server/server.py
CHANGED
|
@@ -282,7 +282,14 @@ class Server:
|
|
|
282
282
|
get_parameters_res = random_client.get_parameters(
|
|
283
283
|
ins=ins, timeout=timeout, group_id=server_round
|
|
284
284
|
)
|
|
285
|
-
|
|
285
|
+
if get_parameters_res.status.code == Code.OK:
|
|
286
|
+
log(INFO, "Received initial parameters from one random client")
|
|
287
|
+
else:
|
|
288
|
+
log(
|
|
289
|
+
WARN,
|
|
290
|
+
"Failed to receive initial parameters from the client."
|
|
291
|
+
" Empty initial parameters will be used.",
|
|
292
|
+
)
|
|
286
293
|
return get_parameters_res.parameters
|
|
287
294
|
|
|
288
295
|
|
|
@@ -486,12 +493,9 @@ def run_fl(
|
|
|
486
493
|
|
|
487
494
|
log(INFO, "")
|
|
488
495
|
log(INFO, "[SUMMARY]")
|
|
489
|
-
log(INFO, "Run finished %s
|
|
490
|
-
for
|
|
491
|
-
|
|
492
|
-
log(INFO, "%s", line.strip("\n"))
|
|
493
|
-
else:
|
|
494
|
-
log(INFO, "\t%s", line.strip("\n"))
|
|
496
|
+
log(INFO, "Run finished %s round(s) in %.2fs", config.num_rounds, elapsed_time)
|
|
497
|
+
for line in io.StringIO(str(hist)):
|
|
498
|
+
log(INFO, "\t%s", line.strip("\n"))
|
|
495
499
|
log(INFO, "")
|
|
496
500
|
|
|
497
501
|
# Graceful shutdown
|
flwr/server/server_app.py
CHANGED
|
@@ -17,7 +17,11 @@
|
|
|
17
17
|
|
|
18
18
|
from typing import Callable, Optional
|
|
19
19
|
|
|
20
|
-
from flwr.common import Context
|
|
20
|
+
from flwr.common import Context
|
|
21
|
+
from flwr.common.logger import (
|
|
22
|
+
warn_deprecated_feature_with_example,
|
|
23
|
+
warn_preview_feature,
|
|
24
|
+
)
|
|
21
25
|
from flwr.server.strategy import Strategy
|
|
22
26
|
|
|
23
27
|
from .client_manager import ClientManager
|
|
@@ -25,7 +29,20 @@ from .compat import start_driver
|
|
|
25
29
|
from .driver import Driver
|
|
26
30
|
from .server import Server
|
|
27
31
|
from .server_config import ServerConfig
|
|
28
|
-
from .typing import ServerAppCallable
|
|
32
|
+
from .typing import ServerAppCallable, ServerFn
|
|
33
|
+
|
|
34
|
+
SERVER_FN_USAGE_EXAMPLE = """
|
|
35
|
+
|
|
36
|
+
def server_fn(context: Context):
|
|
37
|
+
server_config = ServerConfig(num_rounds=3)
|
|
38
|
+
strategy = FedAvg()
|
|
39
|
+
return ServerAppComponents(
|
|
40
|
+
strategy=strategy,
|
|
41
|
+
server_config=server_config,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
app = ServerApp(server_fn=server_fn)
|
|
45
|
+
"""
|
|
29
46
|
|
|
30
47
|
|
|
31
48
|
class ServerApp:
|
|
@@ -35,13 +52,15 @@ class ServerApp:
|
|
|
35
52
|
--------
|
|
36
53
|
Use the `ServerApp` with an existing `Strategy`:
|
|
37
54
|
|
|
38
|
-
>>>
|
|
39
|
-
>>>
|
|
55
|
+
>>> def server_fn(context: Context):
|
|
56
|
+
>>> server_config = ServerConfig(num_rounds=3)
|
|
57
|
+
>>> strategy = FedAvg()
|
|
58
|
+
>>> return ServerAppComponents(
|
|
59
|
+
>>> strategy=strategy,
|
|
60
|
+
>>> server_config=server_config,
|
|
61
|
+
>>> )
|
|
40
62
|
>>>
|
|
41
|
-
>>> app = ServerApp()
|
|
42
|
-
>>> server_config=server_config,
|
|
43
|
-
>>> strategy=strategy,
|
|
44
|
-
>>> )
|
|
63
|
+
>>> app = ServerApp(server_fn=server_fn)
|
|
45
64
|
|
|
46
65
|
Use the `ServerApp` with a custom main function:
|
|
47
66
|
|
|
@@ -52,23 +71,52 @@ class ServerApp:
|
|
|
52
71
|
>>> print("ServerApp running")
|
|
53
72
|
"""
|
|
54
73
|
|
|
74
|
+
# pylint: disable=too-many-arguments
|
|
55
75
|
def __init__(
|
|
56
76
|
self,
|
|
57
77
|
server: Optional[Server] = None,
|
|
58
78
|
config: Optional[ServerConfig] = None,
|
|
59
79
|
strategy: Optional[Strategy] = None,
|
|
60
80
|
client_manager: Optional[ClientManager] = None,
|
|
81
|
+
server_fn: Optional[ServerFn] = None,
|
|
61
82
|
) -> None:
|
|
83
|
+
if any([server, config, strategy, client_manager]):
|
|
84
|
+
warn_deprecated_feature_with_example(
|
|
85
|
+
deprecation_message="Passing either `server`, `config`, `strategy` or "
|
|
86
|
+
"`client_manager` directly to the ServerApp "
|
|
87
|
+
"constructor is deprecated.",
|
|
88
|
+
example_message="Pass `ServerApp` arguments wrapped "
|
|
89
|
+
"in a `flwr.server.ServerAppComponents` object that gets "
|
|
90
|
+
"returned by a function passed as the `server_fn` argument "
|
|
91
|
+
"to the `ServerApp` constructor. For example: ",
|
|
92
|
+
code_example=SERVER_FN_USAGE_EXAMPLE,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
if server_fn:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"Passing `server_fn` is incompatible with passing the "
|
|
98
|
+
"other arguments (now deprecated) to ServerApp. "
|
|
99
|
+
"Use `server_fn` exclusively."
|
|
100
|
+
)
|
|
101
|
+
|
|
62
102
|
self._server = server
|
|
63
103
|
self._config = config
|
|
64
104
|
self._strategy = strategy
|
|
65
105
|
self._client_manager = client_manager
|
|
106
|
+
self._server_fn = server_fn
|
|
66
107
|
self._main: Optional[ServerAppCallable] = None
|
|
67
108
|
|
|
68
109
|
def __call__(self, driver: Driver, context: Context) -> None:
|
|
69
110
|
"""Execute `ServerApp`."""
|
|
70
111
|
# Compatibility mode
|
|
71
112
|
if not self._main:
|
|
113
|
+
if self._server_fn:
|
|
114
|
+
# Execute server_fn()
|
|
115
|
+
components = self._server_fn(context)
|
|
116
|
+
self._server = components.server
|
|
117
|
+
self._config = components.config
|
|
118
|
+
self._strategy = components.strategy
|
|
119
|
+
self._client_manager = components.client_manager
|
|
72
120
|
start_driver(
|
|
73
121
|
server=self._server,
|
|
74
122
|
config=self._config,
|
|
@@ -79,7 +127,6 @@ class ServerApp:
|
|
|
79
127
|
return
|
|
80
128
|
|
|
81
129
|
# New execution mode
|
|
82
|
-
context = Context(state=RecordSet())
|
|
83
130
|
self._main(driver, context)
|
|
84
131
|
|
|
85
132
|
def main(self) -> Callable[[ServerAppCallable], ServerAppCallable]:
|
|
@@ -105,7 +152,7 @@ class ServerApp:
|
|
|
105
152
|
>>> server_config = ServerConfig(num_rounds=3)
|
|
106
153
|
>>> strategy = FedAvg()
|
|
107
154
|
>>>
|
|
108
|
-
>>> app = ServerApp(
|
|
155
|
+
>>> app = ServerApp(
|
|
109
156
|
>>> server_config=server_config,
|
|
110
157
|
>>> strategy=strategy,
|
|
111
158
|
>>> )
|
|
@@ -120,6 +167,8 @@ class ServerApp:
|
|
|
120
167
|
""",
|
|
121
168
|
)
|
|
122
169
|
|
|
170
|
+
warn_preview_feature("ServerApp-register-main-function")
|
|
171
|
+
|
|
123
172
|
# Register provided function with the ServerApp object
|
|
124
173
|
self._main = main_fn
|
|
125
174
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Copyright 2024 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
|
+
"""ServerAppComponents for the ServerApp."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
from .client_manager import ClientManager
|
|
22
|
+
from .server import Server
|
|
23
|
+
from .server_config import ServerConfig
|
|
24
|
+
from .strategy import Strategy
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class ServerAppComponents: # pylint: disable=too-many-instance-attributes
|
|
29
|
+
"""Components to construct a ServerApp.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
server : Optional[Server] (default: None)
|
|
34
|
+
A server implementation, either `flwr.server.Server` or a subclass
|
|
35
|
+
thereof. If no instance is provided, one will be created internally.
|
|
36
|
+
config : Optional[ServerConfig] (default: None)
|
|
37
|
+
Currently supported values are `num_rounds` (int, default: 1) and
|
|
38
|
+
`round_timeout` in seconds (float, default: None).
|
|
39
|
+
strategy : Optional[Strategy] (default: None)
|
|
40
|
+
An implementation of the abstract base class
|
|
41
|
+
`flwr.server.strategy.Strategy`. If no strategy is provided, then
|
|
42
|
+
`flwr.server.strategy.FedAvg` will be used.
|
|
43
|
+
client_manager : Optional[ClientManager] (default: None)
|
|
44
|
+
An implementation of the class `flwr.server.ClientManager`. If no
|
|
45
|
+
implementation is provided, then `flwr.server.SimpleClientManager`
|
|
46
|
+
will be used.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
server: Optional[Server] = None
|
|
50
|
+
config: Optional[ServerConfig] = None
|
|
51
|
+
strategy: Optional[Strategy] = None
|
|
52
|
+
client_manager: Optional[ClientManager] = None
|
flwr/server/strategy/__init__.py
CHANGED
|
@@ -53,9 +53,10 @@ __all__ = [
|
|
|
53
53
|
"DPFedAvgAdaptive",
|
|
54
54
|
"DPFedAvgFixed",
|
|
55
55
|
"DifferentialPrivacyClientSideAdaptiveClipping",
|
|
56
|
-
"DifferentialPrivacyServerSideAdaptiveClipping",
|
|
57
56
|
"DifferentialPrivacyClientSideFixedClipping",
|
|
57
|
+
"DifferentialPrivacyServerSideAdaptiveClipping",
|
|
58
58
|
"DifferentialPrivacyServerSideFixedClipping",
|
|
59
|
+
"FaultTolerantFedAvg",
|
|
59
60
|
"FedAdagrad",
|
|
60
61
|
"FedAdam",
|
|
61
62
|
"FedAvg",
|
|
@@ -69,7 +70,6 @@ __all__ = [
|
|
|
69
70
|
"FedXgbCyclic",
|
|
70
71
|
"FedXgbNnAvg",
|
|
71
72
|
"FedYogi",
|
|
72
|
-
"FaultTolerantFedAvg",
|
|
73
73
|
"Krum",
|
|
74
74
|
"QFedAvg",
|
|
75
75
|
"Strategy",
|
flwr/server/strategy/bulyan.py
CHANGED
|
@@ -200,7 +200,7 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
|
|
|
200
200
|
|
|
201
201
|
log(
|
|
202
202
|
INFO,
|
|
203
|
-
"aggregate_fit: parameters are clipped by value:
|
|
203
|
+
"aggregate_fit: parameters are clipped by value: %.4f.",
|
|
204
204
|
self.clipping_norm,
|
|
205
205
|
)
|
|
206
206
|
|
|
@@ -234,7 +234,7 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
|
|
|
234
234
|
)
|
|
235
235
|
log(
|
|
236
236
|
INFO,
|
|
237
|
-
"aggregate_fit: central DP noise with
|
|
237
|
+
"aggregate_fit: central DP noise with %.4f stdev added",
|
|
238
238
|
compute_stdv(
|
|
239
239
|
self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
|
|
240
240
|
),
|
|
@@ -424,7 +424,7 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
|
|
|
424
424
|
)
|
|
425
425
|
log(
|
|
426
426
|
INFO,
|
|
427
|
-
"aggregate_fit: central DP noise with
|
|
427
|
+
"aggregate_fit: central DP noise with %.4f stdev added",
|
|
428
428
|
compute_stdv(
|
|
429
429
|
self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
|
|
430
430
|
),
|
|
@@ -158,7 +158,7 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
|
|
158
158
|
)
|
|
159
159
|
log(
|
|
160
160
|
INFO,
|
|
161
|
-
"aggregate_fit: parameters are clipped by value:
|
|
161
|
+
"aggregate_fit: parameters are clipped by value: %.4f.",
|
|
162
162
|
self.clipping_norm,
|
|
163
163
|
)
|
|
164
164
|
# Convert back to parameters
|
|
@@ -180,7 +180,7 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
|
|
180
180
|
|
|
181
181
|
log(
|
|
182
182
|
INFO,
|
|
183
|
-
"aggregate_fit: central DP noise with
|
|
183
|
+
"aggregate_fit: central DP noise with %.4f stdev added",
|
|
184
184
|
compute_stdv(
|
|
185
185
|
self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
|
|
186
186
|
),
|
|
@@ -337,11 +337,12 @@ class DifferentialPrivacyClientSideFixedClipping(Strategy):
|
|
|
337
337
|
)
|
|
338
338
|
log(
|
|
339
339
|
INFO,
|
|
340
|
-
"aggregate_fit: central DP noise with
|
|
340
|
+
"aggregate_fit: central DP noise with %.4f stdev added",
|
|
341
341
|
compute_stdv(
|
|
342
342
|
self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
|
|
343
343
|
),
|
|
344
344
|
)
|
|
345
|
+
|
|
345
346
|
return aggregated_params, metrics
|
|
346
347
|
|
|
347
348
|
def aggregate_evaluate(
|
flwr/server/strategy/fedadam.py
CHANGED
flwr/server/strategy/fedavgm.py
CHANGED
flwr/server/strategy/fedopt.py
CHANGED
flwr/server/strategy/fedprox.py
CHANGED
flwr/server/strategy/fedyogi.py
CHANGED
flwr/server/strategy/krum.py
CHANGED
flwr/server/strategy/qfedavg.py
CHANGED