diff --git a/docs/apiclient.rst b/docs/apiclient.rst index 360691d18..c17451820 100644 --- a/docs/apiclient.rst +++ b/docs/apiclient.rst @@ -1,13 +1,12 @@ .. _apiclient-label: -Using the FEDn API Client +Using the API Client ==================== -FEDn comes with an *APIClient* - a Python3 library that can be used to interact with FEDn programmatically. -In this tutorial we show how to use the APIClient to initialize the server-side with the compute package and seed models, -run and control training sessions, use different aggregators, and to retrieve models and metrics. +FEDn comes with an *APIClient* - a Python3 library that is used to interact with FEDn programmatically. -We assume a basic understanding of the FEDn framework, i.e. that the user has taken the :ref:`quickstart-label` tutorial. +This guide assumes that the user has aleady taken the :ref:`quickstart-label` tutorial. If this is not the case, please start there to learn how to set up a FEDn Studio project and learn +to connect clients. In this guide we will build on that same PyTorch example (MNIST), showing how to use the APIClient to control training sessions, use different aggregators, and to retrieve models and metrics. **Installation** @@ -17,14 +16,22 @@ The APIClient is available as a Python package on PyPI, and can be installed usi $ pip install fedn -**Initialize the APIClient to a FEDn Studio project** +**Connect the APIClient to the FEDn project** -The FEDn REST API is available at /api/v1/. To access this API you need the url to the controller-host, as well as an admin API token. The controller host can be found in the project dashboard (top right corner). -To obtain an admin API token, +To access the API you need the URL to the controller-host, as well as an admin API token. You +obtain these from your Studio project. The controller host can be found in the top-right corner of the dashboard: + +.. image:: img/find_controller_url.png + +To obtain an admin API token, #. Navigate to the "Settings" tab in your Studio project and click on the "Generate token" button. #. Copy the 'access' token and use it to access the API using the instructions below. +.. image:: img/generate_admin_token.png + +To initalize the connection to the FEDn REST API: + .. code-block:: python >>> from fedn import APIClient @@ -43,6 +50,11 @@ Then passing a token as an argument is not required. >>> from fedn import APIClient >>> client = APIClient(host="", secure=True, verify=True) +We are now ready to work with the API. + +We here assume that you have worked through steps 1-2 in the quisktart tutorial, i.e. that you have created the compute package and seed model on your local machine. +In the next step, we will use the API to upload these objects to the Studio project (corresponding to step 3 in the quickstart tutorial). + **Set the active compute package and seed model** To set the active compute package in the FEDn Studio Project: @@ -69,6 +81,8 @@ using the default aggregator (FedAvg): >>> model_id = models[-1]['model'] >>> validations = client.get_validations(model_id=model_id) +You can follow the progress of the training in the Studio UI. + To run a session using the FedAdam aggregator using custom hyperparamters: .. code-block:: python @@ -130,9 +144,10 @@ To get a specific session: >>> session = client.get_session(id="session_name") -For more information on how to use the APIClient, see the :py:mod:`fedn.network.api.client`, and the collection of example Jupyter Notebooks: +For more information on how to use the APIClient, see the :py:mod:`fedn.network.api.client`. +There is also a collection of Jupyter Notebooks showcasing more advanced use of the API, including how to work with other built-in aggregators and how to automate hyperparameter tuning: -- `API Example `_ . +- `API Example `_ . .. meta:: diff --git a/docs/img/find_controller_url.png b/docs/img/find_controller_url.png new file mode 100644 index 000000000..c266e2019 Binary files /dev/null and b/docs/img/find_controller_url.png differ diff --git a/docs/img/generate_admin_token.png b/docs/img/generate_admin_token.png new file mode 100644 index 000000000..d0a5b4d8b Binary files /dev/null and b/docs/img/generate_admin_token.png differ diff --git a/examples/api-tutorials/API_Example.ipynb b/examples/api-tutorials/API_Example.ipynb new file mode 100644 index 000000000..bb04472d6 --- /dev/null +++ b/examples/api-tutorials/API_Example.ipynb @@ -0,0 +1,204 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "622f7047", + "metadata": {}, + "source": [ + "## API Example\n", + "\n", + "This notebook provides an example of how to use the FEDn API to organize experiments and to analyze validation results. We will here run one training session (a collection of global rounds) using FedAvg, then retrive and visualize the results. For a complete list of implemented interfaces, please refer to the [FEDn APIs](https://fedn.readthedocs.io/en/latest/fedn.network.api.html#module-fedn.network.api.client).\n", + "\n", + "Before starting this tutorial, make sure you have a project running in FEDn Studio and have created the compute package and the initial model. If you're not sure how to do this, please follow the instructions in sections 1, 2, and 3 of the [quickstart guide](https://fedn.readthedocs.io/en/latest/quickstart.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "743dfe47", + "metadata": {}, + "outputs": [], + "source": [ + "from fedn import APIClient\n", + "import time\n", + "import uuid\n", + "import json\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import collections" + ] + }, + { + "cell_type": "markdown", + "id": "1046a4e5", + "metadata": {}, + "source": [ + "We connect to the FEDn API service. In this example, we assume the project is hosted on the public FEDn Studio. You can find the CONTROLLER_HOST address in the project dashboard. \n", + "\n", + "NOTE: If you're using a local sandbox, the CONTROLLER_HOST will be \"localhost or 127.0.0.1 or your local node's IP address\" and the CONTROLLER_PORT will be 8092. \n", + "\n", + "Next, you'll need to generate an access token. To do this, go to the project page in FEDn Studio, click on \"Settings,\" then \"Generate token.\" Copy the access token from the Studio and paste it into the notebook. In case you need further details, have a look at the [Fedn ClientAPIs](https://fedn.readthedocs.io/en/latest/apiclient.html#). " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1061722d", + "metadata": {}, + "outputs": [], + "source": [ + "CONTROLLER_HOST = '' \n", + "ACCESS_TOKEN = ''\n", + "client = APIClient(CONTROLLER_HOST,token=ACCESS_TOKEN, secure=True,verify=True)" + ] + }, + { + "cell_type": "markdown", + "id": "07f69f5f", + "metadata": {}, + "source": [ + "Initialize FEDn with the compute package and seed model. Note that these files needs to be created separately. If you're not sure how to do this, please follow the instructions in the [quickstart guide](https://fedn.readthedocs.io/en/latest/quickstart.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "5107f6f9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'committed_at': 'Sun, 01 Dec 2024 18:41:40 GMT', 'id': '674cade4e17757ea8146d74d', 'key': 'models', 'model': 'd25f0bd9-6fc9-4cf1-9d8d-4ed9e04dfef0', 'parent_model': None, 'session_id': None}\n" + ] + } + ], + "source": [ + "client.set_active_package('../mnist-pytorch/package.tgz', 'numpyhelper')\n", + "client.set_active_model('../mnist-pytorch/seed.npz')\n", + "seed_model = client.get_active_model()\n", + "print(seed_model)" + ] + }, + { + "cell_type": "markdown", + "id": "4e26c50b", + "metadata": {}, + "source": [ + "Next we start a training session using FedAvg and wait until it has finished:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "f0380d35", + "metadata": {}, + "outputs": [], + "source": [ + "session_id = \"experiment1\"\n", + "\n", + "session_config = {\n", + " \"helper\": \"numpyhelper\",\n", + " \"id\": session_id,\n", + " \"aggregator\": \"fedavg\",\n", + " \"model_id\": seed_model['model'],\n", + " \"rounds\": 10\n", + " }\n", + "\n", + "result_fedavg = client.start_session(**session_config)\n", + "\n", + "# We wait for the session to finish\n", + "while not client.session_is_finished(session_config['id']):\n", + " time.sleep(2)" + ] + }, + { + "cell_type": "markdown", + "id": "16874cec", + "metadata": {}, + "source": [ + "Next, we get the model trail, retrieve all model validations from all clients, extract the training accuracy metric, and compute its mean value accross all clients." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "4e8044b7", + "metadata": {}, + "outputs": [], + "source": [ + "models = client.get_model_trail()\n", + "\n", + "acc = []\n", + "for model in models:\n", + " \n", + " model_id = model[\"model\"]\n", + " validations = client.get_validations(model_id=model_id)\n", + "\n", + " a = []\n", + " for validation in validations['result']: \n", + " metrics = json.loads(validation['data'])\n", + " a.append(metrics['training_accuracy'])\n", + " \n", + " acc.append(a)\n", + "\n", + "mean_acc = [np.mean(x) for x in acc]" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "42425c43", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "x = range(1,len(mean_acc)+1)\n", + "plt.plot(x, mean_acc)\n", + "plt.legend(['Training Accuracy (FedAvg)'])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "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.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/notebooks/Aggregators.ipynb b/examples/api-tutorials/Aggregators.ipynb similarity index 100% rename from examples/notebooks/Aggregators.ipynb rename to examples/api-tutorials/Aggregators.ipynb diff --git a/examples/notebooks/Hyperparameter_Tuning.ipynb b/examples/api-tutorials/Hyperparameter_Tuning.ipynb similarity index 100% rename from examples/notebooks/Hyperparameter_Tuning.ipynb rename to examples/api-tutorials/Hyperparameter_Tuning.ipynb diff --git a/examples/notebooks/API_Example.ipynb b/examples/notebooks/API_Example.ipynb deleted file mode 100644 index 79e3501c6..000000000 --- a/examples/notebooks/API_Example.ipynb +++ /dev/null @@ -1,204 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "622f7047", - "metadata": {}, - "source": [ - "## API Example\n", - "\n", - "This notebook provides an example of how to use the FEDn API to organize experiments and to analyze validation results. We will here run one training session (a collection of global rounds) using FedAvg, then retrive and visualize the results. For a complete list of implemented interfaces, please refer to the [FEDn APIs](https://fedn.readthedocs.io/en/latest/fedn.network.api.html#module-fedn.network.api.client).\n", - "\n", - "Before starting this tutorial, make sure you have a project running in FEDn Studio and have created the compute package and the initial model. If you're not sure how to do this, please follow the instructions in sections 1, 2, and 3 of the [quickstart guide](https://fedn.readthedocs.io/en/latest/quickstart.html)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "743dfe47", - "metadata": {}, - "outputs": [], - "source": [ - "from fedn import APIClient\n", - "import time\n", - "import uuid\n", - "import json\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import collections" - ] - }, - { - "cell_type": "markdown", - "id": "1046a4e5", - "metadata": {}, - "source": [ - "We connect to the FEDn API service. In this example, we assume the project is hosted on the public FEDn Studio. You can find the CONTROLLER_HOST address in the project dashboard. \n", - "\n", - "NOTE: If you're using a local sandbox, the CONTROLLER_HOST will be \"localhost or 127.0.0.1 or your local node's IP address\" and the CONTROLLER_PORT will be 8092. \n", - "\n", - "Next, you'll need to generate an access token. To do this, go to the project page in FEDn Studio, click on \"Settings,\" then \"Generate token.\" Copy the access token from the Studio and paste it into the notebook. In case you need further details, have a look at the [Fedn ClientAPIs](https://fedn.readthedocs.io/en/latest/apiclient.html#). " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "1061722d", - "metadata": {}, - "outputs": [], - "source": [ - "CONTROLLER_HOST = 'fedn.scaleoutsystems.com/my-project...' \n", - "ACCESS_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzI3MzQ3NDA4LCJpYXQiOjE3MjQ3NTU0MDgsImp0aSI6ImQxMTY4OTJkODJlMjRhZjJiYzQzZTllZjVlNGVlZDhmIiwidXNlcl9pZCI6NTUsImNyZWF0b3IiOiJzYWxtYW4iLCJyb2xlIjoiYWRtaW4iLCJwcm9qZWN0X3NsdWciOiJldXJvcGFyMjQtd29ya3Nob3AtZWJ4In0.k9pXUh6Ldb-jEzl77FjsxvAAjcbPoB'\n", - "client = APIClient(CONTROLLER_HOST,token=ACCESS_TOKEN, secure=True,verify=True)" - ] - }, - { - "cell_type": "markdown", - "id": "07f69f5f", - "metadata": {}, - "source": [ - "Initialize FEDn with the compute package and seed model. Note that these files needs to be created separately. If you're not sure how to do this, please follow the instructions only in section 3 of the [quickstart guide](https://fedn.readthedocs.io/en/latest/quickstart.html#create-the-compute-package-and-seed-model)." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "5107f6f9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'committed_at': 'Mon, 01 Apr 2024 17:59:42 GMT', 'id': '660af60e7025e379dc7e8412', 'key': 'models', 'model': '6b7e9ada-0c38-470e-a62b-9ed46f72c465', 'parent_model': None, 'session_id': None}\n" - ] - } - ], - "source": [ - "client.set_active_package('../mnist-pytorch/package.tgz', 'numpyhelper')\n", - "client.set_active_model('../mnist-pytorch/seed.npz')\n", - "seed_model = client.get_active_model()\n", - "print(seed_model)" - ] - }, - { - "cell_type": "markdown", - "id": "4e26c50b", - "metadata": {}, - "source": [ - "Next we start a training session using FedAvg and wait until it has finished:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "f0380d35", - "metadata": {}, - "outputs": [], - "source": [ - "session_id = \"experiment1\"\n", - "\n", - "session_config = {\n", - " \"helper\": \"numpyhelper\",\n", - " \"id\": session_id,\n", - " \"aggregator\": \"fedavg\",\n", - " \"model_id\": seed_model['model'],\n", - " \"rounds\": 10\n", - " }\n", - "\n", - "result_fedavg = client.start_session(**session_config)\n", - "\n", - "# We wait for the session to finish\n", - "while not client.session_is_finished(session_config['id']):\n", - " time.sleep(2)" - ] - }, - { - "cell_type": "markdown", - "id": "16874cec", - "metadata": {}, - "source": [ - "Next, we get the model trail, retrieve all model validations from all clients, extract the training accuracy metric, and compute its mean value accross all clients." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4e8044b7", - "metadata": {}, - "outputs": [], - "source": [ - "models = client.get_model_trail()\n", - "\n", - "acc = []\n", - "for model in models:\n", - " \n", - " model_id = model[\"model\"]\n", - " validations = client.get_validations(model_id=model_id)\n", - "\n", - " a = []\n", - " for validation in validations['result']: \n", - " metrics = json.loads(validation['data'])\n", - " a.append(metrics['training_accuracy'])\n", - " \n", - " acc.append(a)\n", - "\n", - "mean_acc = [np.mean(x) for x in acc]" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "42425c43", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "x = range(1,len(mean_acc)+1)\n", - "plt.plot(x, mean_acc)\n", - "plt.legend(['Training Accuracy (FedAvg)'])" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "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.10.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -}