Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .env.development.example
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ LOCAL_DEV=true
# To run a tutorial on the local NVFLARE simulator, use the make-driven runner:
# make -C fl-tutorials download-xray-data
# make -C fl-tutorials run-tutorial TUTORIAL=xray_classification
# It manages DEV_IMAGES_DIR / DEV_DATAFRAME / RUNS_DIR via fl-tutorials/nvflare/testing/.env.testing.
# Each tutorial carries its own .env.app (DEV_IMAGES_DIR / DEV_DATAFRAME, ...) and a job.py driving the run.

# Directory inside the FL container for admin/startup files
FL_ADMIN_DIRECTORY=/app/admin
Expand Down
13 changes: 7 additions & 6 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
# the per-backend aggregate (single path segment after fl-apps/), never the per-template sources.
fl-apps/*/required_files.json linguist-generated=true

# The *_client_api base app configs (standard_client_api, evaluation_client_api, ...) are generated
# from flip.nvflare.recipes (FlipFedAvgRecipe / FlipEvalRecipe) by each template's recipe.py — do not
# hand-edit; regenerate after any recipe change (see each template's README) and commit the result.
# The NVFLARE base app configs (standard, evaluation, fed_opt, diffusion_model) are generated from
# flip.nvflare.recipes (FlipFedAvgRecipe / FlipEvalRecipe / FlipFedOptRecipe / FlipDiffusionRecipe)
# by each template's recipe.py — do not hand-edit; regenerate after any recipe change (see each
# template's README) and commit the result.
# Marked generated so GitHub collapses them in diffs and flags them as derived.
fl-apps/nvflare/*_client_api/app/config/config_fed_server.json linguist-generated=true
fl-apps/nvflare/*_client_api/app/config/config_fed_client.json linguist-generated=true
fl-apps/nvflare/*_client_api/meta.json linguist-generated=true
fl-apps/nvflare/*/app/config/config_fed_server.json linguist-generated=true
fl-apps/nvflare/*/app/config/config_fed_client.json linguist-generated=true
fl-apps/nvflare/*/meta.json linguist-generated=true
6 changes: 1 addition & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -456,16 +456,12 @@ flip-utils/dist/
# version control (covered by .claude/* above, listed explicitly for clarity).
.claude/worktrees/

