Skip to content

Commit 44add8d

Browse files
Bump min torch to 1.13.1 to mitigate CVE-2022-45907 unsafe usage of eval (#8296)
### Description This bumps the minimum required `torch` version from 1.9.0 to 1.13.1. See GHSA-47fc-vmwq-366v for more details such as the highest severity scoring of "Critical". - https://nvd.nist.gov/vuln/detail/CVE-2022-45907 - https://security.snyk.io/vuln/SNYK-PYTHON-TORCH-3149871 Maintainers will need to update the required status checks for the [`dev`](https://github.com/Project-MONAI/MONAI/tree/dev) branch to: - Remove min-dep-pytorch (1.10.2) - Remove min-dep-pytorch (1.11.0) - Remove min-dep-pytorch (1.12.1) - Remove min-dep-pytorch (1.13) - Add min-dep-pytorch (1.13.1) cc: @KumoLiu ### Types of changes <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Breaking change (fix or new feature that would cause existing functionality to change). (drop of older `torch` versions) - [ ] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [ ] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. --------- Signed-off-by: James Butler <[email protected]> Signed-off-by: YunLiu <[email protected]> Co-authored-by: YunLiu <[email protected]>
1 parent e538f7f commit 44add8d

30 files changed

+53
-554
lines changed

.github/workflows/cron.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,12 @@ jobs:
1313
strategy:
1414
matrix:
1515
environment:
16-
- "PT110+CUDA113"
1716
- "PT113+CUDA118"
1817
- "PT210+CUDA121"
1918
- "PT240+CUDA126"
2019
- "PTLATEST+CUDA126"
2120
include:
2221
# https://docs.nvidia.com/deeplearning/frameworks/pytorch-release-notes
23-
- environment: PT110+CUDA113
24-
pytorch: "torch==1.10.2 torchvision==0.11.3 --extra-index-url https://download.pytorch.org/whl/cu113"
25-
base: "nvcr.io/nvidia/pytorch:21.06-py3" # CUDA 11.3
2622
- environment: PT113+CUDA118
2723
pytorch: "torch==1.13.1 torchvision==0.14.1 --extra-index-url https://download.pytorch.org/whl/cu121"
2824
base: "nvcr.io/nvidia/pytorch:22.10-py3" # CUDA 11.8

.github/workflows/pythonapp-gpu.yml

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,10 @@ jobs:
2222
strategy:
2323
matrix:
2424
environment:
25-
- "PT19+CUDA114DOCKER"
26-
- "PT110+CUDA111"
27-
- "PT112+CUDA118DOCKER"
2825
- "PT113+CUDA116"
2926
- "PT210+CUDA121DOCKER"
3027
include:
3128
# https://docs.nvidia.com/deeplearning/frameworks/pytorch-release-notes
32-
- environment: PT110+CUDA111
33-
pytorch: "torch==1.10.2 torchvision==0.11.3 --extra-index-url https://download.pytorch.org/whl/cu111"
34-
base: "nvcr.io/nvidia/cuda:11.1.1-devel-ubuntu18.04"
35-
- environment: PT112+CUDA118DOCKER
36-
# 22.09: 1.13.0a0+d0d6b1f
37-
pytorch: "-h" # we explicitly set pytorch to -h to avoid pip install error
38-
base: "nvcr.io/nvidia/pytorch:22.09-py3"
3929
- environment: PT113+CUDA116
4030
pytorch: "torch==1.13.1 torchvision==0.14.1"
4131
base: "nvcr.io/nvidia/cuda:11.6.1-devel-ubuntu18.04"
@@ -59,8 +49,7 @@ jobs:
5949
apt-get update
6050
apt-get install -y wget
6151
62-
if [ ${{ matrix.environment }} = "PT110+CUDA111" ] || \
63-
[ ${{ matrix.environment }} = "PT113+CUDA116" ]
52+
if [ ${{ matrix.environment }} = "PT113+CUDA116" ]
6453
then
6554
PYVER=3.9 PYSFX=3 DISTUTILS=python3-distutils && \
6655
apt-get update && apt-get install -y --no-install-recommends \
@@ -94,9 +83,6 @@ jobs:
9483
python get-pip.py && \
9584
rm get-pip.py;
9685
fi
97-
- if: matrix.environment == 'PT19+CUDA114DOCKER'
98-
name: Optional Cupy dependency (cuda114)
99-
run: echo "cupy-cuda114" >> requirements-dev.txt
10086
- name: Install dependencies
10187
if: github.event.pull_request.merged != true
10288
run: |

.github/workflows/pythonapp-min.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ jobs:
124124
strategy:
125125
fail-fast: false
126126
matrix:
127-
pytorch-version: ['1.10.2', '1.11.0', '1.12.1', '1.13', '2.0.1', 'latest']
127+
pytorch-version: ['1.13.1', '2.0.1', '2.2.2', '2.3.1', '2.4.1', 'latest']
128128
timeout-minutes: 40
129129
steps:
130130
- uses: actions/checkout@v4

.github/workflows/pythonapp.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ jobs:
155155
# install the latest pytorch for testing
156156
# however, "pip install monai*.tar.gz" will build cpp/cuda with an isolated
157157
# fresh torch installation according to pyproject.toml
158-
python -m pip install torch>=1.9 torchvision
158+
python -m pip install torch>=1.13.1 torchvision
159159
- name: Check packages
160160
run: |
161161
pip uninstall monai

docs/requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
-f https://download.pytorch.org/whl/cpu/torch-1.12.1%2Bcpu-cp37-cp37m-linux_x86_64.whl
2-
torch>=1.9
1+
-f https://download.pytorch.org/whl/cpu/torch-1.13.1%2Bcpu-cp39-cp39-linux_x86_64.whl
2+
torch>=1.13.1
33
pytorch-ignite==0.4.11
44
numpy>=1.20
55
itk>=5.2

environment-dev.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ channels:
66
- conda-forge
77
dependencies:
88
- numpy>=1.24,<2.0
9-
- pytorch>=1.9
9+
- pytorch>=1.13.1
1010
- torchio
1111
- torchvision
1212
- pytorch-cuda>=11.6

monai/apps/auto3dseg/transforms.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import torch
1919

2020
from monai.config import KeysCollection
21-
from monai.networks.utils import pytorch_after
2221
from monai.transforms import MapTransform
2322
from monai.utils.misc import ImageMetaKey
2423

@@ -74,9 +73,7 @@ def __call__(self, data: Mapping[Hashable, torch.Tensor]) -> dict[Hashable, torc
7473
f", the metadata was not updated {filename}."
7574
)
7675
d[key] = torch.nn.functional.interpolate(
77-
input=d[key].unsqueeze(0),
78-
size=image_shape,
79-
mode="nearest-exact" if pytorch_after(1, 11) else "nearest",
76+
input=d[key].unsqueeze(0), size=image_shape, mode="nearest-exact"
8077
).squeeze(0)
8178
else:
8279
raise ValueError(

monai/data/utils.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@
5050
issequenceiterable,
5151
look_up_option,
5252
optional_import,
53-
pytorch_after,
5453
)
5554

5655
pd, _ = optional_import("pandas")
@@ -450,12 +449,9 @@ def collate_meta_tensor_fn(batch, *, collate_fn_map=None):
450449
Collate a sequence of meta tensor into a single batched metatensor. This is called by `collage_meta_tensor`
451450
and so should not be used as a collate function directly in dataloaders.
452451
"""
453-
if pytorch_after(1, 13):
454-
from torch.utils.data._utils.collate import collate_tensor_fn # imported here for pylint/mypy issues
452+
from torch.utils.data._utils.collate import collate_tensor_fn # imported here for pylint/mypy issues
455453

456-
collated = collate_tensor_fn(batch)
457-
else:
458-
collated = default_collate(batch)
454+
collated = collate_tensor_fn(batch)
459455

460456
meta_dicts = [i.meta or TraceKeys.NONE for i in batch]
461457
common_ = set.intersection(*[set(d.keys()) for d in meta_dicts if isinstance(d, dict)])
@@ -494,18 +490,15 @@ def list_data_collate(batch: Sequence):
494490
Need to use this collate if apply some transforms that can generate batch data.
495491
496492
"""
493+
from torch.utils.data._utils.collate import default_collate_fn_map
497494

498-
if pytorch_after(1, 13):
499-
# needs to go here to avoid circular import
500-
from torch.utils.data._utils.collate import default_collate_fn_map
501-
502-
from monai.data.meta_tensor import MetaTensor
495+
from monai.data.meta_tensor import MetaTensor
503496

504-
default_collate_fn_map.update({MetaTensor: collate_meta_tensor_fn})
497+
default_collate_fn_map.update({MetaTensor: collate_meta_tensor_fn})
505498
elem = batch[0]
506499
data = [i for k in batch for i in k] if isinstance(elem, list) else batch
507500
key = None
508-
collate_fn = default_collate if pytorch_after(1, 13) else collate_meta_tensor
501+
collate_fn = default_collate
509502
try:
510503
if config.USE_META_DICT:
511504
data = pickle_operations(data) # bc 0.9.0

monai/inferers/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,10 @@
3131
fall_back_tuple,
3232
look_up_option,
3333
optional_import,
34-
pytorch_after,
3534
)
3635

