Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ba56a6d
Move test_image_filter.py
garciadias Feb 5, 2025
5216b7a
Merge remote-tracking branch 'origin/dev' into dev
garciadias Feb 12, 2025
eacd783
Merge remote-tracking branch 'origin/dev' into dev
garciadias Feb 14, 2025
c64825f
Merge remote-tracking branch 'upstream/dev' into dev
garciadias Feb 19, 2025
66b6c17
Merge remote-tracking branch 'origin/dev' into dev
garciadias Feb 27, 2025
19cab57
Merge remote-tracking branch 'upstream/dev' into dev
garciadias Apr 11, 2025
09c2cd9
fix(spatial): fall back to PyTorch path on Blackwell (sm_120) GPUs wh…
garciadias Mar 8, 2026
7cd0607
fix(spatial): extend Blackwell fallback to Resample class in array.py
garciadias Mar 8, 2026
3fd7546
lint
garciadias Mar 9, 2026
4f6df07
lint
garciadias Mar 9, 2026
36e2623
lint
garciadias Mar 9, 2026
356956a
Merge remote-tracking branch 'upstream/dev' into 8587-test-erros-on-p…
garciadias Mar 9, 2026
17b9910
autofix
garciadias Mar 17, 2026
8de64af
Add device compatibility check to Warp.forward()
garciadias Mar 20, 2026
7c2ddb6
Fix grid coordinate conversion in Resample fallback path
garciadias Mar 20, 2026
cfe5524
Improve _compiled_unsupported() docstring with Google-style format
garciadias Mar 20, 2026
1dec216
Fix string formatting: add missing spaces in error messages
garciadias Mar 20, 2026
ec8bf1f
Add tests for GPU support detection
garciadias Mar 20, 2026
4b5bf1e
autofix
garciadias Mar 20, 2026
23f0290
fix: lint
garciadias Mar 12, 2026
057ff4d
DCO Remediation Commit for R. Garcia-Dias <rafaelagd@gmail.com>
garciadias Mar 20, 2026
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
3 changes: 1 addition & 2 deletions monai/apps/auto3dseg/bundle_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,7 @@ def _run_cmd(self, cmd: str, devices_info: str = "") -> subprocess.CompletedProc
look_up_option(self.device_setting["MN_START_METHOD"], ["bcprun"])
except ValueError as err:
raise NotImplementedError(
f"{self.device_setting['MN_START_METHOD']} is not supported yet."
"Try modify BundleAlgo._run_cmd for your cluster."
f"{self.device_setting['MN_START_METHOD']} is not supported yet. Try modify BundleAlgo._run_cmd for your cluster."
) from err