# fl-tutorials generated / uncommitted artifacts (data/, tutorials/testing/tmp, the
# spleen-seg uv.lock), scoped under the
# fl-tutorials generated / uncommitted artifacts (data/, the spleen-seg uv.lock), scoped under the
# per-backend tutorial trees (fl-tutorials/<backend>/) so a bare `data/` doesn't over-match
# other data/ dirs in the monorepo:
# - generated tutorial datasets (spleen/xray images + accession CSVs)
# - testing-harness scratch dir
# - tutorial uv.lock (tutorials intentionally don't pin a strict lockfile)
fl-tutorials/nvflare/data/
fl-tutorials/nvflare/testing/tmp/
fl-tutorials/nvflare/testing/runs/workspace/
fl-tutorials/nvflare/image_segmentation/3d_spleen_segmentation/uv.lock
fl-services/flower/provision/creds/
fl-services/flower/runs/
Expand Down
17 changes: 9 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ FLIP/
├── flip-ui/ # Frontend UI (Vue 3 / TypeScript / TailwindCSS)
├── flip-utils/ # FLIP Python library (pip-installable flip-utils)
├── fl-services/ # FL Docker services + network provisioning, per backend (Makefile owns build/provision/up/down/submit; flower also up-secure): fl-services/nvflare/{fl-base,fl-server,fl-client,fl-api-base, provision/{net-*_project_*.yml, scripts/, workspace-{dev,stag,prod}/ gitignored}}, fl-services/flower/{fl-base,superlink,supernode,fl-api-flower, provision/{scripts/, creds/ gitignored}} (#622)
├── fl-apps/ # FL app templates per backend: fl-apps/nvflare/{standard,standard_client_api,fed_opt,evaluation,evaluation_client_api,diffusion_model,diffusion_model_client_api}, fl-apps/flower/{standard,evaluation} + check_required_files.sh (cross-backend CI validator at root)
├── fl-tutorials/ # FL tutorials per backend: fl-tutorials/nvflare/{image_*,testing}, fl-tutorials/flower/{xray_classification,3d_spleen_segmentation*,numpy} (root Makefile forwards by FL_BACKEND); xray classification, spleen seg/eval, diffusion. Plus fl-tutorials/tests/ — CPU-only pytest over the tutorial transform chains (#871), run by `make -C fl-tutorials test`
├── fl-apps/ # FL app templates per backend: fl-apps/nvflare/{standard,evaluation,diffusion_model,fed_opt} (all Client-API), fl-apps/flower/{standard,evaluation} + check_required_files.sh (cross-backend CI validator at root)
├── fl-tutorials/ # FL tutorials per backend (all NVFLARE ones are Client-API apps): fl-tutorials/nvflare/{image_*}, fl-tutorials/flower/{xray_classification,3d_spleen_segmentation*,numpy} (root Makefile forwards by FL_BACKEND); xray classification, spleen seg/eval, diffusion. Plus fl-tutorials/tests/ — CPU-only pytest over the tutorial transform chains (#871), run by `make -C fl-tutorials test`
├── trust/
│ ├── trust-api/ # Trust API gateway (Python/FastAPI)
│ ├── data-access-api/# OMOP database queries (Python/FastAPI)
Expand Down Expand Up @@ -199,19 +199,20 @@ runs old images otherwise): `docker exec flip-fl-api-net-1 cat fl_api/utils/uplo

### Running FL Tutorials Locally

The NVFLARE tutorials live in `fl-tutorials/` and run on the local NVFLARE simulator (needs a GPU +
the `flare-fl-base` image). Each tutorial carries a `.env.app` and delegates to the shared harness in
`fl-tutorials/nvflare/testing/`. From the repo root:
The NVFLARE tutorials live in `fl-tutorials/` and are all **Client-API** apps (the legacy Executor
tutorials, templates and their Docker `testing/` harness are removed; the pre-rename `*_client_api`
job-type names survive only as accepted aliases for models created before the rename). Each tutorial carries a `.env.app` and a `job.py` driving a FLIP recipe;
`make run` delegates to `make sim`, which runs the NVFLARE simulator (SimEnv) in the flip-utils venv
with the `full` ML extra (needs a GPU; per-tutorial `make export` builds the full job config with no
GPU). From the repo root:

```bash
make -C fl-tutorials list-tutorials
make -C fl-tutorials download-xray-data # xray dataset (HF); spleen: download-spleen-data
make -C fl-tutorials run-tutorial TUTORIAL=xray_classification
make -C fl-tutorials run-all-tutorials # all four (heavy; stops on first failure)
make -C fl-tutorials test-template TEMPLATE=fed_opt # smoke-test a template that has no tutorial
make -C fl-tutorials run-all-tutorials # every tutorial (heavy; stops on first failure)
```

The simulator GPU id defaults to `0`; override with `SIM_GPU` in `fl-tutorials/nvflare/testing/.env.testing`.
To iterate on the FL images, `make build-fl` builds them locally as `:dev` (see `fl-services/nvflare/README.md`);
run the stack on them with `make up DOCKER_FL_REGISTRY= DOCKER_FL_TAG=dev`.

Expand Down
17 changes: 9 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ FLIP/
├── flip-ui/ # Frontend UI (Vue 3 / TypeScript / TailwindCSS)
├── flip-utils/ # FLIP Python library (pip-installable flip-utils)
├── fl-services/ # FL Docker services + network provisioning, per backend (Makefile owns build/provision/up/down/submit; flower also up-secure): fl-services/nvflare/{fl-base,fl-server,fl-client,fl-api-base, provision/{net-*_project_*.yml, scripts/, workspace-{dev,stag,prod}/ gitignored}}, fl-services/flower/{fl-base,superlink,supernode,fl-api-flower, provision/{scripts/, creds/ gitignored}} (#622)
├── fl-apps/ # FL app templates per backend: fl-apps/nvflare/{standard,standard_client_api,fed_opt,evaluation,evaluation_client_api,diffusion_model,diffusion_model_client_api}, fl-apps/flower/{standard,evaluation} + check_required_files.sh (cross-backend CI validator at root)
├── fl-tutorials/ # FL tutorials per backend: fl-tutorials/nvflare/{image_*,testing}, fl-tutorials/flower/{xray_classification,3d_spleen_segmentation*,numpy} (root Makefile forwards by FL_BACKEND); xray classification, spleen seg/eval, diffusion. Plus fl-tutorials/tests/ — CPU-only pytest over the tutorial transform chains (#871), run by `make -C fl-tutorials test`
├── fl-apps/ # FL app templates per backend: fl-apps/nvflare/{standard,evaluation,diffusion_model,fed_opt} (all Client-API), fl-apps/flower/{standard,evaluation} + check_required_files.sh (cross-backend CI validator at root)
├── fl-tutorials/ # FL tutorials per backend (all NVFLARE ones are Client-API apps): fl-tutorials/nvflare/{image_*}, fl-tutorials/flower/{xray_classification,3d_spleen_segmentation*,numpy} (root Makefile forwards by FL_BACKEND); xray classification, spleen seg/eval, diffusion. Plus fl-tutorials/tests/ — CPU-only pytest over the tutorial transform chains (#871), run by `make -C fl-tutorials test`
├── trust/
│ ├── trust-api/ # Trust API gateway (Python/FastAPI)
│ ├── data-access-api/# OMOP database queries (Python/FastAPI)
Expand Down Expand Up @@ -199,19 +199,20 @@ runs old images otherwise): `docker exec flip-fl-api-net-1 cat fl_api/utils/uplo

### Running FL Tutorials Locally

The NVFLARE tutorials live in `fl-tutorials/` and run on the local NVFLARE simulator (needs a GPU +
the `flare-fl-base` image). Each tutorial carries a `.env.app` and delegates to the shared harness in
`fl-tutorials/nvflare/testing/`. From the repo root:
The NVFLARE tutorials live in `fl-tutorials/` and are all **Client-API** apps (the legacy Executor
tutorials, templates and their Docker `testing/` harness are removed; the pre-rename `*_client_api`
job-type names survive only as accepted aliases for models created before the rename). Each tutorial carries a `.env.app` and a `job.py` driving a FLIP recipe;
`make run` delegates to `make sim`, which runs the NVFLARE simulator (SimEnv) in the flip-utils venv
with the `full` ML extra (needs a GPU; per-tutorial `make export` builds the full job config with no
GPU). From the repo root:

```bash
make -C fl-tutorials list-tutorials
make -C fl-tutorials download-xray-data # xray dataset (HF); spleen: download-spleen-data
make -C fl-tutorials run-tutorial TUTORIAL=xray_classification
make -C fl-tutorials run-all-tutorials # all four (heavy; stops on first failure)
make -C fl-tutorials test-template TEMPLATE=fed_opt # smoke-test a template that has no tutorial
make -C fl-tutorials run-all-tutorials # every tutorial (heavy; stops on first failure)
```

The simulator GPU id defaults to `0`; override with `SIM_GPU` in `fl-tutorials/nvflare/testing/.env.testing`.
To iterate on the FL images, `make build-fl` builds them locally as `:dev` (see `fl-services/nvflare/README.md`);
run the stack on them with `make up DOCKER_FL_REGISTRY= DOCKER_FL_TAG=dev`.

Expand Down
41 changes: 19 additions & 22 deletions docs/source/components/component-fl-nodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ that the user can choose based on their needs.
Which job types are available depends on the backend.
**Both backends** offer federated averaging (job type `standard`) and an evaluation task
(job type `evaluation`) — for a Flower app, those two are the whole set.
**NVFLARE** adds federated optimisation (job type `fed_opt`) and diffusion model training
(job type `diffusion_model`), which covers multi-stage federated training, along with three further
job types that drive the client code through the modern **NVFLARE Client API**
(a plain training/evaluation script using ``nvflare.client`` instead of a class-based ``Executor``):
federated averaging (job type `standard_client_api`), model evaluation (job type `evaluation_client_api`)
and two-stage diffusion model training (job type `diffusion_model_client_api`).
**NVFLARE** adds two-stage diffusion model training (job type `diffusion_model`) and federated
optimisation (job type `fed_opt`, which shares `standard`'s client contract and differs only in
the server-side optimizer aggregation). Every NVFLARE job type drives the client code through the
modern **NVFLARE Client API** — a plain training/evaluation script using ``nvflare.client``
(these Client-API templates briefly lived under `*_client_api` names alongside the Executor-based
ones, then took over the plain names when those were retired).
The manifests under :ref:`fl-required-files` are the authoritative list for each backend.
More job types will be added in the future, adjusting to the community's needs.

Expand All @@ -61,22 +61,19 @@ Then, the Central Hub API will take care of bundling together:
For more information about currently supported apps, see the per-job-type implementations under
`fl-apps/ <https://github.com/londonaicentre/FLIP/tree/develop/fl-apps>`_.

Examples of how the same job type (standard -> federated averaging) can run different user-uploaded applications are:
The NVFLARE tutorials (all Client-API apps):

- `xray_classification <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_classification/xray_classification>`_
- `3d_spleen_segmentation <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_segmentation/3d_spleen_segmentation>`_
- `xray_classification <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_classification/xray_classification>`_ (job type `standard`)
- `3d_spleen_segmentation <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_segmentation/3d_spleen_segmentation>`_ (job type `standard`)
- `3d_spleen_segmentation_evaluation <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_evaluation/3d_spleen_segmentation_evaluation>`_ (job type `evaluation`)
- `latent_diffusion_model <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_synthesis/latent_diffusion_model>`_ (job type `diffusion_model`)

Both cases perform a supervised federated averaging training, but the data, architecture and training configuration are different.

The NVFLARE Client API job types have their own tutorials:

- `xray_classification_client_api <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_classification/xray_classification_client_api>`_ (job type `standard_client_api`)
- `3d_spleen_segmentation_evaluation_client_api <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_evaluation/3d_spleen_segmentation_evaluation_client_api>`_ (job type `evaluation_client_api`)
- `latent_diffusion_model_client_api <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare/image_synthesis/latent_diffusion_model_client_api>`_ (job type `diffusion_model_client_api`)
The two `standard` examples show how the same job type runs different user-uploaded
applications: both perform a supervised federated averaging training, but the data, architecture
and training configuration are different.

These tutorials run on the local NVFLARE simulator from the repo root — e.g.
``make -C fl-tutorials run-tutorial TUTORIAL=xray_classification`` (requires a GPU and the
``flare-fl-base`` image; see the
``make -C fl-tutorials run-tutorial TUTORIAL=xray_classification`` (requires a GPU; see the
`fl-tutorials/ <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/nvflare>`_ README).


Expand Down Expand Up @@ -307,7 +304,7 @@ NVFLARE: percentile sparsification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Before a client's training result leaves a site, the NVFLARE training job types (`standard`, `fed_opt`,
`diffusion_model`, `standard_client_api`, `diffusion_model_client_api`) pass it through a percentile-based
`diffusion_model`) pass it through a percentile-based
privacy filter (``PercentilePrivacy``, following Shokri & Shmatikov, "Privacy-preserving deep learning",
CCS '15; the diffusion job types use the stage-aware ``StagePercentilePrivacy`` subclass, which computes
the cutoff per training stage):
Expand Down Expand Up @@ -374,10 +371,10 @@ Disclaimer: some things are still under construction!
There are currently some elements that are still under construction, and might not adjust exactly to
the description above:

- for the class-based NVFLARE job types (``standard``, ``evaluation``, ``fed_opt``, ``diffusion_model``) the user upload is intentionally minimal — see :ref:`fl-required-files` for the per-job-type set — and the rest of the app is filled in from
- for every NVFLARE job type the user upload is intentionally minimal — see :ref:`fl-required-files` for the per-job-type set — and the rest of the app is filled in from
the static (non-modifiable) templates baked into the flip-api image at `FL_APP_BASE_DIR` (`fl-apps/`, see FLIP#724).
These templates used to be published to an S3 bucket; that path has been removed. You can check what a fully bundled app looks like by consulting
the per-job-type implementations under `fl-apps/ <https://github.com/londonaicentre/FLIP/tree/develop/fl-apps/nvflare>`_.
- the modern NVFLARE Client API job types (`standard_client_api`, `evaluation_client_api`, `diffusion_model_client_api`) instead let the user upload a plain training/evaluation script that calls
``nvflare.client`` directly. Over time, more job types will migrate to this recipe-driven model.
- every NVFLARE job type takes a plain training/evaluation script that calls
``nvflare.client`` directly (`fed_opt` reuses `standard`'s trainer contract unchanged).

7 changes: 3 additions & 4 deletions docs/source/user-guides/arkplus-fine-tuning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,8 @@ completes.

Navigate to the project's **Models** tab and create a new model. Upload the application files —
the minimum set the FLIP platform expects is listed in
``fl-apps/nvflare/standard_client_api/required_files.json`` in the repository (this app is a
``standard_client_api`` job type — the plain ``standard`` manifest also requires a
``validator.py`` this app doesn't have). For the Ark+ app the key files are:
``fl-apps/nvflare/standard/required_files.json`` in the repository (this app is a
``standard`` job type — the Client-API template, which needs no ``validator.py``). For the Ark+ app the key files are:

* ``config.json`` — model configuration (lesion labels, training hyperparameters, Ark+
architecture settings, finetuning controls)
Expand All @@ -235,7 +234,7 @@ in the client app bundle. Set ``SERVER_CHECKPOINT`` in ``config.json`` to the fi
:caption: config.json (relevant keys)

{
"job_type": "standard_client_api",
"job_type": "standard",
"SERVER_CHECKPOINT": "pretrained_weights.pt",
"AGGREGATE_ONLY_REGEX": "omni_heads",
"GLOBAL_ROUNDS": 50,
Expand Down
6 changes: 3 additions & 3 deletions docs/source/working-with-flip-apps/package-model-as-map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Where the boundary sits

FLIP (training) MONAI Deploy (inference)
───────────────────────────────── ────────────────────────────────────
trainer.py / validator.py DICOM series selection
trainer.py DICOM series selection
models.py :: get_model() ──▶ preprocessing (must match training!)
FL_global_model.pt (aggregated) inference on the exported weights
postprocessing
Expand Down Expand Up @@ -176,8 +176,8 @@ a ``model`` key holding the state dict, alongside ``train_conf`` and optionally

.. warning::

FLIP persists the **last** global model, not the best one. The ``standard`` and
``standard_client_api`` job types wire no model selector, so
FLIP persists the **last** global model by default. The ``standard`` job type wires a model
selector only when ``config.json`` sets ``BEST_MODEL_METRIC`` — without it,
``best_FL_global_model.pt`` is never written. If your run's final round is not its best round,
the exported model will reflect the final round.

Expand Down
Loading
Loading