prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [Feature Request] More general metrics
  I find the metrics to be a bit limited as one might want to pass additional options (even tensors) to the loss.
  For instance in recurrent models with different sequence lengths, one would use a mask to avoid counting errors on padded time steps.
  The mask is necessary in the loss to know which outputs to use in the final averaging/ loss.
  [Feature Request] More general metrics
  I find the metrics to be a bit limited as one might want to pass additional options (even tensors) to the loss.
  For instance in recurrent models with different sequence lengths, one would use a mask to avoid counting errors on padded time steps.
  The mask is necessary in the loss to know which outputs to use in the final averaging/ loss.
  
  --- 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 __future__ import division
  2 
  3 from ignite.exceptions import NotComputableError
  4 from ignite.metrics.metric import Metric
  5 
  6 
  7 class Loss(Metric):
  8     """
  9     Calculates the average loss according to the passed loss_fn.
  10 
  11     - `loss_fn` must return the average loss over all observations in the batch.
  12     - `update` must receive output of the form `(y_pred, y)`.
  13     """
  14     def __init__(self, loss_fn, output_transform=lambda x: x):
  15         super(Loss, self).__init__(output_transform)
  16         self._loss_fn = loss_fn
  17 
  18     def reset(self):
  19         self._sum = 0
  20         self._num_examples = 0
  21 
  22     def update(self, output):
  23         y_pred, y = output
  24         average_loss = self._loss_fn(y_pred, y)
  25         assert len(average_loss.shape) == 0, '`loss_fn` did not return the average loss'
  26         self._sum += average_loss.item() * y.shape[0]
  27         self._num_examples += y.shape[0]
  28 
  29     def compute(self):
  30         if self._num_examples == 0:
  31             raise NotComputableError(
  32                 'Loss must have at least one example before it can be computed')
  33         return self._sum / self._num_examples
  34
  ```
  --- 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/ignite/metrics/loss.py b/ignite/metrics/loss.py
  --- a/ignite/metrics/loss.py
  +++ b/ignite/metrics/loss.py
  @@ -8,9 +8,21 @@
       """
       Calculates the average loss according to the passed loss_fn.
   
  -    - `loss_fn` must return the average loss over all observations in the batch.
  -    - `update` must receive output of the form `(y_pred, y)`.
  +    Args:
  +        loss_fn (callable): a callable taking a prediction tensor, a target
  +            tensor, optionally other arguments, and returns the average loss
  +            over all observations in the batch.
  +        output_transform (callable): a callable that is used to transform the
  +            :class:`ignite.engine.Engine`'s `process_function`'s output into the
  +            form expected by the metric.
  +            This can be useful if, for example, you have a multi-output model and
  +            you want to compute the metric with respect to one of the outputs.
  +            The output is is expected to be a tuple (prediction, target) or
  +            (prediction, target, kwargs) where kwargs is a dictionary of extra
  +            keywords arguments.
  +
       """
  +
       def __init__(self, loss_fn, output_transform=lambda x: x):
           super(Loss, self).__init__(output_transform)
           self._loss_fn = loss_fn
  @@ -20,8 +32,12 @@
           self._num_examples = 0
   
       def update(self, output):
  -        y_pred, y = output
  -        average_loss = self._loss_fn(y_pred, y)
  +        if len(output) == 2:
  +            y_pred, y = output
  +            kwargs = {}
  +        else:
  +            y_pred, y, kwargs = output
  +        average_loss = self._loss_fn(y_pred, y, **kwargs)
           assert len(average_loss.shape) == 0, '`loss_fn` did not return the average loss'
           self._sum += average_loss.item() * y.shape[0]
           self._num_examples += y.shape[0]
  
verification_info: {"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@@ -8,9 +8,21 @@\n     \"\"\"\n     Calculates the average loss according to the passed loss_fn.\n \n-    - `loss_fn` must return the average loss over all observations in the batch.\n-    - `update` must receive output of the form `(y_pred, y)`.\n+    Args:\n+        loss_fn (callable): 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 (callable): a callable that is used to transform the\n+            :class:`ignite.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 is expected to be a tuple (prediction, target) or\n+            (prediction, target, kwargs) where kwargs is a dictionary of extra\n+            keywords arguments.\n+\n     \"\"\"\n+\n     def __init__(self, loss_fn, output_transform=lambda x: x):\n         super(Loss, self).__init__(output_transform)\n         self._loss_fn = loss_fn\n@@ -20,8 +32,12 @@\n         self._num_examples = 0\n \n     def update(self, output):\n-        y_pred, y = output\n-        average_loss = self._loss_fn(y_pred, y)\n+        if len(output) == 2:\n+            y_pred, y = output\n+            kwargs = {}\n+        else:\n+            y_pred, y, kwargs = output\n+        average_loss = self._loss_fn(y_pred, y, **kwargs)\n         assert len(average_loss.shape) == 0, '`loss_fn` did not return the average loss'\n         self._sum += average_loss.item() * y.shape[0]\n         self._num_examples += y.shape[0]\n", "issue": "[Feature Request] More general metrics\nI find the metrics to be a bit limited as one might want to pass additional options (even tensors) to the loss.\r\nFor instance in recurrent models with different sequence lengths, one would use a mask to avoid counting errors on padded time steps.\r\nThe mask is necessary in the loss to know which outputs to use in the final averaging/ loss.\n[Feature Request] More general metrics\nI find the metrics to be a bit limited as one might want to pass additional options (even tensors) to the loss.\r\nFor instance in recurrent models with different sequence lengths, one would use a mask to avoid counting errors on padded time steps.\r\nThe mask is necessary in the loss to know which outputs to use in the final averaging/ loss.\n", "before_files": [{"content": "from __future__ import division\n\nfrom ignite.exceptions import NotComputableError\nfrom ignite.metrics.metric import Metric\n\n\nclass Loss(Metric):\n    \"\"\"\n    Calculates the average loss according to the passed loss_fn.\n\n    - `loss_fn` must return the average loss over all observations in the batch.\n    - `update` must receive output of the form `(y_pred, y)`.\n    \"\"\"\n    def __init__(self, loss_fn, output_transform=lambda x: x):\n        super(Loss, self).__init__(output_transform)\n        self._loss_fn = loss_fn\n\n    def reset(self):\n        self._sum = 0\n        self._num_examples = 0\n\n    def update(self, output):\n        y_pred, y = output\n        average_loss = self._loss_fn(y_pred, y)\n        assert len(average_loss.shape) == 0, '`loss_fn` did not return the average loss'\n        self._sum += average_loss.item() * y.shape[0]\n        self._num_examples += y.shape[0]\n\n    def compute(self):\n        if self._num_examples == 0:\n            raise NotComputableError(\n                'Loss must have at least one example before it can be computed')\n        return self._sum / self._num_examples\n", "path": "ignite/metrics/loss.py"}], "after_files": [{"content": "from __future__ import division\n\nfrom ignite.exceptions import NotComputableError\nfrom ignite.metrics.metric import Metric\n\n\nclass Loss(Metric):\n    \"\"\"\n    Calculates the average loss according to the passed loss_fn.\n\n    Args:\n        loss_fn (callable): 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 (callable): a callable that is used to transform the\n            :class:`ignite.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 is expected to be a tuple (prediction, target) or\n            (prediction, target, kwargs) where kwargs is a dictionary of extra\n            keywords arguments.\n\n    \"\"\"\n\n    def __init__(self, loss_fn, output_transform=lambda x: x):\n        super(Loss, self).__init__(output_transform)\n        self._loss_fn = loss_fn\n\n    def reset(self):\n        self._sum = 0\n        self._num_examples = 0\n\n    def update(self, output):\n        if len(output) == 2:\n            y_pred, y = output\n            kwargs = {}\n        else:\n            y_pred, y, kwargs = output\n        average_loss = self._loss_fn(y_pred, y, **kwargs)\n        assert len(average_loss.shape) == 0, '`loss_fn` did not return the average loss'\n        self._sum += average_loss.item() * y.shape[0]\n        self._num_examples += y.shape[0]\n\n    def compute(self):\n        if self._num_examples == 0:\n            raise NotComputableError(\n                'Loss must have at least one example before it can be computed')\n        return self._sum / self._num_examples\n", "path": "ignite/metrics/loss.py"}]}