internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: Project-MONAI/MONAI

Issue:
Add support for metatensor in `AddGuidanceFromPointsDeepEditd` and `ResizeGuidanceMultipleLabelDeepEditd`
Now it was hard-coded for `meta_dict`.
https://github.com/Project-MONAI/MONAI/blob/8d730cdddb061e248748cb2d9c81113ae0086adb/monai/apps/deepedit/transforms.py#L701
Add support for metatensor in `AddGuidanceFromPointsDeepEditd` and `ResizeGuidanceMultipleLabelDeepEditd`
Now it was hard-coded for `meta_dict`.
https://github.com/Project-MONAI/MONAI/blob/8d730cdddb061e248748cb2d9c81113ae0086adb/monai/apps/deepedit/transforms.py#L701


Discussion:

Resolving patch:
diff --git a/monai/apps/deepedit/transforms.py b/monai/apps/deepedit/transforms.py
--- a/monai/apps/deepedit/transforms.py
+++ b/monai/apps/deepedit/transforms.py
@@ -662,13 +662,21 @@ def _apply(clicks, factor):
     def __call__(self, data):
         d = dict(data)
         meta_dict_key = self.meta_keys or f"{self.ref_image}_{self.meta_key_postfix}"
-        if meta_dict_key not in d:
-            raise RuntimeError(f"Missing meta_dict {meta_dict_key} in data!")
-        if "spatial_shape" not in d[meta_dict_key]:
+        # extract affine matrix from metadata
+        if isinstance(d[self.ref_image], MetaTensor):
+            meta_dict = d[self.ref_image].meta  # type: ignore
+        elif meta_dict_key in d:
+            meta_dict = d[meta_dict_key]
+        else:
+            raise ValueError(
+                f"{meta_dict_key} is not found. Please check whether it is the correct the image meta key."
+            )
+
+        if "spatial_shape" not in meta_dict:
             raise RuntimeError('Missing "spatial_shape" in meta_dict!')
 
         # Assume channel is first and depth is last CHWD
-        original_shape = d[meta_dict_key]["spatial_shape"]
+        original_shape = meta_dict["spatial_shape"]
         current_shape = list(d[self.ref_image].shape)[1:]
 
         # in here we assume the depth dimension is in the last dimension of "original_shape" and "current_shape"
@@ -698,7 +706,19 @@ def __call__(self, data):
         d = dict(data)
         # Assume channel is first and depth is last CHWD
         current_shape = d[self.ref_image].shape[1:]
-        original_shape = d["image_meta_dict"]["spatial_shape"]
+
+        meta_dict_key = "image_meta_dict"
+        # extract affine matrix from metadata
+        if isinstance(d[self.ref_image], MetaTensor):
+            meta_dict = d[self.ref_image].meta  # type: ignore
+        elif meta_dict_key in d:
+            meta_dict = d[meta_dict_key]
+        else:
+            raise ValueError(
+                f"{meta_dict_key} is not found. Please check whether it is the correct the image meta key."
+            )
+
+        original_shape = meta_dict["spatial_shape"]
 
         factor = np.divide(current_shape, original_shape)
         all_guidances = {}


Test patch:
Repository: Project-MONAI/MONAI

Issue:
Reloading of corrupted cached files for PersistentDataset
I use PersistentDataset in my train loop. I needed to abort train script and when I run it again, one of cached files was corrupted because of abortion. PersistentDataset did not finish saving this cache file.
It threw an exception `RuntimeError: Invalid magic number; corrupt file?`

I would like to add a possibility to handle corrupt files. If cached file is corrupted, PersistenDataset will continue like there was no cached file and replace it with a good one.

