Skip to content

Commit ce141b9

Browse files
authored
Merge pull request #558 from VectorInstitute/dbe/upgrade_libraries
Upgrading FL4Health Libraries
2 parents b51ab34 + 8bc82ee commit ce141b9

20 files changed

Lines changed: 1072 additions & 931 deletions

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
uses: actions/checkout@v6
4848

4949
- name: Install uv
50-
uses: astral-sh/setup-uv@v7.6.0
50+
uses: astral-sh/setup-uv@v8.1.0
5151
with:
5252
version: "0.9.11"
5353
enable-cache: true

.github/workflows/nnunet_smoke_tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
uses: actions/checkout@v6
2424

2525
- name: Install uv
26-
uses: astral-sh/setup-uv@v7.6.0
26+
uses: astral-sh/setup-uv@v8.1.0
2727
with:
2828
version: "0.9.11"
2929
enable-cache: true
@@ -53,7 +53,7 @@ jobs:
5353
run: uv run pytest --test-group-count=4 --test-group=${{ matrix.group }} -v --cov fl4health --cov-report=xml tests/smoke_tests/test_nnunet_smoke_tests.py
5454

5555
- name: Upload coverage to Codecov
56-
uses: codecov/codecov-action@v5
56+
uses: codecov/codecov-action@v6
5757
with:
5858
token: ${{ secrets.CODECOV_TOKEN }}
5959
slug: VectorInstitute/FL4Health

.github/workflows/publish_and_release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
uses: actions/checkout@v6
2020

2121
- name: Install uv
22-
uses: astral-sh/setup-uv@v7.6.0
22+
uses: astral-sh/setup-uv@v8.1.0
2323
with:
2424
version: "0.9.11"
2525
enable-cache: true
@@ -33,7 +33,7 @@ jobs:
3333
run: uv build
3434

3535
- name: Publish package
36-
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e
36+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
3737
with:
3838
user: __token__
3939
password: ${{ secrets.PYPI_API_TOKEN }}

.github/workflows/standard_smoke_tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
uses: actions/checkout@v6
2424

2525
- name: Install uv
26-
uses: astral-sh/setup-uv@v7.6.0
26+
uses: astral-sh/setup-uv@v8.1.0
2727
with:
2828
version: "0.9.11"
2929
enable-cache: true
@@ -53,7 +53,7 @@ jobs:
5353
run: uv run pytest --test-group-count=4 --test-group=${{ matrix.group }} -v --cov fl4health --cov-report=xml tests/smoke_tests/test_standard_smoke_tests.py
5454

5555
- name: Upload coverage to Codecov
56-
uses: codecov/codecov-action@v5
56+
uses: codecov/codecov-action@v6
5757
with:
5858
token: ${{ secrets.CODECOV_TOKEN }}
5959
slug: VectorInstitute/FL4Health

.github/workflows/static_code_checks.yaml

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
uses: actions/checkout@v6
2121

2222
- name: Install uv
23-
uses: astral-sh/setup-uv@v7.6.0
23+
uses: astral-sh/setup-uv@v8.1.0
2424
with:
2525
version: "0.9.11"
2626
enable-cache: true
@@ -47,31 +47,15 @@ jobs:
4747
uses: pypa/gh-action-pip-audit@v1.1.0
4848
with:
4949
virtual-environment: .venv/
50-
# GHSA-3749-ghw9-m3mg and GHSA-887c-mr87-cxwp are pytorch vulnerabilities that require 2.7 and 2.8 but we're
51-
# pinning to 2.6.0 for now.
52-
# CVE-2025-53000 NBConvert issue, no fix yet.
53-
# CVE-2026-21851 is a MonAI issue with no fix at the moment.
54-
# CVE-2024-55459, CVE-2025-9906, CVE-2025-12058, CVE-2025-12060 are keras vulnerabilities that require
55-
# keras>=3.12.0 which needs tensorflow>=2.16, but we're pinning to tensorflow 2.15 due to tensorflow-io
56-
# compatibility constraints.
57-
# CVE-2026-0994 is a protobuff vulnerability without a fix yet.
58-
# CVE-2026-26007 is a cryptography vulnerability that requires cryptography>=46.0.5, but flwr (flower)
59-
# requires cryptography<45.0.0, blocking the upgrade.
60-
# GHSA-rf74-v2fm-23pw, CVE-2026-33230, CVE-2026-33231: NLTK vulnerabilities without a fix yet.
50+
# CVE-2026-26007, CVE-2026-34073 are cryptography vulnerability that requires cryptography>=46.0.5, but
51+
# flwr (flower) requires cryptography<45.0.0, blocking the upgrade.
52+
# CVE-2026-1839 is a vulnerability in HF transformers, but they've messed up their typing in 5+ so we're
53+
# deferring this.
6154
ignore-vulns: |
62-
GHSA-3749-ghw9-m3mg
63-
GHSA-887c-mr87-cxwp
64-
CVE-2025-53000
65-
CVE-2026-21851
66-
CVE-2024-55459
67-
CVE-2025-9906
68-
CVE-2025-12058
69-
CVE-2025-12060
70-
CVE-2026-0994
7155
CVE-2026-26007
72-
GHSA-rf74-v2fm-23pw
73-
CVE-2026-33230
74-
CVE-2026-33231
56+
CVE-2026-34073
57+
CVE-2026-1839
58+
7559
7660
# Deleting some temporary files and useless folders to free up space
7761
# Deleting /usr/share/dotnet should clear ~4GB of space.

