We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Improve Accumulation metric on tensors to work with Apex
## 🚀 Feature Request
It seems that the ignite is not compatible with apex. When i am trying to use the (automatic mixed precision)amp from the Apex for the GPU Acceleration, I have encountered the following error. Look around the Ignite source code and I find that it uses the original torch.Tensor. Is there any timeline for Ignite to be compatible with Apex?
```
m.update(loss)
--
File "/usr/local/lib/python3.6/site-packages/ignite/metrics/metric.py", line 575, in wrapper
func(self, *args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/ignite/metrics/accumulation.py", line 73, in update
self.accumulator = self._op(self.accumulator, output)
File "/usr/local/lib/python3.6/site-packages/ignite/metrics/accumulation.py", line 130, in _mean_op
return a + x
File "/usr/local/lib64/python3.6/site-packages/apex/amp/wrap.py", line 62, in wrapper
.format(types))
NotImplementedError: Do not know how to handle these types to promote: {'FloatTensor', 'DoubleTensor'}
```
Apex: https://github.com/NVIDIA/apex

## Environment

- PyTorch Version (1.4.0):
- Ignite Version (0.4.4):
- OS (Linux):
- Python version:  python 3.6
- Apex Version (0.1)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ignite/metrics/accumulation.py`
Content:
```
1 import numbers
2 from typing import Callable, Tuple, Union
3 
4 import torch
5 
6 from ignite.exceptions import NotComputableError
7 from ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce
8 
9 __all__ = ["VariableAccumulation", "GeometricAverage", "Average"]
10 
11 
12 class VariableAccumulation(Metric):
13     """Single variable accumulator helper to compute (arithmetic, geometric, harmonic) average of a single variable.
14 
15     - ``update`` must receive output of the form `x`.
16     - `x` can be a number or `torch.Tensor`.
17 
18     Note:
19 
20         The class stores input into two public variables: `accumulator` and `num_examples`.
21         Number of samples is updated following the rule:
22 
23         - `+1` if input is a number
24         - `+1` if input is a 1D `torch.Tensor`
25         - `+batch_size` if input is a ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).
26 
27     Args:
28         op: a callable to update accumulator. Method's signature is `(accumulator, output)`.
29             For example, to compute arithmetic mean value, `op = lambda a, x: a + x`.
30         output_transform: a callable that is used to transform the
31             :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the
32             form expected by the metric. This can be useful if, for example, you have a multi-output model and
33             you want to compute the metric with respect to one of the outputs.
34         device: specifies which device updates are accumulated on. Setting the metric's
35             device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By
36             default, CPU.
37 
38     """
39 
40     required_output_keys = None
41 
42     def __init__(
43         self,
44         op: Callable,
45         output_transform: Callable = lambda x: x,
46         device: Union[str, torch.device] = torch.device("cpu"),
47     ):
48         if not callable(op):
49             raise TypeError(f"Argument op should be a callable, but given {type(op)}")
50 
51         self._op = op
52 
53         super(VariableAccumulation, self).__init__(output_transform=output_transform, device=device)
54 
55     @reinit__is_reduced
56     def reset(self) -> None:
57         self.accumulator = torch.tensor(0.0, dtype=torch.float64, device=self._device)
58         self.num_examples = 0
59 
60     def _check_output_type(self, output: Union[float, torch.Tensor]) -> None:
61         if not (isinstance(output, numbers.Number) or isinstance(output, torch.Tensor)):
62             raise TypeError(f"Output should be a number or torch.Tensor, but given {type(output)}")
63 
64     @reinit__is_reduced
65     def update(self, output: Union[float, torch.Tensor]) -> None:
66         self._check_output_type(output)
67 
68         if isinstance(output, torch.Tensor):
69             output = output.detach()
70             if output.device != self._device:
71                 output = output.to(self._device)
72 
73         self.accumulator = self._op(self.accumulator, output)
74 
75         if isinstance(output, torch.Tensor):
76             self.num_examples += output.shape[0] if len(output.shape) > 1 else 1
77         else:
78             self.num_examples += 1
79 
80     @sync_all_reduce("accumulator", "num_examples")
81     def compute(self) -> Tuple[torch.Tensor, int]:
82         return self.accumulator, self.num_examples
83 
84 
85 class Average(VariableAccumulation):
86     """Helper class to compute arithmetic average of a single variable.
87 
88     - ``update`` must receive output of the form `x`.
89     - `x` can be a number or `torch.Tensor`.
90 
91     Note:
92 
93         Number of samples is updated following the rule:
94 
95         - `+1` if input is a number
96         - `+1` if input is a 1D `torch.Tensor`
97         - `+batch_size` if input is an ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).
98 
99         For input `x` being an ND `torch.Tensor` with N > 1, the first dimension is seen as the number of samples and
100         is summed up and added to the accumulator: `accumulator += x.sum(dim=0)`
101 
102     Examples:
103 
104     .. code-block:: python
105 
106         evaluator = ...
107 
108         custom_var_mean = Average(output_transform=lambda output: output['custom_var'])
109         custom_var_mean.attach(evaluator, 'mean_custom_var')
110 
111         state = evaluator.run(dataset)
112         # state.metrics['mean_custom_var'] -> average of output['custom_var']
113 
114     Args:
115         output_transform: a callable that is used to transform the
116             :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the
117             form expected by the metric. This can be useful if, for example, you have a multi-output model and
118             you want to compute the metric with respect to one of the outputs.
119         device: specifies which device updates are accumulated on. Setting the metric's
120             device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By
121             default, CPU.
122     """
123 
124     def __init__(
125         self, output_transform: Callable = lambda x: x, device: Union[str, torch.device] = torch.device("cpu")
126     ):
127         def _mean_op(a: Union[float, torch.Tensor], x: Union[float, torch.Tensor]) -> Union[float, torch.Tensor]:
128             if isinstance(x, torch.Tensor) and x.ndim > 1:
129                 x = x.sum(dim=0)
130             return a + x
131 
132         super(Average, self).__init__(op=_mean_op, output_transform=output_transform, device=device)
133 
134     @sync_all_reduce("accumulator", "num_examples")
135     def compute(self) -> Union[float, torch.Tensor]:
136         if self.num_examples < 1:
137             raise NotComputableError(
138                 f"{self.__class__.__name__} must have at least one example before it can be computed."
139             )
140 
141         return self.accumulator / self.num_examples
142 
143 
144 class GeometricAverage(VariableAccumulation):
145     """Helper class to compute geometric average of a single variable.
146 
147     - ``update`` must receive output of the form `x`.
148     - `x` can be a positive number or a positive `torch.Tensor`, such that ``torch.log(x)`` is not `nan`.
149 
150     Note:
151 
152         Number of samples is updated following the rule:
153 
154         - `+1` if input is a number
155         - `+1` if input is a 1D `torch.Tensor`
156         - `+batch_size` if input is a ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).
157 
158         For input `x` being an ND `torch.Tensor` with N > 1, the first dimension is seen as the number of samples and
159         is aggregated and added to the accumulator: `accumulator *= prod(x, dim=0)`
160 
161     Args:
162         output_transform: a callable that is used to transform the
163             :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the
164             form expected by the metric. This can be useful if, for example, you have a multi-output model and
165             you want to compute the metric with respect to one of the outputs.
166         device: specifies which device updates are accumulated on. Setting the metric's
167             device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By
168             default, CPU.
169 
170     """
171 
172     def __init__(
173         self, output_transform: Callable = lambda x: x, device: Union[str, torch.device] = torch.device("cpu")
174     ):
175         def _geom_op(a: torch.Tensor, x: Union[float, torch.Tensor]) -> torch.Tensor:
176             if not isinstance(x, torch.Tensor):
177                 x = torch.tensor(x)
178             x = torch.log(x)
179             if x.ndim > 1:
180                 x = x.sum(dim=0)
181             return a + x
182 
183         super(GeometricAverage, self).__init__(op=_geom_op, output_transform=output_transform, device=device)
184 
185     @sync_all_reduce("accumulator", "num_examples")
186     def compute(self) -> Union[float, torch.Tensor]:
187         if self.num_examples < 1:
188             raise NotComputableError(
189                 f"{self.__class__.__name__} must have at least one example before it can be computed."
190             )
191 
192         tensor = torch.exp(self.accumulator / self.num_examples)
193 
194         if tensor.numel() == 1:
195             return tensor.item()
196 
197         return tensor
198
```
--- 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()

```

