flwr-nightly 1.8.0.dev20240223__tar.gz → 1.8.0.dev20240227__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/PKG-INFO +1 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/pyproject.toml +1 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/__init__.py +1 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/app.py +4 -3
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/message_handler/message_handler.py +1 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/mod/__init__.py +2 -0
- flwr_nightly-1.8.0.dev20240227/src/py/flwr/client/mod/centraldp_mods.py +76 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/differential_privacy_constants.py +2 -0
- flwr_nightly-1.8.0.dev20240227/src/py/flwr/common/exit_handlers.py +87 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/message.py +18 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/app.py +7 -54
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/driver/driver.py +1 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/__init__.py +5 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/dp_fixed_clipping.py +156 -2
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +5 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +39 -16
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +4 -2
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/state/in_memory_state.py +23 -18
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/simulation/ray_transport/ray_actor.py +19 -4
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +2 -1
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/LICENSE +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/README.md +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/example.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/new.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/flower.toml.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/cli/utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/client.py +0 -0
- /flwr_nightly-1.8.0.dev20240223/src/py/flwr/client/clientapp.py → /flwr_nightly-1.8.0.dev20240227/src/py/flwr/client/client_app.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/grpc_client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/grpc_client/connection.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/grpc_rere_client/connection.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/message_handler/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/message_handler/task_handler.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/mod/utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/node_state.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/node_state_tests.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/numpy_client.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/rest_client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/rest_client/connection.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/typing.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/address.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/constant.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/context.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/date.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/differential_privacy.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/dp.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/logger.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/parameter.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/configsrecord.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/conversion_utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/metricsrecord.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/parametersrecord.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/recordset.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/record/typeddict.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/recordset_compat.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/retry_invoker.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/serde.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/telemetry.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/typing.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/version.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/driver_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/driver_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/fleet_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/node_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/node_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/recordset_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/task_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/task_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/transport_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/transport_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/py.typed +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/client_manager.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/compat/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/compat/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/compat/driver_client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/criterion.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/driver/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/driver/grpc_driver.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/history.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/run_serverapp.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/server.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/server_app.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/server_config.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/aggregate.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/bulyan.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedadam.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedavgm.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedmedian.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedopt.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedprox.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/fedyogi.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/krum.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/qfedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/strategy/strategy.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/driver/driver_servicer.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/state/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/state/sqlite_state.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/state/state.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/typing.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/utils/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/utils/tensorboard.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/server/utils/validator.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/simulation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/simulation/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
4
4
|
|
5
5
|
[tool.poetry]
|
6
6
|
name = "flwr-nightly"
|
7
|
-
version = "1.8.0-
|
7
|
+
version = "1.8.0-dev20240227"
|
8
8
|
description = "Flower: A Friendly Federated Learning Framework"
|
9
9
|
license = "Apache-2.0"
|
10
10
|
authors = ["The Flower Authors <hello@flower.ai>"]
|
{flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/__init__.py
RENAMED
@@ -19,7 +19,7 @@ from .app import run_client_app as run_client_app
|
|
19
19
|
from .app import start_client as start_client
|
20
20
|
from .app import start_numpy_client as start_numpy_client
|
21
21
|
from .client import Client as Client
|
22
|
-
from .
|
22
|
+
from .client_app import ClientApp as ClientApp
|
23
23
|
from .numpy_client import NumPyClient as NumPyClient
|
24
24
|
from .typing import ClientFn as ClientFn
|
25
25
|
|
@@ -23,7 +23,7 @@ from pathlib import Path
|
|
23
23
|
from typing import Callable, ContextManager, Optional, Tuple, Union
|
24
24
|
|
25
25
|
from flwr.client.client import Client
|
26
|
-
from flwr.client.
|
26
|
+
from flwr.client.client_app import ClientApp
|
27
27
|
from flwr.client.typing import ClientFn
|
28
28
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, Message, event
|
29
29
|
from flwr.common.address import parse_address
|
@@ -34,9 +34,10 @@ from flwr.common.constant import (
|
|
34
34
|
TRANSPORT_TYPE_REST,
|
35
35
|
TRANSPORT_TYPES,
|
36
36
|
)
|
37
|
+
from flwr.common.exit_handlers import register_exit_handlers
|
37
38
|
from flwr.common.logger import log, warn_deprecated_feature, warn_experimental_feature
|
38
39
|
|
39
|
-
from .
|
40
|
+
from .client_app import load_client_app
|
40
41
|
from .grpc_client.connection import grpc_connection
|
41
42
|
from .grpc_rere_client.connection import grpc_request_response
|
42
43
|
from .message_handler.message_handler import handle_control_message
|
@@ -104,7 +105,7 @@ def run_client_app() -> None:
|
|
104
105
|
root_certificates=root_certificates,
|
105
106
|
insecure=args.insecure,
|
106
107
|
)
|
107
|
-
|
108
|
+
register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
|
108
109
|
|
109
110
|
|
110
111
|
def _parse_args_run_client_app() -> argparse.ArgumentParser:
|
@@ -98,7 +98,7 @@ def handle_legacy_message_from_msgtype(
|
|
98
98
|
client_fn: ClientFn, message: Message, context: Context
|
99
99
|
) -> Message:
|
100
100
|
"""Handle legacy message in the inner most mod."""
|
101
|
-
client = client_fn(str(message.metadata.
|
101
|
+
client = client_fn(str(message.metadata.partition_id))
|
102
102
|
|
103
103
|
# Check if NumPyClient is returend
|
104
104
|
if isinstance(client, NumPyClient):
|
{flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/client/mod/__init__.py
RENAMED
@@ -15,10 +15,12 @@
|
|
15
15
|
"""Mods."""
|
16
16
|
|
17
17
|
|
18
|
+
from .centraldp_mods import fixedclipping_mod
|
18
19
|
from .secure_aggregation.secaggplus_mod import secaggplus_mod
|
19
20
|
from .utils import make_ffn
|
20
21
|
|
21
22
|
__all__ = [
|
22
23
|
"make_ffn",
|
23
24
|
"secaggplus_mod",
|
25
|
+
"fixedclipping_mod",
|
24
26
|
]
|
@@ -0,0 +1,76 @@
|
|
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
|
+
"""Clipping modifiers for central DP with client-side clipping."""
|
16
|
+
|
17
|
+
|
18
|
+
from flwr.client.typing import ClientAppCallable
|
19
|
+
from flwr.common import ndarrays_to_parameters, parameters_to_ndarrays
|
20
|
+
from flwr.common import recordset_compat as compat
|
21
|
+
from flwr.common.constant import MESSAGE_TYPE_FIT
|
22
|
+
from flwr.common.context import Context
|
23
|
+
from flwr.common.differential_privacy import compute_clip_model_update
|
24
|
+
from flwr.common.differential_privacy_constants import KEY_CLIPPING_NORM
|
25
|
+
from flwr.common.message import Message
|
26
|
+
|
27
|
+
|
28
|
+
def fixedclipping_mod(
|
29
|
+
msg: Message, ctxt: Context, call_next: ClientAppCallable
|
30
|
+
) -> Message:
|
31
|
+
"""Client-side fixed clipping modifier.
|
32
|
+
|
33
|
+
This mod needs to be used with the DifferentialPrivacyClientSideFixedClipping
|
34
|
+
server-side strategy wrapper.
|
35
|
+
|
36
|
+
The wrapper sends the clipping_norm value to the client.
|
37
|
+
|
38
|
+
This mod clips the client model updates before sending them to the server.
|
39
|
+
|
40
|
+
It operates on messages with type MESSAGE_TYPE_FIT.
|
41
|
+
|
42
|
+
Notes
|
43
|
+
-----
|
44
|
+
Consider the order of mods when using multiple.
|
45
|
+
|
46
|
+
Typically, fixedclipping_mod should be the last to operate on params.
|
47
|
+
"""
|
48
|
+
if msg.metadata.message_type != MESSAGE_TYPE_FIT:
|
49
|
+
return call_next(msg, ctxt)
|
50
|
+
fit_ins = compat.recordset_to_fitins(msg.content, keep_input=True)
|
51
|
+
if KEY_CLIPPING_NORM not in fit_ins.config:
|
52
|
+
raise KeyError(
|
53
|
+
f"The {KEY_CLIPPING_NORM} value is not supplied by the "
|
54
|
+
f"DifferentialPrivacyClientSideFixedClipping wrapper at"
|
55
|
+
f" the server side."
|
56
|
+
)
|
57
|
+
|
58
|
+
clipping_norm = float(fit_ins.config[KEY_CLIPPING_NORM])
|
59
|
+
server_to_client_params = parameters_to_ndarrays(fit_ins.parameters)
|
60
|
+
|
61
|
+
# Call inner app
|
62
|
+
out_msg = call_next(msg, ctxt)
|
63
|
+
fit_res = compat.recordset_to_fitres(out_msg.content, keep_input=True)
|
64
|
+
|
65
|
+
client_to_server_params = parameters_to_ndarrays(fit_res.parameters)
|
66
|
+
|
67
|
+
# Clip the client update
|
68
|
+
compute_clip_model_update(
|
69
|
+
client_to_server_params,
|
70
|
+
server_to_client_params,
|
71
|
+
clipping_norm,
|
72
|
+
)
|
73
|
+
|
74
|
+
fit_res.parameters = ndarrays_to_parameters(client_to_server_params)
|
75
|
+
out_msg.content = compat.fitres_to_recordset(fit_res, keep_input=True)
|
76
|
+
return out_msg
|
@@ -14,6 +14,8 @@
|
|
14
14
|
# ==============================================================================
|
15
15
|
"""Constants for differential privacy."""
|
16
16
|
|
17
|
+
|
18
|
+
KEY_CLIPPING_NORM = "clipping_norm"
|
17
19
|
CLIENTS_DISCREPANCY_WARNING = (
|
18
20
|
"The number of clients returning parameters (%s)"
|
19
21
|
" differs from the number of sampled clients (%s)."
|
@@ -0,0 +1,87 @@
|
|
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
|
+
"""Common function to register exit handlers for server and client."""
|
16
|
+
|
17
|
+
|
18
|
+
import sys
|
19
|
+
from signal import SIGINT, SIGTERM, signal
|
20
|
+
from threading import Thread
|
21
|
+
from types import FrameType
|
22
|
+
from typing import List, Optional
|
23
|
+
|
24
|
+
from grpc import Server
|
25
|
+
|
26
|
+
from flwr.common.telemetry import EventType, event
|
27
|
+
|
28
|
+
|
29
|
+
def register_exit_handlers(
|
30
|
+
event_type: EventType,
|
31
|
+
grpc_servers: Optional[List[Server]] = None,
|
32
|
+
bckg_threads: Optional[List[Thread]] = None,
|
33
|
+
) -> None:
|
34
|
+
"""Register exit handlers for `SIGINT` and `SIGTERM` signals.
|
35
|
+
|
36
|
+
Parameters
|
37
|
+
----------
|
38
|
+
event_type : EventType
|
39
|
+
The telemetry event that should be logged before exit.
|
40
|
+
grpc_servers: Optional[List[Server]] (default: None)
|
41
|
+
An otpional list of gRPC servers that need to be gracefully
|
42
|
+
terminated before exiting.
|
43
|
+
bckg_threads: Optional[List[Thread]] (default: None)
|
44
|
+
An optional list of threads that need to be gracefully
|
45
|
+
terminated before exiting.
|
46
|
+
"""
|
47
|
+
default_handlers = {
|
48
|
+
SIGINT: None,
|
49
|
+
SIGTERM: None,
|
50
|
+
}
|
51
|
+
|
52
|
+
def graceful_exit_handler( # type: ignore
|
53
|
+
signalnum,
|
54
|
+
frame: FrameType, # pylint: disable=unused-argument
|
55
|
+
) -> None:
|
56
|
+
"""Exit handler to be registered with `signal.signal`.
|
57
|
+
|
58
|
+
When called will reset signal handler to original signal handler from
|
59
|
+
default_handlers.
|
60
|
+
"""
|
61
|
+
# Reset to default handler
|
62
|
+
signal(signalnum, default_handlers[signalnum])
|
63
|
+
|
64
|
+
event_res = event(event_type=event_type)
|
65
|
+
|
66
|
+
if grpc_servers is not None:
|
67
|
+
for grpc_server in grpc_servers:
|
68
|
+
grpc_server.stop(grace=1)
|
69
|
+
|
70
|
+
if bckg_threads is not None:
|
71
|
+
for bckg_thread in bckg_threads:
|
72
|
+
bckg_thread.join()
|
73
|
+
|
74
|
+
# Ensure event has happend
|
75
|
+
event_res.result()
|
76
|
+
|
77
|
+
# Setup things for graceful exit
|
78
|
+
sys.exit(0)
|
79
|
+
|
80
|
+
default_handlers[SIGINT] = signal( # type: ignore
|
81
|
+
SIGINT,
|
82
|
+
graceful_exit_handler, # type: ignore
|
83
|
+
)
|
84
|
+
default_handlers[SIGTERM] = signal( # type: ignore
|
85
|
+
SIGTERM,
|
86
|
+
graceful_exit_handler, # type: ignore
|
87
|
+
)
|
{flwr_nightly-1.8.0.dev20240223 → flwr_nightly-1.8.0.dev20240227}/src/py/flwr/common/message.py
RENAMED
@@ -14,7 +14,6 @@
|
|
14
14
|
# ==============================================================================
|
15
15
|
"""Message."""
|
16
16
|
|
17
|
-
|
18
17
|
from __future__ import annotations
|
19
18
|
|
20
19
|
from dataclasses import dataclass
|
@@ -46,6 +45,10 @@ class Metadata: # pylint: disable=too-many-instance-attributes
|
|
46
45
|
message_type : str
|
47
46
|
A string that encodes the action to be executed on
|
48
47
|
the receiving end.
|
48
|
+
partition_id : Optional[int]
|
49
|
+
An identifier that can be used when loading a particular
|
50
|
+
data partition for a ClientApp. Making use of this identifier
|
51
|
+
is more relevant when conducting simulations.
|
49
52
|
"""
|
50
53
|
|
51
54
|
_run_id: int
|
@@ -56,6 +59,7 @@ class Metadata: # pylint: disable=too-many-instance-attributes
|
|
56
59
|
_group_id: str
|
57
60
|
_ttl: str
|
58
61
|
_message_type: str
|
62
|
+
_partition_id: int | None
|
59
63
|
|
60
64
|
def __init__( # pylint: disable=too-many-arguments
|
61
65
|
self,
|
@@ -67,6 +71,7 @@ class Metadata: # pylint: disable=too-many-instance-attributes
|
|
67
71
|
group_id: str,
|
68
72
|
ttl: str,
|
69
73
|
message_type: str,
|
74
|
+
partition_id: int | None = None,
|
70
75
|
) -> None:
|
71
76
|
self._run_id = run_id
|
72
77
|
self._message_id = message_id
|
@@ -76,6 +81,7 @@ class Metadata: # pylint: disable=too-many-instance-attributes
|
|
76
81
|
self._group_id = group_id
|
77
82
|
self._ttl = ttl
|
78
83
|
self._message_type = message_type
|
84
|
+
self._partition_id = partition_id
|
79
85
|
|
80
86
|
@property
|
81
87
|
def run_id(self) -> int:
|
@@ -137,6 +143,16 @@ class Metadata: # pylint: disable=too-many-instance-attributes
|
|
137
143
|
"""Set message_type."""
|
138
144
|
self._message_type = value
|
139
145
|
|
146
|
+
@property
|
147
|
+
def partition_id(self) -> int | None:
|
148
|
+
"""An identifier telling which data partition a ClientApp should use."""
|
149
|
+
return self._partition_id
|
150
|
+
|
151
|
+
@partition_id.setter
|
152
|
+
def partition_id(self, value: int) -> None:
|
153
|
+
"""Set patition_id."""
|
154
|
+
self._partition_id = value
|
155
|
+
|
140
156
|
|
141
157
|
@dataclass
|
142
158
|
class Message:
|
@@ -202,6 +218,7 @@ class Message:
|
|
202
218
|
group_id=self.metadata.group_id,
|
203
219
|
ttl=ttl,
|
204
220
|
message_type=self.metadata.message_type,
|
221
|
+
partition_id=self.metadata.partition_id,
|
205
222
|
),
|
206
223
|
content=content,
|
207
224
|
)
|
@@ -22,8 +22,6 @@ import threading
|
|
22
22
|
from logging import ERROR, INFO, WARN
|
23
23
|
from os.path import isfile
|
24
24
|
from pathlib import Path
|
25
|
-
from signal import SIGINT, SIGTERM, signal
|
26
|
-
from types import FrameType
|
27
25
|
from typing import List, Optional, Tuple
|
28
26
|
|
29
27
|
import grpc
|
@@ -36,6 +34,7 @@ from flwr.common.constant import (
|
|
36
34
|
TRANSPORT_TYPE_REST,
|
37
35
|
TRANSPORT_TYPE_VCE,
|
38
36
|
)
|
37
|
+
from flwr.common.exit_handlers import register_exit_handlers
|
39
38
|
from flwr.common.logger import log
|
40
39
|
from flwr.proto.driver_pb2_grpc import ( # pylint: disable=E0611
|
41
40
|
add_DriverServicer_to_server,
|
@@ -212,10 +211,10 @@ def run_driver_api() -> None:
|
|
212
211
|
)
|
213
212
|
|
214
213
|
# Graceful shutdown
|
215
|
-
|
214
|
+
register_exit_handlers(
|
215
|
+
event_type=EventType.RUN_DRIVER_API_LEAVE,
|
216
216
|
grpc_servers=[grpc_server],
|
217
217
|
bckg_threads=[],
|
218
|
-
event_type=EventType.RUN_DRIVER_API_LEAVE,
|
219
218
|
)
|
220
219
|
|
221
220
|
# Block
|
@@ -280,10 +279,10 @@ def run_fleet_api() -> None:
|
|
280
279
|
raise ValueError(f"Unknown fleet_api_type: {args.fleet_api_type}")
|
281
280
|
|
282
281
|
# Graceful shutdown
|
283
|
-
|
282
|
+
register_exit_handlers(
|
283
|
+
event_type=EventType.RUN_FLEET_API_LEAVE,
|
284
284
|
grpc_servers=grpc_servers,
|
285
285
|
bckg_threads=bckg_threads,
|
286
|
-
event_type=EventType.RUN_FLEET_API_LEAVE,
|
287
286
|
)
|
288
287
|
|
289
288
|
# Block
|
@@ -375,10 +374,10 @@ def run_superlink() -> None:
|
|
375
374
|
raise ValueError(f"Unknown fleet_api_type: {args.fleet_api_type}")
|
376
375
|
|
377
376
|
# Graceful shutdown
|
378
|
-
|
377
|
+
register_exit_handlers(
|
378
|
+
event_type=EventType.RUN_SUPERLINK_LEAVE,
|
379
379
|
grpc_servers=grpc_servers,
|
380
380
|
bckg_threads=bckg_threads,
|
381
|
-
event_type=EventType.RUN_SUPERLINK_LEAVE,
|
382
381
|
)
|
383
382
|
|
384
383
|
# Block
|
@@ -413,52 +412,6 @@ def _try_obtain_certificates(
|
|
413
412
|
return certificates
|
414
413
|
|
415
414
|
|
416
|
-
def _register_exit_handlers(
|
417
|
-
grpc_servers: List[grpc.Server],
|
418
|
-
bckg_threads: List[threading.Thread],
|
419
|
-
event_type: EventType,
|
420
|
-
) -> None:
|
421
|
-
default_handlers = {
|
422
|
-
SIGINT: None,
|
423
|
-
SIGTERM: None,
|
424
|
-
}
|
425
|
-
|
426
|
-
def graceful_exit_handler( # type: ignore
|
427
|
-
signalnum,
|
428
|
-
frame: FrameType, # pylint: disable=unused-argument
|
429
|
-
) -> None:
|
430
|
-
"""Exit handler to be registered with signal.signal.
|
431
|
-
|
432
|
-
When called will reset signal handler to original signal handler from
|
433
|
-
default_handlers.
|
434
|
-
"""
|
435
|
-
# Reset to default handler
|
436
|
-
signal(signalnum, default_handlers[signalnum])
|
437
|
-
|
438
|
-
event_res = event(event_type=event_type)
|
439
|
-
|
440
|
-
for grpc_server in grpc_servers:
|
441
|
-
grpc_server.stop(grace=1)
|
442
|
-
|
443
|
-
for bckg_thread in bckg_threads:
|
444
|
-
bckg_thread.join()
|
445
|
-
|
446
|
-
# Ensure event has happend
|
447
|
-
event_res.result()
|
448
|
-
|
449
|
-
# Setup things for graceful exit
|
450
|
-
sys.exit(0)
|
451
|
-
|
452
|
-
default_handlers[SIGINT] = signal( # type: ignore
|
453
|
-
SIGINT,
|
454
|
-
graceful_exit_handler, # type: ignore
|
455
|
-
)
|
456
|
-
default_handlers[SIGTERM] = signal( # type: ignore
|
457
|
-
SIGTERM,
|
458
|
-
graceful_exit_handler, # type: ignore
|
459
|
-
)
|
460
|
-
|
461
|
-
|
462
415
|
def _run_driver_api_grpc(
|
463
416
|
address: str,
|
464
417
|
state_factory: StateFactory,
|
@@ -44,6 +44,7 @@ class Driver:
|
|
44
44
|
Tuple containing root certificate, server certificate, and private key
|
45
45
|
to start a secure SSL-enabled server. The tuple is expected to have
|
46
46
|
three bytes elements in the following order:
|
47
|
+
|
47
48
|
* CA certificate.
|
48
49
|
* server certificate.
|
49
50
|
* server private key.
|
@@ -16,7 +16,10 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
from .bulyan import Bulyan as Bulyan
|
19
|
-
from .dp_fixed_clipping import
|
19
|
+
from .dp_fixed_clipping import (
|
20
|
+
DifferentialPrivacyClientSideFixedClipping,
|
21
|
+
DifferentialPrivacyServerSideFixedClipping,
|
22
|
+
)
|
20
23
|
from .dpfedavg_adaptive import DPFedAvgAdaptive as DPFedAvgAdaptive
|
21
24
|
from .dpfedavg_fixed import DPFedAvgFixed as DPFedAvgFixed
|
22
25
|
from .fault_tolerant_fedavg import FaultTolerantFedAvg as FaultTolerantFedAvg
|
@@ -59,4 +62,5 @@ __all__ = [
|
|
59
62
|
"DPFedAvgFixed",
|
60
63
|
"Strategy",
|
61
64
|
"DifferentialPrivacyServerSideFixedClipping",
|
65
|
+
"DifferentialPrivacyClientSideFixedClipping",
|
62
66
|
]
|
@@ -36,7 +36,10 @@ from flwr.common.differential_privacy import (
|
|
36
36
|
add_gaussian_noise_to_params,
|
37
37
|
compute_clip_model_update,
|
38
38
|
)
|
39
|
-
from flwr.common.differential_privacy_constants import
|
39
|
+
from flwr.common.differential_privacy_constants import (
|
40
|
+
CLIENTS_DISCREPANCY_WARNING,
|
41
|
+
KEY_CLIPPING_NORM,
|
42
|
+
)
|
40
43
|
from flwr.common.logger import log
|
41
44
|
from flwr.server.client_manager import ClientManager
|
42
45
|
from flwr.server.client_proxy import ClientProxy
|
@@ -44,7 +47,8 @@ from flwr.server.strategy.strategy import Strategy
|
|
44
47
|
|
45
48
|
|
46
49
|
class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
47
|
-
"""
|
50
|
+
"""Strategy wrapper for central differential privacy with server-side fixed
|
51
|
+
clipping.
|
48
52
|
|
49
53
|
Parameters
|
50
54
|
----------
|
@@ -185,3 +189,153 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
|
|
185
189
|
) -> Optional[Tuple[float, Dict[str, Scalar]]]:
|
186
190
|
"""Evaluate model parameters using an evaluation function from the strategy."""
|
187
191
|
return self.strategy.evaluate(server_round, parameters)
|
192
|
+
|
193
|
+
|
194
|
+
class DifferentialPrivacyClientSideFixedClipping(Strategy):
|
195
|
+
"""Strategy wrapper for central differential privacy with client-side fixed
|
196
|
+
clipping.
|
197
|
+
|
198
|
+
Use `fixedclipping_mod` modifier at the client side.
|
199
|
+
|
200
|
+
In comparison to `DifferentialPrivacyServerSideFixedClipping`,
|
201
|
+
which performs clipping on the server-side, `DifferentialPrivacyClientSideFixedClipping`
|
202
|
+
expects clipping to happen on the client-side, usually by using the built-in
|
203
|
+
`fixedclipping_mod `.
|
204
|
+
|
205
|
+
Parameters
|
206
|
+
----------
|
207
|
+
strategy : Strategy
|
208
|
+
The strategy to which DP functionalities will be added by this wrapper.
|
209
|
+
noise_multiplier : float
|
210
|
+
The noise multiplier for the Gaussian mechanism for model updates.
|
211
|
+
A value of 1.0 or higher is recommended for strong privacy.
|
212
|
+
clipping_norm : float
|
213
|
+
The value of the clipping norm.
|
214
|
+
num_sampled_clients : int
|
215
|
+
The number of clients that are sampled on each round.
|
216
|
+
|
217
|
+
Examples
|
218
|
+
--------
|
219
|
+
Create a strategy:
|
220
|
+
|
221
|
+
>>> strategy = fl.server.strategy.FedAvg(...)
|
222
|
+
|
223
|
+
Wrap the strategy with the `DifferentialPrivacyServerSideFixedClipping` wrapper:
|
224
|
+
|
225
|
+
>>> DifferentialPrivacyClientSideFixedClipping(
|
226
|
+
>>> strategy, cfg.noise_multiplier, cfg.clipping_norm, cfg.num_sampled_clients
|
227
|
+
>>> )
|
228
|
+
|
229
|
+
On the client, add the `fixedclipping_mod` to the client-side mods:
|
230
|
+
|
231
|
+
>>> app = fl.client.ClientApp(
|
232
|
+
>>> client_fn=FlowerClient().to_client(), mods=[fixedclipping_mod]
|
233
|
+
>>> )
|
234
|
+
"""
|
235
|
+
|
236
|
+
# pylint: disable=too-many-arguments,too-many-instance-attributes
|
237
|
+
def __init__(
|
238
|
+
self,
|
239
|
+
strategy: Strategy,
|
240
|
+
noise_multiplier: float,
|
241
|
+
clipping_norm: float,
|
242
|
+
num_sampled_clients: int,
|
243
|
+
) -> None:
|
244
|
+
super().__init__()
|
245
|
+
|
246
|
+
self.strategy = strategy
|
247
|
+
|
248
|
+
if noise_multiplier < 0:
|
249
|
+
raise ValueError("The noise multiplier should be a non-negative value.")
|
250
|
+
|
251
|
+
if clipping_norm <= 0:
|
252
|
+
raise ValueError("The clipping threshold should be a positive value.")
|
253
|
+
|
254
|
+
if num_sampled_clients <= 0:
|
255
|
+
raise ValueError(
|
256
|
+
"The number of sampled clients should be a positive value."
|
257
|
+
)
|
258
|
+
|
259
|
+
self.noise_multiplier = noise_multiplier
|
260
|
+
self.clipping_norm = clipping_norm
|
261
|
+
self.num_sampled_clients = num_sampled_clients
|
262
|
+
|
263
|
+
def __repr__(self) -> str:
|
264
|
+
"""Compute a string representation of the strategy."""
|
265
|
+
rep = "Differential Privacy Strategy Wrapper (Client-Side Fixed Clipping)"
|
266
|
+
return rep
|
267
|
+
|
268
|
+
def initialize_parameters(
|
269
|
+
self, client_manager: ClientManager
|
270
|
+
) -> Optional[Parameters]:
|
271
|
+
"""Initialize global model parameters using given strategy."""
|
272
|
+
return self.strategy.initialize_parameters(client_manager)
|
273
|
+
|
274
|
+
def configure_fit(
|
275
|
+
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
276
|
+
) -> List[Tuple[ClientProxy, FitIns]]:
|
277
|
+
"""Configure the next round of training."""
|
278
|
+
additional_config = {KEY_CLIPPING_NORM: self.clipping_norm}
|
279
|
+
inner_strategy_config_result = self.strategy.configure_fit(
|
280
|
+
server_round, parameters, client_manager
|
281
|
+
)
|
282
|
+
for _, fit_ins in inner_strategy_config_result:
|
283
|
+
fit_ins.config.update(additional_config)
|
284
|
+
|
285
|
+
return inner_strategy_config_result
|
286
|
+
|
287
|
+
def configure_evaluate(
|
288
|
+
self, server_round: int, parameters: Parameters, client_manager: ClientManager
|
289
|
+
) -> List[Tuple[ClientProxy, EvaluateIns]]:
|
290
|
+
"""Configure the next round of evaluation."""
|
291
|
+
return self.strategy.configure_evaluate(
|
292
|
+
server_round, parameters, client_manager
|
293
|
+
)
|
294
|
+
|
295
|
+
def aggregate_fit(
|
296
|
+
self,
|
297
|
+
server_round: int,
|
298
|
+
results: List[Tuple[ClientProxy, FitRes]],
|
299
|
+
failures: List[Union[Tuple[ClientProxy, FitRes], BaseException]],
|
300
|
+
) -> Tuple[Optional[Parameters], Dict[str, Scalar]]:
|
301
|
+
"""Add noise to the aggregated parameters."""
|
302
|
+
if failures:
|
303
|
+
return None, {}
|
304
|
+
|
305
|
+
if len(results) != self.num_sampled_clients:
|
306
|
+
log(
|
307
|
+
WARNING,
|
308
|
+
CLIENTS_DISCREPANCY_WARNING,
|
309
|
+
len(results),
|
310
|
+
self.num_sampled_clients,
|
311
|
+
)
|
312
|
+
|
313
|
+
# Pass the new parameters for aggregation
|
314
|
+
aggregated_params, metrics = self.strategy.aggregate_fit(
|
315
|
+
server_round, results, failures
|
316
|
+
)
|
317
|
+
|
318
|
+
# Add Gaussian noise to the aggregated parameters
|
319
|
+
if aggregated_params:
|
320
|
+
aggregated_params = add_gaussian_noise_to_params(
|
321
|
+
aggregated_params,
|
322
|
+
self.noise_multiplier,
|
323
|
+
self.clipping_norm,
|
324
|
+
self.num_sampled_clients,
|
325
|
+
)
|
326
|
+
return aggregated_params, metrics
|
327
|
+
|
328
|
+
def aggregate_evaluate(
|
329
|
+
self,
|
330
|
+
server_round: int,
|
331
|
+
results: List[Tuple[ClientProxy, EvaluateRes]],
|
332
|
+
failures: List[Union[Tuple[ClientProxy, EvaluateRes], BaseException]],
|
333
|
+
) -> Tuple[Optional[float], Dict[str, Scalar]]:
|
334
|
+
"""Aggregate evaluation losses using the given strategy."""
|
335
|
+
return self.strategy.aggregate_evaluate(server_round, results, failures)
|
336
|
+
|
337
|
+
def evaluate(
|
338
|
+
self, server_round: int, parameters: Parameters
|
339
|
+
) -> Optional[Tuple[float, Dict[str, Scalar]]]:
|
340
|
+
"""Evaluate model parameters using an evaluation function from the strategy."""
|
341
|
+
return self.strategy.evaluate(server_round, parameters)
|
@@ -18,7 +18,7 @@
|
|
18
18
|
from abc import ABC, abstractmethod
|
19
19
|
from typing import Callable, Dict, Tuple
|
20
20
|
|
21
|
-
from flwr.client.
|
21
|
+
from flwr.client.client_app import ClientApp
|
22
22
|
from flwr.common.context import Context
|
23
23
|
from flwr.common.message import Message
|
24
24
|
from flwr.common.typing import ConfigsRecordValues
|
@@ -53,6 +53,10 @@ class Backend(ABC):
|
|
53
53
|
def is_worker_idle(self) -> bool:
|
54
54
|
"""Report whether a backend worker is idle and can therefore run a ClientApp."""
|
55
55
|
|
56
|
+
@abstractmethod
|
57
|
+
async def terminate(self) -> None:
|
58
|
+
"""Terminate backend."""
|
59
|
+
|
56
60
|
@abstractmethod
|
57
61
|
async def process_message(
|
58
62
|
self,
|