flwr-nightly 1.10.0.dev20240707__py3-none-any.whl → 1.11.0.dev20240724__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/build.py +16 -2
- flwr/cli/config_utils.py +47 -27
- flwr/cli/install.py +17 -1
- flwr/cli/new/new.py +32 -21
- flwr/cli/new/templates/app/code/{client.hf.py.tpl → client.huggingface.py.tpl} +15 -5
- flwr/cli/new/templates/app/code/client.jax.py.tpl +2 -1
- flwr/cli/new/templates/app/code/client.mlx.py.tpl +36 -13
- flwr/cli/new/templates/app/code/client.numpy.py.tpl +2 -1
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl +16 -5
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl +6 -3
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +25 -5
- flwr/cli/new/templates/app/code/flwr_tune/app.py.tpl +22 -19
- flwr/cli/new/templates/app/code/flwr_tune/client.py.tpl +5 -3
- flwr/cli/new/templates/app/code/flwr_tune/server.py.tpl +1 -1
- flwr/cli/new/templates/app/code/server.huggingface.py.tpl +23 -0
- flwr/cli/new/templates/app/code/server.jax.py.tpl +16 -8
- flwr/cli/new/templates/app/code/server.mlx.py.tpl +12 -7
- flwr/cli/new/templates/app/code/server.numpy.py.tpl +16 -8
- flwr/cli/new/templates/app/code/server.pytorch.py.tpl +15 -13
- flwr/cli/new/templates/app/code/server.sklearn.py.tpl +17 -10
- flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +16 -13
- flwr/cli/new/templates/app/code/{task.hf.py.tpl → task.huggingface.py.tpl} +14 -2
- flwr/cli/new/templates/app/code/task.mlx.py.tpl +14 -2
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +14 -3
- flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +13 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +9 -12
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +38 -0
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +17 -11
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +17 -12
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +12 -12
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +13 -12
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +12 -12
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +15 -12
- flwr/cli/run/run.py +133 -54
- flwr/client/app.py +56 -24
- flwr/client/client_app.py +28 -8
- flwr/client/grpc_adapter_client/connection.py +3 -2
- flwr/client/grpc_client/connection.py +3 -2
- flwr/client/grpc_rere_client/connection.py +17 -6
- flwr/client/message_handler/message_handler.py +1 -1
- flwr/client/node_state.py +59 -12
- flwr/client/node_state_tests.py +4 -3
- flwr/client/rest_client/connection.py +19 -8
- flwr/client/supernode/app.py +39 -39
- flwr/client/typing.py +2 -2
- flwr/common/config.py +92 -2
- flwr/common/constant.py +3 -0
- flwr/common/context.py +24 -9
- flwr/common/logger.py +25 -0
- flwr/common/object_ref.py +84 -21
- flwr/common/serde.py +45 -0
- flwr/common/telemetry.py +17 -0
- flwr/common/typing.py +5 -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 +24 -19
- flwr/proto/driver_pb2.pyi +21 -1
- flwr/proto/exec_pb2.py +20 -11
- flwr/proto/exec_pb2.pyi +41 -1
- flwr/proto/run_pb2.py +12 -7
- flwr/proto/run_pb2.pyi +22 -1
- flwr/proto/task_pb2.py +7 -8
- flwr/server/__init__.py +2 -0
- flwr/server/compat/legacy_context.py +5 -4
- flwr/server/driver/grpc_driver.py +82 -140
- flwr/server/run_serverapp.py +40 -18
- flwr/server/server_app.py +56 -10
- flwr/server/serverapp_components.py +52 -0
- flwr/server/superlink/driver/driver_servicer.py +18 -3
- flwr/server/superlink/fleet/message_handler/message_handler.py +13 -2
- flwr/server/superlink/fleet/vce/backend/__init__.py +1 -1
- flwr/server/superlink/fleet/vce/backend/backend.py +4 -4
- flwr/server/superlink/fleet/vce/backend/raybackend.py +10 -10
- flwr/server/superlink/fleet/vce/vce_api.py +149 -117
- flwr/server/superlink/state/in_memory_state.py +11 -3
- flwr/server/superlink/state/sqlite_state.py +23 -8
- flwr/server/superlink/state/state.py +7 -2
- flwr/server/typing.py +2 -0
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +18 -2
- flwr/simulation/__init__.py +1 -1
- flwr/simulation/app.py +4 -3
- flwr/simulation/ray_transport/ray_actor.py +15 -19
- flwr/simulation/ray_transport/ray_client_proxy.py +22 -9
- flwr/simulation/run_simulation.py +269 -70
- flwr/superexec/app.py +17 -11
- flwr/superexec/deployment.py +111 -35
- flwr/superexec/exec_grpc.py +5 -1
- flwr/superexec/exec_servicer.py +6 -1
- flwr/superexec/executor.py +21 -0
- flwr/superexec/simulation.py +181 -0
- {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/METADATA +3 -2
- {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/RECORD +97 -91
- flwr/cli/new/templates/app/code/server.hf.py.tpl +0 -17
- flwr/cli/new/templates/app/pyproject.hf.toml.tpl +0 -37
- {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.10.0.dev20240707.dist-info → flwr_nightly-1.11.0.dev20240724.dist-info}/entry_points.txt +0 -0
flwr/server/server_app.py
CHANGED
|
@@ -17,8 +17,11 @@
|
|
|
17
17
|
|
|
18
18
|
from typing import Callable, Optional
|
|
19
19
|
|
|
20
|
-
from flwr.common import Context
|
|
21
|
-
from flwr.common.logger import
|
|
20
|
+
from flwr.common import Context
|
|
21
|
+
from flwr.common.logger import (
|
|
22
|
+
warn_deprecated_feature_with_example,
|
|
23
|
+
warn_preview_feature,
|
|
24
|
+
)
|
|
22
25
|
from flwr.server.strategy import Strategy
|
|
23
26
|
|
|
24
27
|
from .client_manager import ClientManager
|
|
@@ -26,7 +29,20 @@ from .compat import start_driver
|
|
|
26
29
|
from .driver import Driver
|
|
27
30
|
from .server import Server
|
|
28
31
|
from .server_config import ServerConfig
|
|
29
|
-
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
|
+
"""
|
|
30
46
|
|
|
31
47
|
|
|
32
48
|
class ServerApp:
|
|
@@ -36,13 +52,15 @@ class ServerApp:
|
|
|
36
52
|
--------
|
|
37
53
|
Use the `ServerApp` with an existing `Strategy`:
|
|
38
54
|
|
|
39
|
-
>>>
|
|
40
|
-
>>>
|
|
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
|
+
>>> )
|
|
41
62
|
>>>
|
|
42
|
-
>>> app = ServerApp(
|
|
43
|
-
>>> server_config=server_config,
|
|
44
|
-
>>> strategy=strategy,
|
|
45
|
-
>>> )
|
|
63
|
+
>>> app = ServerApp(server_fn=server_fn)
|
|
46
64
|
|
|
47
65
|
Use the `ServerApp` with a custom main function:
|
|
48
66
|
|
|
@@ -53,23 +71,52 @@ class ServerApp:
|
|
|
53
71
|
>>> print("ServerApp running")
|
|
54
72
|
"""
|
|
55
73
|
|
|
74
|
+
# pylint: disable=too-many-arguments
|
|
56
75
|
def __init__(
|
|
57
76
|
self,
|
|
58
77
|
server: Optional[Server] = None,
|
|
59
78
|
config: Optional[ServerConfig] = None,
|
|
60
79
|
strategy: Optional[Strategy] = None,
|
|
61
80
|
client_manager: Optional[ClientManager] = None,
|
|
81
|
+
server_fn: Optional[ServerFn] = None,
|
|
62
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
|
+
|
|
63
102
|
self._server = server
|
|
64
103
|
self._config = config
|
|
65
104
|
self._strategy = strategy
|
|
66
105
|
self._client_manager = client_manager
|
|
106
|
+
self._server_fn = server_fn
|
|
67
107
|
self._main: Optional[ServerAppCallable] = None
|
|
68
108
|
|
|
69
109
|
def __call__(self, driver: Driver, context: Context) -> None:
|
|
70
110
|
"""Execute `ServerApp`."""
|
|
71
111
|
# Compatibility mode
|
|
72
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
|
|
73
120
|
start_driver(
|
|
74
121
|
server=self._server,
|
|
75
122
|
config=self._config,
|
|
@@ -80,7 +127,6 @@ class ServerApp:
|
|
|
80
127
|
return
|
|
81
128
|
|
|
82
129
|
# New execution mode
|
|
83
|
-
context = Context(state=RecordSet())
|
|
84
130
|
self._main(driver, context)
|
|
85
131
|
|
|
86
132
|
def main(self) -> Callable[[ServerAppCallable], ServerAppCallable]:
|
|
@@ -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
|
|
@@ -23,6 +23,7 @@ from uuid import UUID
|
|
|
23
23
|
import grpc
|
|
24
24
|
|
|
25
25
|
from flwr.common.logger import log
|
|
26
|
+
from flwr.common.serde import user_config_from_proto, user_config_to_proto
|
|
26
27
|
from flwr.proto import driver_pb2_grpc # pylint: disable=E0611
|
|
27
28
|
from flwr.proto.driver_pb2 import ( # pylint: disable=E0611
|
|
28
29
|
CreateRunRequest,
|
|
@@ -69,7 +70,11 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
|
|
|
69
70
|
"""Create run ID."""
|
|
70
71
|
log(DEBUG, "DriverServicer.CreateRun")
|
|
71
72
|
state: State = self.state_factory.state()
|
|
72
|
-
run_id = state.create_run(
|
|
73
|
+
run_id = state.create_run(
|
|
74
|
+
request.fab_id,
|
|
75
|
+
request.fab_version,
|
|
76
|
+
user_config_from_proto(request.override_config),
|
|
77
|
+
)
|
|
73
78
|
return CreateRunResponse(run_id=run_id)
|
|
74
79
|
|
|
75
80
|
def PushTaskIns(
|
|
@@ -145,8 +150,18 @@ class DriverServicer(driver_pb2_grpc.DriverServicer):
|
|
|
145
150
|
|
|
146
151
|
# Retrieve run information
|
|
147
152
|
run = state.get_run(request.run_id)
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
|
|
154
|
+
if run is None:
|
|
155
|
+
return GetRunResponse()
|
|
156
|
+
|
|
157
|
+
return GetRunResponse(
|
|
158
|
+
run=Run(
|
|
159
|
+
run_id=run.run_id,
|
|
160
|
+
fab_id=run.fab_id,
|
|
161
|
+
fab_version=run.fab_version,
|
|
162
|
+
override_config=user_config_to_proto(run.override_config),
|
|
163
|
+
)
|
|
164
|
+
)
|
|
150
165
|
|
|
151
166
|
|
|
152
167
|
def _raise_if(validation_error: bool, detail: str) -> None:
|
|
@@ -19,6 +19,7 @@ import time
|
|
|
19
19
|
from typing import List, Optional
|
|
20
20
|
from uuid import UUID
|
|
21
21
|
|
|
22
|
+
from flwr.common.serde import user_config_to_proto
|
|
22
23
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
23
24
|
CreateNodeRequest,
|
|
24
25
|
CreateNodeResponse,
|
|
@@ -113,5 +114,15 @@ def get_run(
|
|
|
113
114
|
) -> GetRunResponse:
|
|
114
115
|
"""Get run information."""
|
|
115
116
|
run = state.get_run(request.run_id)
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
|
|
118
|
+
if run is None:
|
|
119
|
+
return GetRunResponse()
|
|
120
|
+
|
|
121
|
+
return GetRunResponse(
|
|
122
|
+
run=Run(
|
|
123
|
+
run_id=run.run_id,
|
|
124
|
+
fab_id=run.fab_id,
|
|
125
|
+
fab_version=run.fab_version,
|
|
126
|
+
override_config=user_config_to_proto(run.override_config),
|
|
127
|
+
)
|
|
128
|
+
)
|
|
@@ -33,8 +33,8 @@ class Backend(ABC):
|
|
|
33
33
|
"""Construct a backend."""
|
|
34
34
|
|
|
35
35
|
@abstractmethod
|
|
36
|
-
|
|
37
|
-
"""Build backend
|
|
36
|
+
def build(self) -> None:
|
|
37
|
+
"""Build backend.
|
|
38
38
|
|
|
39
39
|
Different components need to be in place before workers in a backend are ready
|
|
40
40
|
to accept jobs. When this method finishes executing, the backend should be fully
|
|
@@ -54,11 +54,11 @@ class Backend(ABC):
|
|
|
54
54
|
"""Report whether a backend worker is idle and can therefore run a ClientApp."""
|
|
55
55
|
|
|
56
56
|
@abstractmethod
|
|
57
|
-
|
|
57
|
+
def terminate(self) -> None:
|
|
58
58
|
"""Terminate backend."""
|
|
59
59
|
|
|
60
60
|
@abstractmethod
|
|
61
|
-
|
|
61
|
+
def process_message(
|
|
62
62
|
self,
|
|
63
63
|
app: Callable[[], ClientApp],
|
|
64
64
|
message: Message,
|
|
@@ -21,6 +21,7 @@ from typing import Callable, Dict, List, Tuple, Union
|
|
|
21
21
|
import ray
|
|
22
22
|
|
|
23
23
|
from flwr.client.client_app import ClientApp
|
|
24
|
+
from flwr.common.constant import PARTITION_ID_KEY
|
|
24
25
|
from flwr.common.context import Context
|
|
25
26
|
from flwr.common.logger import log
|
|
26
27
|
from flwr.common.message import Message
|
|
@@ -153,12 +154,12 @@ class RayBackend(Backend):
|
|
|
153
154
|
"""Report whether the pool has idle actors."""
|
|
154
155
|
return self.pool.is_actor_available()
|
|
155
156
|
|
|
156
|
-
|
|
157
|
+
def build(self) -> None:
|
|
157
158
|
"""Build pool of Ray actors that this backend will submit jobs to."""
|
|
158
|
-
|
|
159
|
+
self.pool.add_actors_to_pool(self.pool.actors_capacity)
|
|
159
160
|
log(DEBUG, "Constructed ActorPool with: %i actors", self.pool.num_actors)
|
|
160
161
|
|
|
161
|
-
|
|
162
|
+
def process_message(
|
|
162
163
|
self,
|
|
163
164
|
app: Callable[[], ClientApp],
|
|
164
165
|
message: Message,
|
|
@@ -168,21 +169,20 @@ class RayBackend(Backend):
|
|
|
168
169
|
|
|
169
170
|
Return output message and updated context.
|
|
170
171
|
"""
|
|
171
|
-
partition_id = context.
|
|
172
|
+
partition_id = context.node_config[PARTITION_ID_KEY]
|
|
172
173
|
|
|
173
174
|
try:
|
|
174
175
|
# Submit a task to the pool
|
|
175
|
-
future =
|
|
176
|
+
future = self.pool.submit(
|
|
176
177
|
lambda a, a_fn, mssg, cid, state: a.run.remote(a_fn, mssg, cid, state),
|
|
177
178
|
(app, message, str(partition_id), context),
|
|
178
179
|
)
|
|
179
180
|
|
|
180
|
-
await future
|
|
181
181
|
# Fetch result
|
|
182
182
|
(
|
|
183
183
|
out_mssg,
|
|
184
184
|
updated_context,
|
|
185
|
-
) =
|
|
185
|
+
) = self.pool.fetch_result_and_return_actor_to_pool(future)
|
|
186
186
|
|
|
187
187
|
return out_mssg, updated_context
|
|
188
188
|
|
|
@@ -193,11 +193,11 @@ class RayBackend(Backend):
|
|
|
193
193
|
self.__class__.__name__,
|
|
194
194
|
)
|
|
195
195
|
# add actor back into pool
|
|
196
|
-
|
|
196
|
+
self.pool.add_actor_back_to_pool(future)
|
|
197
197
|
raise ex
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
def terminate(self) -> None:
|
|
200
200
|
"""Terminate all actors in actor pool."""
|
|
201
|
-
|
|
201
|
+
self.pool.terminate_all_actors()
|
|
202
202
|
ray.shutdown()
|
|
203
203
|
log(DEBUG, "Terminated %s", self.__class__.__name__)
|