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
221 changes: 216 additions & 5 deletions docs/source/components/component-fl-nodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,15 @@ More job types will be added in the future, adjusting to the community's needs.
**How to choose a job type?**

A federated learning job is an ensemble of files (among which we can find `python`, `json` or `toml` files)
we call an app. Some of these files are required to run the app (for instance, the `pyproject.toml` file in a Flower app),
and some are optional.
we call an app. Some of these files are required to run the app, and some are optional — which ones
are required depends on the job type (see :ref:`fl-required-files` below).

The job type is passed as key `job_type` in the `config.json` file (for both NVFLARE and Flower apps).
An unrecognised value is rejected at submission. A missing one falls back to ``standard``, as does an
app carrying no ``config.json`` at all — which is a valid Flower submission, since ``config.json`` is a
required file for the NVFLARE job types but not for the Flower ones (see :ref:`fl-required-files`).

Once uploaded, the UI will indicate which files are required for the specific job.
Once uploaded, the UI will indicate which files are required for the specific job.

Then, the Central Hub API will take care of bundling together:
- The files the user has uploaded
Expand Down Expand Up @@ -83,6 +86,215 @@ These tutorials run on the local NVFLARE simulator from the repo root — e.g.

Workflow of how the user uploads files for a specific job type.

.. _fl-required-files:

Required files per job type
---------------------------

Each job type declares its own set of required files. A submission missing any of them is rejected
before anything is shipped to a Trust, with a message naming the missing files.

The lists below are reproduced from the manifests in the repository
(``fl-apps/<backend>/<job_type>/required_files.json``, aggregated into
``fl-apps/<backend>/required_files.json``), which are the source of truth. The FLIP UI reads the
same manifests through the ``/model/job-types`` endpoint and shows the applicable list on the model
page — so the UI, not this table, is what to trust if the two ever disagree.

**NVFLARE job types**

.. list-table::
:header-rows: 1
:widths: 32 68

* - Job type
- Required files
* - ``standard``
- ``trainer.py``, ``validator.py``, ``models.py``, ``config.json``
* - ``standard_client_api``
- ``trainer.py``, ``models.py``, ``config.json`` (no ``validator.py`` — the Client API script
does its own validation)
* - ``fed_opt``
- ``trainer.py``, ``validator.py``, ``models.py``, ``config.json``
* - ``diffusion_model``
- ``trainer.py``, ``validator.py``, ``models.py``, ``config.json``
* - ``diffusion_model_client_api``
- ``trainer.py``, ``validator.py``, ``models.py``, ``config.json``
* - ``evaluation``
- ``evaluator.py``, ``config.json``
* - ``evaluation_client_api``
- ``evaluator.py``, ``models.py``, ``config.json``

**Flower job types**

.. list-table::
:header-rows: 1
:widths: 32 68

* - Job type
- Required files
* - ``standard``
- ``client_app.py``, ``models.py``
* - ``evaluation``
- ``client_app.py``, ``models.py``

.. note::

``config.json`` is a required file for every NVFLARE job type, because it carries ``job_type``
along with the training configuration below. It is *not* required for Flower job types, but
uploading one is still how a Flower app selects a job type other than ``standard``.

``pyproject.toml`` is **not** a file the researcher supplies for a Flower app. It is part of the
platform's base template for the job type and is bundled automatically; a ``pyproject.toml``
uploaded as a model file does not become the app's project file. Per-run overrides go in
``config.toml`` instead (see below).

Beyond the required set, additional files uploaded with the model are bundled into the app, which is
how apps ship helper modules and transforms. Two exceptions are worth knowing:

- **A file whose name collides with one the base template already provides is silently dropped.**
The template's copy wins and the upload is skipped with only a server-side log line — no error
reaches the UI. For Flower this covers ``server_app.py``, ``strategy.py``, ``__init__.py`` and
``pyproject.toml``, which matters in practice because the Flower tutorials ship the first three in
their app directories; for NVFLARE it covers whatever the chosen job type's template already
contains.
- **A checkpoint declared for server-side use is not shipped to the Trusts.** A file named by
``SERVER_CHECKPOINT``, or by an evaluation job's ``models`` entries, is staged on the FL server
rather than placed in the app bundle, so it never travels to a client. This is deliberate: it
keeps large weights off the client deployment path.

