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

Stop using start_numpy_client in e2e tests #2869

Merged
merged 24 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
304b196
added deprecated warning back
jafermarq Nov 6, 2023
fa68a97
Merge branch 'main' into deprecate-numpyclient-docs-update
jafermarq Dec 18, 2023
099f6cf
Merge branch 'main' into deprecate-numpyclient-docs-update
jafermarq Dec 19, 2023
b5280f8
updating docs
jafermarq Dec 19, 2023
dfd1ba4
format
jafermarq Dec 19, 2023
24cf3a0
better
jafermarq Dec 20, 2023
f0ac956
howto ssl
jafermarq Dec 20, 2023
25063a5
to changelog
jafermarq Dec 20, 2023
22ad72e
Merge branch 'main' into deprecate-numpyclient-docs-update
jafermarq Jan 4, 2024
07d188d
Merge branch 'main' into deprecate-numpyclient-docs-update
jafermarq Jan 18, 2024
a62a4e0
Merge branch 'main' into deprecate-numpyclient-docs-update
jafermarq Jan 29, 2024
bb6b253
using new deprecation logger func
jafermarq Jan 29, 2024
d06ddd2
better docs
jafermarq Jan 29, 2024
4093fd4
revert
jafermarq Jan 29, 2024
d1fa553
Merge branch 'main' into deprecate-numpyclient-docs-update
jafermarq Jan 29, 2024
8c1b0f4
no start_numpy_client
jafermarq Jan 29, 2024
0715990
format
jafermarq Jan 29, 2024
5f2a854
Merge branch 'deprecate-numpyclient-docs-update' into remove-start-nu…
jafermarq Jan 29, 2024
675e77c
Merge branch 'main' into remove-start-numpy-client-e2e-tests
jafermarq Jan 30, 2024
671f941
Update doc/source/ref-changelog.md
danieljanes Jan 30, 2024
d1c675f
Update doc/source/tutorial-quickstart-pytorch.rst
danieljanes Jan 30, 2024
ad09b11
Update src/py/flwr/client/app.py
danieljanes Jan 30, 2024
7a26bba
Update src/py/flwr/client/app.py
danieljanes Jan 30, 2024
fd1a2f6
Update src/py/flwr/client/app.py
danieljanes Jan 30, 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
2 changes: 1 addition & 1 deletion doc/source/example-jax-from-centralized-to-federated.rst
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ Having defined the federation process, we can run it.

# Start Flower client
client = FlowerClient(params, grad_fn, train_x, train_y, test_x, test_y)
fl.client.start_numpy_client(server_address="0.0.0.0:8080", client)
fl.client.start_client(server_address="0.0.0.0:8080", client.to_client())

if __name__ == "__main__":
main()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ We included type annotations to give you a better understanding of the data type
return float(loss), self.num_examples["testset"], {"accuracy": float(accuracy)}

All that's left to do it to define a function that loads both model and data, creates a :code:`CifarClient`, and starts this client.
You load your data and model by using :code:`cifar.py`. Start :code:`CifarClient` with the function :code:`fl.client.start_numpy_client()` by pointing it at the same IP adress we used in :code:`server.py`:
You load your data and model by using :code:`cifar.py`. Start :code:`CifarClient` with the function :code:`fl.client.start_client()` by pointing it at the same IP adress we used in :code:`server.py`:

.. code-block:: python

Expand All @@ -292,7 +292,7 @@ You load your data and model by using :code:`cifar.py`. Start :code:`CifarClient

# Start client
client = CifarClient(model, trainloader, testloader, num_examples)
fl.client.start_numpy_client(server_address="0.0.0.0:8080", client)
fl.client.start_client(server_address="0.0.0.0:8080", client.to_client())


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions doc/source/how-to-enable-ssl-connections.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ We are now going to show how to write a client which uses the previously generat
client = MyFlowerClient()

# Start client
fl.client.start_numpy_client(
fl.client.start_client(
"localhost:8080",
client=client,
client=client.to_client(),
root_certificates=Path(".cache/certificates/ca.crt").read_bytes(),
)

Expand Down
2 changes: 1 addition & 1 deletion doc/source/how-to-run-simulations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Run simulations

Simulating Federated Learning workloads is useful for a multitude of use-cases: you might want to run your workload on a large cohort of clients but without having to source, configure and mange a large number of physical devices; you might want to run your FL workloads as fast as possible on the compute systems you have access to without having to go through a complex setup process; you might want to validate your algorithm on different scenarios at varying levels of data and system heterogeneity, client availability, privacy budgets, etc. These are among some of the use-cases where simulating FL workloads makes sense. Flower can accommodate these scenarios by means of its `VirtualClientEngine <contributor-explanation-architecture.html#virtual-client-engine>`_ or VCE.

