prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add support to move data to `device` after inverting
  **Is your feature request related to a problem? Please describe.**
  Need to enhance the `TransformInverter` handler to move data to expected `device`.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `monai/handlers/transform_inverter.py`
  Content:
  ```
  1 # Copyright 2020 - 2021 MONAI Consortium
  2 # Licensed under the Apache License, Version 2.0 (the "License");
  3 # you may not use this file except in compliance with the License.
  4 # You may obtain a copy of the License at
  5 #     http://www.apache.org/licenses/LICENSE-2.0
  6 # Unless required by applicable law or agreed to in writing, software
  7 # distributed under the License is distributed on an "AS IS" BASIS,
  8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9 # See the License for the specific language governing permissions and
  10 # limitations under the License.
  11 
  12 import warnings
  13 from copy import deepcopy
  14 from typing import TYPE_CHECKING, Callable, Optional, Sequence, Union
  15 
  16 from torch.utils.data import DataLoader as TorchDataLoader
  17 
  18 from monai.data import BatchInverseTransform
  19 from monai.data.utils import no_collation
  20 from monai.engines.utils import CommonKeys, IterationEvents
  21 from monai.transforms import InvertibleTransform, ToTensor, allow_missing_keys_mode, convert_inverse_interp_mode
  22 from monai.utils import InverseKeys, ensure_tuple, ensure_tuple_rep, exact_version, optional_import
  23 
  24 Events, _ = optional_import("ignite.engine", "0.4.4", exact_version, "Events")
  25 if TYPE_CHECKING:
  26     from ignite.engine import Engine
  27 else:
  28     Engine, _ = optional_import("ignite.engine", "0.4.4", exact_version, "Engine")
  29 
  30 
  31 class TransformInverter:
  32     """
  33     Ignite handler to automatically invert `transforms`.
  34     It takes `engine.state.output` as the input data and uses the transforms information from `engine.state.batch`.
  35     The outputs are stored in `engine.state.output` with key: "{output_key}_{postfix}".
  36     """
  37 
  38     def __init__(
  39         self,
  40         transform: InvertibleTransform,
  41         loader: TorchDataLoader,
  42         output_keys: Union[str, Sequence[str]] = CommonKeys.PRED,
  43         batch_keys: Union[str, Sequence[str]] = CommonKeys.IMAGE,
  44         meta_key_postfix: str = "meta_dict",
  45         collate_fn: Optional[Callable] = no_collation,
  46         postfix: str = "inverted",
  47         nearest_interp: Union[bool, Sequence[bool]] = True,
  48         post_func: Union[Callable, Sequence[Callable]] = lambda x: x,
  49         num_workers: Optional[int] = 0,
  50     ) -> None:
  51         """
  52         Args:
  53             transform: a callable data transform on input data.
  54             loader: data loader used to run transforms and generate the batch of data.
  55             output_keys: the key of expected data in `ignite.engine.output`, invert transforms on it.
  56                 it also can be a list of keys, will invert transform for each of them. Default to "pred".
  57             batch_keys: the key of input data in `ignite.engine.batch`. will get the applied transforms
  58                 for this input data, then invert them for the expected data with `output_keys`.
  59                 It can also be a list of keys, each matches to the `output_keys` data. default to "image".
  60             meta_key_postfix: use `{batch_key}_{postfix}` to to fetch the meta data according to the key data,
  61                 default is `meta_dict`, the meta data is a dictionary object.
  62                 For example, to handle key `image`,  read/write affine matrices from the
  63                 metadata `image_meta_dict` dictionary's `affine` field.
  64             collate_fn: how to collate data after inverse transformations.
  65                 default won't do any collation, so the output will be a list of size batch size.
  66             postfix: will save the inverted result into `ignite.engine.output` with key `{output_key}_{postfix}`.
  67             nearest_interp: whether to use `nearest` interpolation mode when inverting the spatial transforms,
  68                 default to `True`. If `False`, use the same interpolation mode as the original transform.
  69                 it also can be a list of bool, each matches to the `output_keys` data.
  70             post_func: post processing for the inverted data, should be a callable function.
  71                 it also can be a list of callable, each matches to the `output_keys` data.
  72             num_workers: number of workers when run data loader for inverse transforms,
  73                 default to 0 as only run one iteration and multi-processing may be even slower.
  74                 Set to `None`, to use the `num_workers` of the input transform data loader.
  75 
  76         """
  77         self.transform = transform
  78         self.inverter = BatchInverseTransform(
  79             transform=transform,
  80             loader=loader,
  81             collate_fn=collate_fn,
  82             num_workers=num_workers,
  83         )
  84         self.output_keys = ensure_tuple(output_keys)
  85         self.batch_keys = ensure_tuple_rep(batch_keys, len(self.output_keys))
  86         self.meta_key_postfix = meta_key_postfix
  87         self.postfix = postfix
  88         self.nearest_interp = ensure_tuple_rep(nearest_interp, len(self.output_keys))
  89         self.post_func = ensure_tuple_rep(post_func, len(self.output_keys))
  90         self._totensor = ToTensor()
  91 
  92     def attach(self, engine: Engine) -> None:
  93         """
  94         Args:
  95             engine: Ignite Engine, it can be a trainer, validator or evaluator.
  96         """
  97         engine.add_event_handler(IterationEvents.MODEL_COMPLETED, self)
  98 
  99     def __call__(self, engine: Engine) -> None:
  100         """
  101         Args:
  102             engine: Ignite Engine, it can be a trainer, validator or evaluator.
  103         """
  104         for output_key, batch_key, nearest_interp, post_funct in zip(
  105             self.output_keys, self.batch_keys, self.nearest_interp, self.post_func
  106         ):
  107             transform_key = batch_key + InverseKeys.KEY_SUFFIX
  108             if transform_key not in engine.state.batch:
  109                 warnings.warn(f"all the transforms on `{batch_key}` are not InvertibleTransform.")
  110                 continue
  111 
  112             transform_info = engine.state.batch[transform_key]
  113             if nearest_interp:
  114                 transform_info = convert_inverse_interp_mode(
  115                     trans_info=deepcopy(transform_info),
  116                     mode="nearest",
  117                     align_corners=None,
  118                 )
  119 
  120             segs_dict = {
  121                 batch_key: engine.state.output[output_key].detach().cpu(),
  122                 transform_key: transform_info,
  123             }
  124             meta_dict_key = f"{batch_key}_{self.meta_key_postfix}"
  125             if meta_dict_key in engine.state.batch:
  126                 segs_dict[meta_dict_key] = engine.state.batch[meta_dict_key]
  127 
  128             with allow_missing_keys_mode(self.transform):  # type: ignore
  129                 inverted_key = f"{output_key}_{self.postfix}"
  130                 engine.state.output[inverted_key] = [
  131                     post_funct(self._totensor(i[batch_key])) for i in self.inverter(segs_dict)
  132                 ]
  133
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/monai/handlers/transform_inverter.py b/monai/handlers/transform_inverter.py
  --- a/monai/handlers/transform_inverter.py
  +++ b/monai/handlers/transform_inverter.py
  @@ -13,6 +13,7 @@
   from copy import deepcopy
   from typing import TYPE_CHECKING, Callable, Optional, Sequence, Union
   
  +import torch
   from torch.utils.data import DataLoader as TorchDataLoader
   
   from monai.data import BatchInverseTransform
  @@ -32,7 +33,7 @@
       """
       Ignite handler to automatically invert `transforms`.
       It takes `engine.state.output` as the input data and uses the transforms information from `engine.state.batch`.
  -    The outputs are stored in `engine.state.output` with key: "{output_key}_{postfix}".
  +    The inverted results are stored in `engine.state.output` with key: "{output_key}_{postfix}".
       """
   
       def __init__(
  @@ -45,6 +46,8 @@
           collate_fn: Optional[Callable] = no_collation,
           postfix: str = "inverted",
           nearest_interp: Union[bool, Sequence[bool]] = True,
  +        to_tensor: Union[bool, Sequence[bool]] = True,
  +        device: Union[Union[str, torch.device], Sequence[Union[str, torch.device]]] = "cpu",
           post_func: Union[Callable, Sequence[Callable]] = lambda x: x,
           num_workers: Optional[int] = 0,
       ) -> None:
  @@ -67,6 +70,11 @@
               nearest_interp: whether to use `nearest` interpolation mode when inverting the spatial transforms,
                   default to `True`. If `False`, use the same interpolation mode as the original transform.
                   it also can be a list of bool, each matches to the `output_keys` data.
  +            to_tensor: whether to convert the inverted data into PyTorch Tensor first, default to `True`.
  +                it also can be a list of bool, each matches to the `output_keys` data.
  +            device: if converted to Tensor, move the inverted results to target device before `post_func`,
  +                default to "cpu", it also can be a list of string or `torch.device`,
  +                each matches to the `output_keys` data.
               post_func: post processing for the inverted data, should be a callable function.
                   it also can be a list of callable, each matches to the `output_keys` data.
               num_workers: number of workers when run data loader for inverse transforms,
  @@ -86,6 +94,8 @@
           self.meta_key_postfix = meta_key_postfix
           self.postfix = postfix
           self.nearest_interp = ensure_tuple_rep(nearest_interp, len(self.output_keys))
  +        self.to_tensor = ensure_tuple_rep(to_tensor, len(self.output_keys))
  +        self.device = ensure_tuple_rep(device, len(self.output_keys))
           self.post_func = ensure_tuple_rep(post_func, len(self.output_keys))
           self._totensor = ToTensor()
   
  @@ -101,8 +111,8 @@
           Args:
               engine: Ignite Engine, it can be a trainer, validator or evaluator.
           """
  -        for output_key, batch_key, nearest_interp, post_funct in zip(
  -            self.output_keys, self.batch_keys, self.nearest_interp, self.post_func
  +        for output_key, batch_key, nearest_interp, to_tensor, device, post_func in zip(
  +            self.output_keys, self.batch_keys, self.nearest_interp, self.to_tensor, self.device, self.post_func
           ):
               transform_key = batch_key + InverseKeys.KEY_SUFFIX
               if transform_key not in engine.state.batch:
  @@ -118,7 +128,7 @@
                   )
   
               segs_dict = {
  -                batch_key: engine.state.output[output_key].detach().cpu(),
  +                batch_key: engine.state.output[output_key],
                   transform_key: transform_info,
               }
               meta_dict_key = f"{batch_key}_{self.meta_key_postfix}"
  @@ -128,5 +138,6 @@
               with allow_missing_keys_mode(self.transform):  # type: ignore
                   inverted_key = f"{output_key}_{self.postfix}"
                   engine.state.output[inverted_key] = [
  -                    post_funct(self._totensor(i[batch_key])) for i in self.inverter(segs_dict)
  +                    post_func(self._totensor(i[batch_key]).to(device) if to_tensor else i[batch_key])
  +                    for i in self.inverter(segs_dict)
                   ]
  
verification_info: {"golden_diff": "diff --git a/monai/handlers/transform_inverter.py b/monai/handlers/transform_inverter.py\n--- a/monai/handlers/transform_inverter.py\n+++ b/monai/handlers/transform_inverter.py\n@@ -13,6 +13,7 @@\n from copy import deepcopy\n from typing import TYPE_CHECKING, Callable, Optional, Sequence, Union\n \n+import torch\n from torch.utils.data import DataLoader as TorchDataLoader\n \n from monai.data import BatchInverseTransform\n@@ -32,7 +33,7 @@\n     \"\"\"\n     Ignite handler to automatically invert `transforms`.\n     It takes `engine.state.output` as the input data and uses the transforms information from `engine.state.batch`.\n-    The outputs are stored in `engine.state.output` with key: \"{output_key}_{postfix}\".\n+    The inverted results are stored in `engine.state.output` with key: \"{output_key}_{postfix}\".\n     \"\"\"\n \n     def __init__(\n@@ -45,6 +46,8 @@\n         collate_fn: Optional[Callable] = no_collation,\n         postfix: str = \"inverted\",\n         nearest_interp: Union[bool, Sequence[bool]] = True,\n+        to_tensor: Union[bool, Sequence[bool]] = True,\n+        device: Union[Union[str, torch.device], Sequence[Union[str, torch.device]]] = \"cpu\",\n         post_func: Union[Callable, Sequence[Callable]] = lambda x: x,\n         num_workers: Optional[int] = 0,\n     ) -> None:\n@@ -67,6 +70,11 @@\n             nearest_interp: whether to use `nearest` interpolation mode when inverting the spatial transforms,\n                 default to `True`. If `False`, use the same interpolation mode as the original transform.\n                 it also can be a list of bool, each matches to the `output_keys` data.\n+            to_tensor: whether to convert the inverted data into PyTorch Tensor first, default to `True`.\n+                it also can be a list of bool, each matches to the `output_keys` data.\n+            device: if converted to Tensor, move the inverted results to target device before `post_func`,\n+                default to \"cpu\", it also can be a list of string or `torch.device`,\n+                each matches to the `output_keys` data.\n             post_func: post processing for the inverted data, should be a callable function.\n                 it also can be a list of callable, each matches to the `output_keys` data.\n             num_workers: number of workers when run data loader for inverse transforms,\n@@ -86,6 +94,8 @@\n         self.meta_key_postfix = meta_key_postfix\n         self.postfix = postfix\n         self.nearest_interp = ensure_tuple_rep(nearest_interp, len(self.output_keys))\n+        self.to_tensor = ensure_tuple_rep(to_tensor, len(self.output_keys))\n+        self.device = ensure_tuple_rep(device, len(self.output_keys))\n         self.post_func = ensure_tuple_rep(post_func, len(self.output_keys))\n         self._totensor = ToTensor()\n \n@@ -101,8 +111,8 @@\n         Args:\n             engine: Ignite Engine, it can be a trainer, validator or evaluator.\n         \"\"\"\n-        for output_key, batch_key, nearest_interp, post_funct in zip(\n-            self.output_keys, self.batch_keys, self.nearest_interp, self.post_func\n+        for output_key, batch_key, nearest_interp, to_tensor, device, post_func in zip(\n+            self.output_keys, self.batch_keys, self.nearest_interp, self.to_tensor, self.device, self.post_func\n         ):\n             transform_key = batch_key + InverseKeys.KEY_SUFFIX\n             if transform_key not in engine.state.batch:\n@@ -118,7 +128,7 @@\n                 )\n \n             segs_dict = {\n-                batch_key: engine.state.output[output_key].detach().cpu(),\n+                batch_key: engine.state.output[output_key],\n                 transform_key: transform_info,\n             }\n             meta_dict_key = f\"{batch_key}_{self.meta_key_postfix}\"\n@@ -128,5 +138,6 @@\n             with allow_missing_keys_mode(self.transform):  # type: ignore\n                 inverted_key = f\"{output_key}_{self.postfix}\"\n                 engine.state.output[inverted_key] = [\n-                    post_funct(self._totensor(i[batch_key])) for i in self.inverter(segs_dict)\n+                    post_func(self._totensor(i[batch_key]).to(device) if to_tensor else i[batch_key])\n+                    for i in self.inverter(segs_dict)\n                 ]\n", "issue": "Add support to move data to `device` after inverting\n**Is your feature request related to a problem? Please describe.**\r\nNeed to enhance the `TransformInverter` handler to move data to expected `device`.\r\n\n", "before_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport warnings\nfrom copy import deepcopy\nfrom typing import TYPE_CHECKING, Callable, Optional, Sequence, Union\n\nfrom torch.utils.data import DataLoader as TorchDataLoader\n\nfrom monai.data import BatchInverseTransform\nfrom monai.data.utils import no_collation\nfrom monai.engines.utils import CommonKeys, IterationEvents\nfrom monai.transforms import InvertibleTransform, ToTensor, allow_missing_keys_mode, convert_inverse_interp_mode\nfrom monai.utils import InverseKeys, ensure_tuple, ensure_tuple_rep, exact_version, optional_import\n\nEvents, _ = optional_import(\"ignite.engine\", \"0.4.4\", exact_version, \"Events\")\nif TYPE_CHECKING:\n    from ignite.engine import Engine\nelse:\n    Engine, _ = optional_import(\"ignite.engine\", \"0.4.4\", exact_version, \"Engine\")\n\n\nclass TransformInverter:\n    \"\"\"\n    Ignite handler to automatically invert `transforms`.\n    It takes `engine.state.output` as the input data and uses the transforms information from `engine.state.batch`.\n    The outputs are stored in `engine.state.output` with key: \"{output_key}_{postfix}\".\n    \"\"\"\n\n    def __init__(\n        self,\n        transform: InvertibleTransform,\n        loader: TorchDataLoader,\n        output_keys: Union[str, Sequence[str]] = CommonKeys.PRED,\n        batch_keys: Union[str, Sequence[str]] = CommonKeys.IMAGE,\n        meta_key_postfix: str = \"meta_dict\",\n        collate_fn: Optional[Callable] = no_collation,\n        postfix: str = \"inverted\",\n        nearest_interp: Union[bool, Sequence[bool]] = True,\n        post_func: Union[Callable, Sequence[Callable]] = lambda x: x,\n        num_workers: Optional[int] = 0,\n    ) -> None:\n        \"\"\"\n        Args:\n            transform: a callable data transform on input data.\n            loader: data loader used to run transforms and generate the batch of data.\n            output_keys: the key of expected data in `ignite.engine.output`, invert transforms on it.\n                it also can be a list of keys, will invert transform for each of them. Default to \"pred\".\n            batch_keys: the key of input data in `ignite.engine.batch`. will get the applied transforms\n                for this input data, then invert them for the expected data with `output_keys`.\n                It can also be a list of keys, each matches to the `output_keys` data. default to \"image\".\n            meta_key_postfix: use `{batch_key}_{postfix}` to to fetch the meta data according to the key data,\n                default is `meta_dict`, the meta data is a dictionary object.\n                For example, to handle key `image`,  read/write affine matrices from the\n                metadata `image_meta_dict` dictionary's `affine` field.\n            collate_fn: how to collate data after inverse transformations.\n                default won't do any collation, so the output will be a list of size batch size.\n            postfix: will save the inverted result into `ignite.engine.output` with key `{output_key}_{postfix}`.\n            nearest_interp: whether to use `nearest` interpolation mode when inverting the spatial transforms,\n                default to `True`. If `False`, use the same interpolation mode as the original transform.\n                it also can be a list of bool, each matches to the `output_keys` data.\n            post_func: post processing for the inverted data, should be a callable function.\n                it also can be a list of callable, each matches to the `output_keys` data.\n            num_workers: number of workers when run data loader for inverse transforms,\n                default to 0 as only run one iteration and multi-processing may be even slower.\n                Set to `None`, to use the `num_workers` of the input transform data loader.\n\n        \"\"\"\n        self.transform = transform\n        self.inverter = BatchInverseTransform(\n            transform=transform,\n            loader=loader,\n            collate_fn=collate_fn,\n            num_workers=num_workers,\n        )\n        self.output_keys = ensure_tuple(output_keys)\n        self.batch_keys = ensure_tuple_rep(batch_keys, len(self.output_keys))\n        self.meta_key_postfix = meta_key_postfix\n        self.postfix = postfix\n        self.nearest_interp = ensure_tuple_rep(nearest_interp, len(self.output_keys))\n        self.post_func = ensure_tuple_rep(post_func, len(self.output_keys))\n        self._totensor = ToTensor()\n\n    def attach(self, engine: Engine) -> None:\n        \"\"\"\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        engine.add_event_handler(IterationEvents.MODEL_COMPLETED, self)\n\n    def __call__(self, engine: Engine) -> None:\n        \"\"\"\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        for output_key, batch_key, nearest_interp, post_funct in zip(\n            self.output_keys, self.batch_keys, self.nearest_interp, self.post_func\n        ):\n            transform_key = batch_key + InverseKeys.KEY_SUFFIX\n            if transform_key not in engine.state.batch:\n                warnings.warn(f\"all the transforms on `{batch_key}` are not InvertibleTransform.\")\n                continue\n\n            transform_info = engine.state.batch[transform_key]\n            if nearest_interp:\n                transform_info = convert_inverse_interp_mode(\n                    trans_info=deepcopy(transform_info),\n                    mode=\"nearest\",\n                    align_corners=None,\n                )\n\n            segs_dict = {\n                batch_key: engine.state.output[output_key].detach().cpu(),\n                transform_key: transform_info,\n            }\n            meta_dict_key = f\"{batch_key}_{self.meta_key_postfix}\"\n            if meta_dict_key in engine.state.batch:\n                segs_dict[meta_dict_key] = engine.state.batch[meta_dict_key]\n\n            with allow_missing_keys_mode(self.transform):  # type: ignore\n                inverted_key = f\"{output_key}_{self.postfix}\"\n                engine.state.output[inverted_key] = [\n                    post_funct(self._totensor(i[batch_key])) for i in self.inverter(segs_dict)\n                ]\n", "path": "monai/handlers/transform_inverter.py"}], "after_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport warnings\nfrom copy import deepcopy\nfrom typing import TYPE_CHECKING, Callable, Optional, Sequence, Union\n\nimport torch\nfrom torch.utils.data import DataLoader as TorchDataLoader\n\nfrom monai.data import BatchInverseTransform\nfrom monai.data.utils import no_collation\nfrom monai.engines.utils import CommonKeys, IterationEvents\nfrom monai.transforms import InvertibleTransform, ToTensor, allow_missing_keys_mode, convert_inverse_interp_mode\nfrom monai.utils import InverseKeys, ensure_tuple, ensure_tuple_rep, exact_version, optional_import\n\nEvents, _ = optional_import(\"ignite.engine\", \"0.4.4\", exact_version, \"Events\")\nif TYPE_CHECKING:\n    from ignite.engine import Engine\nelse:\n    Engine, _ = optional_import(\"ignite.engine\", \"0.4.4\", exact_version, \"Engine\")\n\n\nclass TransformInverter:\n    \"\"\"\n    Ignite handler to automatically invert `transforms`.\n    It takes `engine.state.output` as the input data and uses the transforms information from `engine.state.batch`.\n    The inverted results are stored in `engine.state.output` with key: \"{output_key}_{postfix}\".\n    \"\"\"\n\n    def __init__(\n        self,\n        transform: InvertibleTransform,\n        loader: TorchDataLoader,\n        output_keys: Union[str, Sequence[str]] = CommonKeys.PRED,\n        batch_keys: Union[str, Sequence[str]] = CommonKeys.IMAGE,\n        meta_key_postfix: str = \"meta_dict\",\n        collate_fn: Optional[Callable] = no_collation,\n        postfix: str = \"inverted\",\n        nearest_interp: Union[bool, Sequence[bool]] = True,\n        to_tensor: Union[bool, Sequence[bool]] = True,\n        device: Union[Union[str, torch.device], Sequence[Union[str, torch.device]]] = \"cpu\",\n        post_func: Union[Callable, Sequence[Callable]] = lambda x: x,\n        num_workers: Optional[int] = 0,\n    ) -> None:\n        \"\"\"\n        Args:\n            transform: a callable data transform on input data.\n            loader: data loader used to run transforms and generate the batch of data.\n            output_keys: the key of expected data in `ignite.engine.output`, invert transforms on it.\n                it also can be a list of keys, will invert transform for each of them. Default to \"pred\".\n            batch_keys: the key of input data in `ignite.engine.batch`. will get the applied transforms\n                for this input data, then invert them for the expected data with `output_keys`.\n                It can also be a list of keys, each matches to the `output_keys` data. default to \"image\".\n            meta_key_postfix: use `{batch_key}_{postfix}` to to fetch the meta data according to the key data,\n                default is `meta_dict`, the meta data is a dictionary object.\n                For example, to handle key `image`,  read/write affine matrices from the\n                metadata `image_meta_dict` dictionary's `affine` field.\n            collate_fn: how to collate data after inverse transformations.\n                default won't do any collation, so the output will be a list of size batch size.\n            postfix: will save the inverted result into `ignite.engine.output` with key `{output_key}_{postfix}`.\n            nearest_interp: whether to use `nearest` interpolation mode when inverting the spatial transforms,\n                default to `True`. If `False`, use the same interpolation mode as the original transform.\n                it also can be a list of bool, each matches to the `output_keys` data.\n            to_tensor: whether to convert the inverted data into PyTorch Tensor first, default to `True`.\n                it also can be a list of bool, each matches to the `output_keys` data.\n            device: if converted to Tensor, move the inverted results to target device before `post_func`,\n                default to \"cpu\", it also can be a list of string or `torch.device`,\n                each matches to the `output_keys` data.\n            post_func: post processing for the inverted data, should be a callable function.\n                it also can be a list of callable, each matches to the `output_keys` data.\n            num_workers: number of workers when run data loader for inverse transforms,\n                default to 0 as only run one iteration and multi-processing may be even slower.\n                Set to `None`, to use the `num_workers` of the input transform data loader.\n\n        \"\"\"\n        self.transform = transform\n        self.inverter = BatchInverseTransform(\n            transform=transform,\n            loader=loader,\n            collate_fn=collate_fn,\n            num_workers=num_workers,\n        )\n        self.output_keys = ensure_tuple(output_keys)\n        self.batch_keys = ensure_tuple_rep(batch_keys, len(self.output_keys))\n        self.meta_key_postfix = meta_key_postfix\n        self.postfix = postfix\n        self.nearest_interp = ensure_tuple_rep(nearest_interp, len(self.output_keys))\n        self.to_tensor = ensure_tuple_rep(to_tensor, len(self.output_keys))\n        self.device = ensure_tuple_rep(device, len(self.output_keys))\n        self.post_func = ensure_tuple_rep(post_func, len(self.output_keys))\n        self._totensor = ToTensor()\n\n    def attach(self, engine: Engine) -> None:\n        \"\"\"\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        engine.add_event_handler(IterationEvents.MODEL_COMPLETED, self)\n\n    def __call__(self, engine: Engine) -> None:\n        \"\"\"\n        Args:\n            engine: Ignite Engine, it can be a trainer, validator or evaluator.\n        \"\"\"\n        for output_key, batch_key, nearest_interp, to_tensor, device, post_func in zip(\n            self.output_keys, self.batch_keys, self.nearest_interp, self.to_tensor, self.device, self.post_func\n        ):\n            transform_key = batch_key + InverseKeys.KEY_SUFFIX\n            if transform_key not in engine.state.batch:\n                warnings.warn(f\"all the transforms on `{batch_key}` are not InvertibleTransform.\")\n                continue\n\n            transform_info = engine.state.batch[transform_key]\n            if nearest_interp:\n                transform_info = convert_inverse_interp_mode(\n                    trans_info=deepcopy(transform_info),\n                    mode=\"nearest\",\n                    align_corners=None,\n                )\n\n            segs_dict = {\n                batch_key: engine.state.output[output_key],\n                transform_key: transform_info,\n            }\n            meta_dict_key = f\"{batch_key}_{self.meta_key_postfix}\"\n            if meta_dict_key in engine.state.batch:\n                segs_dict[meta_dict_key] = engine.state.batch[meta_dict_key]\n\n            with allow_missing_keys_mode(self.transform):  # type: ignore\n                inverted_key = f\"{output_key}_{self.postfix}\"\n                engine.state.output[inverted_key] = [\n                    post_func(self._totensor(i[batch_key]).to(device) if to_tensor else i[batch_key])\n                    for i in self.inverter(segs_dict)\n                ]\n", "path": "monai/handlers/transform_inverter.py"}]}