.. _fl-training-configuration:

Training configuration
----------------------

NVFLARE ``config.json``
~~~~~~~~~~~~~~~~~~~~~~~

For NVFLARE job types, ``config.json`` carries both the job type and the platform-recognised
training settings. Every setting has a default, so an app that declares only ``job_type`` is valid.

.. code-block:: json

{
"job_type": "standard",
"GLOBAL_ROUNDS": 5,
"LOCAL_ROUNDS": 2,
"IGNORE_RESULT_ERROR": false,
"AGGREGATOR": "InTimeAccumulateWeightedAggregator",
"AGGREGATION_WEIGHTS": {
"Trust_1": 1.0,
"Trust_2": 0.5
}
}

**GLOBAL_ROUNDS**
Number of global (server-side) rounds — how many times the server distributes the global model,
collects client updates and aggregates them. Accepted range 1–1000 inclusive.

*Default = 1*

**LOCAL_ROUNDS**
Number of local training iterations performed at each client site per global round. Accepted
range 1–1000 inclusive.

*Default = 1*

.. note::

A value that is not a number, or that falls outside the accepted range, is discarded rather
than reported. What happens next differs between the two keys, because the platform consumes
them differently.

``GLOBAL_ROUNDS`` is read by the platform and written into the server's job configuration, so
a discarded value really does produce a **one-round run**. A single-round job is easy to
mistake for a broken one, so check the value that reached the job if training finishes sooner
than expected. The exception is ``BEST_MODEL_METRIC``: because it requires at least two global
rounds, a discarded ``GLOBAL_ROUNDS`` fails the job outright instead of defaulting.

``LOCAL_ROUNDS`` is **not** read by the platform — it is read by your own trainer, straight out
of ``config.json``. The default of 1 is filled in only when the key is *absent*; a key that is
present but invalid is left exactly as written, so the value reaches your trainer verbatim.
``"LOCAL_ROUNDS": 5000`` will run 5000 local iterations, and a non-numeric value will fail
inside your own code rather than at validation.

Neither key is rewritten in the ``config.json`` deployed with the app, so app code that reads
``GLOBAL_ROUNDS`` from that file sees the value you wrote, not the value the server is using.

**IGNORE_RESULT_ERROR**
Whether training should proceed when a client returns an error.

*Default = false*

**AGGREGATOR**
The NVFLARE aggregation component used to combine client updates. FLIP only supports aggregator
components built into NVFLARE; allowed values are ``InTimeAccumulateWeightedAggregator`` and
``AccumulateWeightedAggregator``. Any other value fails config validation and prevents training
from starting.

*Default =* ``InTimeAccumulateWeightedAggregator``

**AGGREGATION_WEIGHTS**
JSON object mapping a client site to the weight its update carries in aggregation. Weights must
be numbers between 0 and 1 inclusive; a non-object value, or a weight outside that range, fails
config validation.

.. warning::

The keys are **FL client site names** — the FL kit slot each Trust occupies (``Trust_1``,
``Trust_2``, …), which is what the FL server knows a client by. They are not the Trust's
hub-side name or code. A key that matches no participating client is simply unused, so a
mistyped key produces no error and no effect.

*Default = no weights supplied, which NVFLARE treats as a weight of 1.0 for every participating
client*

**AGGREGATE_ONLY_REGEX**
Regular expression matching the model-parameter names to keep in each client update. When set,
only matching parameters are sent back to the server — for example, a fine-tune with a frozen
backbone can ship just its head instead of the full model. Must be a valid regular expression.

*Default = unset, i.e. the full model update is sent*

**BEST_MODEL_METRIC** / **BEST_MODEL_METRIC_MINIMIZE**
Validation-metric label driving best-global-model selection. When set, the best global model is
saved alongside the final one and included in the results, and the client trainer must report a
metric under this label. Set ``BEST_MODEL_METRIC_MINIMIZE`` to ``true`` for loss-like metrics
where lower is better. Because selection cannot happen before the first aggregate exists,
``BEST_MODEL_METRIC`` requires ``GLOBAL_ROUNDS`` of at least 2, and setting
``BEST_MODEL_METRIC_MINIMIZE`` on its own is rejected.