I see, that if I add "except" block [here](https://github.com/Project-MONAI/MONAI/blob/2b160b3db3ee2942a28ff3a5628879c3fe46d7c8/monai/data/dataset.py#L376-L381), I can handle such behaviour.

May I take this ticket and make a PR?


Discussion:
sure please go ahead, and I think would be great to create a warning message if that error handling logic is triggered
@wyli here is a proposed try-except block to handle this:

```
if hashfile is not None and hashfile.is_file():  # cache hit
        try:
            return torch.load(hashfile)
        except PermissionError as e:
            if sys.platform != "win32":
                raise e
        except RuntimeError as e:
            if 'Invalid magic number; corrupt file' in str(e):
                print(f"Corrupt cache file detected: {hashfile}. Deleting and recomputing.")
                hashfile.unlink()
            else:
                raise e
```
Hi @ishandutta0098, thanks for the proposal, would you like to create a PR?
Here is the [contribution](https://github.com/Project-MONAI/MONAI/blob/dev/CONTRIBUTING.md) guide you could refer to.
Thanks!
Sure @KumoLiu please assign the issue to me, I will start working on it


Resolving patch:
diff --git a/monai/data/dataset.py b/monai/data/dataset.py
--- a/monai/data/dataset.py
+++ b/monai/data/dataset.py
@@ -387,6 +387,12 @@ def _cachecheck(self, item_transformed):
             except PermissionError as e:
                 if sys.platform != "win32":
                     raise e
+            except RuntimeError as e:
+                if "Invalid magic number; corrupt file" in str(e):
+                    warnings.warn(f"Corrupt cache file detected: {hashfile}. Deleting and recomputing.")
+                    hashfile.unlink()
+                else:
+                    raise e
 
         _item_transformed = self._pre_transform(deepcopy(item_transformed))  # keep the original hashed
         if hashfile is None:


Test patch:
Repository: Project-MONAI/MONAI

Issue:
document differences between transforms `EnsureType` and `CastToType`
this is a feature request for docstring enhancements to describe the use cases respectively.


Discussion:
Hi @wyli I would like to work on this issue, can you assign it to me?


Resolving patch:
diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py
--- a/monai/transforms/utility/array.py
+++ b/monai/transforms/utility/array.py
@@ -333,6 +333,23 @@ class CastToType(Transform):
     """
     Cast the Numpy data to specified numpy data type, or cast the PyTorch Tensor to
     specified PyTorch data type.
+
+    Example:
+        >>> import numpy as np
+        >>> import torch
+        >>> transform = CastToType(dtype=np.float32)
+
+        >>> # Example with a numpy array
+        >>> img_np = np.array([0, 127, 255], dtype=np.uint8)
+        >>> img_np_casted = transform(img_np)
+        >>> img_np_casted
+        array([  0. , 127. , 255. ], dtype=float32)
+
+        >>> # Example with a PyTorch tensor
+        >>> img_tensor = torch.tensor([0, 127, 255], dtype=torch.uint8)
+        >>> img_tensor_casted = transform(img_tensor)
+        >>> img_tensor_casted
+        tensor([  0., 127., 255.])  # dtype is float32
     """
 
     backend = [TransformBackends.TORCH, TransformBackends.NUMPY]
@@ -413,10 +430,26 @@ class EnsureType(Transform):
         dtype: target data content type to convert, for example: np.float32, torch.float, etc.
         device: for Tensor data type, specify the target device.
         wrap_sequence: if `False`, then lists will recursively call this function, default to `True`.
-            E.g., if `False`, `[1, 2]` -> `[tensor(1), tensor(2)]`, if `True`, then `[1, 2]` -> `tensor([1, 2])`.
         track_meta: if `True` convert to ``MetaTensor``, otherwise to Pytorch ``Tensor``,
             if ``None`` behave according to return value of py:func:`monai.data.meta_obj.get_track_meta`.
 
+    Example with wrap_sequence=True:
+        >>> import numpy as np
+        >>> import torch
+        >>> transform = EnsureType(data_type="tensor", wrap_sequence=True)
+        >>> # Converting a list to a tensor
+        >>> data_list = [1, 2., 3]
+        >>> tensor_data = transform(data_list)
+        >>> tensor_data
+        tensor([1., 2., 3.])    # All elements have dtype float32
+
+    Example with wrap_sequence=False:
+        >>> transform = EnsureType(data_type="tensor", wrap_sequence=False)
+        >>> # Converting each element in a list to individual tensors
+        >>> data_list = [1, 2, 3]
+        >>> tensors_list = transform(data_list)
+        >>> tensors_list
+        [tensor(1), tensor(2.), tensor(3)]  # Only second element is float32 rest are int64
     """
 
     backend = [TransformBackends.TORCH, TransformBackends.NUMPY]


Test patch:
Repository: Project-MONAI/MONAI

Issue:
CUDA_VISIBLE_DEVICES setting ignored after `import monai`
**Describe the bug**
CUDA_VISIBLE_DEVICES setting ignored after `import monai`

**To Reproduce**
```
import os
import torch
print('before import monai:', torch.cuda.device_count())
import monai

os.environ["CUDA_VISIBLE_DEVICES"] = "0"
print('after import monai:')
torch.cuda.set_device(1) # should failed
```

**Expected behavior**
CUDA_VISIBLE_DEVICES setting should not ignored after `import monai`
CUDA_VISIBLE_DEVICES setting ignored after `import monai`
**Describe the bug**
CUDA_VISIBLE_DEVICES setting ignored after `import monai`

**To Reproduce**
```
import os
import torch
print('before import monai:', torch.cuda.device_count())
import monai

os.environ["CUDA_VISIBLE_DEVICES"] = "0"
print('after import monai:')
torch.cuda.set_device(1) # should failed
```

**Expected behavior**
CUDA_VISIBLE_DEVICES setting should not ignored after `import monai`


Discussion:

Resolving patch:
diff --git a/monai/metrics/utils.py b/monai/metrics/utils.py
--- a/monai/metrics/utils.py
+++ b/monai/metrics/utils.py
@@ -38,10 +38,6 @@
 binary_erosion, _ = optional_import("scipy.ndimage.morphology", name="binary_erosion")
 distance_transform_edt, _ = optional_import("scipy.ndimage.morphology", name="distance_transform_edt")
 distance_transform_cdt, _ = optional_import("scipy.ndimage.morphology", name="distance_transform_cdt")
-cucim_binary_erosion, has_cucim_binary_erosion = optional_import("cucim.skimage.morphology", name="binary_erosion")
-cucim_distance_transform_edt, has_cucim_distance_transform_edt = optional_import(
-    "cucim.core.operations.morphology", name="distance_transform_edt"
-)
 
 __all__ = [
     "ignore_background",
@@ -179,6 +175,8 @@ def get_mask_edges(
         always_return_as_numpy: whether to a numpy array regardless of the input type.
             If False, return the same type as inputs.
     """
+    # move in the funciton to avoid using all the GPUs
+    cucim_binary_erosion, has_cucim_binary_erosion = optional_import("cucim.skimage.morphology", name="binary_erosion")
     if seg_pred.shape != seg_gt.shape:
         raise ValueError(f"seg_pred and seg_gt should have same shapes, got {seg_pred.shape} and {seg_gt.shape}.")
     converter: Any


Test patch:
diff --git a/tests/test_set_visible_devices.py b/tests/test_set_visible_devices.py
--- a/tests/test_set_visible_devices.py
+++ b/tests/test_set_visible_devices.py
@@ -35,6 +35,13 @@ def test_visible_devices(self):
         )
         self.assertEqual(num_gpus_before, num_gpus_after)
 
+        # test import monai won't affect setting CUDA_VISIBLE_DEVICES
+        num_gpus_after_monai = self.run_process_and_get_exit_code(
+            'python -c "import os; import torch; import monai; '
+            + "os.environ['CUDA_VISIBLE_DEVICES'] = '0'; exit(torch.cuda.device_count())\""
+        )
+        self.assertEqual(num_gpus_after_monai, 1)
+
 
 if __name__ == "__main__":
     unittest.main()
Repository: Project-MONAI/MONAI

Issue:
`rm -rf /opt/hostedtoolcache` may change the python version actually used to run CI tests
**Describe the bug**
When I run some tests on github action in model zoo repo, I found that the following line in the action yml file will remove the installed python version:
```
rm -rf /opt/hostedtoolcache
```
It may lead to the system's default python version will be used to run the tests.

@KumoLiu and I simply check MONAI repo, and found that at least the `deploy` action is impacted. In the corresponding yml file:
https://github.com/Project-MONAI/MONAI/blob/6c9e49ee045c345ecd8d3518cb0d503ed02c61b7/.github/workflows/setupapp.yml#L103
`rm -rf /opt/hostedtoolcache` is used after python env is set. 

If we look at the latest deploy action job, we can see that the python3.9 test actually uses python 3.10 which is not expected.

https://github.com/Project-MONAI/MONAI/actions/runs/7648726812/job/20842001933#step:7:411

Hi @wyli @KumoLiu , I think we should think about how to install the expected python version back before running tests if need `rm -rf /opt/hostedtoolcache`


`rm -rf /opt/hostedtoolcache` may change the python version actually used to run CI tests
**Describe the bug**
When I run some tests on github action in model zoo repo, I found that the following line in the action yml file will remove the installed python version:
```
rm -rf /opt/hostedtoolcache
```
It may lead to the system's default python version will be used to run the tests.

@KumoLiu and I simply check MONAI repo, and found that at least the `deploy` action is impacted. In the corresponding yml file:
https://github.com/Project-MONAI/MONAI/blob/6c9e49ee045c345ecd8d3518cb0d503ed02c61b7/.github/workflows/setupapp.yml#L103
`rm -rf /opt/hostedtoolcache` is used after python env is set. 

If we look at the latest deploy action job, we can see that the python3.9 test actually uses python 3.10 which is not expected.

https://github.com/Project-MONAI/MONAI/actions/runs/7648726812/job/20842001933#step:7:411

Hi @wyli @KumoLiu , I think we should think about how to install the expected python version back before running tests if need `rm -rf /opt/hostedtoolcache`




Discussion:

Resolving patch:
diff --git a/monai/transforms/smooth_field/array.py b/monai/transforms/smooth_field/array.py
--- a/monai/transforms/smooth_field/array.py
+++ b/monai/transforms/smooth_field/array.py
@@ -96,7 +96,7 @@ def __init__(
         self.set_spatial_size(spatial_size)
 
     def randomize(self, data: Any | None = None) -> None:
-        self.field[self.rand_slices] = torch.from_numpy(self.R.uniform(self.low, self.high, self.crand_size))
+        self.field[self.rand_slices] = torch.from_numpy(self.R.uniform(self.low, self.high, self.crand_size))  # type: ignore[index]
 
     def set_spatial_size(self, spatial_size: Sequence[int] | None) -> None:
         """


Test patch:
Repository: Project-MONAI/MONAI

Issue:
test_nnunetv2runner
test nnunetv2runner is broken after the recent update https://pypi.org/project/nnunetv2/#history
```
[2023-09-19T22:32:39.490Z] ======================================================================
[2023-09-19T22:32:39.490Z] ERROR: test_nnunetv2runner (__main__.TestnnUNetV2Runner)
[2023-09-19T22:32:39.490Z] ----------------------------------------------------------------------
[2023-09-19T22:32:39.490Z] Traceback (most recent call last):
[2023-09-19T22:32:39.490Z]   File "/home/jenkins/agent/workspace/Monai-notebooks/MONAI/tests/test_integration_nnunetv2_runner.py", line 89, in test_nnunetv2runner
[2023-09-19T22:32:39.490Z]     runner.predict_ensemble_postprocessing()
[2023-09-19T22:32:39.490Z]   File "/home/jenkins/agent/workspace/Monai-notebooks/MONAI/monai/apps/nnunet/nnunetv2_runner.py", line 900, in predict_ensemble_postprocessing
[2023-09-19T22:32:39.490Z]     self.predict(
[2023-09-19T22:32:39.490Z]   File "/home/jenkins/agent/workspace/Monai-notebooks/MONAI/monai/apps/nnunet/nnunetv2_runner.py", line 827, in predict
[2023-09-19T22:32:39.490Z]     from nnunetv2.inference.predict_from_raw_data import predict_from_raw_data
[2023-09-19T22:32:39.490Z] ImportError: cannot import name 'predict_from_raw_data' from 'nnunetv2.inference.predict_from_raw_data' (/usr/local/lib/python3.10/dist-packages/nnunetv2/inference/predict_from_raw_data.py)
[2023-09-19T22:32:39.490Z] 
[2023-09-19T22:32:39.490Z] ----------------------------------------------------------------------
```


Discussion:

Resolving patch:
diff --git a/monai/metrics/metric.py b/monai/metrics/metric.py
--- a/monai/metrics/metric.py
+++ b/monai/metrics/metric.py
@@ -37,6 +37,9 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any:
         """
         raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.")
 
+    def __str__(self):
+        return self.__class__.__name__
+
 
 class IterationMetric(Metric):
     """


Test patch:
Repository: Project-MONAI/MONAI

Issue:
AssertionError in test_focal_loss
```
FAIL: test_consistency_with_cross_entropy_2d_no_reduction (tests.test_focal_loss.TestFocalLoss)
For gamma=0 the focal loss reduces to the cross entropy loss
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/MONAI/tests/test_focal_loss.py", line 135, in test_consistency_with_cross_entropy_2d_no_reduction
    assert np.allclose(max_error, 0)
AssertionError
```
AssertionError in test_focal_loss
```
FAIL: test_consistency_with_cross_entropy_2d_no_reduction (tests.test_focal_loss.TestFocalLoss)
For gamma=0 the focal loss reduces to the cross entropy loss
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/MONAI/tests/test_focal_loss.py", line 135, in test_consistency_with_cross_entropy_2d_no_reduction
    assert np.allclose(max_error, 0)
AssertionError
```


Discussion:
Error is due to the change from https://github.com/pytorch/pytorch/pull/115539/files#diff-a95ea091724587d4c34bf4d1bb04cf43e3891d8548d61810de08948ab7a9c96e.
Error is due to the change from https://github.com/pytorch/pytorch/pull/115539/files#diff-a95ea091724587d4c34bf4d1bb04cf43e3891d8548d61810de08948ab7a9c96e.

Resolving patch:
diff --git a/monai/losses/focal_loss.py b/monai/losses/focal_loss.py
--- a/monai/losses/focal_loss.py
+++ b/monai/losses/focal_loss.py
@@ -234,9 +234,8 @@ def sigmoid_focal_loss(
     """
     # computing binary cross entropy with logits
     # equivalent to F.binary_cross_entropy_with_logits(input, target, reduction='none')
-    # see also https://github.com/pytorch/pytorch/blob/v1.9.0/aten/src/ATen/native/Loss.cpp#L231
-    max_val = (-input).clamp(min=0)
-    loss: torch.Tensor = input - input * target + max_val + ((-max_val).exp() + (-input - max_val).exp()).log()
+    # see also https://github.com/pytorch/pytorch/blob/main/aten/src/ATen/native/Loss.cpp#L363
+    loss: torch.Tensor = input - input * target - F.logsigmoid(input)
 
     # sigmoid(-i) if t==1; sigmoid(i) if t==0 <=>
     # 1-sigmoid(i) if t==1; sigmoid(i) if t==0 <=>


Test patch:
diff --git a/tests/test_focal_loss.py b/tests/test_focal_loss.py
--- a/tests/test_focal_loss.py
+++ b/tests/test_focal_loss.py
@@ -132,7 +132,7 @@ def test_consistency_with_cross_entropy_2d_no_reduction(self):
             error = np.abs(a - b)
             max_error = np.maximum(error, max_error)
 
-        assert np.allclose(max_error, 0)
+        assert np.allclose(max_error, 0, atol=1e-6)
 
     def test_consistency_with_cross_entropy_2d_onehot_label(self):
         """For gamma=0 the focal loss reduces to the cross entropy loss"""
Repository: Project-MONAI/MONAI

Issue:
Make the RandCropByLabelClassesd warning only show when ratio for a missing class is set to nonzero
**Is your feature request related to a problem? Please describe.**
Warnings such as `no available indices of class 1 to crop, set the crop ratio of this class to zero.` appear even when ratios is already set to 0 for the missing class 1.

**Describe the solution you'd like**
I would suggest that if ratio for a class is already 0 set by the user, then such warnings should not be printed.

I would like to see something similar:
```python
for i, array in enumerate(indices):
  if len(array) == 0:
    if ratios_[i] != 0:  # suggested change
      ratios_[i] = 0
      if warn:
          warnings.warn(f"no available indices of class {i} to crop, set the crop ratio of this class to zero.")
```

**Describe alternatives you've considered**
Suppressing such warnings could be an option too, but I think the other option would be friendlier.

**Additional context**
Found slightly related issue and PR: #6094  #6121 , but it's not completely the same.


Discussion:
Welcome to submit a pull request, thanks!

Resolving patch:
diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py
--- a/monai/transforms/utils.py
+++ b/monai/transforms/utils.py
@@ -625,9 +625,12 @@ def generate_label_classes_crop_centers(
 
     for i, array in enumerate(indices):
         if len(array) == 0:
-            ratios_[i] = 0
-            if warn:
-                warnings.warn(f"no available indices of class {i} to crop, set the crop ratio of this class to zero.")
+            if ratios_[i] != 0:
+                ratios_[i] = 0
+                if warn:
+                    warnings.warn(
+                        f"no available indices of class {i} to crop, setting the crop ratio of this class to zero."
+                    )
 
     centers = []
     classes = rand_state.choice(len(ratios_), size=num_samples, p=np.asarray(ratios_) / np.sum(ratios_))


Test patch:
Repository: Project-MONAI/MONAI

Issue:
Inaccurate error message in regression.py
**Describe the bug**

On line 306 of monai.metrics.regression, the printed error message states that y_pred should have 4 dimensions when in fact the surrounding if-statement is looking for the case where y_pred should have 5 dimensions. This confused me because I got an error message saying:

 "y_pred should have 4 dimensions (batch, channel, height, width, depth) when using 3 spatial dimensions, got 4."

**Expected behavior**

All that needs to be changed is the number 4 to a 5


Inaccurate error message in regression.py
**Describe the bug**

On line 306 of monai.metrics.regression, the printed error message states that y_pred should have 4 dimensions when in fact the surrounding if-statement is looking for the case where y_pred should have 5 dimensions. This confused me because I got an error message saying:

 "y_pred should have 4 dimensions (batch, channel, height, width, depth) when using 3 spatial dimensions, got 4."

**Expected behavior**

All that needs to be changed is the number 4 to a 5




Discussion:

Resolving patch:
diff --git a/monai/metrics/regression.py b/monai/metrics/regression.py
--- a/monai/metrics/regression.py
+++ b/monai/metrics/regression.py
@@ -303,7 +303,7 @@ def _compute_metric(self, y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor
 
         if self.spatial_dims == 3 and dims != 5:
             raise ValueError(
-                f"y_pred should have 4 dimensions (batch, channel, height, width, depth) when using {self.spatial_dims}"
+                f"y_pred should have 5 dimensions (batch, channel, height, width, depth) when using {self.spatial_dims}"
                 f" spatial dimensions, got {dims}."
             )
 


Test patch: