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

refactor(examples) Update Flower example using scikit-learn #3777

Merged
merged 28 commits into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c5a1eed
Update pyproject.toml, delete requirements.txt
chongshenng Jul 11, 2024
632354a
Update readme
chongshenng Jul 11, 2024
a61eb0b
Restructure directory
chongshenng Jul 11, 2024
a9388b3
Rename files
chongshenng Jul 11, 2024
8358b9f
Delete run.sh
chongshenng Jul 11, 2024
bebc750
Delete redundant script
chongshenng Jul 11, 2024
a9491e9
Update clientapp, serverapp
chongshenng Jul 11, 2024
0f84b6e
Merge branch 'main' into update-sklearn-example
chongshenng Jul 11, 2024
d0ede9a
Add numpy
chongshenng Jul 11, 2024
c1361fe
Merge branch 'main' into update-sklearn-example
chongshenng Jul 11, 2024
e46844f
Delete utils.py
chongshenng Jul 11, 2024
b440d70
Update example
chongshenng Jul 24, 2024
7eb838b
Merge branch 'main' into update-sklearn-example
chongshenng Jul 24, 2024
39da71f
Merge branch 'main' into update-sklearn-example
chongshenng Jul 25, 2024
8577c33
Update project name
chongshenng Jul 25, 2024
319e623
Update project name
chongshenng Jul 25, 2024
0d2b810
Merge branch 'main' into update-sklearn-example
chongshenng Aug 8, 2024
db72988
Align readme
chongshenng Aug 8, 2024
13002b3
Refactor
chongshenng Aug 8, 2024
f2e1209
Merge branch 'main' into update-sklearn-example
chongshenng Aug 8, 2024
7137605
Merge branch 'main' into update-sklearn-example
chongshenng Aug 9, 2024
c960b8b
Add server initialized model
chongshenng Aug 9, 2024
2a2885d
Rename app
chongshenng Aug 9, 2024
5cbc1c4
Update examples/sklearn-logreg-mnist/README.md
chongshenng Aug 9, 2024
27044c0
Update examples/sklearn-logreg-mnist/pyproject.toml
chongshenng Aug 9, 2024
810abb4
Apply suggestions from code review
chongshenng Aug 9, 2024
53abb89
Merge branch 'main' into update-sklearn-example
jafermarq Aug 9, 2024
0877907
removed unused config_fit callback; reoredered imports; defined `frac…
jafermarq Aug 9, 2024
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
85 changes: 33 additions & 52 deletions examples/sklearn-logreg-mnist/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,83 +4,64 @@ dataset: [MNIST]
framework: [scikit-learn]
---

# Flower Logistic Regression Example using scikit-learn
# Flower Logistic Regression Example using scikit-learn and Flower (Quickstart Example)

This example of Flower uses `scikit-learn`'s `LogisticRegression` model to train a federated learning system. It will help you understand how to adapt Flower for use with `scikit-learn`.
chongshenng marked this conversation as resolved.
Show resolved Hide resolved
Running this example in itself is quite easy. This example uses [Flower Datasets](https://flower.ai/docs/datasets/) to download, partition and preprocess the MNIST dataset.

## Project Setup
## Set up the project

Start by cloning the example project. We prepared a single-line command that you can copy into your shell which will checkout the example for you:
### Clone the project

```shell
git clone --depth=1 https://github.com/adap/flower.git && mv flower/examples/sklearn-logreg-mnist . && rm -rf flower && cd sklearn-logreg-mnist
```

This will create a new directory called `sklearn-logreg-mnist` containing the following files:
Start by cloning the example project:

```shell
-- pyproject.toml
-- requirements.txt
-- client.py
-- server.py
-- utils.py
-- README.md
git clone --depth=1 https://github.com/adap/flower.git _tmp \
&& mv _tmp/examples/sklearn-logreg-mnist . \
&& rm -rf _tmp && cd sklearn-logreg-mnist
```

### Installing Dependencies

Project dependencies (such as `scikit-learn` and `flwr`) are defined in `pyproject.toml` and `requirements.txt`. We recommend [Poetry](https://python-poetry.org/docs/) to install those dependencies and manage your virtual environment ([Poetry installation](https://python-poetry.org/docs/#installation)) or [pip](https://pip.pypa.io/en/latest/development/), but feel free to use a different way of installing dependencies and managing virtual environments if you have other preferences.

#### Poetry
This will create a new directory called `sklearn-logreg-mnist` with the following structure:

```shell
poetry install
poetry shell
sklearn-logreg-mnist
├── README.md
├── pyproject.toml # Project metadata like dependencies and configs
└── sklearn_example
├── __init__.py
├── client_app.py # Defines your ClientApp
├── server_app.py # Defines your ServerApp
└── task.py # Defines your model, training and data loading
```

Poetry will install all your dependencies in a newly created virtual environment. To verify that everything works correctly you can run the following command:
### Install dependencies and project

```shell
poetry run python3 -c "import flwr"
```

If you don't see any errors you're good to go!

#### pip
Install the dependencies defined in `pyproject.toml` as well as the `sklearn_example` package.

Write the command below in your terminal to install the dependencies according to the configuration file requirements.txt.

```shell
pip install -r requirements.txt
```bash
pip install -e .
```

## Run Federated Learning with scikit-learn and Flower

Afterwards you are ready to start the Flower server as well as the clients. You can simply start the server in a terminal as follows:

```shell
poetry run python3 server.py
```
## Run the project

Now you are ready to start the Flower clients which will participate in the learning. To do so simply open two or more terminals and run the following command in each:
You can run your Flower project in both _simulation_ and _deployment_ mode without making changes to the code. If you are starting with Flower, we recommend you using the _simulation_ mode as it requires fewer components to be launched manually. By default, `flwr run` will make use of the Simulation Engine.