The :code:`VirtualClientEngine` schedules, launches and manages `virtual` clients. These clients are identical to `non-virtual` clients (i.e. the ones you launch via the command `flwr.client.start_numpy_client <ref-api-flwr.html#start-numpy-client>`_) in the sense that they can be configure by creating a class inheriting, for example, from `flwr.client.NumPyClient <ref-api-flwr.html#flwr.client.NumPyClient>`_ and therefore behave in an identical way. In addition to that, clients managed by the :code:`VirtualClientEngine` are:
The :code:`VirtualClientEngine` schedules, launches and manages `virtual` clients. These clients are identical to `non-virtual` clients (i.e. the ones you launch via the command `flwr.client.start_client <ref-api-flwr.html#start-client>`_) in the sense that they can be configure by creating a class inheriting, for example, from `flwr.client.NumPyClient <ref-api-flwr.html#flwr.client.NumPyClient>`_ and therefore behave in an identical way. In addition to that, clients managed by the :code:`VirtualClientEngine` are:

* resource-aware: this means that each client gets assigned a portion of the compute and memory on your system. You as a user can control this at the beginning of the simulation and allows you to control the degree of parallelism of your Flower FL simulation. The fewer the resources per client, the more clients can run concurrently on the same hardware.
* self-managed: this means that you as a user do not need to launch clients manually, instead this gets delegated to :code:`VirtualClientEngine`'s internals.
Expand Down
4 changes: 4 additions & 0 deletions doc/source/ref-changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

