flwr-nightly 1.8.0.dev20240227__tar.gz → 1.8.0.dev20240229__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/PKG-INFO +4 -3
  2. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/README.md +2 -1
  3. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/pyproject.toml +3 -2
  4. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/mod/__init__.py +3 -2
  5. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/mod/centraldp_mods.py +63 -2
  6. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +55 -75
  7. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/differential_privacy.py +77 -0
  8. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/differential_privacy_constants.py +1 -0
  9. flwr_nightly-1.8.0.dev20240229/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +68 -0
  10. flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/error_pb2.py +26 -0
  11. flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/error_pb2.pyi +25 -0
  12. flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/task_pb2.py +34 -0
  13. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/task_pb2.pyi +7 -2
  14. flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/task_pb2_grpc.py +4 -0
  15. flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/task_pb2_grpc.pyi +4 -0
  16. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/__init__.py +4 -0
  17. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/app.py +8 -31
  18. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/client_proxy.py +5 -0
  19. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/compat/__init__.py +2 -0
  20. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/compat/app.py +7 -88
  21. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/compat/app_utils.py +102 -0
  22. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/compat/driver_client_proxy.py +22 -10
  23. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/compat/legacy_context.py +55 -0
  24. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/run_serverapp.py +1 -1
  25. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/server.py +18 -8
  26. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/__init__.py +24 -14
  27. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/strategy/dp_adaptive_clipping.py +449 -0
  28. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/dp_fixed_clipping.py +5 -7
  29. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/superlink/driver/driver_grpc.py +54 -0
  30. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/driver/driver_servicer.py +4 -4
  31. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +5 -0
  32. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/vce/__init__.py +1 -1
  33. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +3 -4
  34. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/superlink/fleet/vce/vce_api.py +312 -0
  35. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/typing.py +1 -0
  36. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/workflow/__init__.py +22 -0
  37. flwr_nightly-1.8.0.dev20240229/src/py/flwr/server/workflow/default_workflows.py +357 -0
  38. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/simulation/__init__.py +3 -0
  39. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +28 -8
  40. flwr_nightly-1.8.0.dev20240229/src/py/flwr/simulation/run_simulation.py +177 -0
  41. flwr_nightly-1.8.0.dev20240227/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -46
  42. flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/task_pb2.py +0 -33
  43. flwr_nightly-1.8.0.dev20240227/src/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -92
  44. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/LICENSE +0 -0
  45. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/__init__.py +0 -0
  46. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/__init__.py +0 -0
  47. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/app.py +0 -0
  48. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/example.py +0 -0
  49. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/__init__.py +0 -0
  50. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/new.py +0 -0
  51. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/__init__.py +0 -0
  52. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
  53. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
  54. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  55. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  56. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  57. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  58. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  59. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  60. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/flower.toml.tpl +0 -0
  61. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -0
  62. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -0
  63. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/cli/utils.py +0 -0
  64. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/__init__.py +0 -0
  65. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/app.py +0 -0
  66. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/client.py +0 -0
  67. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/client_app.py +0 -0
  68. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  69. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/grpc_client/__init__.py +0 -0
  70. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/grpc_client/connection.py +0 -0
  71. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  72. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/grpc_rere_client/connection.py +0 -0
  73. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/message_handler/__init__.py +0 -0
  74. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/message_handler/message_handler.py +0 -0
  75. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/message_handler/task_handler.py +0 -0
  76. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  77. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/mod/utils.py +0 -0
  78. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/node_state.py +0 -0
  79. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/node_state_tests.py +0 -0
  80. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/numpy_client.py +0 -0
  81. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/rest_client/__init__.py +0 -0
  82. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/rest_client/connection.py +0 -0
  83. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/client/typing.py +0 -0
  84. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/__init__.py +0 -0
  85. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/address.py +0 -0
  86. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/constant.py +0 -0
  87. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/context.py +0 -0
  88. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/date.py +0 -0
  89. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/dp.py +0 -0
  90. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/exit_handlers.py +0 -0
  91. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/grpc.py +0 -0
  92. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/logger.py +0 -0
  93. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/message.py +0 -0
  94. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/parameter.py +0 -0
  95. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/__init__.py +0 -0
  96. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/configsrecord.py +0 -0
  97. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/conversion_utils.py +0 -0
  98. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/metricsrecord.py +0 -0
  99. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/parametersrecord.py +0 -0
  100. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/recordset.py +0 -0
  101. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/record/typeddict.py +0 -0
  102. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/recordset_compat.py +0 -0
  103. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/retry_invoker.py +0 -0
  104. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
  105. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  106. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  107. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
  108. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  109. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
  110. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  111. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/serde.py +0 -0
  112. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/telemetry.py +0 -0
  113. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/typing.py +0 -0
  114. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/common/version.py +0 -0
  115. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/__init__.py +0 -0
  116. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/driver_pb2.py +0 -0
  117. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/driver_pb2.pyi +0 -0
  118. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
  119. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
  120. /flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/node_pb2_grpc.py → /flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/error_pb2_grpc.py +0 -0
  121. /flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/node_pb2_grpc.pyi → /flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  122. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/fleet_pb2.py +0 -0
  123. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
  124. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
  125. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
  126. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/node_pb2.py +0 -0
  127. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/node_pb2.pyi +0 -0
  128. /flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/recordset_pb2_grpc.py → /flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/node_pb2_grpc.py +0 -0
  129. /flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/recordset_pb2_grpc.pyi → /flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  130. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/recordset_pb2.py +0 -0
  131. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
  132. /flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/task_pb2_grpc.py → /flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
  133. /flwr_nightly-1.8.0.dev20240227/src/py/flwr/proto/task_pb2_grpc.pyi → /flwr_nightly-1.8.0.dev20240229/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
  134. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/transport_pb2.py +0 -0
  135. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/transport_pb2.pyi +0 -0
  136. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
  137. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  138. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/py.typed +0 -0
  139. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/client_manager.py +0 -0
  140. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/criterion.py +0 -0
  141. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/driver/__init__.py +0 -0
  142. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/driver/driver.py +0 -0
  143. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/driver/grpc_driver.py +0 -0
  144. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/history.py +0 -0
  145. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/server_app.py +0 -0
  146. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/server_config.py +0 -0
  147. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/aggregate.py +0 -0
  148. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/bulyan.py +0 -0
  149. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  150. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  151. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  152. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
  153. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedadam.py +0 -0
  154. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedavg.py +0 -0
  155. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
  156. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedavgm.py +0 -0
  157. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedmedian.py +0 -0
  158. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedopt.py +0 -0
  159. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedprox.py +0 -0
  160. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  161. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  162. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  163. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  164. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/fedyogi.py +0 -0
  165. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/krum.py +0 -0
  166. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/qfedavg.py +0 -0
  167. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/strategy/strategy.py +0 -0
  168. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/__init__.py +0 -0
  169. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
  170. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
  171. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  172. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  173. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  174. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  175. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  176. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
  177. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  178. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
  179. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  180. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
  181. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  182. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  183. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/state/__init__.py +0 -0
  184. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/state/in_memory_state.py +0 -0
  185. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/state/sqlite_state.py +0 -0
  186. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/state/state.py +0 -0
  187. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
  188. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/utils/__init__.py +0 -0
  189. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/utils/tensorboard.py +0 -0
  190. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/server/utils/validator.py +0 -0
  191. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/simulation/app.py +0 -0
  192. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
  193. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
  194. {flwr_nightly-1.8.0.dev20240227 → flwr_nightly-1.8.0.dev20240229}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.8.0.dev20240227
