From e17172ec53f441890d9a52380060e636fc0cc894 Mon Sep 17 00:00:00 2001 From: "Shah, Karan" Date: Tue, 3 Dec 2024 14:15:20 +0530 Subject: [PATCH 1/6] Simplify setup.py Signed-off-by: Shah, Karan --- openfl-docker/__init__.py | 2 + openfl/plugins/__init__.py | 2 + .../plugins/frameworks_adapters/__init__.py | 2 + .../plugins/interface_serializer/__init__.py | 2 + .../processing_units_monitor/__init__.py | 2 + setup.py | 104 ++---------------- 6 files changed, 18 insertions(+), 96 deletions(-) create mode 100644 openfl-docker/__init__.py create mode 100644 openfl/plugins/__init__.py create mode 100644 openfl/plugins/frameworks_adapters/__init__.py create mode 100644 openfl/plugins/interface_serializer/__init__.py create mode 100644 openfl/plugins/processing_units_monitor/__init__.py diff --git a/openfl-docker/__init__.py b/openfl-docker/__init__.py new file mode 100644 index 0000000000..44936c23a2 --- /dev/null +++ b/openfl-docker/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2020-2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 diff --git a/openfl/plugins/__init__.py b/openfl/plugins/__init__.py new file mode 100644 index 0000000000..44936c23a2 --- /dev/null +++ b/openfl/plugins/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2020-2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 diff --git a/openfl/plugins/frameworks_adapters/__init__.py b/openfl/plugins/frameworks_adapters/__init__.py new file mode 100644 index 0000000000..44936c23a2 --- /dev/null +++ b/openfl/plugins/frameworks_adapters/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2020-2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 diff --git a/openfl/plugins/interface_serializer/__init__.py b/openfl/plugins/interface_serializer/__init__.py new file mode 100644 index 0000000000..44936c23a2 --- /dev/null +++ b/openfl/plugins/interface_serializer/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2020-2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 diff --git a/openfl/plugins/processing_units_monitor/__init__.py b/openfl/plugins/processing_units_monitor/__init__.py new file mode 100644 index 0000000000..44936c23a2 --- /dev/null +++ b/openfl/plugins/processing_units_monitor/__init__.py @@ -0,0 +1,2 @@ +# Copyright 2020-2024 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 diff --git a/setup.py b/setup.py index 4133fb69d0..16fc7cad5f 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,9 @@ # Copyright (C) 2020-2023 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +"""Setup script.""" -"""This package includes dependencies of the openfl project.""" - -from setuptools import Command -from setuptools import setup +from setuptools import Command, find_packages, setup from setuptools.command.build_py import build_py -from setuptools.command.develop import develop class BuildPackageProtos(Command): @@ -61,90 +58,17 @@ def run(self): super().run() -class DevelopGRPC(develop): - """Command for develop installation.""" - - def __init__(self, dist): - """Create a sub-command to execute.""" - self.subcommand = BuildPackageProtos(dist) - super().__init__(dist) - - def run(self): - """Build GRPC modules before the default installation.""" - self.subcommand.run() - super().run() - - -with open('README.md', encoding='utf-8') as f: - long_description = f.read() - setup( name='openfl', version='1.6', - author='The OpenFL Team', + author='OpenFL Team', description='Federated Learning for the Edge', - long_description=long_description, + long_description=open("README.md", encoding="utf-8").read(), long_description_content_type='text/markdown', url='https://github.com/securefederatedai/openfl', - packages=[ - 'openfl', - 'openfl.component', - 'openfl.interface.aggregation_functions', - 'openfl.interface.aggregation_functions.core', - 'openfl.interface.aggregation_functions.experimental', - 'openfl.component.aggregator', - 'openfl.component.assigner', - 'openfl.component.collaborator', - 'openfl.component.director', - 'openfl.component.envoy', - 'openfl.component.straggler_handling_functions', - 'openfl.cryptography', - 'openfl.databases', - 'openfl.databases.utilities', - 'openfl.experimental', - 'openfl.experimental.workflow', - 'openfl.experimental.workflow.workspace_export', - 'openfl.experimental.workflow.federated', - 'openfl.experimental.workflow.federated.plan', - 'openfl.experimental.workflow.component', - 'openfl.experimental.workflow.component.aggregator', - 'openfl.experimental.workflow.component.collaborator', - 'openfl.experimental.workflow.interface.cli', - 'openfl.experimental.workflow.interface', - 'openfl.experimental.workflow.placement', - 'openfl.experimental.workflow.runtime', - 'openfl.experimental.workflow.protocols', - 'openfl.experimental.workflow.transport', - 'openfl.experimental.workflow.transport.grpc', - 'openfl.experimental.workflow.utilities', - 'openfl.federated', - 'openfl.federated.data', - 'openfl.federated.plan', - 'openfl.federated.task', - 'openfl.interface', - 'openfl.interface.interactive_api', - 'openfl.native', - 'openfl.pipelines', - 'openfl.plugins', - 'openfl.plugins.frameworks_adapters', - 'openfl.plugins.interface_serializer', - 'openfl.plugins.processing_units_monitor', - 'openfl.protocols', - 'openfl.transport', - 'openfl.transport.grpc', - 'openfl.utilities', - 'openfl.utilities.ca', - 'openfl.utilities.data_splitters', - 'openfl.utilities.fedcurv', - 'openfl.utilities.fedcurv.torch', - 'openfl.utilities.optimizers.keras', - 'openfl.utilities.optimizers.numpy', - 'openfl.utilities.optimizers.torch', - 'openfl-docker', - 'openfl-tutorials', - 'openfl-workspace', - ], + packages=find_packages(include=("openfl", "openfl.*", "openfl-docker", "openfl-workspace")), include_package_data=True, + setup_requires=['grpcio-tools>=1.56.2,<1.66.0'], install_requires=[ 'Click==8.1.7', 'PyYAML>=5.4.1', @@ -167,7 +91,6 @@ def run(self): 'tensorboardX>=2.6', 'tqdm', ], - setup_requires=['grpcio-tools>=1.56.2,<1.66.0'], python_requires='>=3.8, <3.12', project_urls={ 'Bug Tracker': 'https://github.com/securefederatedai/openfl/issues', @@ -176,31 +99,20 @@ def run(self): }, classifiers=[ 'Environment :: Console', - # How mature is this project? Common values are - # 3 - Alpha, 4 - Beta, 5 - Production/Stable 'Development Status :: 5 - Production/Stable', - # Indicate who your project is intended for - 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', 'Topic :: Scientific/Engineering :: Artificial Intelligence', - 'Topic :: Scientific/Engineering :: Image Recognition', 'Topic :: System :: Distributed Computing', - # Pick your license as you wish 'License :: OSI Approved :: Apache Software License', - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', - ], - entry_points={ - 'console_scripts': ['fx=openfl.interface.cli:entry'] - }, + entry_points={'console_scripts': ['fx=openfl.interface.cli:entry']}, cmdclass={ 'build_py': BuildPyGRPC, 'build_grpc': BuildPackageProtos, - 'develop': DevelopGRPC }, ) From 6191d8222c8efecf2ed83b092a0b44c9ffa42881 Mon Sep 17 00:00:00 2001 From: "Shah, Karan" Date: Tue, 3 Dec 2024 15:17:33 +0530 Subject: [PATCH 2/6] Remove tensorboardX and never-used log_metric code Signed-off-by: Shah, Karan --- openfl/component/aggregator/aggregator.py | 19 +------------- openfl/utilities/logs.py | 30 ----------------------- 2 files changed, 1 insertion(+), 48 deletions(-) diff --git a/openfl/component/aggregator/aggregator.py b/openfl/component/aggregator/aggregator.py index 3128ef3e89..72296130b6 100644 --- a/openfl/component/aggregator/aggregator.py +++ b/openfl/component/aggregator/aggregator.py @@ -15,7 +15,7 @@ from openfl.pipelines import NoCompressionPipeline, TensorCodec from openfl.protocols import base_pb2, utils from openfl.utilities import TaskResultKey, TensorKey, change_tags -from openfl.utilities.logs import get_memory_usage, write_metric +from openfl.utilities.logs import get_memory_usage class Aggregator: @@ -38,8 +38,6 @@ class Aggregator: tensor_db (TensorDB): Object for tensor database. db_store_rounds* (int): Rounds to store in TensorDB. logger: Object for logging. - write_logs (bool): Flag to enable log writing. - log_metric_callback: Callback for logging metrics. best_model_score (optional): Score of the best model. Defaults to None. metric_queue (queue.Queue): Queue for metrics. @@ -76,9 +74,7 @@ def __init__( single_col_cert_common_name=None, compression_pipeline=None, db_store_rounds=1, - write_logs=False, log_memory_usage=False, - log_metric_callback=None, **kwargs, ): """Initializes the Aggregator. @@ -104,10 +100,6 @@ def __init__( NoCompressionPipeline. db_store_rounds (int, optional): Rounds to store in TensorDB. Defaults to 1. - write_logs (bool, optional): Whether to write logs. Defaults to - False. - log_metric_callback (optional): Callback for log metric. Defaults - to None. **kwargs: Additional keyword arguments. """ self.round_number = 0 @@ -144,15 +136,6 @@ def __init__( # Gathered together logging-related objects self.logger = getLogger(__name__) - self.write_logs = write_logs - self.log_metric_callback = log_metric_callback - - if self.write_logs: - self.log_metric = write_metric - if self.log_metric_callback: - self.log_metric = log_metric_callback - self.logger.info("Using custom log metric: %s", self.log_metric) - self.best_model_score = None self.metric_queue = queue.Queue() diff --git a/openfl/utilities/logs.py b/openfl/utilities/logs.py index a17f0742fc..747e2165df 100644 --- a/openfl/utilities/logs.py +++ b/openfl/utilities/logs.py @@ -10,36 +10,6 @@ import psutil from rich.console import Console from rich.logging import RichHandler -from tensorboardX import SummaryWriter - -writer = None - - -def get_writer(): - """Create global writer object. - - This function creates a global `SummaryWriter` object for logging to - TensorBoard. - """ - global writer - if not writer: - writer = SummaryWriter("./logs/tensorboard", flush_secs=5) - - -def write_metric(node_name, task_name, metric_name, metric, round_number): - """Write metric callback. - - This function logs a metric to TensorBoard. - - Args: - node_name (str): The name of the node. - task_name (str): The name of the task. - metric_name (str): The name of the metric. - metric (float): The value of the metric. - round_number (int): The current round number. - """ - get_writer() - writer.add_scalar(f"{node_name}/{task_name}/{metric_name}", metric, round_number) def setup_loggers(log_level=logging.INFO): From 6017900b44d3992fd4c9b30058a140dbca88d1a2 Mon Sep 17 00:00:00 2001 From: "Shah, Karan" Date: Tue, 3 Dec 2024 15:17:55 +0530 Subject: [PATCH 3/6] Test reducing requirements Signed-off-by: Shah, Karan --- .../interface/interactive_api/experiment.py | 4 +-- setup.py | 31 ++++++++----------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/openfl/interface/interactive_api/experiment.py b/openfl/interface/interactive_api/experiment.py index 111c6f1238..d8096df8ad 100644 --- a/openfl/interface/interactive_api/experiment.py +++ b/openfl/interface/interactive_api/experiment.py @@ -15,8 +15,6 @@ from shutil import copytree, ignore_patterns, make_archive from typing import Dict, Tuple -from tensorboardX import SummaryWriter - from openfl.component.assigner.tasks import Task, TrainTask, ValidateTask from openfl.federated import Plan from openfl.interface.aggregation_functions import AggregationFunction, WeightedAverage @@ -206,6 +204,8 @@ def stream_metrics(self, tensorboard_logs: bool = True) -> None: def write_tensorboard_metric(self, metric: dict) -> None: """Write metric callback.""" if not self.summary_writer: + from tensorboardX import SummaryWriter + self.summary_writer = SummaryWriter(f"./logs/{self.experiment_name}", flush_secs=5) self.summary_writer.add_scalar( diff --git a/setup.py b/setup.py index 16fc7cad5f..3340e9a487 100644 --- a/setup.py +++ b/setup.py @@ -68,28 +68,23 @@ def run(self): url='https://github.com/securefederatedai/openfl', packages=find_packages(include=("openfl", "openfl.*", "openfl-docker", "openfl-workspace")), include_package_data=True, - setup_requires=['grpcio-tools>=1.56.2,<1.66.0'], + setup_requires=['grpcio-tools>=1.56.2,<1.66.0'], # ensure it is in-sync with `install_requires` install_requires=[ - 'Click==8.1.7', - 'PyYAML>=5.4.1', - 'cloudpickle', - 'cryptography>=3.4.6', - 'docker', - 'dynaconf==3.2.6', - 'flatten_json', - 'grpcio>=1.56.2,<1.66.0', - 'ipykernel', - 'jupyterlab', + 'click', + 'psutil', + 'pyyaml', + 'rich', + 'dynaconf', + 'tqdm', 'numpy', + 'requests', + 'cloudpickle', + 'cryptography', 'pandas', - 'protobuf>=4.22,<6.0.0', - 'pyzmq<=26.2.0', - 'requests>=2.32.0', - 'rich', 'scikit-learn', - 'tensorboard', - 'tensorboardX>=2.6', - 'tqdm', + 'flatten_json', + 'protobuf>=4.22,<6.0.0', + 'grpcio>=1.56.2,<1.66.0', ], python_requires='>=3.8, <3.12', project_urls={ From 51df6d6999e1a09bca8c05b9a0fe11fd6576d156 Mon Sep 17 00:00:00 2001 From: "Shah, Karan" Date: Wed, 4 Dec 2024 10:23:01 +0530 Subject: [PATCH 4/6] Revert "Remove tensorboardX and never-used log_metric code" and add fn calls Signed-off-by: Shah, Karan --- openfl/component/aggregator/aggregator.py | 35 ++++++++++++++++++++++- openfl/utilities/logs.py | 30 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/openfl/component/aggregator/aggregator.py b/openfl/component/aggregator/aggregator.py index 72296130b6..038a1e00d3 100644 --- a/openfl/component/aggregator/aggregator.py +++ b/openfl/component/aggregator/aggregator.py @@ -15,7 +15,7 @@ from openfl.pipelines import NoCompressionPipeline, TensorCodec from openfl.protocols import base_pb2, utils from openfl.utilities import TaskResultKey, TensorKey, change_tags -from openfl.utilities.logs import get_memory_usage +from openfl.utilities.logs import get_memory_usage, write_metric class Aggregator: @@ -38,6 +38,8 @@ class Aggregator: tensor_db (TensorDB): Object for tensor database. db_store_rounds* (int): Rounds to store in TensorDB. logger: Object for logging. + write_logs (bool): Flag to enable log writing. + log_metric_callback: Callback for logging metrics. best_model_score (optional): Score of the best model. Defaults to None. metric_queue (queue.Queue): Queue for metrics. @@ -74,7 +76,9 @@ def __init__( single_col_cert_common_name=None, compression_pipeline=None, db_store_rounds=1, + write_logs=False, log_memory_usage=False, + log_metric_callback=None, **kwargs, ): """Initializes the Aggregator. @@ -100,6 +104,10 @@ def __init__( NoCompressionPipeline. db_store_rounds (int, optional): Rounds to store in TensorDB. Defaults to 1. + write_logs (bool, optional): Whether to write logs. Defaults to + False. + log_metric_callback (optional): Callback for log metric. Defaults + to None. **kwargs: Additional keyword arguments. """ self.round_number = 0 @@ -136,6 +144,15 @@ def __init__( # Gathered together logging-related objects self.logger = getLogger(__name__) + self.write_logs = write_logs + self.log_metric_callback = log_metric_callback + + if self.write_logs: + self.log_metric = write_metric + if self.log_metric_callback: + self.log_metric = log_metric_callback + self.logger.info("Using custom log metric: %s", self.log_metric) + self.best_model_score = None self.metric_queue = queue.Queue() @@ -647,6 +664,14 @@ def send_local_task_results( } self.metric_queue.put(metrics) self.logger.metric("%s", str(metrics)) + if self.write_logs: + self.log_metric( + collaborator_name, + task_name, + tensor_key.tensor_name, + float(value), + round_number, + ) task_results.append(tensor_key) @@ -921,6 +946,14 @@ def _compute_validation_related_task_metrics(self, task_name): self.metric_queue.put(metrics) self.logger.metric("%s", metrics) + if self.write_logs: + self.log_metric( + "aggregator", + task_name, + tensor_key.tensor_name, + float(agg_results), + round_number, + ) # FIXME: Configurable logic for min/max criteria in saving best. if "validate_agg" in tags: diff --git a/openfl/utilities/logs.py b/openfl/utilities/logs.py index 747e2165df..a17f0742fc 100644 --- a/openfl/utilities/logs.py +++ b/openfl/utilities/logs.py @@ -10,6 +10,36 @@ import psutil from rich.console import Console from rich.logging import RichHandler +from tensorboardX import SummaryWriter + +writer = None + + +def get_writer(): + """Create global writer object. + + This function creates a global `SummaryWriter` object for logging to + TensorBoard. + """ + global writer + if not writer: + writer = SummaryWriter("./logs/tensorboard", flush_secs=5) + + +def write_metric(node_name, task_name, metric_name, metric, round_number): + """Write metric callback. + + This function logs a metric to TensorBoard. + + Args: + node_name (str): The name of the node. + task_name (str): The name of the task. + metric_name (str): The name of the metric. + metric (float): The value of the metric. + round_number (int): The current round number. + """ + get_writer() + writer.add_scalar(f"{node_name}/{task_name}/{metric_name}", metric, round_number) def setup_loggers(log_level=logging.INFO): From 01662c58268c10e99e819232cdd93688cba540de Mon Sep 17 00:00:00 2001 From: "Shah, Karan" Date: Wed, 4 Dec 2024 10:57:10 +0530 Subject: [PATCH 5/6] Revert tb removal Signed-off-by: Shah, Karan --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 3340e9a487..bbdfa03b96 100644 --- a/setup.py +++ b/setup.py @@ -83,6 +83,7 @@ def run(self): 'pandas', 'scikit-learn', 'flatten_json', + 'tensorboardX', 'protobuf>=4.22,<6.0.0', 'grpcio>=1.56.2,<1.66.0', ], From 9fda1d75b4c79bae2f33dc6218266dde228dcfbc Mon Sep 17 00:00:00 2001 From: "Shah, Karan" Date: Wed, 4 Dec 2024 19:20:01 +0530 Subject: [PATCH 6/6] Disable tensorboard logging for gramine CI test Signed-off-by: Shah, Karan --- .github/workflows/tr_docker_gramine_direct.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/tr_docker_gramine_direct.yml b/.github/workflows/tr_docker_gramine_direct.yml index d8f7480ea1..be2afea5f9 100644 --- a/.github/workflows/tr_docker_gramine_direct.yml +++ b/.github/workflows/tr_docker_gramine_direct.yml @@ -31,6 +31,11 @@ jobs: fx workspace create --prefix example_workspace --template keras_cnn_mnist cd example_workspace fx plan initialize -a localhost + + # Disable tensorboard logging as multiprocessing is not supported in Gramine + # https://github.com/gramineproject/examples/issues/33 + sed -i 's/write_logs: true/write_logs: false/g' plan/plan.yaml + fx workspace dockerize --save --revision https://github.com/${GITHUB_REPOSITORY}.git@${{ github.event.pull_request.head.sha }} - name: Create certificate authority for workspace