Example: Running APPFL using MONAI Bundle ========================================= .. raw:: html
monai
This tutorial describes how to run federated learning experiments via APPFL using MONAI Bundles to leverage a collection of medical imaging models available in `MONAI model zoo `_. This examples shows how to use MONAI Bundle to do 3D spleen CT segmentation using gRPC with two clients. .. note:: **Acknowledgement**: We extend our gratitude to the MONAI and NVFlare teams for their invaluable support and information throughout this tutorial. Specifically, this tutorial refers to the `NVFlare-MONAI integration tutorial `_. .. note:: This tutorial is the beta version of the integration of MONAI Bundle with APPFL. The integration is still under active development. Installation ------------ User can install ``appfl`` and ``monai`` packages from ``appfl``'s source code by running the following commands: .. code-block:: bash git clone --single-branch --branch main https://github.com/APPFL/APPFL.git cd APPFL pip install -e ".[monai,examples]" Download MONAI Bundle --------------------- We suggest user to download the bundle into the ``examples/resources/monai`` directory. .. code-block:: bash mkdir -p examples/resources/monai cd examples/resources/monai Then, download the spleen CT segmentation bundle from MONAI Bundle repository: .. code-block:: bash JOB_NAME=job python3 -m monai.bundle download --name "spleen_ct_segmentation" --version "0.4.6" --bundle_dir ./${JOB_NAME}/app/config Download Data ------------- User can create a ``download_spleen_data.py`` script within the ``examples/resources/monai`` directory with the following content to download spleen CT data: .. code-block:: python import argparse from monai.apps.utils import download_and_extract def download_spleen_dataset(filepath, output_dir): url = "https://msd-for-monai.s3-us-west-2.amazonaws.com/Task09_Spleen.tar" download_and_extract(url=url, filepath=filepath, output_dir=output_dir) if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( "--filepath", "-f", type=str, help="the file path of the downloaded compressed file.", default="./data/Task09_Spleen.tar", ) parser.add_argument( "--output_dir", "-o", type=str, help="target directory to save extracted files.", default="./data" ) args = parser.parse_args() download_spleen_dataset(args.filepath, args.output_dir) Then, user can run the script to download the spleen CT data: .. code-block:: bash JOB_NAME=job python download_spleen_dataset.py sed -i "s|/workspace/data/Task09_Spleen|${PWD}/data/Task09_Spleen|g" ${JOB_NAME}/app/config/spleen_ct_segmentation/configs/train.json Launch the server ----------------- User can launch the server in one terminal using the FedAvg algorithm by the following command: .. code-block:: bash cd examples python grpc/run_server.py --config ./resources/configs/monai/server_fedavg.yaml .. note:: User can change to other federated learning algorithms by using other server configuration files in the ``./resources/configs/monai`` directory. Launch the clients ------------------ In the server configuration file, we specify that the number of clients is two, so we open two separate terminals to launch the clients: .. code-block:: bash cd examples python grpc/run_client_monai.py --config ./resources/configs/monai/client_1.yaml # terminal 1 python grpc/run_client_monai.py --config ./resources/configs/monai/client_2.yaml # terminal 2 Experiment Results ------------------ A sample server log for the experiment is shown below: .. code-block:: bash appfl: ✅[2025-01-19 04:04:05,174 server]: Logging to ./output/result_Server_2025-01-19-04-04-05.txt appfl: ✅[2025-01-19 04:07:00,973 server]: Received GetConfiguration request from client Client1 appfl: ✅[2025-01-19 04:07:39,732 server]: Received UpdateGlobalModel request from client Client1 appfl: ✅[2025-01-19 04:07:39,741 server]: Received the following meta data from Client1: {'round': 1, 'val_accuracy': 0.9534343488656791, 'val_accuracy_before_train': 0.7170387863353559, 'val_mean_dice': 0.06496836245059967, 'val_mean_dice_before_train': 0.03413229435682297} appfl: ✅[2025-01-19 04:08:02,911 server]: Received GetConfiguration request from client Client2 appfl: ✅[2025-01-19 04:08:44,316 server]: Received UpdateGlobalModel request from client Client2 appfl: ✅[2025-01-19 04:08:44,319 server]: Received the following meta data from Client2: {'round': 1, 'val_accuracy': 0.9544978111412874, 'val_accuracy_before_train': 0.7170388106327907, 'val_mean_dice': 0.06501330435276031, 'val_mean_dice_before_train': 0.034132301807403564} appfl: ✅[2025-01-19 04:09:01,715 server]: Received UpdateGlobalModel request from client Client2 appfl: ✅[2025-01-19 04:09:01,717 server]: Received the following meta data from Client2: {'round': 2, 'val_accuracy': 0.9604373494530939, 'val_accuracy_before_train': 0.9539599266781169, 'val_mean_dice': 0.06739335507154465, 'val_mean_dice_before_train': 0.06500281393527985} appfl: ✅[2025-01-19 04:09:02,419 server]: Received UpdateGlobalModel request from client Client1 appfl: ✅[2025-01-19 04:09:02,421 server]: Received the following meta data from Client1: {'round': 2, 'val_accuracy': 0.9590474329176982, 'val_accuracy_before_train': 0.9539599327524756, 'val_mean_dice': 0.06810087710618973, 'val_mean_dice_before_train': 0.06500281393527985} appfl: ✅[2025-01-19 04:09:18,915 server]: Received UpdateGlobalModel request from client Client2 appfl: ✅[2025-01-19 04:09:18,916 server]: Received the following meta data from Client2: {'round': 3, 'val_accuracy': 0.9941919290336074, 'val_accuracy_before_train': 0.9597333312793902, 'val_mean_dice': 0.005374908447265625, 'val_mean_dice_before_train': 0.06778988242149353} appfl: ✅[2025-01-19 04:09:20,032 server]: Received UpdateGlobalModel request from client Client1 appfl: ✅[2025-01-19 04:09:20,034 server]: Received the following meta data from Client1: {'round': 3, 'val_accuracy': 0.9942095143020533, 'val_accuracy_before_train': 0.9597333312793902, 'val_mean_dice': 0.005186689551919699, 'val_mean_dice_before_train': 0.06778988242149353} appfl: ✅[2025-01-19 04:09:36,668 server]: Received UpdateGlobalModel request from client Client2 appfl: ✅[2025-01-19 04:09:36,670 server]: Received the following meta data from Client2: {'round': 4, 'val_accuracy': 0.9946757274068845, 'val_accuracy_before_train': 0.9941966548846786, 'val_mean_dice': 0.0, 'val_mean_dice_before_train': 0.00541022839024663} appfl: ✅[2025-01-19 04:09:37,791 server]: Received UpdateGlobalModel request from client Client1 appfl: ✅[2025-01-19 04:09:37,793 server]: Received the following meta data from Client1: {'round': 4, 'val_accuracy': 0.9946757091838083, 'val_accuracy_before_train': 0.9941966548846786, 'val_mean_dice': 0.0, 'val_mean_dice_before_train': 0.00541022839024663} appfl: ✅[2025-01-19 04:09:53,942 server]: Received UpdateGlobalModel request from client Client1 appfl: ✅[2025-01-19 04:09:53,944 server]: Received the following meta data from Client1: {'round': 5, 'val_accuracy': 0.9708507136934122, 'val_accuracy_before_train': 0.9946757274068845, 'val_mean_dice': 0.18941788375377655, 'val_mean_dice_before_train': 0.0} appfl: ✅[2025-01-19 04:09:56,546 server]: Received UpdateGlobalModel request from client Client2 appfl: ✅[2025-01-19 04:09:56,548 server]: Received the following meta data from Client2: {'round': 5, 'val_accuracy': 0.9699774821093128, 'val_accuracy_before_train': 0.9946757274068845, 'val_mean_dice': 0.19541805982589722, 'val_mean_dice_before_train': 0.0} appfl: ✅[2025-01-19 04:09:56,649 server]: Received InvokeCustomAction close_connection request from client Client1 appfl: ✅[2025-01-19 04:09:56,651 server]: Received InvokeCustomAction close_connection request from client Client2 appfl: ✅[2025-01-19 04:09:57,537 server]: Terminating the server ...