.github/workflows/tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
uses: actions/checkout@v6
2121

2222
- name: Install uv
23-
uses: astral-sh/setup-uv@v7.6.0
23+
uses: astral-sh/setup-uv@v8.1.0
2424
with:
2525
version: "0.9.11"
2626
enable-cache: true
@@ -48,7 +48,7 @@ jobs:
4848
run: uv run pytest -m "not smoketest" -v --cov fl4health --cov-report=xml tests
4949

5050
- name: Upload coverage to Codecov
51-
uses: codecov/codecov-action@v5
51+
uses: codecov/codecov-action@v6
5252
with:
5353
token: ${{ secrets.CODECOV_TOKEN }}
5454
slug: VectorInstitute/FL4Health

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/uv-pre-commit
3-
rev: 0.10.12
3+
rev: 0.11.13
44
hooks:
55
- id: uv-lock
66

@@ -26,7 +26,7 @@ repos:
2626
- id: check-toml
2727

2828
- repo: https://github.com/astral-sh/ruff-pre-commit
29-
rev: 'v0.15.7'
29+
rev: 'v0.15.12'
3030
hooks:
3131
- id: ruff-check
3232
args: [--fix, --exit-non-zero-on-fix]
@@ -35,7 +35,7 @@ repos:
3535
types_or: [python, jupyter]
3636

3737
- repo: https://github.com/pre-commit/mirrors-mypy
38-
rev: v1.19.1
38+
rev: v2.0.0
3939
hooks:
4040
- id: mypy
4141
name: mypy