3736
tqdm, _ = optional_import("tqdm", name="tqdm")
38-
_nearest_mode = "nearest-exact" if pytorch_after(1, 11) else "nearest"
37+
_nearest_mode = "nearest-exact"
3938

4039
__all__ = ["sliding_window_inference"]
4140

monai/losses/dice.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from monai.losses.spatial_mask import MaskedLoss
2626
from monai.losses.utils import compute_tp_fp_fn
2727
from monai.networks import one_hot
28-
from monai.utils import DiceCEReduction, LossReduction, Weight, look_up_option, pytorch_after
28+
from monai.utils import DiceCEReduction, LossReduction, Weight, look_up_option
2929

3030

3131
class DiceLoss(_Loss):
@@ -738,20 +738,14 @@ def __init__(
738738
batch=batch,
739739
weight=dice_weight,
740740
)
741-
if pytorch_after(1, 10):
742-
self.cross_entropy = nn.CrossEntropyLoss(
743-
weight=weight, reduction=reduction, label_smoothing=label_smoothing
744-
)
745-
else:
746-
self.cross_entropy = nn.CrossEntropyLoss(weight=weight, reduction=reduction)
741+
self.cross_entropy = nn.CrossEntropyLoss(weight=weight, reduction=reduction, label_smoothing=label_smoothing)
747742
self.binary_cross_entropy = nn.BCEWithLogitsLoss(pos_weight=weight, reduction=reduction)
748743
if lambda_dice < 0.0:
749744
raise ValueError("lambda_dice should be no less than 0.0.")
750745
if lambda_ce < 0.0:
751746
raise ValueError("lambda_ce should be no less than 0.0.")
752747
self.lambda_dice = lambda_dice
753748
self.lambda_ce = lambda_ce
754-
self.old_pt_ver = not pytorch_after(1, 10)
755749