Start client 1 in the first terminal:
### Run with the Simulation Engine

```shell
python3 client.py --partition-id 0 # or any integer in {0-9}
```bash
flwr run .
```

Start client 2 in the second terminal:
You can also override some of the settings for your `ClientApp` and `ServerApp` defined in `pyproject.toml`. For example:

```shell
python3 client.py --partition-id 1 # or any integer in {0-9}
```bash
flwr run . --run-config num-server-rounds=5
```

Alternatively, you can run all of it in one shell as follows:
> \[!TIP\]
> For a more detailed walk-through check our [quickstart PyTorch tutorial](https://flower.ai/docs/framework/tutorial-quickstart-scikitlearn.html)

```bash
bash run.sh
```
### Run with the Deployment Engine

You will see that Flower is starting a federated training.
> \[!NOTE\]
> An update to this example will show how to run this Flower application with the Deployment Engine and TLS certificates, or with Docker.
67 changes: 0 additions & 67 deletions examples/sklearn-logreg-mnist/client.py

This file was deleted.

46 changes: 33 additions & 13 deletions examples/sklearn-logreg-mnist/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
[build-system]
requires = ["poetry-core>=1.4.0"]
build-backend = "poetry.core.masonry.api"
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.poetry]
name = "sklearn-mnist"
version = "0.1.0"
[project]
name = "sklearnexample"
version = "1.0.0"
chongshenng marked this conversation as resolved.
Show resolved Hide resolved
description = "Federated learning with scikit-learn and Flower"
authors = [
"The Flower Authors <hello@flower.ai>",
"Kaushik Amar Das <kaushik.das@iiitg.ac.in>",
{ name = "The Flower Authors", email = "hello@flower.ai" },
{ name = "Kaushik Amar Das", email = "kaushik.das@iiitg.ac.in" },
]
dependencies = [
"flwr[simulation]>=1.10.0",
"flwr-datasets[vision]>=0.3.0",
"numpy<2.0.0",
"scikit-learn~=1.2.2",
]

[tool.hatch.build.targets.wheel]
packages = ["."]

[tool.flwr.app]
publisher = "flowerlabs"
chongshenng marked this conversation as resolved.
Show resolved Hide resolved

[tool.flwr.app.components]
serverapp = "sklearnexample.server_app:app"
clientapp = "sklearnexample.client_app:app"

[tool.flwr.app.config]
penalty = "l1"
chongshenng marked this conversation as resolved.
Show resolved Hide resolved
num-server-rounds = 3
min-available-clients = 2

[tool.flwr.federations]
default = "local-simulation"

[tool.poetry.dependencies]
python = "^3.8"
flwr = ">=1.0,<2.0"
# flwr = { path = "../../", develop = true } # Development
flwr-datasets = { extras = ["vision"], version = ">=0.0.2,<1.0.0" }
scikit-learn = "^1.1.1"
[tool.flwr.federations.local-simulation]
options.num-supernodes = 10
4 changes: 0 additions & 4 deletions examples/sklearn-logreg-mnist/requirements.txt

This file was deleted.

17 changes: 0 additions & 17 deletions examples/sklearn-logreg-mnist/run.sh

This file was deleted.

47 changes: 0 additions & 47 deletions examples/sklearn-logreg-mnist/server.py

This file was deleted.

1 change: 1 addition & 0 deletions examples/sklearn-logreg-mnist/sklearnexample/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""sklearn_example."""
63 changes: 63 additions & 0 deletions examples/sklearn-logreg-mnist/sklearnexample/client_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""sklearnexample: A Flower / scikit-learn app."""

import warnings

from sklearn.metrics import log_loss
from sklearnexample.task import (
create_log_reg_and_instantiate_parameters,
get_model_parameters,
load_data,
set_model_params,
)

from flwr.client import Client, ClientApp, NumPyClient
from flwr.common import Context


# Define Flower client
class MnistClient(NumPyClient):
def __init__(
self, model, X_train, X_test, y_train, y_test
): # pylint: disable=R0913
self.model = model
self.X_train = X_train
self.X_test = X_test
self.y_train = y_train
self.y_test = y_test

def fit(self, parameters, config): # type: ignore
set_model_params(self.model, parameters)
# Ignore convergence failure due to low local epochs
with warnings.catch_warnings():
warnings.simplefilter("ignore")
self.model.fit(self.X_train, self.y_train)
print(f"Training finished for round {config['server_round']}")
chongshenng marked this conversation as resolved.
Show resolved Hide resolved
return get_model_parameters(self.model), len(self.X_train), {}

def evaluate(self, parameters, config): # type: ignore
set_model_params(self.model, parameters)
loss = log_loss(self.y_test, self.model.predict_proba(self.X_test))
accuracy = self.model.score(self.X_test, self.y_test)
return loss, len(self.X_test), {"accuracy": accuracy}


def client_fn(context: Context) -> Client:
"""Construct a Client that will be run in a ClientApp."""

# Read the node_config to fetch data partition associated to this node
partition_id = context.node_config["partition-id"]
num_partitions = context.node_config["num-partitions"]
X_train, X_test, y_train, y_test = load_data(partition_id, num_partitions)

# Read the run config to get settings to configure the Client
penalty = context.run_config["penalty"]

# Create LogisticRegression Model
model = create_log_reg_and_instantiate_parameters(penalty)

# Return Client instance
return MnistClient(model, X_train, X_test, y_train, y_test).to_client()


# Create ClientApp
app = ClientApp(client_fn=client_fn)
Loading