diff --git a/ignite/metrics/accumulation.py b/ignite/metrics/accumulation.py
--- a/ignite/metrics/accumulation.py
+++ b/ignite/metrics/accumulation.py
@@ -67,8 +67,8 @@
 
         if isinstance(output, torch.Tensor):
             output = output.detach()
-            if output.device != self._device:
-                output = output.to(self._device)
+            if not (output.device == self._device and output.dtype == self.accumulator.dtype):
+                output = output.to(self.accumulator)
 
         self.accumulator = self._op(self.accumulator, output)

{"golden_diff": "diff --git a/ignite/metrics/accumulation.py b/ignite/metrics/accumulation.py\n--- a/ignite/metrics/accumulation.py\n+++ b/ignite/metrics/accumulation.py\n@@ -67,8 +67,8 @@\n \n         if isinstance(output, torch.Tensor):\n             output = output.detach()\n-            if output.device != self._device:\n-                output = output.to(self._device)\n+            if not (output.device == self._device and output.dtype == self.accumulator.dtype):\n+                output = output.to(self.accumulator)\n \n         self.accumulator = self._op(self.accumulator, output)\n", "issue": "Improve Accumulation metric on tensors to work with Apex\n## \ud83d\ude80 Feature Request\r\nIt seems that the ignite is not compatible with apex. When i am trying to use the (automatic mixed precision)amp from the Apex for the GPU Acceleration, I have encountered the following error. Look around the Ignite source code and I find that it uses the original torch.Tensor. Is there any timeline for Ignite to be compatible with Apex?\r\n```\r\nm.update(loss)\r\n--\r\nFile \"/usr/local/lib/python3.6/site-packages/ignite/metrics/metric.py\", line 575, in wrapper\r\nfunc(self, *args, **kwargs)\r\nFile \"/usr/local/lib/python3.6/site-packages/ignite/metrics/accumulation.py\", line 73, in update\r\nself.accumulator = self._op(self.accumulator, output)\r\nFile \"/usr/local/lib/python3.6/site-packages/ignite/metrics/accumulation.py\", line 130, in _mean_op\r\nreturn a + x\r\nFile \"/usr/local/lib64/python3.6/site-packages/apex/amp/wrap.py\", line 62, in wrapper\r\n.format(types))\r\nNotImplementedError: Do not know how to handle these types to promote: {'FloatTensor', 'DoubleTensor'}\r\n```\r\nApex: https://github.com/NVIDIA/apex\r\n\r\n## Environment\r\n\r\n- PyTorch Version (1.4.0):\r\n- Ignite Version (0.4.4):\r\n- OS (Linux):\r\n- Python version:  python 3.6\r\n- Apex Version (0.1)\n", "before_files": [{"content": "import numbers\nfrom typing import Callable, Tuple, Union\n\nimport torch\n\nfrom ignite.exceptions import NotComputableError\nfrom ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce\n\n__all__ = [\"VariableAccumulation\", \"GeometricAverage\", \"Average\"]\n\n\nclass VariableAccumulation(Metric):\n    \"\"\"Single variable accumulator helper to compute (arithmetic, geometric, harmonic) average of a single variable.\n\n    - ``update`` must receive output of the form `x`.\n    - `x` can be a number or `torch.Tensor`.\n\n    Note:\n\n        The class stores input into two public variables: `accumulator` and `num_examples`.\n        Number of samples is updated following the rule:\n\n        - `+1` if input is a number\n        - `+1` if input is a 1D `torch.Tensor`\n        - `+batch_size` if input is a ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).\n\n    Args:\n        op: a callable to update accumulator. Method's signature is `(accumulator, output)`.\n            For example, to compute arithmetic mean value, `op = lambda a, x: a + x`.\n        output_transform: a callable that is used to transform the\n            :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the\n            form expected by the metric. This can be useful if, for example, you have a multi-output model and\n            you want to compute the metric with respect to one of the outputs.\n        device: specifies which device updates are accumulated on. Setting the metric's\n            device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By\n            default, CPU.\n\n    \"\"\"\n\n    required_output_keys = None\n\n    def __init__(\n        self,\n        op: Callable,\n        output_transform: Callable = lambda x: x,\n        device: Union[str, torch.device] = torch.device(\"cpu\"),\n    ):\n        if not callable(op):\n            raise TypeError(f\"Argument op should be a callable, but given {type(op)}\")\n\n        self._op = op\n\n        super(VariableAccumulation, self).__init__(output_transform=output_transform, device=device)\n\n    @reinit__is_reduced\n    def reset(self) -> None:\n        self.accumulator = torch.tensor(0.0, dtype=torch.float64, device=self._device)\n        self.num_examples = 0\n\n    def _check_output_type(self, output: Union[float, torch.Tensor]) -> None:\n        if not (isinstance(output, numbers.Number) or isinstance(output, torch.Tensor)):\n            raise TypeError(f\"Output should be a number or torch.Tensor, but given {type(output)}\")\n\n    @reinit__is_reduced\n    def update(self, output: Union[float, torch.Tensor]) -> None:\n        self._check_output_type(output)\n\n        if isinstance(output, torch.Tensor):\n            output = output.detach()\n            if output.device != self._device:\n                output = output.to(self._device)\n\n        self.accumulator = self._op(self.accumulator, output)\n\n        if isinstance(output, torch.Tensor):\n            self.num_examples += output.shape[0] if len(output.shape) > 1 else 1\n        else:\n            self.num_examples += 1\n\n    @sync_all_reduce(\"accumulator\", \"num_examples\")\n    def compute(self) -> Tuple[torch.Tensor, int]:\n        return self.accumulator, self.num_examples\n\n\nclass Average(VariableAccumulation):\n    \"\"\"Helper class to compute arithmetic average of a single variable.\n\n    - ``update`` must receive output of the form `x`.\n    - `x` can be a number or `torch.Tensor`.\n\n    Note:\n\n        Number of samples is updated following the rule:\n\n        - `+1` if input is a number\n        - `+1` if input is a 1D `torch.Tensor`\n        - `+batch_size` if input is an ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).\n\n        For input `x` being an ND `torch.Tensor` with N > 1, the first dimension is seen as the number of samples and\n        is summed up and added to the accumulator: `accumulator += x.sum(dim=0)`\n\n    Examples:\n\n    .. code-block:: python\n\n        evaluator = ...\n\n        custom_var_mean = Average(output_transform=lambda output: output['custom_var'])\n        custom_var_mean.attach(evaluator, 'mean_custom_var')\n\n        state = evaluator.run(dataset)\n        # state.metrics['mean_custom_var'] -> average of output['custom_var']\n\n    Args:\n        output_transform: a callable that is used to transform the\n            :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the\n            form expected by the metric. This can be useful if, for example, you have a multi-output model and\n            you want to compute the metric with respect to one of the outputs.\n        device: specifies which device updates are accumulated on. Setting the metric's\n            device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By\n            default, CPU.\n    \"\"\"\n\n    def __init__(\n        self, output_transform: Callable = lambda x: x, device: Union[str, torch.device] = torch.device(\"cpu\")\n    ):\n        def _mean_op(a: Union[float, torch.Tensor], x: Union[float, torch.Tensor]) -> Union[float, torch.Tensor]:\n            if isinstance(x, torch.Tensor) and x.ndim > 1:\n                x = x.sum(dim=0)\n            return a + x\n\n        super(Average, self).__init__(op=_mean_op, output_transform=output_transform, device=device)\n\n    @sync_all_reduce(\"accumulator\", \"num_examples\")\n    def compute(self) -> Union[float, torch.Tensor]:\n        if self.num_examples < 1:\n            raise NotComputableError(\n                f\"{self.__class__.__name__} must have at least one example before it can be computed.\"\n            )\n\n        return self.accumulator / self.num_examples\n\n\nclass GeometricAverage(VariableAccumulation):\n    \"\"\"Helper class to compute geometric average of a single variable.\n\n    - ``update`` must receive output of the form `x`.\n    - `x` can be a positive number or a positive `torch.Tensor`, such that ``torch.log(x)`` is not `nan`.\n\n    Note:\n\n        Number of samples is updated following the rule:\n\n        - `+1` if input is a number\n        - `+1` if input is a 1D `torch.Tensor`\n        - `+batch_size` if input is a ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).\n\n        For input `x` being an ND `torch.Tensor` with N > 1, the first dimension is seen as the number of samples and\n        is aggregated and added to the accumulator: `accumulator *= prod(x, dim=0)`\n\n    Args:\n        output_transform: a callable that is used to transform the\n            :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the\n            form expected by the metric. This can be useful if, for example, you have a multi-output model and\n            you want to compute the metric with respect to one of the outputs.\n        device: specifies which device updates are accumulated on. Setting the metric's\n            device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By\n            default, CPU.\n\n    \"\"\"\n\n    def __init__(\n        self, output_transform: Callable = lambda x: x, device: Union[str, torch.device] = torch.device(\"cpu\")\n    ):\n        def _geom_op(a: torch.Tensor, x: Union[float, torch.Tensor]) -> torch.Tensor:\n            if not isinstance(x, torch.Tensor):\n                x = torch.tensor(x)\n            x = torch.log(x)\n            if x.ndim > 1:\n                x = x.sum(dim=0)\n            return a + x\n\n        super(GeometricAverage, self).__init__(op=_geom_op, output_transform=output_transform, device=device)\n\n    @sync_all_reduce(\"accumulator\", \"num_examples\")\n    def compute(self) -> Union[float, torch.Tensor]:\n        if self.num_examples < 1:\n            raise NotComputableError(\n                f\"{self.__class__.__name__} must have at least one example before it can be computed.\"\n            )\n\n        tensor = torch.exp(self.accumulator / self.num_examples)\n\n        if tensor.numel() == 1:\n            return tensor.item()\n\n        return tensor\n", "path": "ignite/metrics/accumulation.py"}], "after_files": [{"content": "import numbers\nfrom typing import Callable, Tuple, Union\n\nimport torch\n\nfrom ignite.exceptions import NotComputableError\nfrom ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce\n\n__all__ = [\"VariableAccumulation\", \"GeometricAverage\", \"Average\"]\n\n\nclass VariableAccumulation(Metric):\n    \"\"\"Single variable accumulator helper to compute (arithmetic, geometric, harmonic) average of a single variable.\n\n    - ``update`` must receive output of the form `x`.\n    - `x` can be a number or `torch.Tensor`.\n\n    Note:\n\n        The class stores input into two public variables: `accumulator` and `num_examples`.\n        Number of samples is updated following the rule:\n\n        - `+1` if input is a number\n        - `+1` if input is a 1D `torch.Tensor`\n        - `+batch_size` if input is a ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).\n\n    Args:\n        op: a callable to update accumulator. Method's signature is `(accumulator, output)`.\n            For example, to compute arithmetic mean value, `op = lambda a, x: a + x`.\n        output_transform: a callable that is used to transform the\n            :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the\n            form expected by the metric. This can be useful if, for example, you have a multi-output model and\n            you want to compute the metric with respect to one of the outputs.\n        device: specifies which device updates are accumulated on. Setting the metric's\n            device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By\n            default, CPU.\n\n    \"\"\"\n\n    required_output_keys = None\n\n    def __init__(\n        self,\n        op: Callable,\n        output_transform: Callable = lambda x: x,\n        device: Union[str, torch.device] = torch.device(\"cpu\"),\n    ):\n        if not callable(op):\n            raise TypeError(f\"Argument op should be a callable, but given {type(op)}\")\n\n        self._op = op\n\n        super(VariableAccumulation, self).__init__(output_transform=output_transform, device=device)\n\n    @reinit__is_reduced\n    def reset(self) -> None:\n        self.accumulator = torch.tensor(0.0, dtype=torch.float64, device=self._device)\n        self.num_examples = 0\n\n    def _check_output_type(self, output: Union[float, torch.Tensor]) -> None:\n        if not (isinstance(output, numbers.Number) or isinstance(output, torch.Tensor)):\n            raise TypeError(f\"Output should be a number or torch.Tensor, but given {type(output)}\")\n\n    @reinit__is_reduced\n    def update(self, output: Union[float, torch.Tensor]) -> None:\n        self._check_output_type(output)\n\n        if isinstance(output, torch.Tensor):\n            output = output.detach()\n            if not (output.device == self._device and output.dtype == self.accumulator.dtype):\n                output = output.to(self.accumulator)\n\n        self.accumulator = self._op(self.accumulator, output)\n\n        if isinstance(output, torch.Tensor):\n            self.num_examples += output.shape[0] if len(output.shape) > 1 else 1\n        else:\n            self.num_examples += 1\n\n    @sync_all_reduce(\"accumulator\", \"num_examples\")\n    def compute(self) -> Tuple[torch.Tensor, int]:\n        return self.accumulator, self.num_examples\n\n\nclass Average(VariableAccumulation):\n    \"\"\"Helper class to compute arithmetic average of a single variable.\n\n    - ``update`` must receive output of the form `x`.\n    - `x` can be a number or `torch.Tensor`.\n\n    Note:\n\n        Number of samples is updated following the rule:\n\n        - `+1` if input is a number\n        - `+1` if input is a 1D `torch.Tensor`\n        - `+batch_size` if input is an ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).\n\n        For input `x` being an ND `torch.Tensor` with N > 1, the first dimension is seen as the number of samples and\n        is summed up and added to the accumulator: `accumulator += x.sum(dim=0)`\n\n    Examples:\n\n    .. code-block:: python\n\n        evaluator = ...\n\n        custom_var_mean = Average(output_transform=lambda output: output['custom_var'])\n        custom_var_mean.attach(evaluator, 'mean_custom_var')\n\n        state = evaluator.run(dataset)\n        # state.metrics['mean_custom_var'] -> average of output['custom_var']\n\n    Args:\n        output_transform: a callable that is used to transform the\n            :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the\n            form expected by the metric. This can be useful if, for example, you have a multi-output model and\n            you want to compute the metric with respect to one of the outputs.\n        device: specifies which device updates are accumulated on. Setting the metric's\n            device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By\n            default, CPU.\n    \"\"\"\n\n    def __init__(\n        self, output_transform: Callable = lambda x: x, device: Union[str, torch.device] = torch.device(\"cpu\")\n    ):\n        def _mean_op(a: Union[float, torch.Tensor], x: Union[float, torch.Tensor]) -> Union[float, torch.Tensor]:\n            if isinstance(x, torch.Tensor) and x.ndim > 1:\n                x = x.sum(dim=0)\n            return a + x\n\n        super(Average, self).__init__(op=_mean_op, output_transform=output_transform, device=device)\n\n    @sync_all_reduce(\"accumulator\", \"num_examples\")\n    def compute(self) -> Union[float, torch.Tensor]:\n        if self.num_examples < 1:\n            raise NotComputableError(\n                f\"{self.__class__.__name__} must have at least one example before it can be computed.\"\n            )\n\n        return self.accumulator / self.num_examples\n\n\nclass GeometricAverage(VariableAccumulation):\n    \"\"\"Helper class to compute geometric average of a single variable.\n\n    - ``update`` must receive output of the form `x`.\n    - `x` can be a positive number or a positive `torch.Tensor`, such that ``torch.log(x)`` is not `nan`.\n\n    Note:\n\n        Number of samples is updated following the rule:\n\n        - `+1` if input is a number\n        - `+1` if input is a 1D `torch.Tensor`\n        - `+batch_size` if input is a ND `torch.Tensor`. Batch size is the first dimension (`shape[0]`).\n\n        For input `x` being an ND `torch.Tensor` with N > 1, the first dimension is seen as the number of samples and\n        is aggregated and added to the accumulator: `accumulator *= prod(x, dim=0)`\n\n    Args:\n        output_transform: a callable that is used to transform the\n            :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the\n            form expected by the metric. This can be useful if, for example, you have a multi-output model and\n            you want to compute the metric with respect to one of the outputs.\n        device: specifies which device updates are accumulated on. Setting the metric's\n            device to be the same as your ``update`` arguments ensures the ``update`` method is non-blocking. By\n            default, CPU.\n\n    \"\"\"\n\n    def __init__(\n        self, output_transform: Callable = lambda x: x, device: Union[str, torch.device] = torch.device(\"cpu\")\n    ):\n        def _geom_op(a: torch.Tensor, x: Union[float, torch.Tensor]) -> torch.Tensor:\n            if not isinstance(x, torch.Tensor):\n                x = torch.tensor(x)\n            x = torch.log(x)\n            if x.ndim > 1:\n                x = x.sum(dim=0)\n            return a + x\n\n        super(GeometricAverage, self).__init__(op=_geom_op, output_transform=output_transform, device=device)\n\n    @sync_all_reduce(\"accumulator\", \"num_examples\")\n    def compute(self) -> Union[float, torch.Tensor]:\n        if self.num_examples < 1:\n            raise NotComputableError(\n                f\"{self.__class__.__name__} must have at least one example before it can be computed.\"\n            )\n\n        tensor = torch.exp(self.accumulator / self.num_examples)\n\n        if tensor.numel() == 1:\n            return tensor.item()\n\n        return tensor\n", "path": "ignite/metrics/accumulation.py"}]}