flwr-nightly 1.21.0.dev20250824__tar.gz → 1.21.0.dev20250827__tar.gz
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_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/PKG-INFO +1 -1
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/exit/exit_code.py +13 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/serverapp/__init__.py +10 -0
- flwr_nightly-1.21.0.dev20250827/py/flwr/serverapp/fedavg.py +292 -0
- flwr_nightly-1.21.0.dev20250827/py/flwr/serverapp/result.py +30 -0
- flwr_nightly-1.21.0.dev20250827/py/flwr/serverapp/strategy.py +286 -0
- flwr_nightly-1.21.0.dev20250827/py/flwr/serverapp/strategy_utils.py +256 -0
- flwr_nightly-1.21.0.dev20250827/py/flwr/serverapp/strategy_utils_tests.py +277 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/pyproject.toml +1 -1
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/README.md +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/app/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/app/error.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/app/metadata.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/auth_plugin/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/build.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/cli_user_auth_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/config_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/constant.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/example.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/install.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/log.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/login/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/login/login.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/ls.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/new.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/run/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/run/run.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/stop.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/cli/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/client.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/client_app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/clientapp/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/clientapp/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/dpfedavg_numpy_client.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/grpc_adapter_client/connection.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/grpc_rere_client/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/grpc_rere_client/connection.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/grpc_rere_client/grpc_adapter.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/message_handler/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/message_handler/message_handler.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/centraldp_mods.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/comms_mods.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/localdp_mod.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/mod/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/numpy_client.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/rest_client/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/rest_client/connection.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/run_info_store.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/client/typing.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/clientapp/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/address.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/args.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/auth_plugin/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/auth_plugin/auth_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/config.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/constant.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/context.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/date.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/differential_privacy.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/differential_privacy_constants.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/dp.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/event_log_plugin/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/event_log_plugin/event_log_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/exit/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/exit/exit.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/exit_handlers.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/heartbeat.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/inflatable.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/inflatable_protobuf_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/inflatable_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/logger.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/message.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/object_ref.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/parameter.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/pyproject.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/array.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/arraychunk.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/arrayrecord.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/configrecord.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/conversion_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/metricrecord.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/recorddict.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/record/typeddict.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/recorddict_compat.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/retry_invoker.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/quantization.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/serde.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/serde_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/telemetry.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/typing.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/version.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/client/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/client/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/client/grpc_client/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/client/grpc_client/connection.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/common/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/server/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/server/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/compat/simulation/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/appio_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/appio_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/appio_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/appio_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/clientappio_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/clientappio_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/control_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/control_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/control_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/control_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/error_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/error_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/error_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/error_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fab_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fab_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fab_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fleet_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fleet_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fleet_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/grpcadapter_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/heartbeat_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/heartbeat_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/heartbeat_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/heartbeat_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/log_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/log_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/log_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/log_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/message_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/message_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/message_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/message_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/node_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/node_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/node_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/node_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/recorddict_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/recorddict_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/recorddict_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/recorddict_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/run_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/run_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/run_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/run_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/serverappio_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/serverappio_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/serverappio_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/serverappio_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/simulationio_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/simulationio_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/simulationio_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/simulationio_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/transport_pb2.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/transport_pb2.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/transport_pb2_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/py.typed +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/client_manager.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/client_proxy.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/compat/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/compat/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/compat/app_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/compat/grid_client_proxy.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/compat/legacy_context.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/criterion.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/fleet_event_log_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/grid/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/grid/grid.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/grid/grpc_grid.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/grid/inmemory_grid.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/history.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/run_serverapp.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/server.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/server_app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/server_config.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/serverapp/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/serverapp/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/serverapp_components.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/aggregate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/bulyan.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedadagrad.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedadam.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedavg.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedavg_android.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedavgm.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedmedian.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedopt.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedprox.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/fedyogi.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/krum.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/qfedavg.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/strategy/strategy.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/linkstate/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/linkstate/linkstate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/linkstate/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/serverappio/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/serverappio/serverappio_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/serverappio/serverappio_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/simulation/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/simulation/simulationio_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/simulation/simulationio_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/superlink/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/typing.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/utils/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/utils/tensorboard.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/utils/validator.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/workflow/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/workflow/constant.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/workflow/default_workflows.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/legacy_app.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/ray_transport/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/ray_transport/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/run_simulation.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/simulation/simulationio_connection.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/app_utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/cli/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/cli/flower_superexec.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/corestate/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/corestate/corestate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/ffs/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/ffs/disk_ffs.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/ffs/ffs.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/ffs/ffs_factory.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/grpc_health/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/grpc_health/simple_health_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/license_plugin/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/license_plugin/license_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/object_store/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/object_store/in_memory_object_store.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/object_store/object_store.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/object_store/object_store_factory.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/object_store/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/plugin/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/plugin/base_exec_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/plugin/clientapp_exec_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/plugin/exec_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/plugin/serverapp_exec_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/plugin/simulation_exec_plugin.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/superexec/run_superexec.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supercore/utils.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/control/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/control/control_event_log_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/control/control_grpc.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/control/control_license_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/control/control_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/superlink/servicer/control/control_user_auth_interceptor.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/cli/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/cli/flower_supernode.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/cli/flwr_clientapp.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/nodestate/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/nodestate/in_memory_nodestate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/nodestate/nodestate.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/nodestate/nodestate_factory.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/runtime/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/runtime/run_clientapp.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/servicer/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/servicer/clientappio/__init__.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/servicer/clientappio/clientappio_servicer.py +0 -0
- {flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/supernode/start_client_internal.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.21.0.
|
3
|
+
Version: 1.21.0.dev20250827
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
License: Apache-2.0
|
6
6
|
Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
|
{flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/common/exit/exit_code.py
RENAMED
@@ -34,6 +34,9 @@ class ExitCode:
|
|
34
34
|
SUPERLINK_LICENSE_URL_INVALID = 103
|
35
35
|
SUPERLINK_INVALID_ARGS = 104
|
36
36
|
|
37
|
+
# ServerApp-specific exit codes (200-299)
|
38
|
+
SERVERAPP_STRATEGY_PRECONDITION_UNMET = 200
|
39
|
+
|
37
40
|
# SuperNode-specific exit codes (300-399)
|
38
41
|
SUPERNODE_REST_ADDRESS_INVALID = 300
|
39
42
|
SUPERNODE_NODE_AUTH_KEYS_REQUIRED = 301
|
@@ -76,6 +79,16 @@ EXIT_CODE_HELP = {
|
|
76
79
|
"Invalid arguments provided to SuperLink. Use `--help` check for the correct "
|
77
80
|
"usage. Alternatively, check the documentation."
|
78
81
|
),
|
82
|
+
# ServerApp-specific exit codes (200-299)
|
83
|
+
ExitCode.SERVERAPP_STRATEGY_PRECONDITION_UNMET: (
|
84
|
+
"The strategy received replies that cannot be aggregated. Please ensure all "
|
85
|
+
"replies returned by ClientApps have one `ArrayRecord` (none when replies are "
|
86
|
+
"from a round of federated evaluation, i.e. when message type is "
|
87
|
+
"`MessageType.EVALUATE`) and one `MetricRecord`. The records in all replies "
|
88
|
+
"must use identical keys. In addition, if the strategy expects a key to "
|
89
|
+
"perform weighted average (e.g. in FedAvg) please ensure the returned "
|
90
|
+
"MetricRecord from ClientApps do include this key."
|
91
|
+
),
|
79
92
|
# SuperNode-specific exit codes (300-399)
|
80
93
|
ExitCode.SUPERNODE_REST_ADDRESS_INVALID: (
|
81
94
|
"When using the REST API, please provide `https://` or "
|
{flwr_nightly-1.21.0.dev20250824 → flwr_nightly-1.21.0.dev20250827}/py/flwr/serverapp/__init__.py
RENAMED
@@ -13,3 +13,13 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
# ==============================================================================
|
15
15
|
"""Public Flower ServerApp APIs."""
|
16
|
+
|
17
|
+
from .fedavg import FedAvg
|
18
|
+
from .result import Result
|
19
|
+
from .strategy import Strategy
|
20
|
+
|
21
|
+
__all__ = [
|
22
|
+
"FedAvg",
|
23
|
+
"Result",
|
24
|
+
"Strategy",
|
25
|
+
]
|
@@ -0,0 +1,292 @@
|
|
1
|
+
# Copyright 2025 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
|
+
"""Flower message-based FedAvg strategy."""
|
16
|
+
|
17
|
+
|
18
|
+
from collections.abc import Iterable
|
19
|
+
from logging import INFO
|
20
|
+
from typing import Callable, Optional
|
21
|
+
|
22
|
+
from flwr.common import (
|
23
|
+
ArrayRecord,
|
24
|
+
ConfigRecord,
|
25
|
+
Message,
|
26
|
+
MessageType,
|
27
|
+
MetricRecord,
|
28
|
+
RecordDict,
|
29
|
+
log,
|
30
|
+
)
|
31
|
+
from flwr.server import Grid
|
32
|
+
|
33
|
+
from .strategy import Strategy
|
34
|
+
from .strategy_utils import (
|
35
|
+
aggregate_arrayrecords,
|
36
|
+
aggregate_metricrecords,
|
37
|
+
sample_nodes,
|
38
|
+
validate_message_reply_consistency,
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
# pylint: disable=too-many-instance-attributes
|
43
|
+
class FedAvg(Strategy):
|
44
|
+
"""Federated Averaging strategy.
|
45
|
+
|
46
|
+
Implementation based on https://arxiv.org/abs/1602.05629
|
47
|
+
|
48
|
+
Parameters
|
49
|
+
----------
|
50
|
+
fraction_train : float (default: 1.0)
|
51
|
+
Fraction of nodes used during training. In case `min_train_nodes`
|
52
|
+
is larger than `fraction_train * total_connected_nodes`, `min_train_nodes`
|
53
|
+
will still be sampled.
|
54
|
+
fraction_evaluate : float (default: 1.0)
|
55
|
+
Fraction of nodes used during validation. In case `min_evaluate_nodes`
|
56
|
+
is larger than `fraction_evaluate * total_connected_nodes`,
|
57
|
+
`min_evaluate_nodes` will still be sampled.
|
58
|
+
min_train_nodes : int (default: 2)
|
59
|
+
Minimum number of nodes used during training.
|
60
|
+
min_evaluate_nodes : int (default: 2)
|
61
|
+
Minimum number of nodes used during validation.
|
62
|
+
min_available_nodes : int (default: 2)
|
63
|
+
Minimum number of total nodes in the system.
|
64
|
+
weighted_by_key : str (default: "num-examples")
|
65
|
+
The key within each MetricRecord whose value is used as the weight when
|
66
|
+
computing weighted averages for both ArrayRecords and MetricRecords.
|
67
|
+
arrayrecord_key : str (default: "arrays")
|
68
|
+
Key used to store the ArrayRecord when constructing Messages.
|
69
|
+
configrecord_key : str (default: "config")
|
70
|
+
Key used to store the ConfigRecord when constructing Messages.
|
71
|
+
train_metrics_aggr_fn : Optional[callable] (default: None)
|
72
|
+
Function with signature (list[RecordDict], str) -> MetricRecord,
|
73
|
+
used to aggregate MetricRecords from training round replies.
|
74
|
+
If `None`, defaults to `aggregate_metricrecords`, which performs a weighted
|
75
|
+
average using the provided weight factor key.
|
76
|
+
evaluate_metrics_aggr_fn : Optional[callable] (default: None)
|
77
|
+
Function with signature (list[RecordDict], str) -> MetricRecord,
|
78
|
+
used to aggregate MetricRecords from training round replies.
|
79
|
+
If `None`, defaults to `aggregate_metricrecords`, which performs a weighted
|
80
|
+
average using the provided weight factor key.
|
81
|
+
"""
|
82
|
+
|
83
|
+
# pylint: disable=too-many-arguments,too-many-positional-arguments
|
84
|
+
def __init__(
|
85
|
+
self,
|
86
|
+
fraction_train: float = 1.0,
|
87
|
+
fraction_evaluate: float = 1.0,
|
88
|
+
min_train_nodes: int = 2,
|
89
|
+
min_evaluate_nodes: int = 2,
|
90
|
+
min_available_nodes: int = 2,
|
91
|
+
weighted_by_key: str = "num-examples",
|
92
|
+
arrayrecord_key: str = "arrays",
|
93
|
+
configrecord_key: str = "config",
|
94
|
+
train_metrics_aggr_fn: Optional[
|
95
|
+
Callable[[list[RecordDict], str], MetricRecord]
|
96
|
+
] = None,
|
97
|
+
evaluate_metrics_aggr_fn: Optional[
|
98
|
+
Callable[[list[RecordDict], str], MetricRecord]
|
99
|
+
] = None,
|
100
|
+
) -> None:
|
101
|
+
self.fraction_train = fraction_train
|
102
|
+
self.fraction_evaluate = fraction_evaluate
|
103
|
+
self.min_train_nodes = min_train_nodes
|
104
|
+
self.min_evaluate_nodes = min_evaluate_nodes
|
105
|
+
self.min_available_nodes = min_available_nodes
|
106
|
+
self.weighted_by_key = weighted_by_key
|
107
|
+
self.arrayrecord_key = arrayrecord_key
|
108
|
+
self.configrecord_key = configrecord_key
|
109
|
+
self.train_metrics_aggr_fn = train_metrics_aggr_fn or aggregate_metricrecords
|
110
|
+
self.evaluate_metrics_aggr_fn = (
|
111
|
+
evaluate_metrics_aggr_fn or aggregate_metricrecords
|
112
|
+
)
|
113
|
+
|
114
|
+
def summary(self) -> None:
|
115
|
+
"""Log summary configuration of the strategy."""
|
116
|
+
log(INFO, "\t├──> Sampling:")
|
117
|
+
log(
|
118
|
+
INFO,
|
119
|
+
"\t│\t├──Fraction: train (%.2f) | evaluate ( %.2f)",
|
120
|
+
self.fraction_train,
|
121
|
+
self.fraction_evaluate,
|
122
|
+
) # pylint: disable=line-too-long
|
123
|
+
log(
|
124
|
+
INFO,
|
125
|
+
"\t│\t├──Minimum nodes: train (%d) | evaluate (%d)",
|
126
|
+
self.min_train_nodes,
|
127
|
+
self.min_evaluate_nodes,
|
128
|
+
) # pylint: disable=line-too-long
|
129
|
+
log(INFO, "\t│\t└──Minimum available nodes: %d", self.min_available_nodes)
|
130
|
+
log(INFO, "\t└──> Keys in records:")
|
131
|
+
log(INFO, "\t\t├── Weighted by: '%s'", self.weighted_by_key)
|
132
|
+
log(INFO, "\t\t├── ArrayRecord key: '%s'", self.arrayrecord_key)
|
133
|
+
log(INFO, "\t\t└── ConfigRecord key: '%s'", self.configrecord_key)
|
134
|
+
|
135
|
+
def _construct_messages(
|
136
|
+
self, record: RecordDict, node_ids: list[int], message_type: str
|
137
|
+
) -> Iterable[Message]:
|
138
|
+
"""Construct N Messages carrying the same RecordDict payload."""
|
139
|
+
messages = []
|
140
|
+
for node_id in node_ids: # one message for each node
|
141
|
+
message = Message(
|
142
|
+
content=record,
|
143
|
+
message_type=message_type,
|
144
|
+
dst_node_id=node_id,
|
145
|
+
)
|
146
|
+
messages.append(message)
|
147
|
+
return messages
|
148
|
+
|
149
|
+
def configure_train(
|
150
|
+
self, server_round: int, arrays: ArrayRecord, config: ConfigRecord, grid: Grid
|
151
|
+
) -> Iterable[Message]:
|
152
|
+
"""Configure the next round of federated training."""
|
153
|
+
# Sample nodes
|
154
|
+
num_nodes = int(len(list(grid.get_node_ids())) * self.fraction_train)
|
155
|
+
sample_size = max(num_nodes, self.min_train_nodes)
|
156
|
+
node_ids, num_total = sample_nodes(grid, self.min_available_nodes, sample_size)
|
157
|
+
log(
|
158
|
+
INFO,
|
159
|
+
"configure_train: Sampled %s nodes (out of %s)",
|
160
|
+
len(node_ids),
|
161
|
+
len(num_total),
|
162
|
+
)
|
163
|
+
# Always inject current server round
|
164
|
+
config["server-round"] = server_round
|
165
|
+
|
166
|
+
# Construct messages
|
167
|
+
record = RecordDict(
|
168
|
+
{self.arrayrecord_key: arrays, self.configrecord_key: config}
|
169
|
+
)
|
170
|
+
return self._construct_messages(record, node_ids, MessageType.TRAIN)
|
171
|
+
|
172
|
+
def aggregate_train(
|
173
|
+
self,
|
174
|
+
server_round: int,
|
175
|
+
replies: Iterable[Message],
|
176
|
+
) -> tuple[Optional[ArrayRecord], Optional[MetricRecord]]:
|
177
|
+
"""Aggregate ArrayRecords and MetricRecords in the received Messages."""
|
178
|
+
if not replies:
|
179
|
+
return None, None
|
180
|
+
|
181
|
+
# Log if any Messages carried errors
|
182
|
+
# Filter messages that carry content
|
183
|
+
num_errors = 0
|
184
|
+
replies_with_content = []
|
185
|
+
for msg in replies:
|
186
|
+
if msg.has_error():
|
187
|
+
log(
|
188
|
+
INFO,
|
189
|
+
"Received error in reply from node %d: %s",
|
190
|
+
msg.metadata.src_node_id,
|
191
|
+
msg.error,
|
192
|
+
)
|
193
|
+
num_errors += 1
|
194
|
+
else:
|
195
|
+
replies_with_content.append(msg.content)
|
196
|
+
|
197
|
+
log(
|
198
|
+
INFO,
|
199
|
+
"aggregate_train: Received %s results and %s failures",
|
200
|
+
len(replies_with_content) - num_errors,
|
201
|
+
num_errors,
|
202
|
+
)
|
203
|
+
|
204
|
+
# Ensure expected ArrayRecords and MetricRecords are received
|
205
|
+
validate_message_reply_consistency(
|
206
|
+
replies=replies_with_content,
|
207
|
+
weighted_by_key=self.weighted_by_key,
|
208
|
+
check_arrayrecord=True,
|
209
|
+
)
|
210
|
+
|
211
|
+
# Aggregate ArrayRecords
|
212
|
+
arrays = aggregate_arrayrecords(
|
213
|
+
replies_with_content,
|
214
|
+
self.weighted_by_key,
|
215
|
+
)
|
216
|
+
|
217
|
+
# Aggregate MetricRecords
|
218
|
+
metrics = self.train_metrics_aggr_fn(
|
219
|
+
replies_with_content,
|
220
|
+
self.weighted_by_key,
|
221
|
+
)
|
222
|
+
return arrays, metrics
|
223
|
+
|
224
|
+
def configure_evaluate(
|
225
|
+
self, server_round: int, arrays: ArrayRecord, config: ConfigRecord, grid: Grid
|
226
|
+
) -> Iterable[Message]:
|
227
|
+
"""Configure the next round of federated evaluation."""
|
228
|
+
# Sample nodes
|
229
|
+
num_nodes = int(len(list(grid.get_node_ids())) * self.fraction_evaluate)
|
230
|
+
sample_size = max(num_nodes, self.min_evaluate_nodes)
|
231
|
+
node_ids, num_total = sample_nodes(grid, self.min_available_nodes, sample_size)
|
232
|
+
log(
|
233
|
+
INFO,
|
234
|
+
"configure_evaluate: Sampled %s nodes (out of %s)",
|
235
|
+
len(node_ids),
|
236
|
+
len(num_total),
|
237
|
+
)
|
238
|
+
|
239
|
+
# Always inject current server round
|
240
|
+
config["server-round"] = server_round
|
241
|
+
|
242
|
+
# Construct messages
|
243
|
+
record = RecordDict(
|
244
|
+
{self.arrayrecord_key: arrays, self.configrecord_key: config}
|
245
|
+
)
|
246
|
+
return self._construct_messages(record, node_ids, MessageType.EVALUATE)
|
247
|
+
|
248
|
+
def aggregate_evaluate(
|
249
|
+
self,
|
250
|
+
server_round: int,
|
251
|
+
replies: Iterable[Message],
|
252
|
+
) -> Optional[MetricRecord]:
|
253
|
+
"""Aggregate MetricRecords in the received Messages."""
|
254
|
+
if not replies:
|
255
|
+
return None
|
256
|
+
|
257
|
+
# Log if any Messages carried errors
|
258
|
+
# Filter messages that carry content
|
259
|
+
num_errors = 0
|
260
|
+
replies_with_content = []
|
261
|
+
for msg in replies:
|
262
|
+
if msg.has_error():
|
263
|
+
log(
|
264
|
+
INFO,
|
265
|
+
"Received error in reply from node %d: %s",
|
266
|
+
msg.metadata.src_node_id,
|
267
|
+
msg.error,
|
268
|
+
)
|
269
|
+
num_errors += 1
|
270
|
+
else:
|
271
|
+
replies_with_content.append(msg.content)
|
272
|
+
|
273
|
+
log(
|
274
|
+
INFO,
|
275
|
+
"aggregate_evaluate: Received %s results and %s failures",
|
276
|
+
len(replies_with_content) - num_errors,
|
277
|
+
num_errors,
|
278
|
+
)
|
279
|
+
|
280
|
+
# Ensure expected ArrayRecords and MetricRecords are received
|
281
|
+
validate_message_reply_consistency(
|
282
|
+
replies=replies_with_content,
|
283
|
+
weighted_by_key=self.weighted_by_key,
|
284
|
+
check_arrayrecord=False,
|
285
|
+
)
|
286
|
+
|
287
|
+
# Aggregate MetricRecords
|
288
|
+
metrics = self.evaluate_metrics_aggr_fn(
|
289
|
+
replies_with_content,
|
290
|
+
self.weighted_by_key,
|
291
|
+
)
|
292
|
+
return metrics
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2025 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
|
+
"""Strategy results."""
|
16
|
+
|
17
|
+
|
18
|
+
from dataclasses import dataclass, field
|
19
|
+
|
20
|
+
from flwr.common import ArrayRecord, MetricRecord
|
21
|
+
|
22
|
+
|
23
|
+
@dataclass
|
24
|
+
class Result:
|
25
|
+
"""Data class carrying records generated during the execution of a strategy."""
|
26
|
+
|
27
|
+
arrays: ArrayRecord = field(default_factory=ArrayRecord)
|
28
|
+
train_metrics_clientapp: dict[int, MetricRecord] = field(default_factory=dict)
|
29
|
+
evaluate_metrics_clientapp: dict[int, MetricRecord] = field(default_factory=dict)
|
30
|
+
evaluate_metrics_serverapp: dict[int, MetricRecord] = field(default_factory=dict)
|
@@ -0,0 +1,286 @@
|
|
1
|
+
# Copyright 2025 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
|
+
"""Flower message-based strategy."""
|
16
|
+
|
17
|
+
|
18
|
+
import time
|
19
|
+
from abc import ABC, abstractmethod
|
20
|
+
from collections.abc import Iterable
|
21
|
+
from logging import INFO
|
22
|
+
from typing import Callable, Optional
|
23
|
+
|
24
|
+
from flwr.common import ArrayRecord, ConfigRecord, Message, MetricRecord, log
|
25
|
+
from flwr.common.exit import ExitCode, flwr_exit
|
26
|
+
from flwr.server import Grid
|
27
|
+
|
28
|
+
from .result import Result
|
29
|
+
from .strategy_utils import InconsistentMessageReplies, log_strategy_start_info
|
30
|
+
|
31
|
+
|
32
|
+
class Strategy(ABC):
|
33
|
+
"""Abstract base class for server strategy implementations."""
|
34
|
+
|
35
|
+
@abstractmethod
|
36
|
+
def configure_train(
|
37
|
+
self, server_round: int, arrays: ArrayRecord, config: ConfigRecord, grid: Grid
|
38
|
+
) -> Iterable[Message]:
|
39
|
+
"""Configure the next round of training.
|
40
|
+
|
41
|
+
Parameters
|
42
|
+
----------
|
43
|
+
server_round : int
|
44
|
+
The current round of federated learning.
|
45
|
+
arrays : ArrayRecord
|
46
|
+
Current global ArrayRecord (e.g. global model) to be sent to client
|
47
|
+
nodes for training.
|
48
|
+
config : ConfigRecord
|
49
|
+
Configuration to be sent to clients nodes for training.
|
50
|
+
grid : Grid
|
51
|
+
The Grid instance used for node sampling and communication.
|
52
|
+
|
53
|
+
Returns
|
54
|
+
-------
|
55
|
+
Iterable[Message]
|
56
|
+
An iterable of messages to be sent to selected client nodes for training.
|
57
|
+
"""
|
58
|
+
|
59
|
+
@abstractmethod
|
60
|
+
def aggregate_train(
|
61
|
+
self,
|
62
|
+
server_round: int,
|
63
|
+
replies: Iterable[Message],
|
64
|
+
) -> tuple[Optional[ArrayRecord], Optional[MetricRecord]]:
|
65
|
+
"""Aggregate training results from client nodes.
|
66
|
+
|
67
|
+
Parameters
|
68
|
+
----------
|
69
|
+
server_round : int
|
70
|
+
The current round of federated learning, starting from 1.
|
71
|
+
replies : Iterable[Message]
|
72
|
+
Iterable of reply messages received from client nodes after training.
|
73
|
+
Each message contains ArrayRecords and MetricRecords that get aggregated.
|
74
|
+
|
75
|
+
Returns
|
76
|
+
-------
|
77
|
+
tuple[Optional[ArrayRecord], Optional[MetricRecord]]
|
78
|
+
A tuple containing:
|
79
|
+
- ArrayRecord: Aggregated ArrayRecord, or None if aggregation failed
|
80
|
+
- MetricRecord: Aggregated MetricRecord, or None if aggregation failed
|
81
|
+
"""
|
82
|
+
|
83
|
+
@abstractmethod
|
84
|
+
def configure_evaluate(
|
85
|
+
self, server_round: int, arrays: ArrayRecord, config: ConfigRecord, grid: Grid
|
86
|
+
) -> Iterable[Message]:
|
87
|
+
"""Configure the next round of evaluation.
|
88
|
+
|
89
|
+
Parameters
|
90
|
+
----------
|
91
|
+
server_round : int
|
92
|
+
The current round of federated learning.
|
93
|
+
arrays : ArrayRecord
|
94
|
+
Current global ArrayRecord (e.g. global model) to be sent to client
|
95
|
+
nodes for evaluation.
|
96
|
+
config : ConfigRecord
|
97
|
+
Configuration to be sent to clients nodes for evaluation.
|
98
|
+
grid : Grid
|
99
|
+
The Grid instance used for node sampling and communication.
|
100
|
+
|
101
|
+
Returns
|
102
|
+
-------
|
103
|
+
Iterable[Message]
|
104
|
+
An iterable of messages to be sent to selected client nodes for evaluation.
|
105
|
+
"""
|
106
|
+
|
107
|
+
@abstractmethod
|
108
|
+
def aggregate_evaluate(
|
109
|
+
self,
|
110
|
+
server_round: int,
|
111
|
+
replies: Iterable[Message],
|
112
|
+
) -> Optional[MetricRecord]:
|
113
|
+
"""Aggregate evaluation metrics from client nodes.
|
114
|
+
|
115
|
+
Parameters
|
116
|
+
----------
|
117
|
+
server_round : int
|
118
|
+
The current round of federated learning.
|
119
|
+
replies : Iterable[Message]
|
120
|
+
Iterable of reply messages received from client nodes after evaluation.
|
121
|
+
MetricRecords in the messages are aggregated.
|
122
|
+
|
123
|
+
Returns
|
124
|
+
-------
|
125
|
+
Optional[MetricRecord]
|
126
|
+
Aggregated evaluation metrics from all participating clients,
|
127
|
+
or None if aggregation failed.
|
128
|
+
"""
|
129
|
+
|
130
|
+
@abstractmethod
|
131
|
+
def summary(self) -> None:
|
132
|
+
"""Log summary configuration of the strategy."""
|
133
|
+
|
134
|
+
# pylint: disable=too-many-arguments, too-many-positional-arguments, too-many-locals
|
135
|
+
def start(
|
136
|
+
self,
|
137
|
+
grid: Grid,
|
138
|
+
initial_arrays: ArrayRecord,
|
139
|
+
num_rounds: int = 3,
|
140
|
+
timeout: float = 3600,
|
141
|
+
train_config: Optional[ConfigRecord] = None,
|
142
|
+
evaluate_config: Optional[ConfigRecord] = None,
|
143
|
+
evaluate_fn: Optional[Callable[[int, ArrayRecord], MetricRecord]] = None,
|
144
|
+
) -> Result:
|
145
|
+
"""Execute the federated learning strategy.
|
146
|
+
|
147
|
+
Runs the complete federated learning workflow for the specified number of
|
148
|
+
rounds, including training, evaluation, and optional centralized evaluation.
|
149
|
+
|
150
|
+
Parameters
|
151
|
+
----------
|
152
|
+
grid : Grid
|
153
|
+
The Grid instance used to send/receive Messages from nodes executing a
|
154
|
+
ClientApp.
|
155
|
+
initial_arrays : ArrayRecord
|
156
|
+
Initial model parameters (arrays) to be used for federated learning.
|
157
|
+
num_rounds : int (default: 3)
|
158
|
+
Number of federated learning rounds to execute.
|
159
|
+
timeout : float (default: 3600)
|
160
|
+
Timeout in seconds for waiting for node responses.
|
161
|
+
train_config : ConfigRecord, optional
|
162
|
+
Configuration to be sent to nodes during training rounds.
|
163
|
+
If unset, an empty ConfigRecord will be used.
|
164
|
+
evaluate_config : ConfigRecord, optional
|
165
|
+
Configuration to be sent to nodes during evaluation rounds.
|
166
|
+
If unset, an empty ConfigRecord will be used.
|
167
|
+
evaluate_fn : Callable[[int, ArrayRecord], MetricRecord], optional
|
168
|
+
Optional function for centralized evaluation of the global model. Takes
|
169
|
+
server round number and array record, returns a MetricRecord. If provided,
|
170
|
+
will be called before the first round and after each round. Defaults to
|
171
|
+
None.
|
172
|
+
|
173
|
+
Returns
|
174
|
+
-------
|
175
|
+
Results
|
176
|
+
Results containing final model arrays and also training metrics, evaluation
|
177
|
+
metrics and global evaluation metrics (if provided) from all rounds.
|
178
|
+
"""
|
179
|
+
log(INFO, "Starting %s strategy:", self.__class__.__name__)
|
180
|
+
log_strategy_start_info(
|
181
|
+
num_rounds, initial_arrays, train_config, evaluate_config
|
182
|
+
)
|
183
|
+
self.summary()
|
184
|
+
log(INFO, "")
|
185
|
+
|
186
|
+
# Initialize if None
|
187
|
+
train_config = ConfigRecord() if train_config is None else train_config
|
188
|
+
evaluate_config = ConfigRecord() if evaluate_config is None else evaluate_config
|
189
|
+
result = Result()
|
190
|
+
|
191
|
+
t_start = time.time()
|
192
|
+
# Evaluate starting global parameters
|
193
|
+
if evaluate_fn:
|
194
|
+
res = evaluate_fn(0, initial_arrays)
|
195
|
+
log(INFO, "Initial global evaluation results: %s", res)
|
196
|
+
result.evaluate_metrics_serverapp[0] = res
|
197
|
+
|
198
|
+
arrays = initial_arrays
|
199
|
+
|
200
|
+
for current_round in range(1, num_rounds + 1):
|
201
|
+
log(INFO, "")
|
202
|
+
log(INFO, "[ROUND %s/%s]", current_round, num_rounds)
|
203
|
+
|
204
|
+
# -----------------------------------------------------------------
|
205
|
+
# --- TRAINING ----------------------------------------------------
|
206
|
+
# -----------------------------------------------------------------
|
207
|
+
|
208
|
+
# Call strategy to configure training round
|
209
|
+
# Send messages and wait for replies
|
210
|
+
train_replies = grid.send_and_receive(
|
211
|
+
messages=self.configure_train(
|
212
|
+
current_round,
|
213
|
+
arrays,
|
214
|
+
train_config,
|
215
|
+
grid,
|
216
|
+
),
|
217
|
+
timeout=timeout,
|
218
|
+
)
|
219
|
+
|
220
|
+
# Aggregate train
|
221
|
+
try:
|
222
|
+
agg_arrays, agg_train_metrics = self.aggregate_train(
|
223
|
+
current_round,
|
224
|
+
train_replies,
|
225
|
+
)
|
226
|
+
except InconsistentMessageReplies as e:
|
227
|
+
flwr_exit(
|
228
|
+
ExitCode.SERVERAPP_STRATEGY_PRECONDITION_UNMET, message=str(e)
|
229
|
+
)
|
230
|
+
|
231
|
+
# Log training metrics and append to history
|
232
|
+
if agg_arrays is not None:
|
233
|
+
result.arrays = agg_arrays
|
234
|
+
arrays = agg_arrays
|
235
|
+
if agg_train_metrics is not None:
|
236
|
+
log(INFO, "\t└──> Aggregated MetricRecord: %s", agg_train_metrics)
|
237
|
+
result.train_metrics_clientapp[current_round] = agg_train_metrics
|
238
|
+
|
239
|
+
# -----------------------------------------------------------------
|
240
|
+
# --- EVALUATION (LOCAL) ------------------------------------------
|
241
|
+
# -----------------------------------------------------------------
|
242
|
+
|
243
|
+
# Call strategy to configure evaluation round
|
244
|
+
# Send messages and wait for replies
|
245
|
+
evaluate_replies = grid.send_and_receive(
|
246
|
+
messages=self.configure_evaluate(
|
247
|
+
current_round,
|
248
|
+
arrays,
|
249
|
+
evaluate_config,
|
250
|
+
grid,
|
251
|
+
),
|
252
|
+
timeout=timeout,
|
253
|
+
)
|
254
|
+
|
255
|
+
# Aggregate evaluate
|
256
|
+
try:
|
257
|
+
agg_evaluate_metrics = self.aggregate_evaluate(
|
258
|
+
current_round,
|
259
|
+
evaluate_replies,
|
260
|
+
)
|
261
|
+
except InconsistentMessageReplies as e:
|
262
|
+
flwr_exit(
|
263
|
+
ExitCode.SERVERAPP_STRATEGY_PRECONDITION_UNMET, message=str(e)
|
264
|
+
)
|
265
|
+
|
266
|
+
# Log training metrics and append to history
|
267
|
+
if agg_evaluate_metrics is not None:
|
268
|
+
log(INFO, "\t└──> Aggregated MetricRecord: %s", agg_evaluate_metrics)
|
269
|
+
result.evaluate_metrics_clientapp[current_round] = agg_evaluate_metrics
|
270
|
+
|
271
|
+
# -----------------------------------------------------------------
|
272
|
+
# --- EVALUATION (GLOBAL) -----------------------------------------
|
273
|
+
# -----------------------------------------------------------------
|
274
|
+
|
275
|
+
# Centralized evaluation
|
276
|
+
if evaluate_fn:
|
277
|
+
log(INFO, "Global evaluation")
|
278
|
+
res = evaluate_fn(current_round, arrays)
|
279
|
+
log(INFO, "\t└──> MetricRecord: %s", res)
|
280
|
+
result.evaluate_metrics_serverapp[current_round] = res
|
281
|
+
|
282
|
+
log(INFO, "")
|
283
|
+
log(INFO, "Strategy execution finished in %.2fs", time.time() - t_start)
|
284
|
+
log(INFO, "")
|
285
|
+
|
286
|
+
return result
|