756750
def ce(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
757751
"""
@@ -764,12 +758,6 @@ def ce(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
764758
if n_pred_ch != n_target_ch and n_target_ch == 1:
765759
target = torch.squeeze(target, dim=1)
766760
target = target.long()
767-
elif self.old_pt_ver:
768-
warnings.warn(
769-
f"Multichannel targets are not supported in this older Pytorch version {torch.__version__}. "
770-
"Using argmax (as a workaround) to convert target to a single channel."
771-
)
772-
target = torch.argmax(target, dim=1)
773761
elif not torch.is_floating_point(target):
774762
target = target.to(dtype=input.dtype)
775763

monai/losses/ds_loss.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
import torch.nn.functional as F
1818
from torch.nn.modules.loss import _Loss
1919

20-
from monai.utils import pytorch_after
21-
2220

2321
class DeepSupervisionLoss(_Loss):
2422
"""
@@ -42,7 +40,7 @@ def __init__(self, loss: _Loss, weight_mode: str = "exp", weights: list[float] |
4240
self.loss = loss
4341
self.weight_mode = weight_mode
4442
self.weights = weights
45-
self.interp_mode = "nearest-exact" if pytorch_after(1, 11) else "nearest"
43+
self.interp_mode = "nearest-exact"
4644

4745
def get_weights(self, levels: int = 1) -> list[float]:
4846
"""

monai/networks/layers/simplelayers.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
issequenceiterable,
3232
look_up_option,
3333
optional_import,
34-
pytorch_after,
3534
)
3635

3736
_C, _ = optional_import("monai._C")
@@ -293,14 +292,7 @@ def apply_filter(x: torch.Tensor, kernel: torch.Tensor, **kwargs) -> torch.Tenso
293292
x = x.view(1, kernel.shape[0], *spatials)
294293
conv = [F.conv1d, F.conv2d, F.conv3d][n_spatial - 1]
295294
if "padding" not in kwargs:
296-
if pytorch_after(1, 10):
297-
kwargs["padding"] = "same"
298-
else:
299-
# even-sized kernels are not supported
300-
kwargs["padding"] = [(k - 1) // 2 for k in kernel.shape[2:]]
301-
elif kwargs["padding"] == "same" and not pytorch_after(1, 10):
302-
# even-sized kernels are not supported
303-
kwargs["padding"] = [(k - 1) // 2 for k in kernel.shape[2:]]
295+
kwargs["padding"] = "same"
304296

305297
if "stride" not in kwargs:
306298
kwargs["stride"] = 1
@@ -372,11 +364,7 @@ def _make_coeffs(window_length, order):
372364
a = idx ** torch.arange(order + 1, dtype=torch.float, device="cpu").reshape(-1, 1)
373365
y = torch.zeros(order + 1, dtype=torch.float, device="cpu")
374366
y[0] = 1.0
375-
return (
376-
torch.lstsq(y, a).solution.squeeze() # type: ignore
377-
if not pytorch_after(1, 11)
378-
else torch.linalg.lstsq(a, y).solution.squeeze()
379-
)
367+
return torch.linalg.lstsq(a, y).solution.squeeze()
380368

381369

382370
class HilbertTransform(nn.Module):

monai/networks/utils.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from monai.apps.utils import get_logger
3232
from monai.config import PathLike
3333
from monai.utils.misc import ensure_tuple, save_obj, set_determinism
34-
from monai.utils.module import look_up_option, optional_import, pytorch_after
34+
from monai.utils.module import look_up_option, optional_import
3535
from monai.utils.type_conversion import convert_to_dst_type, convert_to_tensor
3636

3737
onnx, _ = optional_import("onnx")
@@ -676,15 +676,6 @@ def convert_to_onnx(
676676
torch_versioned_kwargs["verify"] = verify
677677
verify = False
678678
else:
679-
if not pytorch_after(1, 10):
680-
if "example_outputs" not in kwargs:
681-
# https://github.com/pytorch/pytorch/blob/release/1.9/torch/onnx/__init__.py#L182
682-
raise TypeError(
683-
"example_outputs is required in scripting mode before PyTorch 1.10."
684-
"Please provide example outputs or use trace mode to export onnx model."
685-
)
686-
torch_versioned_kwargs["example_outputs"] = kwargs["example_outputs"]
687-
del kwargs["example_outputs"]
688679
mode_to_export = torch.jit.script(model, **kwargs)
689680

690681
if torch.is_tensor(inputs) or isinstance(inputs, dict):
@@ -746,8 +737,7 @@ def convert_to_onnx(
746737
# compare onnx/ort and PyTorch results
747738
for r1, r2 in zip(torch_out, onnx_out):
748739
if isinstance(r1, torch.Tensor):
749-
assert_fn = torch.testing.assert_close if pytorch_after(1, 11) else torch.testing.assert_allclose
750-
assert_fn(r1.cpu(), convert_to_tensor(r2, dtype=r1.dtype), rtol=rtol, atol=atol) # type: ignore
740+
torch.testing.assert_close(r1.cpu(), convert_to_tensor(r2, dtype=r1.dtype), rtol=rtol, atol=atol) # type: ignore
751741

752742
return onnx_model
753743

@@ -817,8 +807,7 @@ def convert_to_torchscript(
817807
# compare TorchScript and PyTorch results
818808
for r1, r2 in zip(torch_out, torchscript_out):
819809
if isinstance(r1, torch.Tensor) or isinstance(r2, torch.Tensor):
820-
assert_fn = torch.testing.assert_close if pytorch_after(1, 11) else torch.testing.assert_allclose
821-
assert_fn(r1, r2, rtol=rtol, atol=atol) # type: ignore
810+
torch.testing.assert_close(r1, r2, rtol=rtol, atol=atol) # type: ignore
822811

823812
return script_module
824813

@@ -1031,8 +1020,7 @@ def convert_to_trt(
10311020
# compare TorchScript and PyTorch results
10321021
for r1, r2 in zip(torch_out, trt_out):
10331022
if isinstance(r1, torch.Tensor) or isinstance(r2, torch.Tensor):
1034-
assert_fn = torch.testing.assert_close if pytorch_after(1, 11) else torch.testing.assert_allclose
1035-
assert_fn(r1, r2, rtol=rtol, atol=atol) # type: ignore
1023+
torch.testing.assert_close(r1, r2, rtol=rtol, atol=atol) # type: ignore
10361024

10371025
return trt_model
10381026

monai/transforms/croppad/array.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
ensure_tuple_rep,
5757
fall_back_tuple,
5858
look_up_option,
59-
pytorch_after,
6059
)
6160

6261
__all__ = [
@@ -392,11 +391,7 @@ def compute_slices(
392391
roi_center_t = convert_to_tensor(data=roi_center, dtype=torch.int16, wrap_sequence=True, device="cpu")
393392
roi_size_t = convert_to_tensor(data=roi_size, dtype=torch.int16, wrap_sequence=True, device="cpu")
394393
_zeros = torch.zeros_like(roi_center_t)
395-
half = (
396-
torch.divide(roi_size_t, 2, rounding_mode="floor")
397-
if pytorch_after(1, 8)
398-
else torch.floor_divide(roi_size_t, 2)
399-
)
394+
half = torch.divide(roi_size_t, 2, rounding_mode="floor")
400395
roi_start_t = torch.maximum(roi_center_t - half, _zeros)
401396
roi_end_t = torch.maximum(roi_start_t + roi_size_t, roi_start_t)
402397
else:

monai/transforms/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
look_up_option,
6969
min_version,
7070
optional_import,
71-
pytorch_after,
7271
unsqueeze_left,
7372
unsqueeze_right,
7473
)
@@ -2255,7 +2254,7 @@ def _to_torch_resample_interp_mode(interp_mode):
22552254
if ret is not None:
22562255
return ret
22572256
_mapping = {
2258-
SplineMode.ZERO: InterpolateMode.NEAREST_EXACT if pytorch_after(1, 11) else InterpolateMode.NEAREST,
2257+
SplineMode.ZERO: InterpolateMode.NEAREST_EXACT,
22592258
SplineMode.ONE: InterpolateMode.LINEAR,
22602259
SplineMode.THREE: InterpolateMode.BICUBIC,
22612260
}

monai/utils/tf32.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,6 @@ def detect_default_tf32() -> bool:
6060
if not has_ampere_or_later():
6161
return False
6262

63-
from monai.utils.module import pytorch_after
64-
65-
if pytorch_after(1, 7, 0) and not pytorch_after(1, 12, 0):
66-
warnings.warn(
67-
"torch.backends.cuda.matmul.allow_tf32 = True by default.\n"
68-
" This value defaults to True when PyTorch version in [1.7, 1.11] and may affect precision.\n"
69-
" See https://docs.monai.io/en/latest/precision_accelerating.html#precision-and-accelerating"
70-
)
71-
may_enable_tf32 = True
72-
7363
override_tf32_env_vars = {"NVIDIA_TF32_OVERRIDE": "1"} # TORCH_ALLOW_TF32_CUBLAS_OVERRIDE not checked #6907
7464
for name, override_val in override_tf32_env_vars.items():
7565
if os.environ.get(name) == override_val:

0 commit comments

Comments
 (0)