return _run_cmd_bcprun(cmd, n=self.device_setting["NUM_NODES"], p=self.device_setting["n_devices"])
Expand Down
5 changes: 2 additions & 3 deletions monai/apps/detection/networks/retinanet_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,7 @@ def set_regular_matcher(
"""
if fg_iou_thresh < bg_iou_thresh:
raise ValueError(
"Require fg_iou_thresh >= bg_iou_thresh. "
f"Got fg_iou_thresh={fg_iou_thresh}, bg_iou_thresh={bg_iou_thresh}."
f"Require fg_iou_thresh >= bg_iou_thresh. Got fg_iou_thresh={fg_iou_thresh}, bg_iou_thresh={bg_iou_thresh}."
)
self.proposal_matcher = Matcher(
fg_iou_thresh, bg_iou_thresh, allow_low_quality_matches=allow_low_quality_matches
Expand Down Expand Up @@ -519,7 +518,7 @@ def forward(
else:
if self.inferer is None:
raise ValueError(
"`self.inferer` is not defined." "Please refer to function self.set_sliding_window_inferer(*)."
"`self.inferer` is not defined. Please refer to function self.set_sliding_window_inferer(*)."
)
head_outputs = predict_with_inferer(
images, self.network, keys=[self.cls_key, self.box_reg_key], inferer=self.inferer
Expand Down
2 changes: 1 addition & 1 deletion monai/apps/detection/transforms/box_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ def convert_box_to_mask(
boxes_only_mask = np.ones(box_size, dtype=np.int16) * np.int16(labels_np[b])
# apply to global mask
slicing = [b]
slicing.extend(slice(boxes_np[b, d], boxes_np[b, d + spatial_dims]) for d in range(spatial_dims)) # type:ignore
slicing.extend(slice(boxes_np[b, d], boxes_np[b, d + spatial_dims]) for d in range(spatial_dims)) # type: ignore
boxes_mask_np[tuple(slicing)] = boxes_only_mask
return convert_to_dst_type(src=boxes_mask_np, dst=boxes, dtype=torch.int16)[0]

Expand Down
36 changes: 12 additions & 24 deletions monai/apps/detection/transforms/dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,8 @@ def __init__(self, box_keys: KeysCollection, box_ref_image_keys: str, allow_miss
super().__init__(box_keys, allow_missing_keys)
box_ref_image_keys_tuple = ensure_tuple(box_ref_image_keys)
if len(box_ref_image_keys_tuple) > 1:
raise ValueError(
"Please provide a single key for box_ref_image_keys.\
All boxes of box_keys are attached to box_ref_image_keys."
)
raise ValueError("Please provide a single key for box_ref_image_keys.\
All boxes of box_keys are attached to box_ref_image_keys.")
self.box_ref_image_keys = box_ref_image_keys

def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> dict[Hashable, NdarrayOrTensor]:
Expand Down Expand Up @@ -289,10 +287,8 @@ def __init__(
super().__init__(box_keys, allow_missing_keys)
box_ref_image_keys_tuple = ensure_tuple(box_ref_image_keys)
if len(box_ref_image_keys_tuple) > 1:
raise ValueError(
"Please provide a single key for box_ref_image_keys.\
All boxes of box_keys are attached to box_ref_image_keys."
)
raise ValueError("Please provide a single key for box_ref_image_keys.\
All boxes of box_keys are attached to box_ref_image_keys.")
self.box_ref_image_keys = box_ref_image_keys
self.image_meta_key = image_meta_key or f"{box_ref_image_keys}_{image_meta_key_postfix}"
self.converter_to_image_coordinate = AffineBox()
Expand All @@ -310,10 +306,8 @@ def extract_affine(self, data: Mapping[Hashable, torch.Tensor]) -> tuple[Ndarray
else:
raise ValueError(f"{meta_key} is not found. Please check whether it is the correct the image meta key.")
if "affine" not in meta_dict:
raise ValueError(
f"'affine' is not found in {meta_key}. \
Please check whether it is the correct the image meta key."
)
raise ValueError(f"'affine' is not found in {meta_key}. \
Please check whether it is the correct the image meta key.")
affine: NdarrayOrTensor = meta_dict["affine"]

if self.affine_lps_to_ras: # RAS affine
Expand Down Expand Up @@ -815,16 +809,12 @@ def __init__(
) -> None:
box_keys_tuple = ensure_tuple(box_keys)
if len(box_keys_tuple) != 1:
raise ValueError(
"Please provide a single key for box_keys.\
All label_keys are attached to this box_keys."
)
raise ValueError("Please provide a single key for box_keys.\
All label_keys are attached to this box_keys.")
box_ref_image_keys_tuple = ensure_tuple(box_ref_image_keys)
if len(box_ref_image_keys_tuple) != 1:
raise ValueError(
"Please provide a single key for box_ref_image_keys.\
All box_keys and label_keys are attached to this box_ref_image_keys."
)
raise ValueError("Please provide a single key for box_ref_image_keys.\
All box_keys and label_keys are attached to this box_ref_image_keys.")
self.label_keys = ensure_tuple(label_keys)
super().__init__(box_keys_tuple, allow_missing_keys)

Expand Down Expand Up @@ -1091,10 +1081,8 @@ def __init__(

box_keys_tuple = ensure_tuple(box_keys)
if len(box_keys_tuple) != 1:
raise ValueError(
"Please provide a single key for box_keys.\
All label_keys are attached to this box_keys."
)
raise ValueError("Please provide a single key for box_keys.\
All label_keys are attached to this box_keys.")
self.box_keys = box_keys_tuple[0]
self.label_keys = ensure_tuple(label_keys)

Expand Down
18 changes: 6 additions & 12 deletions monai/apps/detection/utils/anchor_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,8 @@ def __init__(
aspect_ratios = (aspect_ratios,) * len(self.sizes)

if len(self.sizes) != len(aspect_ratios):
raise ValueError(
"len(sizes) and len(aspect_ratios) should be equal. \
It represents the number of feature maps."
)
raise ValueError("len(sizes) and len(aspect_ratios) should be equal. \
It represents the number of feature maps.")

spatial_dims = len(ensure_tuple(aspect_ratios[0][0])) + 1
spatial_dims = look_up_option(spatial_dims, [2, 3])
Expand Down Expand Up @@ -172,16 +170,12 @@ def generate_anchors(
scales_t = torch.as_tensor(scales, dtype=dtype, device=device) # sized (N,)
aspect_ratios_t = torch.as_tensor(aspect_ratios, dtype=dtype, device=device) # sized (M,) or (M,2)
if (self.spatial_dims >= 3) and (len(aspect_ratios_t.shape) != 2):
raise ValueError(
f"In {self.spatial_dims}-D image, aspect_ratios for each level should be \
{len(aspect_ratios_t.shape) - 1}-D. But got aspect_ratios with shape {aspect_ratios_t.shape}."
)
raise ValueError(f"In {self.spatial_dims}-D image, aspect_ratios for each level should be \
{len(aspect_ratios_t.shape) - 1}-D. But got aspect_ratios with shape {aspect_ratios_t.shape}.")

if (self.spatial_dims >= 3) and (aspect_ratios_t.shape[1] != self.spatial_dims - 1):
raise ValueError(
f"In {self.spatial_dims}-D image, aspect_ratios for each level should has \
shape (_,{self.spatial_dims - 1}). But got aspect_ratios with shape {aspect_ratios_t.shape}."
)
raise ValueError(f"In {self.spatial_dims}-D image, aspect_ratios for each level should has \
shape (_,{self.spatial_dims - 1}). But got aspect_ratios with shape {aspect_ratios_t.shape}.")

# if 2d, w:h = 1:aspect_ratios
if self.spatial_dims == 2:
Expand Down
6 changes: 2 additions & 4 deletions monai/apps/reconstruction/transforms/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,8 @@ def __init__(
real/imaginary parts.
"""
if len(center_fractions) != len(accelerations):
raise ValueError(
"Number of center fractions \
should match number of accelerations"
)
raise ValueError("Number of center fractions \
should match number of accelerations")

self.center_fractions = center_fractions
self.accelerations = accelerations
Expand Down
5 changes: 2 additions & 3 deletions monai/auto3dseg/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def update_ops_nested_label(self, nested_key: str, op: Operations) -> None:
raise ValueError("Nested_key input format is wrong. Please ensure it is like key1#0#key2")
root: str
child_key: str
(root, _, child_key) = keys
root, _, child_key = keys
if root not in self.ops:
self.ops[root] = [{}]
self.ops[root][0].update({child_key: None})
Expand Down Expand Up @@ -952,8 +952,7 @@ def __call__(self, data: dict) -> dict:
self.hist_range = nr_channels * self.hist_range
if len(self.hist_range) != nr_channels:
raise ValueError(
f"There is a mismatch between the number of channels ({nr_channels}) "
f"and histogram ranges ({len(self.hist_range)})."
f"There is a mismatch between the number of channels ({nr_channels}) and histogram ranges ({len(self.hist_range)})."
)

# perform calculation
Expand Down
2 changes: 1 addition & 1 deletion monai/bundle/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1948,7 +1948,7 @@ def create_workflow(

"""
_args = update_kwargs(args=args_file, workflow_name=workflow_name, config_file=config_file, **kwargs)
(workflow_name, config_file) = _pop_args(
workflow_name, config_file = _pop_args(
_args, workflow_name=ConfigWorkflow, config_file=None
) # the default workflow name is "ConfigWorkflow"
if isinstance(workflow_name, str):
Expand Down
6 changes: 2 additions & 4 deletions monai/bundle/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,8 @@
"run_name": None,
# may fill it at runtime
"save_execute_config": True,
"is_not_rank0": (
"$torch.distributed.is_available() \
and torch.distributed.is_initialized() and torch.distributed.get_rank() > 0"
),
"is_not_rank0": ("$torch.distributed.is_available() \
and torch.distributed.is_initialized() and torch.distributed.get_rank() > 0"),
# MLFlowHandler config for the trainer
"trainer": {
"_target_": "MLFlowHandler",
Expand Down
4 changes: 2 additions & 2 deletions monai/data/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class DatasetFunc(Dataset):
"""

def __init__(self, data: Any, func: Callable, **kwargs) -> None:
super().__init__(data=None, transform=None) # type:ignore
super().__init__(data=None, transform=None) # type: ignore
self.src = data
self.func = func
self.kwargs = kwargs
Expand Down Expand Up @@ -1635,7 +1635,7 @@ def _cachecheck(self, item_transformed):
return (_data, _meta)
return _data
else:
item: list[dict[Any, Any]] = [{} for _ in range(len(item_transformed))] # type:ignore
item: list[dict[Any, Any]] = [{} for _ in range(len(item_transformed))] # type: ignore
for i, _item in enumerate(item_transformed):
for k in _item:
meta_i_k = self._load_meta_cache(meta_hash_file_name=f"{hashfile.name}-{k}-meta-{i}")
Expand Down
3 changes: 1 addition & 2 deletions monai/data/wsi_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,7 @@ def get_data(
# Check if there are three color channels for RGB
elif mode in "RGB" and patch.shape[self.channel_dim] != 3:
raise ValueError(
f"The image is expected to have three color channels in '{mode}' mode but has "
f"{patch.shape[self.channel_dim]}. "
f"The image is expected to have three color channels in '{mode}' mode but has {patch.shape[self.channel_dim]}. "
)
# Get patch-related metadata
metadata: dict = self._get_metadata(wsi=each_wsi, patch=patch, location=location, size=size, level=level)
Expand Down
2 changes: 1 addition & 1 deletion monai/handlers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def stopping_fn_from_loss() -> Callable[[Engine], Any]:
"""

def stopping_fn(engine: Engine) -> Any:
return -engine.state.output # type:ignore
return -engine.state.output # type: ignore

return stopping_fn

Expand Down
6 changes: 2 additions & 4 deletions monai/losses/dice.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,9 @@ def forward(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
self.class_weight = torch.as_tensor([self.class_weight] * num_of_classes)
else:
if self.class_weight.shape[0] != num_of_classes:
raise ValueError(
"""the length of the `weight` sequence should be the same as the number of classes.
raise ValueError("""the length of the `weight` sequence should be the same as the number of classes.
If `include_background=False`, the weight should not include
the background category class 0."""
)
the background category class 0.""")
if self.class_weight.min() < 0:
raise ValueError("the value/values of the `weight` should be no less than 0.")
# apply class_weight to loss
Expand Down
6 changes: 2 additions & 4 deletions monai/losses/focal_loss.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,9 @@ def forward(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
self.class_weight = torch.as_tensor([self.class_weight] * num_of_classes)
else:
if self.class_weight.shape[0] != num_of_classes:
raise ValueError(
"""the length of the `weight` sequence should be the same as the number of classes.
raise ValueError("""the length of the `weight` sequence should be the same as the number of classes.
If `include_background=False`, the weight should not include
the background category class 0."""
)
the background category class 0.""")
if self.class_weight.min() < 0:
raise ValueError("the value/values of the `weight` should be no less than 0.")
# apply class_weight to loss
Expand Down
2 changes: 1 addition & 1 deletion monai/metrics/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ def get_edge_surface_distance(
edges_spacing = None
if use_subvoxels:
edges_spacing = spacing if spacing is not None else ([1] * len(y_pred.shape))
(edges_pred, edges_gt, *areas) = get_mask_edges(
edges_pred, edges_gt, *areas = get_mask_edges(
y_pred, y, crop=True, spacing=edges_spacing, always_return_as_numpy=False
)
if not edges_gt.any():
Expand Down
5 changes: 4 additions & 1 deletion monai/networks/blocks/warp.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from monai.config.deviceconfig import USE_COMPILED
from monai.networks.layers.spatial_transforms import grid_pull
from monai.networks.utils import meshgrid_ij
from monai.transforms.spatial.functional import _compiled_unsupported
from monai.utils import GridSampleMode, GridSamplePadMode, optional_import

_C, _ = optional_import("monai._C")
Expand Down Expand Up @@ -138,7 +139,9 @@ def forward(self, image: torch.Tensor, ddf: torch.Tensor):
grid = self.get_reference_grid(ddf, jitter=self.jitter) + ddf
grid = grid.permute([0] + list(range(2, 2 + spatial_dims)) + [1]) # (batch, ..., spatial_dims)

if not USE_COMPILED: # pytorch native grid_sample
_use_compiled = USE_COMPILED and not _compiled_unsupported(image.device)

if not _use_compiled: # pytorch native grid_sample
for i, dim in enumerate(grid.shape[1:-1]):
grid[..., i] = grid[..., i] * 2 / (dim - 1) - 1
index_ordering: list[int] = list(range(spatial_dims - 1, -1, -1))
Expand Down
1 change: 1 addition & 0 deletions monai/transforms/io/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""
A collection of "vanilla" transforms for IO functions.
"""

from __future__ import annotations

import inspect
Expand Down
1 change: 0 additions & 1 deletion monai/transforms/regularization/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@


class Mixer(RandomizableTransform):

def __init__(self, batch_size: int, alpha: float = 1.0) -> None:
"""
Mixer is a base class providing the basic logic for the mixup-class of
Expand Down
22 changes: 19 additions & 3 deletions monai/transforms/spatial/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from monai.transforms.croppad.array import CenterSpatialCrop, ResizeWithPadOrCrop
from monai.transforms.inverse import InvertibleTransform
from monai.transforms.spatial.functional import (
_compiled_unsupported,
affine_func,
convert_box_to_points,
convert_points_to_box,
Expand Down Expand Up @@ -2104,14 +2105,15 @@ def __call__(
_align_corners = self.align_corners if align_corners is None else align_corners
img_t, *_ = convert_data_type(img, torch.Tensor, dtype=_dtype, device=_device)
sr = min(len(img_t.peek_pending_shape() if isinstance(img_t, MetaTensor) else img_t.shape[1:]), 3)
_use_compiled = USE_COMPILED and not _compiled_unsupported(img_t.device)
backend, _interp_mode, _padding_mode, _ = resolves_modes(
self.mode if mode is None else mode,
self.padding_mode if padding_mode is None else padding_mode,
backend=None,
use_compiled=USE_COMPILED,
use_compiled=_use_compiled,
)

if USE_COMPILED or backend == TransformBackends.NUMPY:
if _use_compiled or backend == TransformBackends.NUMPY:
grid_t, *_ = convert_to_dst_type(grid[:sr], img_t, dtype=grid.dtype, wrap_sequence=True)
if isinstance(grid, torch.Tensor) and grid_t.data_ptr() == grid.data_ptr():
grid_t = grid_t.clone(memory_format=torch.contiguous_format)
Expand All @@ -2122,7 +2124,7 @@ def __call__(
grid_t[i] = ((_dim - 1) / _dim) * grid_t[i] + t if _align_corners else grid_t[i] + t
elif _align_corners:
grid_t[i] = ((_dim - 1) / _dim) * (grid_t[i] + 0.5)
if USE_COMPILED and backend == TransformBackends.TORCH: # compiled is using torch backend param name
if _use_compiled and backend == TransformBackends.TORCH: # compiled is using torch backend param name
grid_t = moveaxis(grid_t, 0, -1) # type: ignore
out = grid_pull(
img_t.unsqueeze(0),
Expand All @@ -2140,6 +2142,20 @@ def __call__(
[_map_coord(c, grid_np, order=_interp_mode, mode=_padding_mode) for c in img_np]
)
out = convert_to_dst_type(out, img_t)[0]
else:
# Fallback to PyTorch grid_sample when compiled extension is unsupported.
# Convert grid coordinates from compiled convention [0, size-1] to PyTorch [-1, 1]
for i, dim in enumerate(img_t.shape[1 : 1 + sr]):
_dim = max(2, dim)
grid_t[i] = (grid_t[i] * 2.0 / _dim) - 1.0
grid_t = moveaxis(grid_t, 0, -1) # type: ignore
out = torch.nn.functional.grid_sample(
img_t.unsqueeze(0),
grid_t.unsqueeze(0),
mode=_interp_mode,
padding_mode=_padding_mode,
align_corners=None if _align_corners == TraceKeys.NONE else _align_corners, # type: ignore
)[0]
else:
grid_t = moveaxis(grid[list(range(sr - 1, -1, -1))], 0, -1) # type: ignore
grid_t = convert_to_dst_type(grid_t, img_t, wrap_sequence=True)[0].unsqueeze(0)
Expand Down
Loading
Loading