fl4health/clients/flexible/nnunet.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from fl4health.utils.nnunet_utils import (
3535
NNUNET_DEFAULT_NP,
3636
NNUNET_N_SPATIAL_DIMS,
37+
LocalPolyLRScheduler,
3738
Module2LossWrapper,
3839
NnunetConfig,
3940
NnUNetDataLoaderWrapper,
@@ -56,6 +57,7 @@
5657
# silences a bunch of deprecation warnings related to scipy.ndimage
5758
# Raised an issue with nnunet. https://github.com/MIC-DKFZ/nnUNet/issues/2370
5859
warnings.filterwarnings("ignore", category=DeprecationWarning)
60+
import nnunetv2.training.nnUNetTrainer.nnUNetTrainer as nnUNetTrainerModule
5961
from batchgenerators.utilities.file_and_folder_operations import (
6062
load_json,
6163
save_json,
@@ -72,7 +74,6 @@
7274
from nnunetv2.training.dataloading.utils import unpack_dataset
7375
from nnunetv2.training.loss.deep_supervision import DeepSupervisionWrapper
7476
from nnunetv2.training.lr_scheduler.polylr import PolyLRScheduler
75-
from nnunetv2.training.nnUNetTrainer.nnUNetTrainer import nnUNetTrainer
7677
from nnunetv2.utilities.dataset_name_id_conversion import convert_id_to_dataset_name
7778

7879
# grpcio currently has a log spamming bug that seems to be triggered by multithreading/multiprocessing
@@ -100,7 +101,7 @@ def __init__(
100101
checkpoint_and_state_module: ClientCheckpointAndStateModule | None = None,
101102
reporters: Sequence[BaseReporter] | None = None,
102103
client_name: str | None = None,
103-
nnunet_trainer_class: type[nnUNetTrainer] = nnUNetTrainer,
104+
nnunet_trainer_class: type[nnUNetTrainerModule.nnUNetTrainer] = nnUNetTrainerModule.nnUNetTrainer,
104105
nnunet_trainer_class_kwargs: dict[str, Any] | None = None,
105106
) -> None:
106107
"""
@@ -208,7 +209,7 @@ def __init__(
208209
# nnunet specific attributes to be initialized in setup_client
209210
self.nnunet_trainer_class = nnunet_trainer_class
210211
self.nnunet_trainer_class_kwargs = nnunet_trainer_class_kwargs or {}
211-
self.nnunet_trainer: nnUNetTrainer
212+
self.nnunet_trainer: nnUNetTrainerModule.nnUNetTrainer
212213
self.nnunet_config: NnunetConfig
213214
self.plans: dict[str, Any] | None = None
214215
self.steps_per_round: int # N steps per server round
@@ -620,6 +621,12 @@ def setup_client(self, config: Config) -> None:
620621
device=self.device,
621622
**self.nnunet_trainer_class_kwargs,
622623
)
624+
625+
# NOTE: Monkey Patch to force the nnunet_trainer to use our version of the PolyLRScheduler instead of
626+
# NnUnet version. This is because NnUnet's hasn't updated their scheduler to the new torch signature and
627+
# does not appear to intend to do so. The fix is very minimum. So we patch it here.
628+
nnUNetTrainerModule.PolyLRScheduler = LocalPolyLRScheduler
629+
623630
# nnunet_trainer initialization
624631
self.nnunet_trainer.initialize()
625632
# This is done by nnunet_trainer in self.on_train_start, we

fl4health/clients/nnunet_client.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from fl4health.utils.nnunet_utils import (
3434
NNUNET_DEFAULT_NP,
3535
NNUNET_N_SPATIAL_DIMS,
36+
LocalPolyLRScheduler,
3637
Module2LossWrapper,
3738
NnunetConfig,
3839
NnUNetDataLoaderWrapper,
@@ -50,6 +51,7 @@
5051
# silences a bunch of deprecation warnings related to scipy.ndimage
5152
# Raised an issue with nnunet. https://github.com/MIC-DKFZ/nnUNet/issues/2370
5253
warnings.filterwarnings("ignore", category=DeprecationWarning)
54+
import nnunetv2.training.nnUNetTrainer.nnUNetTrainer as nnUNetTrainerModule
5355
from batchgenerators.utilities.file_and_folder_operations import load_json, save_json
5456
from nnunetv2.experiment_planning.experiment_planners.default_experiment_planner import ExperimentPlanner
5557
from nnunetv2.experiment_planning.plan_and_preprocess_api import extract_fingerprints, preprocess_dataset
@@ -58,7 +60,6 @@
5860
from nnunetv2.training.dataloading.utils import unpack_dataset
5961
from nnunetv2.training.loss.deep_supervision import DeepSupervisionWrapper
6062
from nnunetv2.training.lr_scheduler.polylr import PolyLRScheduler
61-
from nnunetv2.training.nnUNetTrainer.nnUNetTrainer import nnUNetTrainer
6263
from nnunetv2.utilities.dataset_name_id_conversion import convert_id_to_dataset_name
6364

6465
# grpcio currently has a log spamming bug that seems to be triggered by multithreading/multiprocessing
@@ -86,7 +87,7 @@ def __init__(
8687
checkpoint_and_state_module: ClientCheckpointAndStateModule | None = None,
8788
reporters: Sequence[BaseReporter] | None = None,
8889
client_name: str | None = None,
89-
nnunet_trainer_class: type[nnUNetTrainer] = nnUNetTrainer,
90+
nnunet_trainer_class: type[nnUNetTrainerModule.nnUNetTrainer] = nnUNetTrainerModule.nnUNetTrainer,
9091
nnunet_trainer_class_kwargs: dict[str, Any] | None = None,
9192
) -> None:
9293
"""
@@ -191,7 +192,7 @@ def __init__(
191192
self.nnunet_trainer_class_kwargs = (
192193
nnunet_trainer_class_kwargs if nnunet_trainer_class_kwargs is not None else {}
193194
)
194-
self.nnunet_trainer: nnUNetTrainer
195+
self.nnunet_trainer: nnUNetTrainerModule.nnUNetTrainer
195196
self.nnunet_config: NnunetConfig
196197
self.plans: dict[str, Any] | None = None
197198
self.steps_per_round: int # N steps per server round
@@ -585,6 +586,12 @@ def setup_client(self, config: Config) -> None:
585586
device=self.device,
586587
**self.nnunet_trainer_class_kwargs,
587588
)
589+
590+
# NOTE: Monkey Patch to force the nnunet_trainer to use our version of the PolyLRScheduler instead of
591+
# NnUnet version. This is because NnUnet's hasn't updated their scheduler to the new torch signature and
592+
# does not appear to intend to do so. The fix is very minimum. So we patch it here.
593+
nnUNetTrainerModule.PolyLRScheduler = LocalPolyLRScheduler
594+
588595
# nnunet_trainer initialization
589596
self.nnunet_trainer.initialize()
590597
# This is done by nnunet_trainer in self.on_train_start, we

fl4health/mixins/personalized/ditto.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ def _copy_optimizer_with_new_params(self: DittoPersonalizedProtocol, original_op
124124

125125
optimizer_kwargs = {k: v for k, v in param_group.items() if k not in ("params", "initial_lr")}
126126
assert self.global_model is not None
127+
128+
# NOTE: This is a small workaround for torch back-compatibility in AdamW. Torch injects a key (that isn't part
129+
# of the class signature) into the param groups called "decoupled_weight_decay" which causes an error in the
130+
# kwargs below. See: https://github.com/pytorch/pytorch/blob/v2.11.0/torch/optim/adamw.py#L57
131+
if optim_class == torch.optim.AdamW:
132+
optimizer_kwargs.pop("decoupled_weight_decay")
133+
127134
global_optimizer = optim_class(self.global_model.parameters(), **optimizer_kwargs)
128135

129136
# maintain initial_lr for schedulers

0 commit comments

Comments
 (0)