3
+ Version: 1.8.0.dev20240229
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -32,7 +32,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
32
  Classifier: Typing :: Typed
33
33
  Provides-Extra: rest
34
34
  Provides-Extra: simulation
35
- Requires-Dist: cryptography (>=41.0.2,<42.0.0)
35
+ Requires-Dist: cryptography (>=42.0.4,<43.0.0)
36
36
  Requires-Dist: grpcio (>=1.60.0,<2.0.0)
37
37
  Requires-Dist: iterators (>=0.0.2,<0.0.3)
38
38
  Requires-Dist: numpy (>=1.21.0,<2.0.0)
@@ -83,7 +83,7 @@ design of Flower is based on a few guiding principles:
83
83
 
84
84
  - **Framework-agnostic**: Different machine learning frameworks have different
85
85
  strengths. Flower can be used with any machine learning framework, for
86
- example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
86
+ example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
87
87
  for users who enjoy computing gradients by hand.
88
88
 
89
89
  - **Understandable**: Flower is written with maintainability in mind. The
@@ -180,6 +180,7 @@ Quickstart examples:
180
180
  - [Quickstart (fastai)](https://github.com/adap/flower/tree/main/examples/quickstart-fastai)
181
181
  - [Quickstart (Pandas)](https://github.com/adap/flower/tree/main/examples/quickstart-pandas)
182
182
  - [Quickstart (JAX)](https://github.com/adap/flower/tree/main/examples/quickstart-jax)
183
+ - [Quickstart (MONAI)](https://github.com/adap/flower/tree/main/examples/quickstart-monai)
183
184
  - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/sklearn-logreg-mnist)
184
185
  - [Quickstart (XGBoost)](https://github.com/adap/flower/tree/main/examples/xgboost-quickstart)
185
186
  - [Quickstart (Android [TFLite])](https://github.com/adap/flower/tree/main/examples/android)
@@ -33,7 +33,7 @@ design of Flower is based on a few guiding principles:
33
33
 
34
34
  - **Framework-agnostic**: Different machine learning frameworks have different
35
35
  strengths. Flower can be used with any machine learning framework, for
36
- example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
36
+ example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
37
37
  for users who enjoy computing gradients by hand.
38
38
 
39
39
  - **Understandable**: Flower is written with maintainability in mind. The
@@ -130,6 +130,7 @@ Quickstart examples:
130
130
  - [Quickstart (fastai)](https://github.com/adap/flower/tree/main/examples/quickstart-fastai)
131
131
  - [Quickstart (Pandas)](https://github.com/adap/flower/tree/main/examples/quickstart-pandas)
132
132
  - [Quickstart (JAX)](https://github.com/adap/flower/tree/main/examples/quickstart-jax)
133
+ - [Quickstart (MONAI)](https://github.com/adap/flower/tree/main/examples/quickstart-monai)
133
134
  - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/sklearn-logreg-mnist)
134
135
  - [Quickstart (XGBoost)](https://github.com/adap/flower/tree/main/examples/xgboost-quickstart)
135
136
  - [Quickstart (Android [TFLite])](https://github.com/adap/flower/tree/main/examples/android)
@@ -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-dev20240227"
7
+ version = "1.8.0-dev20240229"
8
8
  description = "Flower: A Friendly Federated Learning Framework"
9
9
  license = "Apache-2.0"
10
10
  authors = ["The Flower Authors <hello@flower.ai>"]
@@ -58,6 +58,7 @@ flower-fleet-api = "flwr.server:run_fleet_api"
58
58
  flower-superlink = "flwr.server:run_superlink"
59
59
  flower-client-app = "flwr.client:run_client_app"
60
60
  flower-server-app = "flwr.server:run_server_app"
61
+ flower-simulation = "flwr.simulation:run_simulation"
61
62
 
62
63
  [tool.poetry.dependencies]
63
64
  python = "^3.8"
@@ -65,7 +66,7 @@ python = "^3.8"
65
66
  numpy = "^1.21.0"
66
67
  grpcio = "^1.60.0"
67
68
  protobuf = "^4.25.2"
68
- cryptography = "^41.0.2"
69
+ cryptography = "^42.0.4"
69
70
  pycryptodome = "^3.18.0"
70
71
  iterators = "^0.0.2"
71
72
  typer = { version = "^0.9.0", extras=["all"] }
@@ -15,12 +15,13 @@
15
15
  """Mods."""
16
16
 
17
17
 
18
- from .centraldp_mods import fixedclipping_mod
18
+ from .centraldp_mods import adaptiveclipping_mod, fixedclipping_mod
19
19
  from .secure_aggregation.secaggplus_mod import secaggplus_mod
20
20
  from .utils import make_ffn
21
21
 
22
22
  __all__ = [
23
+ "adaptiveclipping_mod",
24
+ "fixedclipping_mod",
23
25
  "make_ffn",
24
26
  "secaggplus_mod",
25
- "fixedclipping_mod",
26
27
  ]
@@ -20,8 +20,11 @@ from flwr.common import ndarrays_to_parameters, parameters_to_ndarrays
20
20
  from flwr.common import recordset_compat as compat
21
21
  from flwr.common.constant import MESSAGE_TYPE_FIT
22
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
23
+ from flwr.common.differential_privacy import (
24
+ compute_adaptive_clip_model_update,
25
+ compute_clip_model_update,
26
+ )
27
+ from flwr.common.differential_privacy_constants import KEY_CLIPPING_NORM, KEY_NORM_BIT
25
28
  from flwr.common.message import Message
26
29
 
27
30
 
@@ -74,3 +77,61 @@ def fixedclipping_mod(
74
77
  fit_res.parameters = ndarrays_to_parameters(client_to_server_params)
75
78
  out_msg.content = compat.fitres_to_recordset(fit_res, keep_input=True)
76
79
  return out_msg
80
+
81
+
82
+ def adaptiveclipping_mod(
83
+ msg: Message, ctxt: Context, call_next: ClientAppCallable
84
+ ) -> Message:
85
+ """Client-side adaptive clipping modifier.
86
+
87
+ This mod needs to be used with the DifferentialPrivacyClientSideAdaptiveClipping
88
+ server-side strategy wrapper.
89
+
90
+ The wrapper sends the clipping_norm value to the client.
91
+
92
+ This mod clips the client model updates before sending them to the server.
93
+
94
+ It also sends KEY_NORM_BIT to the server for computing the new clipping value.
95
+
96
+ It operates on messages with type MESSAGE_TYPE_FIT.
97
+
98
+ Notes
99
+ -----
100
+ Consider the order of mods when using multiple.
101
+
102
+ Typically, adaptiveclipping_mod should be the last to operate on params.
103
+ """
104
+ if msg.metadata.message_type != MESSAGE_TYPE_FIT:
105
+ return call_next(msg, ctxt)
106
+
107
+ fit_ins = compat.recordset_to_fitins(msg.content, keep_input=True)
108
+
109
+ if KEY_CLIPPING_NORM not in fit_ins.config:
110
+ raise KeyError(
111
+ f"The {KEY_CLIPPING_NORM} value is not supplied by the "
112
+ f"DifferentialPrivacyClientSideFixedClipping wrapper at"
113
+ f" the server side."
114
+ )
115
+ if not isinstance(fit_ins.config[KEY_CLIPPING_NORM], float):
116
+ raise ValueError(f"{KEY_CLIPPING_NORM} should be a float value.")
117
+ clipping_norm = float(fit_ins.config[KEY_CLIPPING_NORM])
118
+ server_to_client_params = parameters_to_ndarrays(fit_ins.parameters)
119
+
120
+ # Call inner app
121
+ out_msg = call_next(msg, ctxt)
122
+ fit_res = compat.recordset_to_fitres(out_msg.content, keep_input=True)
123
+
124
+ client_to_server_params = parameters_to_ndarrays(fit_res.parameters)
125
+
126
+ # Clip the client update
127
+ norm_bit = compute_adaptive_clip_model_update(
128
+ client_to_server_params,
129
+ server_to_client_params,
130
+ clipping_norm,
131
+ )
132
+
133
+ fit_res.parameters = ndarrays_to_parameters(client_to_server_params)
134
+
135
+ fit_res.metrics[KEY_NORM_BIT] = norm_bit
136
+ out_msg.content = compat.fitres_to_recordset(fit_res, keep_input=True)
137
+ return out_msg
@@ -52,31 +52,10 @@ from flwr.common.secure_aggregation.ndarrays_arithmetic import (
52
52
  )
53
53
  from flwr.common.secure_aggregation.quantization import quantize
54
54
  from flwr.common.secure_aggregation.secaggplus_constants import (
55
- KEY_ACTIVE_SECURE_ID_LIST,
56
- KEY_CIPHERTEXT_LIST,
57
- KEY_CLIPPING_RANGE,
58
- KEY_DEAD_SECURE_ID_LIST,
59
- KEY_DESTINATION_LIST,
60
- KEY_MASKED_PARAMETERS,
61
- KEY_MOD_RANGE,
62
- KEY_PUBLIC_KEY_1,
63
- KEY_PUBLIC_KEY_2,
64
- KEY_SAMPLE_NUMBER,
65
- KEY_SECURE_ID,
66
- KEY_SECURE_ID_LIST,
67
- KEY_SHARE_LIST,
68
- KEY_SHARE_NUMBER,
69
- KEY_SOURCE_LIST,
70
- KEY_STAGE,
71
- KEY_TARGET_RANGE,
72
- KEY_THRESHOLD,
73
55
  RECORD_KEY_CONFIGS,
74
56
  RECORD_KEY_STATE,
75
- STAGE_COLLECT_MASKED_INPUT,
76
- STAGE_SETUP,
77
- STAGE_SHARE_KEYS,
78
- STAGE_UNMASK,
79
- STAGES,
57
+ Key,
58
+ Stage,
80
59
  )
81
60
  from flwr.common.secure_aggregation.secaggplus_utils import (
82
61
  pseudo_rand_gen,
@@ -91,7 +70,7 @@ from flwr.common.typing import ConfigsRecordValues, FitRes
91
70
  class SecAggPlusState:
92
71
  """State of the SecAgg+ protocol."""
93
72
 
94
- current_stage: str = STAGE_UNMASK
73
+ current_stage: str = Stage.UNMASK
95
74
 
96
75
  sid: int = 0
97
76
  sample_num: int = 0
@@ -187,20 +166,20 @@ def secaggplus_mod(
187
166
  check_stage(state.current_stage, configs)
188
167
 
189
168
  # Update the current stage
190
- state.current_stage = cast(str, configs.pop(KEY_STAGE))
169
+ state.current_stage = cast(str, configs.pop(Key.STAGE))
191
170
 
192
171
  # Check the validity of the configs based on the current stage
193
172
  check_configs(state.current_stage, configs)
194
173
 
195
174
  # Execute
196
- if state.current_stage == STAGE_SETUP:
175
+ if state.current_stage == Stage.SETUP:
197
176
  res = _setup(state, configs)
198
- elif state.current_stage == STAGE_SHARE_KEYS:
177
+ elif state.current_stage == Stage.SHARE_KEYS:
199
178
  res = _share_keys(state, configs)
200
- elif state.current_stage == STAGE_COLLECT_MASKED_INPUT:
179
+ elif state.current_stage == Stage.COLLECT_MASKED_INPUT:
201
180
  fit = _get_fit_fn(msg, ctxt, call_next)
202
181
  res = _collect_masked_input(state, configs, fit)
203
- elif state.current_stage == STAGE_UNMASK:
182
+ elif state.current_stage == Stage.UNMASK:
204
183
  res = _unmask(state, configs)
205
184
  else:
206
185
  raise ValueError(f"Unknown secagg stage: {state.current_stage}")
@@ -215,28 +194,29 @@ def secaggplus_mod(
215
194
 
216
195
  def check_stage(current_stage: str, configs: ConfigsRecord) -> None:
217
196
  """Check the validity of the next stage."""
218
- # Check the existence of KEY_STAGE
219
- if KEY_STAGE not in configs:
197
+ # Check the existence of Config.STAGE
198
+ if Key.STAGE not in configs:
220
199
  raise KeyError(
221
- f"The required key '{KEY_STAGE}' is missing from the input `named_values`."
200
+ f"The required key '{Key.STAGE}' is missing from the input `named_values`."
222
201
  )
223
202
 
224
- # Check the value type of the KEY_STAGE
225
- next_stage = configs[KEY_STAGE]
203
+ # Check the value type of the Config.STAGE
204
+ next_stage = configs[Key.STAGE]
226
205
  if not isinstance(next_stage, str):
227
206
  raise TypeError(
228
- f"The value for the key '{KEY_STAGE}' must be of type {str}, "
207
+ f"The value for the key '{Key.STAGE}' must be of type {str}, "
229
208
  f"but got {type(next_stage)} instead."
230
209
  )
231
210
 
232
211
  # Check the validity of the next stage
233
- if next_stage == STAGE_SETUP:
234
- if current_stage != STAGE_UNMASK:
212
+ if next_stage == Stage.SETUP:
213
+ if current_stage != Stage.UNMASK:
235
214
  log(WARNING, "Restart from the setup stage")
236
215
  # If stage is not "setup",
237
216
  # the stage from `named_values` should be the expected next stage
238
217
  else:
239
- expected_next_stage = STAGES[(STAGES.index(current_stage) + 1) % len(STAGES)]
218
+ stages = Stage.all()
219
+ expected_next_stage = stages[(stages.index(current_stage) + 1) % len(stages)]
240
220
  if next_stage != expected_next_stage:
241
221
  raise ValueError(
242
222
  "Abort secure aggregation: "
@@ -248,20 +228,20 @@ def check_stage(current_stage: str, configs: ConfigsRecord) -> None:
248
228
  def check_configs(stage: str, configs: ConfigsRecord) -> None:
249
229
  """Check the validity of the configs."""
250
230
  # Check `named_values` for the setup stage
251
- if stage == STAGE_SETUP:
231
+ if stage == Stage.SETUP:
252
232
  key_type_pairs = [
253
- (KEY_SAMPLE_NUMBER, int),
254
- (KEY_SECURE_ID, int),
255
- (KEY_SHARE_NUMBER, int),
256
- (KEY_THRESHOLD, int),
257
- (KEY_CLIPPING_RANGE, float),
258
- (KEY_TARGET_RANGE, int),
259
- (KEY_MOD_RANGE, int),
233
+ (Key.SAMPLE_NUMBER, int),
234
+ (Key.SECURE_ID, int),
235
+ (Key.SHARE_NUMBER, int),
236
+ (Key.THRESHOLD, int),
237
+ (Key.CLIPPING_RANGE, float),
238
+ (Key.TARGET_RANGE, int),
239
+ (Key.MOD_RANGE, int),
260
240
  ]
261
241
  for key, expected_type in key_type_pairs:
262
242
  if key not in configs:
263
243
  raise KeyError(
264
- f"Stage {STAGE_SETUP}: the required key '{key}' is "
244
+ f"Stage {Stage.SETUP}: the required key '{key}' is "
265
245
  "missing from the input `named_values`."
266
246
  )
267
247
  # Bool is a subclass of int in Python,
@@ -269,11 +249,11 @@ def check_configs(stage: str, configs: ConfigsRecord) -> None:
269
249
  # pylint: disable-next=unidiomatic-typecheck
270
250
  if type(configs[key]) is not expected_type:
271
251
  raise TypeError(
272
- f"Stage {STAGE_SETUP}: The value for the key '{key}' "
252
+ f"Stage {Stage.SETUP}: The value for the key '{key}' "
273
253
  f"must be of type {expected_type}, "
274
254
  f"but got {type(configs[key])} instead."
275
255
  )
276
- elif stage == STAGE_SHARE_KEYS:
256
+ elif stage == Stage.SHARE_KEYS:
277
257
  for key, value in configs.items():
278
258
  if (
279
259
  not isinstance(value, list)
@@ -282,18 +262,18 @@ def check_configs(stage: str, configs: ConfigsRecord) -> None:
282
262
  or not isinstance(value[1], bytes)
283
263
  ):
284
264
  raise TypeError(
285
- f"Stage {STAGE_SHARE_KEYS}: "
265
+ f"Stage {Stage.SHARE_KEYS}: "
286
266
  f"the value for the key '{key}' must be a list of two bytes."
287
267
  )
288
- elif stage == STAGE_COLLECT_MASKED_INPUT:
268
+ elif stage == Stage.COLLECT_MASKED_INPUT:
289
269
  key_type_pairs = [
290
- (KEY_CIPHERTEXT_LIST, bytes),
291
- (KEY_SOURCE_LIST, int),
270
+ (Key.CIPHERTEXT_LIST, bytes),
271
+ (Key.SOURCE_LIST, int),
292
272
  ]
293
273
  for key, expected_type in key_type_pairs:
294
274
  if key not in configs:
295
275
  raise KeyError(
296
- f"Stage {STAGE_COLLECT_MASKED_INPUT}: "
276
+ f"Stage {Stage.COLLECT_MASKED_INPUT}: "
297
277
  f"the required key '{key}' is "
298
278
  "missing from the input `named_values`."
299
279
  )
@@ -304,19 +284,19 @@ def check_configs(stage: str, configs: ConfigsRecord) -> None:
304
284
  if type(elm) is not expected_type
305
285
  ):
306
286
  raise TypeError(
307
- f"Stage {STAGE_COLLECT_MASKED_INPUT}: "
287
+ f"Stage {Stage.COLLECT_MASKED_INPUT}: "
308
288
  f"the value for the key '{key}' "
309
289
  f"must be of type List[{expected_type.__name__}]"
310
290
  )
311
- elif stage == STAGE_UNMASK:
291
+ elif stage == Stage.UNMASK:
312
292
  key_type_pairs = [
313
- (KEY_ACTIVE_SECURE_ID_LIST, int),
314
- (KEY_DEAD_SECURE_ID_LIST, int),
293
+ (Key.ACTIVE_SECURE_ID_LIST, int),
294
+ (Key.DEAD_SECURE_ID_LIST, int),
315
295
  ]
316
296
  for key, expected_type in key_type_pairs:
317
297
  if key not in configs:
318
298
  raise KeyError(
319
- f"Stage {STAGE_UNMASK}: "
299
+ f"Stage {Stage.UNMASK}: "
320
300
  f"the required key '{key}' is "
321
301
  "missing from the input `named_values`."
322
302
  )
@@ -327,7 +307,7 @@ def check_configs(stage: str, configs: ConfigsRecord) -> None:
327
307
  if type(elm) is not expected_type
328
308
  ):
329
309
  raise TypeError(
330
- f"Stage {STAGE_UNMASK}: "
310
+ f"Stage {Stage.UNMASK}: "
331
311
  f"the value for the key '{key}' "
332
312
  f"must be of type List[{expected_type.__name__}]"
333
313
  )
@@ -340,15 +320,15 @@ def _setup(
340
320
  ) -> Dict[str, ConfigsRecordValues]:
341
321
  # Assigning parameter values to object fields
342
322
  sec_agg_param_dict = configs
343
- state.sample_num = cast(int, sec_agg_param_dict[KEY_SAMPLE_NUMBER])
344
- state.sid = cast(int, sec_agg_param_dict[KEY_SECURE_ID])
323
+ state.sample_num = cast(int, sec_agg_param_dict[Key.SAMPLE_NUMBER])
324
+ state.sid = cast(int, sec_agg_param_dict[Key.SECURE_ID])
345
325
  log(INFO, "Client %d: starting stage 0...", state.sid)
346
326
 
347
- state.share_num = cast(int, sec_agg_param_dict[KEY_SHARE_NUMBER])
348
- state.threshold = cast(int, sec_agg_param_dict[KEY_THRESHOLD])
349
- state.clipping_range = cast(float, sec_agg_param_dict[KEY_CLIPPING_RANGE])
350
- state.target_range = cast(int, sec_agg_param_dict[KEY_TARGET_RANGE])
351
- state.mod_range = cast(int, sec_agg_param_dict[KEY_MOD_RANGE])
327
+ state.share_num = cast(int, sec_agg_param_dict[Key.SHARE_NUMBER])
328
+ state.threshold = cast(int, sec_agg_param_dict[Key.THRESHOLD])
329
+ state.clipping_range = cast(float, sec_agg_param_dict[Key.CLIPPING_RANGE])
330
+ state.target_range = cast(int, sec_agg_param_dict[Key.TARGET_RANGE])
331
+ state.mod_range = cast(int, sec_agg_param_dict[Key.MOD_RANGE])
352
332
 
353
333
  # Dictionaries containing client secure IDs as keys
354
334
  # and their respective secret shares as values.
@@ -367,7 +347,7 @@ def _setup(
367
347
  state.sk1, state.pk1 = private_key_to_bytes(sk1), public_key_to_bytes(pk1)
368
348
  state.sk2, state.pk2 = private_key_to_bytes(sk2), public_key_to_bytes(pk2)
369
349
  log(INFO, "Client %d: stage 0 completes. uploading public keys...", state.sid)
370
- return {KEY_PUBLIC_KEY_1: state.pk1, KEY_PUBLIC_KEY_2: state.pk2}
350
+ return {Key.PUBLIC_KEY_1: state.pk1, Key.PUBLIC_KEY_2: state.pk2}
371
351
 
372
352
 
373
353
  # pylint: disable-next=too-many-locals
@@ -429,7 +409,7 @@ def _share_keys(
429
409
  ciphertexts.append(ciphertext)
430
410
 
431
411
  log(INFO, "Client %d: stage 1 completes. uploading key shares...", state.sid)
432
- return {KEY_DESTINATION_LIST: dsts, KEY_CIPHERTEXT_LIST: ciphertexts}
412
+ return {Key.DESTINATION_LIST: dsts, Key.CIPHERTEXT_LIST: ciphertexts}
433
413
 
434
414
 
435
415
  # pylint: disable-next=too-many-locals
@@ -440,8 +420,8 @@ def _collect_masked_input(
440
420
  ) -> Dict[str, ConfigsRecordValues]:
441
421
  log(INFO, "Client %d: starting stage 2...", state.sid)
442
422
  available_clients: List[int] = []
443
- ciphertexts = cast(List[bytes], configs[KEY_CIPHERTEXT_LIST])
444
- srcs = cast(List[int], configs[KEY_SOURCE_LIST])
423
+ ciphertexts = cast(List[bytes], configs[Key.CIPHERTEXT_LIST])
424
+ srcs = cast(List[int], configs[Key.SOURCE_LIST])
445
425
  if len(ciphertexts) + 1 < state.threshold:
446
426
  raise ValueError("Not enough available neighbour clients.")
447
427
 
@@ -505,7 +485,7 @@ def _collect_masked_input(
505
485
  quantized_parameters = parameters_mod(quantized_parameters, state.mod_range)
506
486
  log(INFO, "Client %d: stage 2 completes. uploading masked parameters...", state.sid)
507
487
  return {
508
- KEY_MASKED_PARAMETERS: [ndarray_to_bytes(arr) for arr in quantized_parameters]
488
+ Key.MASKED_PARAMETERS: [ndarray_to_bytes(arr) for arr in quantized_parameters]
509
489
  }
510
490
 
511
491
 
@@ -514,8 +494,8 @@ def _unmask(
514
494
  ) -> Dict[str, ConfigsRecordValues]:
515
495
  log(INFO, "Client %d: starting stage 3...", state.sid)
516
496
 
517
- active_sids = cast(List[int], configs[KEY_ACTIVE_SECURE_ID_LIST])
518
- dead_sids = cast(List[int], configs[KEY_DEAD_SECURE_ID_LIST])
497
+ active_sids = cast(List[int], configs[Key.ACTIVE_SECURE_ID_LIST])
498
+ dead_sids = cast(List[int], configs[Key.DEAD_SECURE_ID_LIST])
519
499
  # Send private mask seed share for every avaliable client (including itclient)
520
500
  # Send first private key share for building pairwise mask for every dropped client
521
501
  if len(active_sids) < state.threshold:
@@ -528,4 +508,4 @@ def _unmask(
528
508
  shares += [state.sk1_share_dict[sid] for sid in dead_sids]
529
509
 
530
510
  log(INFO, "Client %d: stage 3 completes. uploading key shares...", state.sid)
531
- return {KEY_SECURE_ID_LIST: sids, KEY_SHARE_LIST: shares}
511
+ return {Key.SECURE_ID_LIST: sids, Key.SHARE_LIST: shares}
@@ -15,6 +15,9 @@
15
15
  """Utility functions for differential privacy."""
16
16
 
17
17
 
18
+ from logging import WARNING
19
+ from typing import Optional, Tuple
20
+
18
21
  import numpy as np
19
22
 
20
23
  from flwr.common import (
@@ -23,6 +26,7 @@ from flwr.common import (
23
26
  ndarrays_to_parameters,
24
27
  parameters_to_ndarrays,
25
28
  )
29
+ from flwr.common.logger import log
26
30
 
27
31
 
28
32
  def get_norm(input_arrays: NDArrays) -> float:
@@ -72,6 +76,36 @@ def compute_clip_model_update(
72
76
  param1[i] = param2[i] + model_update[i]
73
77
 
74
78
 
79
+ def adaptive_clip_inputs_inplace(input_arrays: NDArrays, clipping_norm: float) -> bool:
80
+ """Clip model update based on the clipping norm in-place.
81
+
82
+ It returns true if scaling_factor < 1 which is used for norm_bit
83
+ FlatClip method of the paper: https://arxiv.org/abs/1710.06963
84
+ """
85
+ input_norm = get_norm(input_arrays)
86
+ scaling_factor = min(1, clipping_norm / input_norm)
87
+ for array in input_arrays:
88
+ array *= scaling_factor
89
+ return scaling_factor < 1
90
+
91
+
92
+ def compute_adaptive_clip_model_update(
93
+ param1: NDArrays, param2: NDArrays, clipping_norm: float
94
+ ) -> bool:
95
+ """Compute model update, clip it, then add the clipped value to param1.
96
+
97
+ model update = param1 - param2
98
+ Return the norm_bit
99
+ """
100
+ model_update = [np.subtract(x, y) for (x, y) in zip(param1, param2)]
101
+ norm_bit = adaptive_clip_inputs_inplace(model_update, clipping_norm)
102
+
103
+ for i, _ in enumerate(param2):
104
+ param1[i] = param2[i] + model_update[i]
105
+
106
+ return norm_bit
107
+
108
+
75
109
  def add_gaussian_noise_to_params(
76
110
  model_params: Parameters,
77
111
  noise_multiplier: float,
@@ -85,3 +119,46 @@ def add_gaussian_noise_to_params(
85
119
  compute_stdv(noise_multiplier, clipping_norm, num_sampled_clients),
86
120
  )
87
121
  return ndarrays_to_parameters(model_params_ndarrays)
122
+
123
+
124
+ def compute_adaptive_noise_params(
125
+ noise_multiplier: float,
126
+ num_sampled_clients: float,
127
+ clipped_count_stddev: Optional[float],
128
+ ) -> Tuple[float, float]:
129
+ """Compute noising parameters for the adaptive clipping.
130
+
131
+ Paper: https://arxiv.org/abs/1905.03871
132
+ """
133
+ if noise_multiplier > 0:
134
+ if clipped_count_stddev is None:
135
+ clipped_count_stddev = num_sampled_clients / 20
136
+ if noise_multiplier >= 2 * clipped_count_stddev:
137
+ raise ValueError(
138
+ f"If not specified, `clipped_count_stddev` is set to "
139
+ f"`num_sampled_clients`/20 by default. This value "
140
+ f"({num_sampled_clients / 20}) is too low to achieve the "
141
+ f"desired effective `noise_multiplier` ({noise_multiplier}). "
142
+ f"Consider increasing `clipped_count_stddev` or decreasing "
143
+ f"`noise_multiplier`."
144
+ )
145
+ noise_multiplier_value = (
146
+ noise_multiplier ** (-2) - (2 * clipped_count_stddev) ** (-2)
147
+ ) ** -0.5
148
+
149
+ adding_noise = noise_multiplier_value / noise_multiplier
150
+ if adding_noise >= 2:
151
+ log(
152
+ WARNING,
153
+ "A significant amount of noise (%s) has to be "
154
+ "added. Consider increasing `clipped_count_stddev` or "
155
+ "`num_sampled_clients`.",
156
+ adding_noise,
157
+ )
158
+
159
+ else:
160
+ if clipped_count_stddev is None:
161
+ clipped_count_stddev = 0.0
162
+ noise_multiplier_value = 0.0
163
+
164
+ return clipped_count_stddev, noise_multiplier_value
@@ -16,6 +16,7 @@
16
16
 
17
17
 
18
18
  KEY_CLIPPING_NORM = "clipping_norm"
19
+ KEY_NORM_BIT = "norm_bit"
19
20
  CLIENTS_DISCREPANCY_WARNING = (
20
21
  "The number of clients returning parameters (%s)"
21
22
  " differs from the number of sampled clients (%s)."
@@ -0,0 +1,68 @@
1
+ # Copyright 2020 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
+ """Constants for the SecAgg/SecAgg+ protocol."""
16
+
17
+
18
+ from __future__ import annotations
19
+
20
+ RECORD_KEY_STATE = "secaggplus_state"
21
+ RECORD_KEY_CONFIGS = "secaggplus_configs"
22
+
23
+
24
+ class Stage:
25
+ """Stages for the SecAgg+ protocol."""
26
+
27
+ SETUP = "setup"
28
+ SHARE_KEYS = "share_keys"
29
+ COLLECT_MASKED_INPUT = "collect_masked_input"
30
+ UNMASK = "unmask"
31
+ _stages = (SETUP, SHARE_KEYS, COLLECT_MASKED_INPUT, UNMASK)
32
+
33
+ @classmethod
34
+ def all(cls) -> tuple[str, str, str, str]:
35
+ """Return all stages."""
36
+ return cls._stages
37
+
38
+ def __new__(cls) -> Stage:
39
+ """Prevent instantiation."""
40
+ raise TypeError(f"{cls.__name__} cannot be instantiated.")
41
+
42
+
43
+ class Key:
44
+ """Keys for the configs in the ConfigsRecord."""
45
+
46
+ STAGE = "stage"
47
+ SAMPLE_NUMBER = "sample_num"
48
+ SECURE_ID = "secure_id"
49
+ SHARE_NUMBER = "share_num"
50
+ THRESHOLD = "threshold"
51
+ CLIPPING_RANGE = "clipping_range"
52
+ TARGET_RANGE = "target_range"
53
+ MOD_RANGE = "mod_range"
54
+ PUBLIC_KEY_1 = "pk1"
55
+ PUBLIC_KEY_2 = "pk2"
56
+ DESTINATION_LIST = "dsts"
57
+ CIPHERTEXT_LIST = "ctxts"
58
+ SOURCE_LIST = "srcs"
59
+ PARAMETERS = "params"
60
+ MASKED_PARAMETERS = "masked_params"
61
+ ACTIVE_SECURE_ID_LIST = "active_sids"
62
+ DEAD_SECURE_ID_LIST = "dead_sids"
63
+ SECURE_ID_LIST = "sids"
64
+ SHARE_LIST = "shares"
65
+
66
+ def __new__(cls) -> Key:
67
+ """Prevent instantiation."""
68
+ raise TypeError(f"{cls.__name__} cannot be instantiated.")
@@ -0,0 +1,26 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: flwr/proto/error.proto
4
+ # Protobuf Python Version: 4.25.0
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/error.proto\x12\nflwr.proto\"%\n\x05\x45rror\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x12\x12\x0e\n\x06reason\x18\x02 \x01(\tb\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.error_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ DESCRIPTOR._options = None
24
+ _globals['_ERROR']._serialized_start=38
25
+ _globals['_ERROR']._serialized_end=75
26
+ # @@protoc_insertion_point(module_scope)