Repository: Project-MONAI/MONAI

Issue:
randaffined collating datatype inconsistency
**Describe the bug**
looks like an error with torch 1.5.1
full log: https://github.com/Project-MONAI/MONAI/runs/2180798490?check_suite_focus=true
```
======================================================================
ERROR: test_collation_17_RandAffined_default_collate (tests.test_inverse_collation.TestInverseCollation)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/conda/lib/python3.6/site-packages/parameterized/parameterized.py", line 533, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "/__w/MONAI/MONAI/tests/test_inverse_collation.py", line 111, in test_collation
    for item in loader:
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 345, in __next__
    data = self._next_data()
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 856, in _next_data
    return self._process_data(data)
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 881, in _process_data
    data.reraise()
  File "/opt/conda/lib/python3.6/site-packages/torch/_utils.py", line 395, in reraise
    raise self.exc_type(msg)
RuntimeError: Caught RuntimeError in DataLoader worker process 0.
Original Traceback (most recent call last):
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/worker.py", line 178, in _worker_loop
    data = fetcher.fetch(index)
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/fetch.py", line 47, in fetch
    return self.collate_fn(data)
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 74, in default_collate
    return {key: default_collate([d[key] for d in batch]) for key in elem}
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 74, in <dictcomp>
    return {key: default_collate([d[key] for d in batch]) for key in elem}
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 79, in default_collate
    return [default_collate(samples) for samples in transposed]
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 79, in <listcomp>
    return [default_collate(samples) for samples in transposed]
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 74, in default_collate
    return {key: default_collate([d[key] for d in batch]) for key in elem}
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 74, in <dictcomp>
    return {key: default_collate([d[key] for d in batch]) for key in elem}
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 74, in default_collate
    return {key: default_collate([d[key] for d in batch]) for key in elem}
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 74, in <dictcomp>
    return {key: default_collate([d[key] for d in batch]) for key in elem}
  File "/opt/conda/lib/python3.6/site-packages/torch/utils/data/_utils/collate.py", line 55, in default_collate
    return torch.stack(batch, 0, out=out)
RuntimeError: Expected object of scalar type float but got scalar type double for sequence element 1.
```


Discussion:
the other cron jobs didn't run, so is it possible that this problem isn't only present for torch 1.5.1?
![image](https://user-images.githubusercontent.com/33289025/112282696-3bfb6b00-8c7f-11eb-8587-71fafe0cbd9a.png)

the other crons didn't finish, but these particular tests worked fine in those logs...
Ok, thanks.
I just tried to replicate this on my OSX and linux, both with torch==1.5.1, but I can't reproduce the error...
I can replicate this with `nvcr.io/nvidia/pytorch:20.03-py3` docker image...I'll submit a PR now

Resolving patch:
diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py
--- a/monai/transforms/spatial/dictionary.py
+++ b/monai/transforms/spatial/dictionary.py
@@ -698,7 +698,8 @@ def __call__(
             affine = self.rand_affine.rand_affine_grid.get_transformation_matrix()
         else:
             grid = create_grid(spatial_size=sp_size)
-            affine = torch.eye(len(sp_size) + 1)
+            # to be consistent with the self._do_transform case (dtype and device)
+            affine = torch.as_tensor(np.eye(len(sp_size) + 1), device=self.rand_affine.rand_affine_grid.device)
 
         for key, mode, padding_mode in self.key_iterator(d, self.mode, self.padding_mode):
             self.push_transform(d, key, extra_info={"affine": affine})


Test patch:
diff --git a/tests/test_inverse_collation.py b/tests/test_inverse_collation.py
--- a/tests/test_inverse_collation.py
+++ b/tests/test_inverse_collation.py
@@ -14,6 +14,7 @@
 from typing import TYPE_CHECKING
 
 import numpy as np
+import torch
 from parameterized import parameterized
 
 from monai.data import CacheDataset, DataLoader, create_test_image_2d, create_test_image_3d, pad_list_data_collate
@@ -49,7 +50,13 @@
         RandRotate90d(keys=KEYS, spatial_axes=(1, 2)),
         RandZoomd(keys=KEYS, prob=0.5, min_zoom=0.5, max_zoom=1.1, keep_size=True),
         RandRotated(keys=KEYS, prob=0.5, range_x=np.pi),
-        RandAffined(keys=KEYS, prob=0.5, rotate_range=np.pi),
+        RandAffined(
+            keys=KEYS,
+            prob=0.5,
+            rotate_range=np.pi,
+            device=torch.device("cuda" if torch.cuda.is_available() else "cpu"),
+            as_tensor_output=False,
+        ),
     ]
 ]
 
@@ -62,7 +69,13 @@
         RandRotate90d(keys=KEYS, prob=0.5, spatial_axes=(0, 1)),
         RandZoomd(keys=KEYS, prob=0.5, min_zoom=0.5, max_zoom=1.1, keep_size=True),
         RandRotated(keys=KEYS, prob=0.5, range_x=np.pi),
-        RandAffined(keys=KEYS, prob=0.5, rotate_range=np.pi),
+        RandAffined(
+            keys=KEYS,
+            prob=0.5,
+            rotate_range=np.pi,
+            device=torch.device("cuda" if torch.cuda.is_available() else "cpu"),
+            as_tensor_output=False,
+        ),
     ]
 ]
 
@@ -102,8 +115,8 @@ def test_collation(self, _, transform, collate_fn, ndim):
         else:
             modified_transform = Compose([transform, ResizeWithPadOrCropd(KEYS, 100)])
 
-        # num workers = 0 for mac
-        num_workers = 2 if sys.platform != "darwin" else 0
+        # num workers = 0 for mac or gpu transforms
+        num_workers = 0 if sys.platform == "darwin" or torch.cuda.is_available() else 2
 
         dataset = CacheDataset(data, transform=modified_transform, progress=False)
         loader = DataLoader(dataset, num_workers, batch_size=self.batch_size, collate_fn=collate_fn)