*Default = unset, i.e. only the final model is saved*

Three further keys are read by FLIP's own NVFLARE components rather than by the FL API's validator,
so they are unvalidated but are not simply passed through either: ``SERVER_CHECKPOINT`` (names a
model file to stage on the FL server instead of bundling it into the app — a string or a list of
strings), ``GLOBAL_ROUNDS_AE`` and ``GLOBAL_ROUNDS_DM`` (per-phase round counts for the two-phase
``diffusion_model`` job types, which bypass the range check applied to ``GLOBAL_ROUNDS``), and
``models`` (the checkpoints an evaluation job loads, each entry naming a ``checkpoint`` file).

Any other key the platform does not recognise is passed through to the app untouched, for the
uploaded code to read at runtime. This is how the tutorials carry app-specific settings such as
``LEARNING_RATE`` or ``VAL_SPLIT`` — those are conventions of individual apps, not platform
settings, and they are neither validated nor defaulted. A misspelled key of this kind is therefore
silently absent at runtime rather than reported as an error.

Flower run configuration
~~~~~~~~~~~~~~~~~~~~~~~~

Flower apps do not use the NVFLARE keys above. Their run configuration lives in the
``[tool.flwr.app.config]`` table of the base template's ``pyproject.toml``, which the platform
supplies. An app overrides those values with a ``config.toml`` file uploaded alongside its code:
the FL API passes it to ``flwr run --run-config`` at submission, and the FLIP runtime parameters
(model id, project id, cohort query, job directory) are injected into it automatically.

``config.toml`` can only override keys that the template's ``pyproject.toml`` already declares — it
cannot introduce new ones. Round counts follow Flower's naming rather than NVFLARE's, as
``num-server-rounds`` (global rounds) and ``local-epochs`` (local rounds).

For a worked example of both files, see the Flower tutorials under
`fl-tutorials/flower/ <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials/flower>`_
and :doc:`/working-with-flip-apps/create-flip-app-from-flower`.

Data access and communication with external services
----------------------------------------------------

Expand Down Expand Up @@ -143,8 +355,7 @@ 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 Flower framework, users have to upload the `server_app.py` in addition to the `client_app.py` and additional auxiliary code, but in the future, this will not be the case.
- for the class-based NVFLARE job types (`standard`, `evaluation`, `fed_opt`, `diffusion_model`) the user upload is intentionally minimal — `trainer.py` / `validator.py` / `models.py` / `config.json` — and the rest of the app is filled in from
- 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
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>`_.
Expand Down
115 changes: 44 additions & 71 deletions docs/source/user-guides/user-common.rst
Original file line number Diff line number Diff line change
Expand Up @@ -351,16 +351,33 @@ Model Files

A model must be created before proceeding to upload model files and prepare the model for training.

**For NVIDIA FLARE apps**, the minimum required files are:

- ``validator.py``
- ``trainer.py``

Additional files may be uploaded, especially if these are referenced by the validator or trainer. A config file may also be uploaded (see :ref:`training-configuration` section for more information), in which optional variables can be defined.

**For Flower apps**, the required files differ (e.g. ``client_app.py``, ``pyproject.toml``). See the :ref:`FL nodes documentation <flip-fl-nodes>` for Flower-specific file requirements and job types.

For more information on model training and model files, please see the `FLIP tutorials <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials>`_.
There is no single list of required files. What a model must contain depends on its **job type**
— the kind of federated job it runs, such as federated averaging or evaluation — and on which FL
backend your platform is running. An app declares its job type with the ``job_type`` key in
``config.json``. Every NVFLARE app carries a ``config.json``, because it is itself a required file
for those job types; a Flower app only needs one in order to run a job type other than the default.
Where the key — or the file itself — is absent, the ``standard`` job type is assumed.

**You do not need to look this up.** FLIP tells you which files your model needs, in two places on
the model page:

- The Model Files panel shows the job type currently detected from your uploaded ``config.json``.
- The Training panel lists the files that job type requires, and highlights any that are still
missing.

Both update as soon as you upload or replace ``config.json``, and training cannot be initiated
until every required file has been uploaded.

Files beyond the required set may be uploaded freely — anything your code imports (helper modules,
transforms) is bundled with the app and shipped to the participating Trusts. Two things do not
follow that rule: a file whose name matches one the platform's own app template supplies is quietly
dropped in favour of the template's copy, and a checkpoint declared for server-side use stays on the
FL server rather than travelling to the Trusts. Both are covered under
:ref:`fl-required-files` on the FL nodes component page.

The full per-job-type file lists, and the configuration each backend accepts, are documented on
the :ref:`FL nodes component page <flip-fl-nodes>`. For worked examples of complete, working apps,
see the `FLIP tutorials <https://github.com/londonaicentre/FLIP/tree/develop/fl-tutorials>`_.

