Upgrade to Flower 1.13¶
Welcome to the migration guide for updating Flower to Flower 1.13! Whether you’re a seasoned user or just getting started, this guide will help you smoothly transition your existing setup to take advantage of the latest features and improvements in Flower 1.13.
Note
This guide shows how to make pre-1.13
Flower code compatible with Flower 1.13
(and later) with only minimal code changes.
Let’s dive in!
Install update¶
Here’s how to update an existing installation of Flower to Flower 1.13 with pip
:
$ python -m pip install -U flwr
or if you need Flower 1.13 with simulation:
$ python -m pip install -U "flwr[simulation]"
Ensure you set the following version constraint in your requirements.txt
# Without simulation support
flwr>=1.13,<2.0
# With simulation support
flwr[simulation]>=1.13, <2.0
or pyproject.toml
:
# Without simulation support
dependencies = [
"flwr>=1.13,2.0",
]
# With simulation support
dependencies = [
"flwr[simulation]>=1.13,2.0",
]
Required changes¶
Starting with Flower 1.8, the infrastructure and application layers have been decoupled. Flower 1.13 enforces this separation further. Among other things, this allows you to run the exact same code in a simulation as in a real deployment.
Instead of starting a client in code via start_client()
, you create a
ClientApp
. Instead of starting a server in code via start_server()
, you
create a ServerApp
. Both ClientApp
and ServerApp
are started by the
long-running components of the server and client: the SuperLink and SuperNode,
respectively.
Tip
For more details on SuperLink and SuperNode, please see the Flower Architecture .
The following non-breaking changes require manual updates and allow you to run your project both in the traditional (now deprecated) way and in the new (recommended) Flower 1.13 way:
ClientApp
¶
Wrap your existing client with
ClientApp
instead of launching it viastart_client()
. Here’s an example:
from flwr.client import ClientApp, start_client
from flwr.common import Context
# Flower 1.10 and later (recommended)
def client_fn(context: Context):
return FlowerClient().to_client()
app = ClientApp(client_fn=client_fn)
# # Flower 1.8 - 1.9 (deprecated, no longer supported)
# def client_fn(cid: str):
# return FlowerClient().to_client()
#
#
# app = ClientApp(client_fn=client_fn)
# Flower 1.7 (deprecated, only for backwards-compatibility)
if __name__ == "__main__":
start_client(
server_address="127.0.0.1:8080",
client=FlowerClient().to_client(),
)
ServerApp
¶
Wrap your existing strategy with
ServerApp
instead of starting the server viastart_server()
. Here’s an example:
from flwr.common import Context
from flwr.server import ServerApp, ServerAppComponents, ServerConfig, start_server
from flwr.server.strategy import FedAvg
# Flower 1.10 and later (recommended)
def server_fn(context: Context):
strategy = FedAvg()
config = ServerConfig()
return ServerAppComponents(config=config, strategy=strategy)
app = ServerApp(server_fn=server_fn)
# # Flower 1.8 - 1.9 (deprecated, no longer supported)
# app = flwr.server.ServerApp(
# config=config,
# strategy=strategy,
# )
# Flower 1.7 (deprecated, only for backwards-compatibility)
if __name__ == "__main__":
start_server(
server_address="0.0.0.0:8080",
config=config,
strategy=strategy,
)
Deployment¶
In a terminal window, start the SuperLink using
flower-superlink
. Then, in two additional terminal windows, start two SuperNodes usingflower-supernode
(2x). There is no need to directly runclient.py
andserver.py
as Python scripts.Here’s an example to start the server without HTTPS (insecure mode, only for prototyping):
Tip
For a comprehensive walk-through on how to deploy Flower using Docker, please refer to the Run Flower using Docker guide.
# Start a SuperLink
$ flower-superlink --insecure
# In a new terminal window, start a long-running SuperNode
$ flower-supernode \
--insecure \
--superlink 127.0.0.1:9092 \
--clientappio-api-address 127.0.0.1:9094 \
<other-args>
# In another terminal window, start another long-running SuperNode (at least 2 SuperNodes are required)
$ flower-supernode \
--insecure \
--superlink 127.0.0.1:9092 \
--clientappio-api-address 127.0.0.1:9095 \
<other-args>
Here’s another example to start both SuperLink and SuperNodes with HTTPS. Use the
--ssl-ca-certfile
,--ssl-certfile
, and--ssl-keyfile
command line options to pass paths to (CA certificate, server certificate, and server private key).
# Start a secure SuperLink
$ flower-superlink \
--ssl-ca-certfile <your-ca-cert-filepath> \
--ssl-certfile <your-server-cert-filepath> \
--ssl-keyfile <your-privatekey-filepath>
# In a new terminal window, start a long-running SuperNode
$ flower-supernode \
--superlink 127.0.0.1:9092 \
--clientappio-api-address 127.0.0.1:9094 \
--root-certificates <your-ca-cert-filepath> \
<other-args>
# In another terminal window, start another long-running SuperNode (at least 2 SuperNodes are required)
$ flower-supernode \
--superlink 127.0.0.1:9092 \
--clientappio-api-address 127.0.0.1:9095 \
--root-certificates <your-ca-cert-filepath> \
<other-args>
Simulation (CLI)¶
Wrap your existing client and strategy with ClientApp
and ServerApp
,
respectively. There is no need to use start_simulation()
anymore. Here’s an example:
Tip
For a comprehensive guide on how to setup and run Flower simulations please read the How-to Run Simulations guide.
from flwr.client import ClientApp
from flwr.common import Context
from flwr.server import ServerApp, ServerAppComponents, ServerConfig
from flwr.server.strategy import FedAvg
from flwr.simulation import start_simulation
# Regular Flower client implementation
class FlowerClient(NumPyClient):
# ...
pass
# Flower 1.10 and later (recommended)
def client_fn(context: Context):
return FlowerClient().to_client()
app = ClientApp(client_fn=client_fn)
def server_fn(context: Context):
strategy = FedAvg(...)
config = ServerConfig(...)
return ServerAppComponents(strategy=strategy, config=config)
server_app = ServerApp(server_fn=server_fn)
# # Flower 1.8 - 1.9 (deprecated, no longer supported)
# def client_fn(cid: str):
# return FlowerClient().to_client()
#
#
# client_app = ClientApp(client_fn=client_fn)
#
#
# server_app = ServerApp(
# config=config,
# strategy=strategy,
# )
# Flower 1.7 (deprecated, only for backwards-compatibility)
if __name__ == "__main__":
hist = start_simulation(
num_clients=10,
# ...
)
Depending on your Flower version, you can run your simulation as follows:
For Flower 1.11 and later, run
flwr run
in the terminal. This is the recommended way to start simulations, other ways are deprecated and no longer recommended.DEPRECATED For Flower versions between 1.8 and 1.10, run
flower-simulation
in the terminal and point to theserver_app
/client_app
object in the code instead of executing the Python script. In the code snippet below, there is an example (assuming theserver_app
andclient_app
objects are in asim.py
module).DEPRECATED For Flower versions before 1.8, run the Python script directly.
# Flower 1.11 and later (recommended)
$ flwr run
# # Flower 1.8 - 1.10 (deprecated, no longer supported)
# $ flower-simulation \
# --server-app=sim:server_app \
# --client-app=sim:client_app \
# --num-supernodes=10
# Flower 1.7 (deprecated)
$ python sim.py
Depending on your Flower version, you can also define the default resources as follows:
For Flower 1.11 and later, you can edit your
pyproject.toml
file and then runflwr run
in the terminal as shown in the example below.DEPRECATED For Flower versions between 1.8 and 1.10, you can adjust the resources for each
ClientApp
using the--backend-config
command line argument instead of setting theclient_resources
argument instart_simulation()
.DEPRECATED For Flower versions before 1.8, you need to run
start_simulation()
and pass a dictionary of the required resources to theclient_resources
argument.
# Flower 1.11 and later (recommended)
# [file: pyproject.toml]
[tool.flwr.federations.local-sim-gpu]
options.num-supernodes = 10
options.backend.client-resources.num-cpus = 2
options.backend.client-resources.num-gpus = 0.25
$ flwr run
# # Flower 1.8 - 1.10 (deprecated, no longer supported)
# $ flower-simulation \
# --client-app=sim:client_app \
# --server-app=sim:server_app \
# --num-supernodes=10 \
# --backend-config='{"client_resources": {"num_cpus": 2, "num_gpus": 0.25}}'
# Flower 1.7 (in `sim.py`, deprecated)
if __name__ == "__main__":
hist = start_simulation(
num_clients=10, client_resources={"num_cpus": 2, "num_gpus": 0.25}, ...
)
Simulation (Notebook)¶
To run your simulation from within a notebook, please consider the following examples depending on your Flower version:
For Flower 1.11 and later, you need to run
run_simulation()
in your notebook instead ofstart_simulation()
.DEPRECATED For Flower versions between 1.8 and 1.10, you need to run
run_simulation()
in your notebook instead ofstart_simulation()
and configure the resources.DEPRECATED For Flower versions before 1.8, you need to run
start_simulation()
and pass a dictionary of the required resources to theclient_resources
argument.
Tip
For a comprehensive guide on how to setup and run Flower simulations please read the How-to Run Simulations guide.
from flwr.client import ClientApp
from flwr.common import Context
from flwr.server import ServerApp
from flwr.simulation import run_simulation, start_simulation
# Flower 1.10 and later (recommended)
# Omitted: client_fn and server_fn
client_app = ClientApp(client_fn=client_fn)
server_app = ServerApp(server_fn=server_fn)
run_simulation(
server_app=server_app,
client_app=client_app,
)
# # Flower v1.8 - v1.10 (deprecated, no longer supported)
# NUM_CLIENTS = 10 # Replace by any integer greater than zero
# backend_config = {"client_resources": {"num_cpus": 2, "num_gpus": 0.25}}
#
#
# def client_fn(cid: str):
# # ...
# return FlowerClient().to_client()
#
#
# client_app = ClientApp(client_fn=client_fn)
#
# server_app = ServerApp(
# config=config,
# strategy=strategy,
# )
#
# run_simulation(
# server_app=server_app,
# client_app=client_app,
# num_supernodes=NUM_CLIENTS,
# backend_config=backend_config,
# )
# Flower v1.7 (deprecated)
NUM_CLIENTS = 10 # Replace by any integer greater than zero
backend_config = {"client_resources": {"num_cpus": 2, "num_gpus": 0.25}}
start_simulation(
client_fn=client_fn,
num_clients=NUM_CLIENTS,
config=config,
strategy=strategy,
client_resources=backend_config["client_resources"],
)
Further help¶
Most official Flower code examples are already
updated to Flower 1.13 so they can serve as a reference for using the Flower 1.13 API.
If there are further questions, join the Flower Slack
(and use the channel #questions
) or post them on Flower Discuss where you can find the community posting and answering
questions.
Important
As we continuously enhance Flower at a rapid pace, we’ll be periodically updating this guide. Please feel free to share any feedback with us!
Happy migrating! 🚀