flwr-nightly 1.18.0.dev20250407__py3-none-any.whl → 1.18.0.dev20250409__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/cli/new/new.py +3 -3
- flwr/client/app.py +51 -51
- flwr/client/client_app.py +138 -136
- flwr/client/grpc_client/connection.py +12 -12
- flwr/client/mod/localdp_mod.py +5 -5
- flwr/common/exit/exit.py +6 -6
- flwr/common/record/arrayrecord.py +31 -31
- flwr/common/record/configrecord.py +13 -13
- flwr/common/record/metricrecord.py +16 -16
- flwr/common/record/recorddict.py +31 -31
- flwr/common/retry_invoker.py +9 -9
- flwr/server/app.py +10 -10
- flwr/server/grid/grid.py +1 -1
- flwr/server/server_app.py +64 -57
- flwr/server/strategy/dp_adaptive_clipping.py +16 -16
- flwr/server/strategy/dp_fixed_clipping.py +16 -16
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +12 -12
- {flwr_nightly-1.18.0.dev20250407.dist-info → flwr_nightly-1.18.0.dev20250409.dist-info}/METADATA +1 -1
- {flwr_nightly-1.18.0.dev20250407.dist-info → flwr_nightly-1.18.0.dev20250409.dist-info}/RECORD +21 -21
- {flwr_nightly-1.18.0.dev20250407.dist-info → flwr_nightly-1.18.0.dev20250409.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.18.0.dev20250407.dist-info → flwr_nightly-1.18.0.dev20250409.dist-info}/entry_points.txt +0 -0
flwr/cli/new/new.py
CHANGED
@@ -201,15 +201,15 @@ def new(
|
|
201
201
|
if llm_challenge_str == "generalnlp":
|
202
202
|
challenge_name = "General NLP"
|
203
203
|
num_clients = "20"
|
204
|
-
dataset_name = "
|
204
|
+
dataset_name = "flwrlabs/alpaca-gpt4"
|
205
205
|
elif llm_challenge_str == "finance":
|
206
206
|
challenge_name = "Finance"
|
207
207
|
num_clients = "50"
|
208
|
-
dataset_name = "
|
208
|
+
dataset_name = "flwrlabs/fingpt-sentiment-train"
|
209
209
|
elif llm_challenge_str == "medical":
|
210
210
|
challenge_name = "Medical"
|
211
211
|
num_clients = "20"
|
212
|
-
dataset_name = "
|
212
|
+
dataset_name = "flwrlabs/medical-meadow-medical-flashcards"
|
213
213
|
else:
|
214
214
|
challenge_name = "Code"
|
215
215
|
num_clients = "10"
|
flwr/client/app.py
CHANGED
@@ -158,33 +158,33 @@ def start_client(
|
|
158
158
|
|
159
159
|
Examples
|
160
160
|
--------
|
161
|
-
Starting a gRPC client with an insecure server connection
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
Starting
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
Starting
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
161
|
+
Starting a gRPC client with an insecure server connection::
|
162
|
+
|
163
|
+
start_client(
|
164
|
+
server_address=localhost:8080,
|
165
|
+
client_fn=client_fn,
|
166
|
+
)
|
167
|
+
|
168
|
+
Starting a TLS-enabled gRPC client using system certificates::
|
169
|
+
|
170
|
+
def client_fn(context: Context):
|
171
|
+
return FlowerClient().to_client()
|
172
|
+
|
173
|
+
start_client(
|
174
|
+
server_address=localhost:8080,
|
175
|
+
client_fn=client_fn,
|
176
|
+
insecure=False,
|
177
|
+
)
|
178
|
+
|
179
|
+
Starting a TLS-enabled gRPC client using provided certificates::
|
180
|
+
|
181
|
+
from pathlib import Path
|
182
|
+
|
183
|
+
start_client(
|
184
|
+
server_address=localhost:8080,
|
185
|
+
client_fn=client_fn,
|
186
|
+
root_certificates=Path("/crts/root.pem").read_bytes(),
|
187
|
+
)
|
188
188
|
"""
|
189
189
|
msg = (
|
190
190
|
"flwr.client.start_client() is deprecated."
|
@@ -684,30 +684,30 @@ def start_numpy_client(
|
|
684
684
|
|
685
685
|
Examples
|
686
686
|
--------
|
687
|
-
Starting a gRPC client with an insecure server connection
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
Starting
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
Starting
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
687
|
+
Starting a gRPC client with an insecure server connection::
|
688
|
+
|
689
|
+
start_numpy_client(
|
690
|
+
server_address=localhost:8080,
|
691
|
+
client=FlowerClient(),
|
692
|
+
)
|
693
|
+
|
694
|
+
Starting a TLS-enabled gRPC client using system certificates::
|
695
|
+
|
696
|
+
start_numpy_client(
|
697
|
+
server_address=localhost:8080,
|
698
|
+
client=FlowerClient(),
|
699
|
+
insecure=False,
|
700
|
+
)
|
701
|
+
|
702
|
+
Starting a TLS-enabled gRPC client using provided certificates::
|
703
|
+
|
704
|
+
from pathlib import Path
|
705
|
+
|
706
|
+
start_numpy_client(
|
707
|
+
server_address=localhost:8080,
|
708
|
+
client=FlowerClient(),
|
709
|
+
root_certificates=Path("/crts/root.pem").read_bytes(),
|
710
|
+
)
|
711
711
|
"""
|
712
712
|
mssg = (
|
713
713
|
"flwr.client.start_numpy_client() is deprecated. \n\tInstead, use "
|
flwr/client/client_app.py
CHANGED
@@ -95,16 +95,16 @@ class ClientApp:
|
|
95
95
|
|
96
96
|
Examples
|
97
97
|
--------
|
98
|
-
Assuming a typical
|
99
|
-
a
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
98
|
+
Assuming a typical ``Client`` implementation named ``FlowerClient``, you can wrap
|
99
|
+
it in a ``ClientApp`` as follows::
|
100
|
+
|
101
|
+
class FlowerClient(NumPyClient):
|
102
|
+
# ...
|
103
|
+
|
104
|
+
def client_fn(context: Context):
|
105
|
+
return FlowerClient().to_client()
|
106
|
+
|
107
|
+
app = ClientApp(client_fn)
|
108
108
|
"""
|
109
109
|
|
110
110
|
def __init__(
|
@@ -181,39 +181,39 @@ class ClientApp:
|
|
181
181
|
|
182
182
|
Examples
|
183
183
|
--------
|
184
|
-
Registering a train function
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
Registering a train function with a custom action name
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
Registering a train function with a function-specific Flower Mod
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
184
|
+
Registering a train function::
|
185
|
+
|
186
|
+
app = ClientApp()
|
187
|
+
|
188
|
+
@app.train()
|
189
|
+
def train(message: Message, context: Context) -> Message:
|
190
|
+
print("Executing default train function")
|
191
|
+
# Create and return an echo reply message
|
192
|
+
return Message(message.content, reply_to=message)
|
193
|
+
|
194
|
+
Registering a train function with a custom action name::
|
195
|
+
|
196
|
+
app = ClientApp()
|
197
|
+
|
198
|
+
# Messages with `message_type="train.custom_action"` will be
|
199
|
+
# routed to this function.
|
200
|
+
@app.train("custom_action")
|
201
|
+
def custom_action(message: Message, context: Context) -> Message:
|
202
|
+
print("Executing train function for custom action")
|
203
|
+
return Message(message.content, reply_to=message)
|
204
|
+
|
205
|
+
Registering a train function with a function-specific Flower Mod::
|
206
|
+
|
207
|
+
from flwr.client.mod import message_size_mod
|
208
|
+
|
209
|
+
app = ClientApp()
|
210
|
+
|
211
|
+
# Using the `mods` argument to apply a function-specific mod.
|
212
|
+
@app.train(mods=[message_size_mod])
|
213
|
+
def train(message: Message, context: Context) -> Message:
|
214
|
+
print("Executing train function with message size mod")
|
215
|
+
# Create and return an echo reply message
|
216
|
+
return Message(message.content, reply_to=message)
|
217
217
|
"""
|
218
218
|
return _get_decorator(self, MessageType.TRAIN, action, mods)
|
219
219
|
|
@@ -236,39 +236,39 @@ class ClientApp:
|
|
236
236
|
|
237
237
|
Examples
|
238
238
|
--------
|
239
|
-
Registering an evaluate function
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
Registering an evaluate function with a custom action name
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
Registering an evaluate function with a function-specific Flower Mod
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
239
|
+
Registering an evaluate function::
|
240
|
+
|
241
|
+
app = ClientApp()
|
242
|
+
|
243
|
+
@app.evaluate()
|
244
|
+
def evaluate(message: Message, context: Context) -> Message:
|
245
|
+
print("Executing default evaluate function")
|
246
|
+
# Create and return an echo reply message
|
247
|
+
return Message(message.content, reply_to=message)
|
248
|
+
|
249
|
+
Registering an evaluate function with a custom action name::
|
250
|
+
|
251
|
+
app = ClientApp()
|
252
|
+
|
253
|
+
# Messages with `message_type="evaluate.custom_action"` will be
|
254
|
+
# routed to this function.
|
255
|
+
@app.evaluate("custom_action")
|
256
|
+
def custom_action(message: Message, context: Context) -> Message:
|
257
|
+
print("Executing evaluate function for custom action")
|
258
|
+
return Message(message.content, reply_to=message)
|
259
|
+
|
260
|
+
Registering an evaluate function with a function-specific Flower Mod::
|
261
|
+
|
262
|
+
from flwr.client.mod import message_size_mod
|
263
|
+
|
264
|
+
app = ClientApp()
|
265
|
+
|
266
|
+
# Using the `mods` argument to apply a function-specific mod.
|
267
|
+
@app.evaluate(mods=[message_size_mod])
|
268
|
+
def evaluate(message: Message, context: Context) -> Message:
|
269
|
+
print("Executing evaluate function with message size mod")
|
270
|
+
# Create and return an echo reply message
|
271
|
+
return Message(message.content, reply_to=message)
|
272
272
|
"""
|
273
273
|
return _get_decorator(self, MessageType.EVALUATE, action, mods)
|
274
274
|
|
@@ -291,39 +291,39 @@ class ClientApp:
|
|
291
291
|
|
292
292
|
Examples
|
293
293
|
--------
|
294
|
-
Registering a query function
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
Registering a query function with a custom action name
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
Registering a query function with a function-specific Flower Mod
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
294
|
+
Registering a query function::
|
295
|
+
|
296
|
+
app = ClientApp()
|
297
|
+
|
298
|
+
@app.query()
|
299
|
+
def query(message: Message, context: Context) -> Message:
|
300
|
+
print("Executing default query function")
|
301
|
+
# Create and return an echo reply message
|
302
|
+
return Message(message.content, reply_to=message)
|
303
|
+
|
304
|
+
Registering a query function with a custom action name::
|
305
|
+
|
306
|
+
app = ClientApp()
|
307
|
+
|
308
|
+
# Messages with `message_type="query.custom_action"` will be
|
309
|
+
# routed to this function.
|
310
|
+
@app.query("custom_action")
|
311
|
+
def custom_action(message: Message, context: Context) -> Message:
|
312
|
+
print("Executing query function for custom action")
|
313
|
+
return Message(message.content, reply_to=message)
|
314
|
+
|
315
|
+
Registering a query function with a function-specific Flower Mod::
|
316
|
+
|
317
|
+
from flwr.client.mod import message_size_mod
|
318
|
+
|
319
|
+
app = ClientApp()
|
320
|
+
|
321
|
+
# Using the `mods` argument to apply a function-specific mod.
|
322
|
+
@app.query(mods=[message_size_mod])
|
323
|
+
def query(message: Message, context: Context) -> Message:
|
324
|
+
print("Executing query function with message size mod")
|
325
|
+
# Create and return an echo reply message
|
326
|
+
return Message(message.content, reply_to=message)
|
327
327
|
"""
|
328
328
|
return _get_decorator(self, MessageType.QUERY, action, mods)
|
329
329
|
|
@@ -339,17 +339,19 @@ class ClientApp:
|
|
339
339
|
|
340
340
|
Examples
|
341
341
|
--------
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
342
|
+
::
|
343
|
+
|
344
|
+
app = ClientApp()
|
345
|
+
|
346
|
+
@app.lifespan()
|
347
|
+
def lifespan(context: Context) -> None:
|
348
|
+
# Perform initialization tasks before the app starts
|
349
|
+
print("Initializing ClientApp")
|
350
|
+
|
351
|
+
yield # ClientApp is running
|
352
|
+
|
353
|
+
# Perform cleanup tasks after the app stops
|
354
|
+
print("Cleaning up ClientApp")
|
353
355
|
"""
|
354
356
|
|
355
357
|
def lifespan_decorator(
|
@@ -436,24 +438,24 @@ def _registration_error(fn_name: str) -> ValueError:
|
|
436
438
|
|
437
439
|
Use the `ClientApp` with an existing `client_fn`:
|
438
440
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
441
|
+
class FlowerClient(NumPyClient):
|
442
|
+
# ...
|
443
|
+
|
444
|
+
def client_fn(context: Context):
|
445
|
+
return FlowerClient().to_client()
|
446
|
+
|
447
|
+
app = ClientApp(
|
448
|
+
client_fn=client_fn,
|
449
|
+
)
|
448
450
|
|
449
451
|
Use the `ClientApp` with a custom {fn_name} function:
|
450
452
|
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
453
|
+
app = ClientApp()
|
454
|
+
|
455
|
+
@app.{fn_name}()
|
456
|
+
def {fn_name}(message: Message, context: Context) -> Message:
|
457
|
+
print("ClientApp {fn_name} running")
|
458
|
+
# Create and return an echo reply message
|
459
|
+
return Message(message.content, reply_to=message)
|
458
460
|
""",
|
459
461
|
)
|
@@ -104,18 +104,18 @@ def grpc_connection( # pylint: disable=R0913,R0915,too-many-positional-argument
|
|
104
104
|
|
105
105
|
Examples
|
106
106
|
--------
|
107
|
-
Establishing a
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
107
|
+
Establishing a TLS-enabled connection to the server::
|
108
|
+
|
109
|
+
from pathlib import Path
|
110
|
+
with grpc_connection(
|
111
|
+
server_address,
|
112
|
+
max_message_length=max_message_length,
|
113
|
+
root_certificates=Path("/crts/root.pem").read_bytes(),
|
114
|
+
) as conn:
|
115
|
+
receive, send = conn
|
116
|
+
server_message = receive()
|
117
|
+
# do something here
|
118
|
+
send(client_message)
|
119
119
|
"""
|
120
120
|
if isinstance(root_certificates, str):
|
121
121
|
root_certificates = Path(root_certificates).read_bytes()
|
flwr/client/mod/localdp_mod.py
CHANGED
@@ -57,12 +57,12 @@ class LocalDpMod:
|
|
57
57
|
|
58
58
|
Examples
|
59
59
|
--------
|
60
|
-
Create an instance of the local DP mod and add it to the client-side mods
|
60
|
+
Create an instance of the local DP mod and add it to the client-side mods::
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
local_dp_mod = LocalDpMod( ... )
|
63
|
+
app = fl.client.ClientApp(
|
64
|
+
client_fn=client_fn, mods=[local_dp_mod]
|
65
|
+
)
|
66
66
|
"""
|
67
67
|
|
68
68
|
def __init__(
|
flwr/common/exit/exit.py
CHANGED
@@ -37,13 +37,13 @@ def flwr_exit(
|
|
37
37
|
) -> NoReturn:
|
38
38
|
"""Handle application exit with an optional message.
|
39
39
|
|
40
|
-
The exit message logged and displayed will follow this structure
|
40
|
+
The exit message logged and displayed will follow this structure::
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
Exit Code: <code>
|
43
|
+
<message>
|
44
|
+
<short-help-message>
|
45
|
+
|
46
|
+
For more information, visit: <help-page-url>
|
47
47
|
|
48
48
|
- `<code>`: The unique exit code representing the termination reason.
|
49
49
|
- `<message>`: Optional context or additional information about the exit.
|
@@ -96,24 +96,24 @@ class Array:
|
|
96
96
|
|
97
97
|
Examples
|
98
98
|
--------
|
99
|
-
Initializing by specifying all fields directly
|
99
|
+
Initializing by specifying all fields directly::
|
100
100
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
101
|
+
arr1 = Array(
|
102
|
+
dtype="float32",
|
103
|
+
shape=[3, 3],
|
104
|
+
stype="numpy.ndarray",
|
105
|
+
data=b"serialized_data...",
|
106
|
+
)
|
107
107
|
|
108
|
-
Initializing with a NumPy ndarray
|
108
|
+
Initializing with a NumPy ndarray::
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
import numpy as np
|
111
|
+
arr2 = Array(np.random.randn(3, 3))
|
112
112
|
|
113
|
-
Initializing with a PyTorch tensor
|
113
|
+
Initializing with a PyTorch tensor::
|
114
114
|
|
115
|
-
|
116
|
-
|
115
|
+
import torch
|
116
|
+
arr3 = Array(torch.randn(3, 3))
|
117
117
|
"""
|
118
118
|
|
119
119
|
dtype: str
|
@@ -315,33 +315,33 @@ class ArrayRecord(TypedDict[str, Array]):
|
|
315
315
|
|
316
316
|
Examples
|
317
317
|
--------
|
318
|
-
Initializing an empty ArrayRecord
|
318
|
+
Initializing an empty ArrayRecord::
|
319
319
|
|
320
|
-
|
320
|
+
record = ArrayRecord()
|
321
321
|
|
322
|
-
Initializing with a dictionary of :class:`Array
|
322
|
+
Initializing with a dictionary of :class:`Array`::
|
323
323
|
|
324
|
-
|
325
|
-
|
324
|
+
arr = Array("float32", [5, 5], "numpy.ndarray", b"serialized_data...")
|
325
|
+
record = ArrayRecord({"weight": arr})
|
326
326
|
|
327
|
-
Initializing with a list of NumPy arrays
|
327
|
+
Initializing with a list of NumPy arrays::
|
328
328
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
329
|
+
import numpy as np
|
330
|
+
arr1 = np.random.randn(3, 3)
|
331
|
+
arr2 = np.random.randn(2, 2)
|
332
|
+
record = ArrayRecord([arr1, arr2])
|
333
333
|
|
334
|
-
Initializing with a PyTorch model state_dict
|
334
|
+
Initializing with a PyTorch model state_dict::
|
335
335
|
|
336
|
-
|
337
|
-
|
338
|
-
|
336
|
+
import torch.nn as nn
|
337
|
+
model = nn.Linear(10, 5)
|
338
|
+
record = ArrayRecord(model.state_dict())
|
339
339
|
|
340
|
-
Initializing with a TensorFlow model weights (a list of NumPy arrays)
|
340
|
+
Initializing with a TensorFlow model weights (a list of NumPy arrays)::
|
341
341
|
|
342
|
-
|
343
|
-
|
344
|
-
|
342
|
+
import tensorflow as tf
|
343
|
+
model = tf.keras.Sequential([tf.keras.layers.Dense(5, input_shape=(10,))])
|
344
|
+
record = ArrayRecord(model.get_weights())
|
345
345
|
"""
|
346
346
|
|
347
347
|
@overload
|