.. warning::

Expand Down Expand Up @@ -417,71 +434,27 @@ If model files need to be managed further after uploading, the uploader function
Training Configuration
----------------------

.. note::

The following configuration applies to **NVIDIA FLARE** apps. For Flower apps, training configuration is managed via ``pyproject.toml``. See the :ref:`FL nodes documentation <flip-fl-nodes>` for details.

Prior to commencing training you may also upload an optional ``config.json`` file (see example below). The config file defines variables which are used during FLIP training (e.g. ``GLOBAL_ROUNDS``, ``LOCAL_ROUNDS``, ``AGGREGATION_WEIGHTS``, ``AGGREGATOR``).

.. code-block:: json

{
"GLOBAL_ROUNDS": 5,
"LOCAL_ROUNDS": 2,
"IGNORE_RESULT_ERROR": false,
"AGGREGATOR": "InTimeAccumulateWeightedAggregator",
"AGGREGATION_WEIGHTS": {
"KCH": 1.0,
"UCLH": 0.5
}
}

.. note::

All config properties have default values. If a ``config.json`` file is not uploaded, or some properties are missing from the file, default values will be utilised at runtime.
See default values specified below.
Alongside your code, an app carries a small configuration file that sets how the federated run
behaves — how many rounds it trains for, how client updates are combined, and any settings your
own code reads.

**GLOBAL_ROUNDS**
Number of global training iterations. How many times the server should execute the ``trainer.py``.
Must be between 1 and 1000 (inclusive).

*Default=1*

**LOCAL_ROUNDS**
Number of local training iterations at client sites.
Must be between 1 and 1000 (inclusive).

*Default=1*

**IGNORE_RESULT_ERROR**
Whether training should proceed if a client returns an error.

*Default=false*

**AGGREGATOR**
The nvflare aggregation component used to aggregate training results from each client.

.. warning::
Allowed values are "InTimeAccumulateWeightedAggregator" or "AccumulateWeightedAggregator". As of v4, FLIP only supports aggregator components built into nvflare. Specifying any other value will cause
a config validation error and prevent training from initiating.

*Default="InTimeAccumulateWeightedAggregator"*

**AGGREGATION_WEIGHTS**
Weight dictionary passed into the aggregator component to define its aggregation behaviour.

.. warning::
Client sites *must* be referenced via their common abbreviation e.g KCH=Kings College Hospital, UCLH=University College London Hospital.
Weights must be provided as a valid json object.
Where that configuration lives, and which settings are available, depends on the FL backend:

*Default=1.0 applied to each client site*
- **NVIDIA FLARE apps** are configured through ``config.json``, which is one of the required files
for every NVFLARE job type. As well as declaring ``job_type``, it may set platform-recognised
keys such as ``GLOBAL_ROUNDS`` and ``LOCAL_ROUNDS``.
- **Flower apps** take their run configuration from the platform's app template, which your app
can override with a ``config.toml`` file. Flower apps do not use the NVFLARE keys.

.. code-block:: json
For NVFLARE apps, any key the platform does not recognise is passed through untouched, for your own
code to read at runtime — which is how the tutorials carry app-specific settings such as learning
rate or validation split. Flower works the other way round: ``config.toml`` may only override keys
the app template already declares, and a key it does not declare fails the run at submission rather
than being ignored.

{
"KCH": 1.0,
"UCLH": 1.0
}
Every platform-recognised key has a default, so an app that sets only ``job_type`` will still run.
For the full list of keys, their accepted values and defaults per backend, see
:ref:`fl-training-configuration` on the FL nodes component page.

View Files
----------
Expand Down
Loading
Loading