- **Retiring MXNet examples** The development of the MXNet fremework has ended and the project is now [archived on GitHub](https://github.com/apache/mxnet). Existing MXNet examples won't receive updates [#2724](https://github.com/adap/flower/pull/2724)

- **Deprecated `start_numpy_client`**. ([#2563](https://github.com/adap/flower/pull/2563))

Until now, clients of type `NumPyClient` needed to be started via `start_numpy_client`. In our efforts to consolidate the core framework, we have introduced changes, and now all client types should start via `start_client`. To continue using `NumPyClient` clients, you simply need to first call the `.to_client()` method and then pass returned `Client` object to `start_client`. The examples and the documentation have been updated accordingly.

- **Update Flower Baselines**

- HFedXGBoost [#2226](https://github.com/adap/flower/pull/2226)
Expand Down
4 changes: 2 additions & 2 deletions doc/source/tutorial-quickstart-huggingface.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,9 @@ We can now start client instances using:

.. code-block:: python

fl.client.start_numpy_client(
fl.client.start_client(
server_address="127.0.0.1:8080",
client=IMDBClient()
client=IMDBClient().to_client()
)


Expand Down
2 changes: 1 addition & 1 deletion doc/source/tutorial-quickstart-jax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ Having defined the federation process, we can run it.

# Start Flower client
client = FlowerClient(params, grad_fn, train_x, train_y, test_x, test_y)
fl.client.start_numpy_client(server_address="0.0.0.0:8080", client)
fl.client.start_client(server_address="0.0.0.0:8080", client=client.to_client())

if __name__ == "__main__":
main()
Expand Down
4 changes: 2 additions & 2 deletions doc/source/tutorial-quickstart-pytorch.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ to actually run this client:

.. code-block:: python

fl.client.start_numpy_client(server_address="[::]:8080", client=CifarClient())
fl.client.start_client(server_address="[::]:8080", client=CifarClient().to_client())

That's it for the client. We only have to implement :code:`Client` or
:code:`NumPyClient` and call :code:`fl.client.start_client()` or :code:`fl.client.start_numpy_client()`. The string :code:`"[::]:8080"` tells the client which server to connect to. In our case we can run the server and the client on the same machine, therefore we use
:code:`NumPyClient` and call :code:`fl.client.start_client()`. If you implement a client of type :code:`NumPyClient` you'll need to first call its :code:`to_client()` method. The string :code:`"[::]:8080"` tells the client which server to connect to. In our case we can run the server and the client on the same machine, therefore we use
:code:`"[::]:8080"`. If we run a truly federated workload with the server and
clients running on different machines, all that needs to change is the
:code:`server_address` we point the client at.
Expand Down
4 changes: 2 additions & 2 deletions doc/source/tutorial-quickstart-scikitlearn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,10 @@ to actually run this client:

.. code-block:: python

fl.client.start_numpy_client("0.0.0.0:8080", client=MnistClient())
fl.client.start_client("0.0.0.0:8080", client=MnistClient().to_client())

That's it for the client. We only have to implement :code:`Client` or
:code:`NumPyClient` and call :code:`fl.client.start_client()` or :code:`fl.client.start_numpy_client()`. The string :code:`"0.0.0.0:8080"` tells the client which server to connect to. In our case we can run the server and the client on the same machine, therefore we use
:code:`NumPyClient` and call :code:`fl.client.start_client()`. If you implement a client of type :code:`NumPyClient` you'll need to first call its :code:`to_client()` method. The string :code:`"0.0.0.0:8080"` tells the client which server to connect to. In our case we can run the server and the client on the same machine, therefore we use
:code:`"0.0.0.0:8080"`. If we run a truly federated workload with the server and
clients running on different machines, all that needs to change is the
:code:`server_address` we pass to the client.
Expand Down
4 changes: 2 additions & 2 deletions doc/source/tutorial-quickstart-tensorflow.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,11 @@ to actually run this client:

.. code-block:: python

fl.client.start_numpy_client(server_address="[::]:8080", client=CifarClient())
fl.client.start_client(server_address="[::]:8080", client=CifarClient().to_client())


That's it for the client. We only have to implement :code:`Client` or
:code:`NumPyClient` and call :code:`fl.client.start_client()` or :code:`fl.client.start_numpy_client()`. The string :code:`"[::]:8080"` tells the client which server to connect to. In our case we can run the server and the client on the same machine, therefore we use
:code:`NumPyClient` and call :code:`fl.client.start_client()`. If you implement a client of type :code:`NumPyClient` you'll need to first call its :code:`to_client()` method. The string :code:`"[::]:8080"` tells the client which server to connect to. In our case we can run the server and the client on the same machine, therefore we use
:code:`"[::]:8080"`. If we run a truly federated workload with the server and
clients running on different machines, all that needs to change is the
:code:`server_address` we point the client at.
Expand Down
4 changes: 2 additions & 2 deletions e2e/bare-https/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(
fl.client.start_client(
server_address="127.0.0.1:8080",
client=FlowerClient(),
client=FlowerClient().to_client(),
root_certificates=Path("certificates/ca.crt").read_bytes(),
insecure=False,
)
2 changes: 1 addition & 1 deletion e2e/bare/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=FlowerClient())
fl.client.start_client(server_address="127.0.0.1:8080", client=FlowerClient().to_client())
4 changes: 2 additions & 2 deletions e2e/fastai/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(
fl.client.start_client(
server_address="127.0.0.1:8080",
client=FlowerClient(),
client=FlowerClient().to_client(),
)
2 changes: 1 addition & 1 deletion e2e/jax/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=FlowerClient())
fl.client.start_client(server_address="127.0.0.1:8080", client=FlowerClient().to_client())
4 changes: 2 additions & 2 deletions e2e/opacus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def client_fn(cid):
)

if __name__ == "__main__":
fl.client.start_numpy_client(
fl.client.start_client(
server_address="127.0.0.1:8080",
client=FlowerClient(model)
client=FlowerClient(model).to_client()
)
4 changes: 2 additions & 2 deletions e2e/pandas/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(
fl.client.start_client(
server_address="127.0.0.1:8080",
client=FlowerClient(),
client=FlowerClient().to_client(),
)
4 changes: 2 additions & 2 deletions e2e/pytorch-lightning/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ def main() -> None:
train_loader, val_loader, test_loader = mnist.load_data()

# Flower client
client = FlowerClient(model, train_loader, val_loader, test_loader)
fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=client)
client = FlowerClient(model, train_loader, val_loader, test_loader).to_client()
fl.client.start_client(server_address="127.0.0.1:8080", client=client)


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions e2e/pytorch/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(
fl.client.start_client(
server_address="127.0.0.1:8080",
client=FlowerClient(),
client=FlowerClient().to_client(),
)
2 changes: 1 addition & 1 deletion e2e/scikit-learn/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(server_address="0.0.0.0:8080", client=FlowerClient())
fl.client.start_client(server_address="0.0.0.0:8080", client=FlowerClient().to_client())
2 changes: 1 addition & 1 deletion e2e/strategies/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=FlowerClient())
fl.client.start_client(server_address="127.0.0.1:8080", client=FlowerClient().to_client())
2 changes: 1 addition & 1 deletion e2e/tabnet/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=FlowerClient())
fl.client.start_client(server_address="127.0.0.1:8080", client=FlowerClient().to_client())
2 changes: 1 addition & 1 deletion e2e/tensorflow/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ def client_fn(cid):

if __name__ == "__main__":
# Start Flower client
fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=FlowerClient())
fl.client.start_client(server_address="127.0.0.1:8080", client=FlowerClient().to_client())
35 changes: 21 additions & 14 deletions src/py/flwr/client/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
TRANSPORT_TYPE_REST,
TRANSPORT_TYPES,
)
from flwr.common.logger import log, warn_experimental_feature
from flwr.common.logger import log, warn_deprecated_feature, warn_experimental_feature
from flwr.common.message import Message

from .flower import load_flower_callable
Expand Down Expand Up @@ -399,6 +399,12 @@ def start_numpy_client(
) -> None:
"""Start a Flower NumPyClient which connects to a gRPC server.

Warning
-------
This function is deprecated since 1.7.0. Use :code:`flwr.client.start_client`
instead and first convert your :code:`NumPyClient` to type :code:`flwr.client.Client` by
exectuing its :code:`to_client()` method.
danieljanes marked this conversation as resolved.
Show resolved Hide resolved

Parameters
----------
server_address : str
Expand Down Expand Up @@ -454,21 +460,22 @@ def start_numpy_client(
>>> root_certificates=Path("/crts/root.pem").read_bytes(),
>>> )
"""
# warnings.warn(
# "flwr.client.start_numpy_client() is deprecated and will "
# "be removed in a future version of Flower. Instead, pass "
# "your client to `flwr.client.start_client()` by calling "
# "first the `.to_client()` method as shown below: \n"
# "\tflwr.client.start_client(\n"
# "\t\tserver_address='<IP>:<PORT>',\n"
# "\t\tclient=FlowerClient().to_client()\n"
# "\t)",
# DeprecationWarning,
# stacklevel=2,
# )
mssg = (
"flwr.client.start_numpy_client() is deprecated. \n\tInstead, use "
"`flwr.client.start_client()` by ensuring you first call "
"the `.to_client()` method as shown below: \n"
"\tflwr.client.start_client(\n"
"\t\tserver_address='<IP>:<PORT>',\n"
"\t\tclient=FlowerClient().to_client(),"
" # <-- where FlowerClient is of type flwr.client.NumPyClient object\n"
"\t)\n"
"\tUsing `start_numpy_client()` is deprecated."
)

warn_deprecated_feature(name=mssg)

# Calling this function is deprecated. A warning is thrown.
# We first need to convert either the supplied client to `Client.`
# We first need to convert the supplied client to `Client.`

wrp_client = client.to_client()

Expand Down
21 changes: 11 additions & 10 deletions src/py/flwr/simulation/ray_transport/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""Utilities for Actors in the Virtual Client Engine."""

import traceback
import warnings
from logging import ERROR

from flwr.client import Client
Expand All @@ -26,7 +27,7 @@
TF = None

# Display Deprecation warning once
# warnings.filterwarnings("once", category=DeprecationWarning)
warnings.filterwarnings("once", category=DeprecationWarning)


def enable_tf_gpu_growth() -> None:
Expand Down Expand Up @@ -69,15 +70,15 @@ def check_clientfn_returns_client(client: Client) -> Client:
the client internally to `Client` by calling `.to_client()`.
"""
if not isinstance(client, Client):
# mssg = (
# " Ensure your client is of type `Client`. Please convert it"
# " using the `.to_client()` method before returning it"
# " in the `client_fn` you pass to `start_simulation`."
# " We have applied this conversion on your behalf."
# " Not returning a `Client` might trigger an error in future"
# " versions of Flower."
# )
mssg = (
" Ensure your client is of type `flwr.client.Client`. Please convert it"
" using the `.to_client()` method before returning it"
" in the `client_fn` you pass to `start_simulation`."
" We have applied this conversion on your behalf."
" Not returning a `Client` might trigger an error in future"
" versions of Flower."
)

# warnings.warn(mssg, DeprecationWarning, stacklevel=2)
warnings.warn(mssg, DeprecationWarning, stacklevel=2)
client = client.to_client()
return client
Loading