Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert step-by-step stats examples to use new Job API #2842

Merged
merged 7 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/getting_started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ such as [FedOpt](https://arxiv.org/abs/2003.00295), or [SCAFFOLD](https://arxiv.
### 2. [Tensorflow Examples](./tf/README.md)
### 3. [Scikit-Learn Examples](./sklearn/README.md)

Once you finished above examples,
you can look at the ["hello-world"](../hello-world) examples or look at more examples at tutorial catelog https://nvidia.github.io/NVFlare/.
Once you finished above examples, you also read about [getting started documentation](https://nvflare.readthedocs.io/en/main/getting_started.html),
look at the ["hello-world"](../hello-world) examples or checkout more examples at tutorial catelog https://nvidia.github.io/NVFlare/.


91 changes: 91 additions & 0 deletions examples/getting_started/readme.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "63c63334-1046-4e32-9e72-94997fc9db27",
"metadata": {
"tags": []
},
"outputs": [
{
"data": {
"text/markdown": [
"# Getting Started with NVFlare\n",
"NVFlare is an open-source framework that allows researchers and data scientists to seamlessly move their \n",
"machine learning and deep learning workflows into a federated paradigm.\n",
"\n",
"### Basic Concepts\n",
"At the heart of NVFlare lies the concept of collaboration through \"tasks.\" An FL controller assigns tasks \n",
"(e.g., training on local data) to one or more FL clients, processes returned results (e.g., model weight updates), \n",
"and may assign additional tasks based on these results and other factors (e.g., a pre-configured number of training rounds). \n",
"The clients run executors which can listen for tasks and perform the necessary computations locally, such as model training. \n",
"This task-based interaction repeats until the experiment’s objectives are met.\n",
"\n",
"We can also add data filters (for example, for [homomorphic encryption](https://www.usenix.org/conference/atc20/presentation/zhang-chengliang)\n",
"or [differential privacy filters](https://arxiv.org/abs/1910.00962)) to the task data\n",
"or results received or produced by the server or clients.\n",
"\n",
"![NVIDIA FLARE Overview](../../docs/resources/controller_executor_no_filter.png)\n",
"\n",
"\n",
"### Examples\n",
"We provide several examples to quickly get you started using NVFlare's Job API. \n",
"Each example folder includes basic job configurations for running different FL algorithms. \n",
"Starting from [FedAvg](https://arxiv.org/abs/1602.05629), to more advanced ones, \n",
"such as [FedOpt](https://arxiv.org/abs/2003.00295), or [SCAFFOLD](https://arxiv.org/abs/1910.06378).\n",
"\n",
"### 1. [PyTorch Examples](./pt/README.md)\n",
"### 2. [Tensorflow Examples](./tf/README.md)\n",
"### 3. [Scikit-Learn Examples](./sklearn/README.md)\n",
"\n",
"Once you finished above examples, you also read about [getting started documentation](https://nvflare.readthedocs.io/en/main/getting_started.html), \n",
"look at the [\"hello-world\"](../hello-world) examples or checkout more examples at tutorial catelog https://nvidia.github.io/NVFlare/.\n",
"\n",
"\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from IPython.display import Markdown, display\n",
"\n",
"display(Markdown(\"README.md\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d55b76f4-6374-45f7-80fd-72e735851c45",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "nvflare_example",
"language": "python",
"name": "nvflare_example"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.19"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
113 changes: 16 additions & 97 deletions examples/hello-world/step-by-step/cifar10/stats/image_stats.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"\n",
"## Setup NVFLARE\n",
"\n",
"Follow [Getting Started](https://nvflare.readthedocs.io/en/main/getting_started.html) to set up a virtual environment and install NVFLARE."
"Follow [Getting Started](../../../../getting_started/readme.ipynb) to set up a virtual environment and install NVFLARE.\n"
YuanTingHsieh marked this conversation as resolved.
Show resolved Hide resolved
]
},
{
Expand Down Expand Up @@ -417,10 +417,7 @@
"metadata": {},
"source": [
"## Create Federated Histogram Job\n",
"We are going to use NVFLARE job cli to create job. For detailed instructions on Job CLI, please follow the [job cli tutorial](https://github.com/NVIDIA/NVFlare/blob/main/examples/tutorials/job_cli.ipynb).\n",
"\n",
"Let's check the available job templates, we are going to use one of the existing job template and modify to fit our needs. \n",
"The job template is nothing but server and client-side job configurations.\n"
"We are going to use NVFLARE job API to construct a FedJob"
]
},
{
Expand All @@ -432,127 +429,49 @@
},
"outputs": [],
"source": [
"! nvflare job list_templates"
"! cat image_stats_job.py"
]
},
{
"cell_type": "markdown",
"id": "ed966234-9f97-4ad9-9a86-6b19371595a7",
"metadata": {},
"source": [
"there is \"stats_image\" job template, which what we need. We are going to use that. Now, use ```nvflare job create``` command\n",
"Let's try using the default values\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a361a4b-745d-49d4-9fcb-1125c4d6ba82",
"id": "a09aed14-5011-4418-8840-5f7c16c97534",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"! nvflare job create -w stats_image -j /tmp/nvflare/jobs/stats_image "
]
},
{
"cell_type": "markdown",
"id": "5ff1da2e-3151-4e69-b266-d387b460a2e8",
"metadata": {},
"source": [
"The default seems to be ok, execept for few values: \n",
"* data_root=/tmp/nvflare/image_stats/data, it not the same as CIFAR10_ROOT\n",
"* meta.conf's min_clients should be 2, as we are going to use two clients\n",
"\n",
"Now let's look closer at the configurations, in particular, the client side, and make sure it matches to the new class we just created"
]
},
{
"cell_type": "markdown",
"id": "379cbf3b-b058-4b5a-b3f8-aa6824f0cf2d",
"metadata": {},
"source": [
">Note: \n",
"In the upcoming sections, we'll utilize the 'tree' command. To install this command on a Linux system, you can use the sudo apt install tree command. As an alternative to 'tree', you can use the ls -al command."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e2de9b6f-35eb-4491-9bce-412fc3025e64",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"! tree /tmp/nvflare/jobs/stats_image "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "87fb3651-76cd-4955-945b-ccfbe29d0774",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"! nvflare job create -w stats_image -j /tmp/nvflare/jobs/stats_image -force \\\n",
"-f meta.conf min_clients=2 \\\n",
"-f config_fed_client.conf app_script=image_statistics.py data_root={CIFAR10_ROOT} \\\n",
"-f config_fed_server.conf bins=20 \\\n",
"-sd ./ \\\n",
"-debug"
"## Run Job in FL Simulator\n",
"\n",
"\n",
"**Run job.simulator_run()**\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "655e1a05-200f-4e7b-bc57-1fa8a7742842",
"id": "1a3b8638-d7a2-4207-9821-e444cf40f8ae",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"! tree /tmp/nvflare/jobs/stats_image "
"! python image_stats_job.py -w /tmp/nvflare/image_stats -n 2 -d /tmp/nvflare/data/cifar10 -o \"statistics/image_statistics.json\""
]
},
{
"cell_type": "markdown",
"id": "eeaa3e33-0c41-4d5f-875a-3bef85aaae79",
"id": "8c6e73b8-efa9-4a52-8342-324eb07a0422",
"metadata": {},
"source": [
"We can see we also copied some files doesn't belong there. Let's remove them. "
]
},
{
"cell_type": "markdown",
"id": "a09aed14-5011-4418-8840-5f7c16c97534",
"metadata": {
"tags": []
},
"source": [
"> **Note**: if your histogram calculator file name is not \"image_statistics.py\" but other file name such as \"image_histogram.py\" and the class name is not 'ImageStatistics' but \"HistogramStatistics\", you will need to manually edit the config_fed_client.conf to replace 'image_statistics.ImageStatistics' with 'image_histogram.HistogramStatistics'. Any other adjustments that your need to change, you can directly edit the server and client configurations\n",
"\n",
"\n",
"Now we have created the job folder. we are ready to run job\n",
"**Run Job using Simulator CLI**\n",
"\n",
"## Run Job in FL Simulator\n",
"```\n",
"! python image_stats_job.py -co -j /tmp/nvflare/jobs/stats_image -n 2\n",
"! nvflare simulator /tmp/nvflare/jobs/stats_image -w /tmp/nvflare/image_stats -n 2 -t 2\n",
"\n",
"**Run Job using Simulator CLI**\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0cdc008c-2447-4d4a-9911-4c1fb1c28aaa",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"! nvflare simulator /tmp/nvflare/jobs/stats_image -w /tmp/nvflare/image_stats -n 2 -t 2\n"
"```\n"
]
},
{
Expand Down
64 changes: 64 additions & 0 deletions examples/hello-world/step-by-step/cifar10/stats/image_stats_job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse

from image_statistics import ImageStatistics

from nvflare.job_config.stats_job import StatsJob


def define_parser():
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--n_clients", type=int, default=3)
parser.add_argument("-d", "--data_root_dir", type=str, nargs="?", default="/tmp/nvflare/dataset/output")
parser.add_argument("-o", "--stats_output_path", type=str, nargs="?", default="statistics/stats.json")
parser.add_argument("-j", "--job_dir", type=str, nargs="?", default="/tmp/nvflare/jobs/stats_df")
parser.add_argument("-w", "--work_dir", type=str, nargs="?", default="/tmp/nvflare/jobs/stats_df/work_dir")
parser.add_argument("-co", "--export_config", action="store_true", help="config only mode, export config")

return parser.parse_args()


def main():
args = define_parser()

n_clients = args.n_clients
data_root_dir = args.data_root_dir
output_path = args.stats_output_path
job_dir = args.job_dir
work_dir = args.work_dir
export_config = args.export_config

statistic_configs = {"count": {}, "histogram": {"*": {"bins": 20, "range": [0, 256]}}}
# define local stats generator
stats_generator = ImageStatistics(data_root_dir)

job = StatsJob(
job_name="stats_image",
statistic_configs=statistic_configs,
stats_generator=stats_generator,
output_path=output_path,
)

sites = [f"site-{i + 1}" for i in range(n_clients)]
job.setup_client(sites)

if export_config:
job.export_job(job_dir)
else:
job.simulator_run(work_dir, gpu="0")


if __name__ == "__main__":
main()
Loading
Loading