We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Loss metric to use required_output_keys
## 🚀 Feature

Currently, if we have custom metrics that require data other then `y_pred` and `y`, [we suggest](https://discuss.pytorch.org/t/how-access-inputs-in-custom-ignite-metric/91221/6) to do the following: 
```python
metrics = {
    "Accuracy": Accuracy(),
    "Loss": Loss(criterion, output_transform=lambda out_dict: (out_dict["y_pred"], out_dict["y"])),
    "CustomMetric": CustomMetric()
}

evaluator = create_supervised_evaluator(
    model, 
    metrics=metrics, 
    output_transform=lambda x, y, y_pred: {"x": x, "y": y, "y_pred": y_pred}
)
```

where `CustomMetric` is defined as 
```python
class CustomMetric(Metric):

    required_output_keys = ("y_pred", "y", "x")
```

The idea is to extend this for `Loss` metric to support `required_output_keys`. The main issue with `Loss` now is with `(prediction, target, kwargs)` optional input, where `kwargs` is a dict for extra args for criterion function.

--- 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/loss.py`
Content:
```
1 from typing import Callable, Dict, Sequence, Tuple, Union, cast
2 
3 import torch
4 
5 from ignite.exceptions import NotComputableError
6 from ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce
7 
8 __all__ = ["Loss"]
9 
10 
11 class Loss(Metric):
12     """
13     Calculates the average loss according to the passed loss_fn.
14 
15     Args:
16         loss_fn: a callable taking a prediction tensor, a target
17             tensor, optionally other arguments, and returns the average loss
18             over all observations in the batch.
19         output_transform: a callable that is used to transform the
20             :class:`~ignite.engine.engine.Engine`'s ``process_function``'s output into the
21             form expected by the metric.
22             This can be useful if, for example, you have a multi-output model and
23             you want to compute the metric with respect to one of the outputs.
24             The output is expected to be a tuple `(prediction, target)` or
25             (prediction, target, kwargs) where kwargs is a dictionary of extra
26             keywords arguments. If extra keywords arguments are provided they are passed to `loss_fn`.
27         batch_size: a callable taking a target tensor that returns the
28             first dimension size (usually the batch size).
29         device: specifies which device updates are accumulated on. Setting the
30             metric's device to be the same as your ``update`` arguments ensures the ``update`` method is
31             non-blocking. By default, CPU.
32 
33     """
34 
35     required_output_keys = None
36 
37     def __init__(
38         self,
39         loss_fn: Callable,
40         output_transform: Callable = lambda x: x,
41         batch_size: Callable = len,
42         device: Union[str, torch.device] = torch.device("cpu"),
43     ):
44         super(Loss, self).__init__(output_transform, device=device)
45         self._loss_fn = loss_fn
46         self._batch_size = batch_size
47 
48     @reinit__is_reduced
49     def reset(self) -> None:
50         self._sum = torch.tensor(0.0, device=self._device)
51         self._num_examples = 0
52 
53     @reinit__is_reduced
54     def update(self, output: Sequence[Union[torch.Tensor, Dict]]) -> None:
55         if len(output) == 2:
56             y_pred, y = cast(Tuple[torch.Tensor, torch.Tensor], output)
57             kwargs = {}  # type: Dict
58         else:
59             y_pred, y, kwargs = cast(Tuple[torch.Tensor, torch.Tensor, Dict], output)
60         average_loss = self._loss_fn(y_pred, y, **kwargs).detach()
61 
62         if len(average_loss.shape) != 0:
63             raise ValueError("loss_fn did not return the average loss.")
64 
65         n = self._batch_size(y)
66         self._sum += average_loss.to(self._device) * n
67         self._num_examples += n
68 
69     @sync_all_reduce("_sum", "_num_examples")
70     def compute(self) -> float:
71         if self._num_examples == 0:
72             raise NotComputableError("Loss must have at least one example before it can be computed.")
73         return self._sum.item() / self._num_examples
74
```
--- 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/loss.py b/ignite/metrics/loss.py
--- a/ignite/metrics/loss.py
+++ b/ignite/metrics/loss.py
@@ -30,9 +30,52 @@
             metric's device to be the same as your ``update`` arguments ensures the ``update`` method is
             non-blocking. By default, CPU.
 
+    Attributes:
+        required_output_keys: dictionary defines required keys to be found in ``engine.state.output`` if the
+            latter is a dictionary. Default, ``("y_pred", "y", "criterion_kwargs")``. This is useful when the
+            criterion function requires additional arguments, which can be passed using ``criterion_kwargs``.
+            See notes below for an example.
+
+    Note:
+
+        Let's implement a Loss metric that requires ``x``, ``y_pred``, ``y`` and ``criterion_kwargs`` as input
+        for ``criterion`` function. In the example below we show how to setup standard metric like Accuracy
+        and the Loss metric using an ``evaluator`` created with
+        :meth:`~ignite.engine.create_supervised_evaluator` method.
+
+        .. code-block:: python
+
+            import torch
+            import torch.nn as nn
+            from torch.nn.functional import nll_loss
+
+            from ignite.metrics import Accuracy, Loss
+            from ignite.engine import create_supervised_evaluator
+
+            model = ...
+
+            criterion = nll_loss
+
+            metrics = {
+                "Accuracy": Accuracy(),
+                "Loss": Loss(criterion)
+            }
+
+            # global criterion kwargs
+            criterion_kwargs = {...}
+
+            evaluator = create_supervised_evaluator(
+                model,
+                metrics=metrics,
+                output_transform=lambda x, y, y_pred: {
+                    "x": x, "y": y, "y_pred": y_pred, "criterion_kwargs": criterion_kwargs}
+            )
+
+            res = evaluator.run(data)
+
     """
 
-    required_output_keys = None
+    required_output_keys = ("y_pred", "y", "criterion_kwargs")
 
     def __init__(
         self,

{"golden_diff": "diff --git a/ignite/metrics/loss.py b/ignite/metrics/loss.py\n--- a/ignite/metrics/loss.py\n+++ b/ignite/metrics/loss.py\n@@ -30,9 +30,52 @@\n             metric's device to be the same as your ``update`` arguments ensures the ``update`` method is\n             non-blocking. By default, CPU.\n \n+    Attributes:\n+        required_output_keys: dictionary defines required keys to be found in ``engine.state.output`` if the\n+            latter is a dictionary. Default, ``(\"y_pred\", \"y\", \"criterion_kwargs\")``. This is useful when the\n+            criterion function requires additional arguments, which can be passed using ``criterion_kwargs``.\n+            See notes below for an example.\n+\n+    Note:\n+\n+        Let's implement a Loss metric that requires ``x``, ``y_pred``, ``y`` and ``criterion_kwargs`` as input\n+        for ``criterion`` function. In the example below we show how to setup standard metric like Accuracy\n+        and the Loss metric using an ``evaluator`` created with\n+        :meth:`~ignite.engine.create_supervised_evaluator` method.\n+\n+        .. code-block:: python\n+\n+            import torch\n+            import torch.nn as nn\n+            from torch.nn.functional import nll_loss\n+\n+            from ignite.metrics import Accuracy, Loss\n+            from ignite.engine import create_supervised_evaluator\n+\n+            model = ...\n+\n+            criterion = nll_loss\n+\n+            metrics = {\n+                \"Accuracy\": Accuracy(),\n+                \"Loss\": Loss(criterion)\n+            }\n+\n+            # global criterion kwargs\n+            criterion_kwargs = {...}\n+\n+            evaluator = create_supervised_evaluator(\n+                model,\n+                metrics=metrics,\n+                output_transform=lambda x, y, y_pred: {\n+                    \"x\": x, \"y\": y, \"y_pred\": y_pred, \"criterion_kwargs\": criterion_kwargs}\n+            )\n+\n+            res = evaluator.run(data)\n+\n     \"\"\"\n \n-    required_output_keys = None\n+    required_output_keys = (\"y_pred\", \"y\", \"criterion_kwargs\")\n \n     def __init__(\n         self,\n", "issue": "Loss metric to use required_output_keys\n## \ud83d\ude80 Feature\r\n\r\nCurrently, if we have custom metrics that require data other then `y_pred` and `y`, [we suggest](https://discuss.pytorch.org/t/how-access-inputs-in-custom-ignite-metric/91221/6) to do the following: \r\n```python\r\nmetrics = {\r\n    \"Accuracy\": Accuracy(),\r\n    \"Loss\": Loss(criterion, output_transform=lambda out_dict: (out_dict[\"y_pred\"], out_dict[\"y\"])),\r\n    \"CustomMetric\": CustomMetric()\r\n}\r\n\r\nevaluator = create_supervised_evaluator(\r\n    model, \r\n    metrics=metrics, \r\n    output_transform=lambda x, y, y_pred: {\"x\": x, \"y\": y, \"y_pred\": y_pred}\r\n)\r\n```\r\n\r\nwhere `CustomMetric` is defined as \r\n```python\r\nclass CustomMetric(Metric):\r\n\r\n    required_output_keys = (\"y_pred\", \"y\", \"x\")\r\n```\r\n\r\nThe idea is to extend this for `Loss` metric to support `required_output_keys`. The main issue with `Loss` now is with `(prediction, target, kwargs)` optional input, where `kwargs` is a dict for extra args for criterion function.\n", "before_files": [{"content": "from typing import Callable, Dict, Sequence, Tuple, Union, cast\n\nimport torch\n\nfrom ignite.exceptions import NotComputableError\nfrom ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce\n\n__all__ = [\"Loss\"]\n\n\nclass Loss(Metric):\n    \"\"\"\n    Calculates the average loss according to the passed loss_fn.\n\n    Args:\n        loss_fn: a callable taking a prediction tensor, a target\n            tensor, optionally other arguments, and returns the average loss\n            over all observations in the batch.\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.\n            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            The output is expected to be a tuple `(prediction, target)` or\n            (prediction, target, kwargs) where kwargs is a dictionary of extra\n            keywords arguments. If extra keywords arguments are provided they are passed to `loss_fn`.\n        batch_size: a callable taking a target tensor that returns the\n            first dimension size (usually the batch size).\n        device: specifies which device updates are accumulated on. Setting the\n            metric's device to be the same as your ``update`` arguments ensures the ``update`` method is\n            non-blocking. By default, CPU.\n\n    \"\"\"\n\n    required_output_keys = None\n\n    def __init__(\n        self,\n        loss_fn: Callable,\n        output_transform: Callable = lambda x: x,\n        batch_size: Callable = len,\n        device: Union[str, torch.device] = torch.device(\"cpu\"),\n    ):\n        super(Loss, self).__init__(output_transform, device=device)\n        self._loss_fn = loss_fn\n        self._batch_size = batch_size\n\n    @reinit__is_reduced\n    def reset(self) -> None:\n        self._sum = torch.tensor(0.0, device=self._device)\n        self._num_examples = 0\n\n    @reinit__is_reduced\n    def update(self, output: Sequence[Union[torch.Tensor, Dict]]) -> None:\n        if len(output) == 2:\n            y_pred, y = cast(Tuple[torch.Tensor, torch.Tensor], output)\n            kwargs = {}  # type: Dict\n        else:\n            y_pred, y, kwargs = cast(Tuple[torch.Tensor, torch.Tensor, Dict], output)\n        average_loss = self._loss_fn(y_pred, y, **kwargs).detach()\n\n        if len(average_loss.shape) != 0:\n            raise ValueError(\"loss_fn did not return the average loss.\")\n\n        n = self._batch_size(y)\n        self._sum += average_loss.to(self._device) * n\n        self._num_examples += n\n\n    @sync_all_reduce(\"_sum\", \"_num_examples\")\n    def compute(self) -> float:\n        if self._num_examples == 0:\n            raise NotComputableError(\"Loss must have at least one example before it can be computed.\")\n        return self._sum.item() / self._num_examples\n", "path": "ignite/metrics/loss.py"}], "after_files": [{"content": "from typing import Callable, Dict, Sequence, Tuple, Union, cast\n\nimport torch\n\nfrom ignite.exceptions import NotComputableError\nfrom ignite.metrics.metric import Metric, reinit__is_reduced, sync_all_reduce\n\n__all__ = [\"Loss\"]\n\n\nclass Loss(Metric):\n    \"\"\"\n    Calculates the average loss according to the passed loss_fn.\n\n    Args:\n        loss_fn: a callable taking a prediction tensor, a target\n            tensor, optionally other arguments, and returns the average loss\n            over all observations in the batch.\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.\n            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            The output is expected to be a tuple `(prediction, target)` or\n            (prediction, target, kwargs) where kwargs is a dictionary of extra\n            keywords arguments. If extra keywords arguments are provided they are passed to `loss_fn`.\n        batch_size: a callable taking a target tensor that returns the\n            first dimension size (usually the batch size).\n        device: specifies which device updates are accumulated on. Setting the\n            metric's device to be the same as your ``update`` arguments ensures the ``update`` method is\n            non-blocking. By default, CPU.\n\n    Attributes:\n        required_output_keys: dictionary defines required keys to be found in ``engine.state.output`` if the\n            latter is a dictionary. Default, ``(\"y_pred\", \"y\", \"criterion_kwargs\")``. This is useful when the\n            criterion function requires additional arguments, which can be passed using ``criterion_kwargs``.\n            See notes below for an example.\n\n    Note:\n\n        Let's implement a Loss metric that requires ``x``, ``y_pred``, ``y`` and ``criterion_kwargs`` as input\n        for ``criterion`` function. In the example below we show how to setup standard metric like Accuracy\n        and the Loss metric using an ``evaluator`` created with\n        :meth:`~ignite.engine.create_supervised_evaluator` method.\n\n        .. code-block:: python\n\n            import torch\n            import torch.nn as nn\n            from torch.nn.functional import nll_loss\n\n            from ignite.metrics import Accuracy, Loss\n            from ignite.engine import create_supervised_evaluator\n\n            model = ...\n\n            criterion = nll_loss\n\n            metrics = {\n                \"Accuracy\": Accuracy(),\n                \"Loss\": Loss(criterion)\n            }\n\n            # global criterion kwargs\n            criterion_kwargs = {...}\n\n            evaluator = create_supervised_evaluator(\n                model,\n                metrics=metrics,\n                output_transform=lambda x, y, y_pred: {\n                    \"x\": x, \"y\": y, \"y_pred\": y_pred, \"criterion_kwargs\": criterion_kwargs}\n            )\n\n            res = evaluator.run(data)\n\n    \"\"\"\n\n    required_output_keys = (\"y_pred\", \"y\", \"criterion_kwargs\")\n\n    def __init__(\n        self,\n        loss_fn: Callable,\n        output_transform: Callable = lambda x: x,\n        batch_size: Callable = len,\n        device: Union[str, torch.device] = torch.device(\"cpu\"),\n    ):\n        super(Loss, self).__init__(output_transform, device=device)\n        self._loss_fn = loss_fn\n        self._batch_size = batch_size\n\n    @reinit__is_reduced\n    def reset(self) -> None:\n        self._sum = torch.tensor(0.0, device=self._device)\n        self._num_examples = 0\n\n    @reinit__is_reduced\n    def update(self, output: Sequence[Union[torch.Tensor, Dict]]) -> None:\n        if len(output) == 2:\n            y_pred, y = cast(Tuple[torch.Tensor, torch.Tensor], output)\n            kwargs = {}  # type: Dict\n        else:\n            y_pred, y, kwargs = cast(Tuple[torch.Tensor, torch.Tensor, Dict], output)\n        average_loss = self._loss_fn(y_pred, y, **kwargs).detach()\n\n        if len(average_loss.shape) != 0:\n            raise ValueError(\"loss_fn did not return the average loss.\")\n\n        n = self._batch_size(y)\n        self._sum += average_loss.to(self._device) * n\n        self._num_examples += n\n\n    @sync_all_reduce(\"_sum\", \"_num_examples\")\n    def compute(self) -> float:\n        if self._num_examples == 0:\n            raise NotComputableError(\"Loss must have at least one example before it can be computed.\")\n        return self._sum.item() / self._num_examples\n", "path": "ignite/metrics/loss.py"}]}