prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Improve create_supervised_trainer with optional output_transform
  Following [the discussion](https://github.com/pytorch/ignite/pull/476#discussion_r272108999), idea is to give more flexibility to users who are using `create_supervised_trainer`:
  ```python
  def default_output_transform(x, y, y_pred, loss):
      return loss.item() 
  
  
  def create_supervised_trainer(model, optimizer, loss_fn,
                                device=None, non_blocking=False, prepare_batch=_prepare_batch, 
                                output_transform=default_output_transform):
      if device:
          model.to(device)
  
      def _update(engine, batch):
          model.train()
          optimizer.zero_grad()
          x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)
          y_pred = model(x)
          loss = loss_fn(y_pred, y)
          loss.backward()
          optimizer.step()
          return output_transform(x, y, y_pred, loss)
  
      return Engine(_update)    
  ```
  
  cc @IlyaOvodov
  Improve create_supervised_trainer with optional output_transform
  Following [the discussion](https://github.com/pytorch/ignite/pull/476#discussion_r272108999), idea is to give more flexibility to users who are using `create_supervised_trainer`:
  ```python
  def default_output_transform(x, y, y_pred, loss):
      return loss.item() 
  
  
  def create_supervised_trainer(model, optimizer, loss_fn,
                                device=None, non_blocking=False, prepare_batch=_prepare_batch, 
                                output_transform=default_output_transform):
      if device:
          model.to(device)
  
      def _update(engine, batch):
          model.train()
          optimizer.zero_grad()
          x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)
          y_pred = model(x)
          loss = loss_fn(y_pred, y)
          loss.backward()
          optimizer.step()
          return output_transform(x, y, y_pred, loss)
  
      return Engine(_update)    
  ```
  
  cc @IlyaOvodov
  
  --- 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/engine/__init__.py`
  Content:
  ```
  1 import torch
  2 
  3 from ignite.engine.engine import Engine, State, Events
  4 from ignite.utils import convert_tensor
  5 
  6 
  7 def _prepare_batch(batch, device=None, non_blocking=False):
  8     """Prepare batch for training: pass to a device with options.
  9 
  10     """
  11     x, y = batch
  12     return (convert_tensor(x, device=device, non_blocking=non_blocking),
  13             convert_tensor(y, device=device, non_blocking=non_blocking))
  14 
  15 
  16 def create_supervised_trainer(model, optimizer, loss_fn,
  17                               device=None, non_blocking=False,
  18                               prepare_batch=_prepare_batch):
  19     """
  20     Factory function for creating a trainer for supervised models.
  21 
  22     Args:
  23         model (`torch.nn.Module`): the model to train.
  24         optimizer (`torch.optim.Optimizer`): the optimizer to use.
  25         loss_fn (torch.nn loss function): the loss function to use.
  26         device (str, optional): device type specification (default: None).
  27             Applies to both model and batches.
  28         non_blocking (bool, optional): if True and this copy is between CPU and GPU, the copy may occur asynchronously
  29             with respect to the host. For other cases, this argument has no effect.
  30         prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs
  31             tuple of tensors `(batch_x, batch_y)`.
  32 
  33     Note: `engine.state.output` for this engine is the loss of the processed batch.
  34 
  35     Returns:
  36         Engine: a trainer engine with supervised update function.
  37     """
  38     if device:
  39         model.to(device)
  40 
  41     def _update(engine, batch):
  42         model.train()
  43         optimizer.zero_grad()
  44         x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)
  45         y_pred = model(x)
  46         loss = loss_fn(y_pred, y)
  47         loss.backward()
  48         optimizer.step()
  49         return loss.item()
  50 
  51     return Engine(_update)
  52 
  53 
  54 def create_supervised_evaluator(model, metrics={},
  55                                 device=None, non_blocking=False,
  56                                 prepare_batch=_prepare_batch):
  57     """
  58     Factory function for creating an evaluator for supervised models.
  59 
  60     Args:
  61         model (`torch.nn.Module`): the model to train.
  62         metrics (dict of str - :class:`~ignite.metrics.Metric`): a map of metric names to Metrics.
  63         device (str, optional): device type specification (default: None).
  64             Applies to both model and batches.
  65         non_blocking (bool, optional): if True and this copy is between CPU and GPU, the copy may occur asynchronously
  66             with respect to the host. For other cases, this argument has no effect.
  67         prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs
  68             tuple of tensors `(batch_x, batch_y)`.
  69 
  70     Note: `engine.state.output` for this engine is a tuple of `(batch_pred, batch_y)`.
  71 
  72     Returns:
  73         Engine: an evaluator engine with supervised inference function.
  74     """
  75     if device:
  76         model.to(device)
  77 
  78     def _inference(engine, batch):
  79         model.eval()
  80         with torch.no_grad():
  81             x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)
  82             y_pred = model(x)
  83             return y_pred, y
  84 
  85     engine = Engine(_inference)
  86 
  87     for name, metric in metrics.items():
  88         metric.attach(engine, name)
  89 
  90     return engine
  91
  ```
  --- 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/engine/__init__.py b/ignite/engine/__init__.py
  --- a/ignite/engine/__init__.py
  +++ b/ignite/engine/__init__.py
  @@ -15,7 +15,8 @@
   
   def create_supervised_trainer(model, optimizer, loss_fn,
                                 device=None, non_blocking=False,
  -                              prepare_batch=_prepare_batch):
  +                              prepare_batch=_prepare_batch,
  +                              output_transform=lambda x, y, y_pred, loss: loss.item()):
       """
       Factory function for creating a trainer for supervised models.
   
  @@ -29,8 +30,11 @@
               with respect to the host. For other cases, this argument has no effect.
           prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs
               tuple of tensors `(batch_x, batch_y)`.
  +        output_transform (callable, optional): function that receives 'x', 'y', 'y_pred', 'loss' and returns value
  +            to be assigned to engine's state.output after each iteration. Default is returning `loss.item()`.
   
  -    Note: `engine.state.output` for this engine is the loss of the processed batch.
  +    Note: `engine.state.output` for this engine is defind by `output_transform` parameter and is the loss
  +        of the processed batch by default.
   
       Returns:
           Engine: a trainer engine with supervised update function.
  @@ -46,14 +50,15 @@
           loss = loss_fn(y_pred, y)
           loss.backward()
           optimizer.step()
  -        return loss.item()
  +        return output_transform(x, y, y_pred, loss)
   
       return Engine(_update)
   
   
   def create_supervised_evaluator(model, metrics={},
                                   device=None, non_blocking=False,
  -                                prepare_batch=_prepare_batch):
  +                                prepare_batch=_prepare_batch,
  +                                output_transform=lambda x, y, y_pred: (y_pred, y,)):
       """
       Factory function for creating an evaluator for supervised models.
   
  @@ -66,8 +71,12 @@
               with respect to the host. For other cases, this argument has no effect.
           prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs
               tuple of tensors `(batch_x, batch_y)`.
  +        output_transform (callable, optional): function that receives 'x', 'y', 'y_pred' and returns value
  +            to be assigned to engine's state.output after each iteration. Default is returning `(y_pred, y,)` which fits
  +            output expected by metrics. If you change it you should use `output_transform` in metrics.
   
  -    Note: `engine.state.output` for this engine is a tuple of `(batch_pred, batch_y)`.
  +    Note: `engine.state.output` for this engine is defind by `output_transform` parameter and is
  +        a tuple of `(batch_pred, batch_y)` by default.
   
       Returns:
           Engine: an evaluator engine with supervised inference function.
  @@ -80,7 +89,7 @@
           with torch.no_grad():
               x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)
               y_pred = model(x)
  -            return y_pred, y
  +            return output_transform(x, y, y_pred)
   
       engine = Engine(_inference)
  
verification_info: {"golden_diff": "diff --git a/ignite/engine/__init__.py b/ignite/engine/__init__.py\n--- a/ignite/engine/__init__.py\n+++ b/ignite/engine/__init__.py\n@@ -15,7 +15,8 @@\n \n def create_supervised_trainer(model, optimizer, loss_fn,\n                               device=None, non_blocking=False,\n-                              prepare_batch=_prepare_batch):\n+                              prepare_batch=_prepare_batch,\n+                              output_transform=lambda x, y, y_pred, loss: loss.item()):\n     \"\"\"\n     Factory function for creating a trainer for supervised models.\n \n@@ -29,8 +30,11 @@\n             with respect to the host. For other cases, this argument has no effect.\n         prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs\n             tuple of tensors `(batch_x, batch_y)`.\n+        output_transform (callable, optional): function that receives 'x', 'y', 'y_pred', 'loss' and returns value\n+            to be assigned to engine's state.output after each iteration. Default is returning `loss.item()`.\n \n-    Note: `engine.state.output` for this engine is the loss of the processed batch.\n+    Note: `engine.state.output` for this engine is defind by `output_transform` parameter and is the loss\n+        of the processed batch by default.\n \n     Returns:\n         Engine: a trainer engine with supervised update function.\n@@ -46,14 +50,15 @@\n         loss = loss_fn(y_pred, y)\n         loss.backward()\n         optimizer.step()\n-        return loss.item()\n+        return output_transform(x, y, y_pred, loss)\n \n     return Engine(_update)\n \n \n def create_supervised_evaluator(model, metrics={},\n                                 device=None, non_blocking=False,\n-                                prepare_batch=_prepare_batch):\n+                                prepare_batch=_prepare_batch,\n+                                output_transform=lambda x, y, y_pred: (y_pred, y,)):\n     \"\"\"\n     Factory function for creating an evaluator for supervised models.\n \n@@ -66,8 +71,12 @@\n             with respect to the host. For other cases, this argument has no effect.\n         prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs\n             tuple of tensors `(batch_x, batch_y)`.\n+        output_transform (callable, optional): function that receives 'x', 'y', 'y_pred' and returns value\n+            to be assigned to engine's state.output after each iteration. Default is returning `(y_pred, y,)` which fits\n+            output expected by metrics. If you change it you should use `output_transform` in metrics.\n \n-    Note: `engine.state.output` for this engine is a tuple of `(batch_pred, batch_y)`.\n+    Note: `engine.state.output` for this engine is defind by `output_transform` parameter and is\n+        a tuple of `(batch_pred, batch_y)` by default.\n \n     Returns:\n         Engine: an evaluator engine with supervised inference function.\n@@ -80,7 +89,7 @@\n         with torch.no_grad():\n             x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\n             y_pred = model(x)\n-            return y_pred, y\n+            return output_transform(x, y, y_pred)\n \n     engine = Engine(_inference)\n", "issue": "Improve create_supervised_trainer with optional output_transform\nFollowing [the discussion](https://github.com/pytorch/ignite/pull/476#discussion_r272108999), idea is to give more flexibility to users who are using `create_supervised_trainer`:\r\n```python\r\ndef default_output_transform(x, y, y_pred, loss):\r\n    return loss.item() \r\n\r\n\r\ndef create_supervised_trainer(model, optimizer, loss_fn,\r\n                              device=None, non_blocking=False, prepare_batch=_prepare_batch, \r\n                              output_transform=default_output_transform):\r\n    if device:\r\n        model.to(device)\r\n\r\n    def _update(engine, batch):\r\n        model.train()\r\n        optimizer.zero_grad()\r\n        x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\r\n        y_pred = model(x)\r\n        loss = loss_fn(y_pred, y)\r\n        loss.backward()\r\n        optimizer.step()\r\n        return output_transform(x, y, y_pred, loss)\r\n\r\n    return Engine(_update)    \r\n```\r\n\r\ncc @IlyaOvodov\nImprove create_supervised_trainer with optional output_transform\nFollowing [the discussion](https://github.com/pytorch/ignite/pull/476#discussion_r272108999), idea is to give more flexibility to users who are using `create_supervised_trainer`:\r\n```python\r\ndef default_output_transform(x, y, y_pred, loss):\r\n    return loss.item() \r\n\r\n\r\ndef create_supervised_trainer(model, optimizer, loss_fn,\r\n                              device=None, non_blocking=False, prepare_batch=_prepare_batch, \r\n                              output_transform=default_output_transform):\r\n    if device:\r\n        model.to(device)\r\n\r\n    def _update(engine, batch):\r\n        model.train()\r\n        optimizer.zero_grad()\r\n        x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\r\n        y_pred = model(x)\r\n        loss = loss_fn(y_pred, y)\r\n        loss.backward()\r\n        optimizer.step()\r\n        return output_transform(x, y, y_pred, loss)\r\n\r\n    return Engine(_update)    \r\n```\r\n\r\ncc @IlyaOvodov\n", "before_files": [{"content": "import torch\n\nfrom ignite.engine.engine import Engine, State, Events\nfrom ignite.utils import convert_tensor\n\n\ndef _prepare_batch(batch, device=None, non_blocking=False):\n    \"\"\"Prepare batch for training: pass to a device with options.\n\n    \"\"\"\n    x, y = batch\n    return (convert_tensor(x, device=device, non_blocking=non_blocking),\n            convert_tensor(y, device=device, non_blocking=non_blocking))\n\n\ndef create_supervised_trainer(model, optimizer, loss_fn,\n                              device=None, non_blocking=False,\n                              prepare_batch=_prepare_batch):\n    \"\"\"\n    Factory function for creating a trainer for supervised models.\n\n    Args:\n        model (`torch.nn.Module`): the model to train.\n        optimizer (`torch.optim.Optimizer`): the optimizer to use.\n        loss_fn (torch.nn loss function): the loss function to use.\n        device (str, optional): device type specification (default: None).\n            Applies to both model and batches.\n        non_blocking (bool, optional): if True and this copy is between CPU and GPU, the copy may occur asynchronously\n            with respect to the host. For other cases, this argument has no effect.\n        prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs\n            tuple of tensors `(batch_x, batch_y)`.\n\n    Note: `engine.state.output` for this engine is the loss of the processed batch.\n\n    Returns:\n        Engine: a trainer engine with supervised update function.\n    \"\"\"\n    if device:\n        model.to(device)\n\n    def _update(engine, batch):\n        model.train()\n        optimizer.zero_grad()\n        x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\n        y_pred = model(x)\n        loss = loss_fn(y_pred, y)\n        loss.backward()\n        optimizer.step()\n        return loss.item()\n\n    return Engine(_update)\n\n\ndef create_supervised_evaluator(model, metrics={},\n                                device=None, non_blocking=False,\n                                prepare_batch=_prepare_batch):\n    \"\"\"\n    Factory function for creating an evaluator for supervised models.\n\n    Args:\n        model (`torch.nn.Module`): the model to train.\n        metrics (dict of str - :class:`~ignite.metrics.Metric`): a map of metric names to Metrics.\n        device (str, optional): device type specification (default: None).\n            Applies to both model and batches.\n        non_blocking (bool, optional): if True and this copy is between CPU and GPU, the copy may occur asynchronously\n            with respect to the host. For other cases, this argument has no effect.\n        prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs\n            tuple of tensors `(batch_x, batch_y)`.\n\n    Note: `engine.state.output` for this engine is a tuple of `(batch_pred, batch_y)`.\n\n    Returns:\n        Engine: an evaluator engine with supervised inference function.\n    \"\"\"\n    if device:\n        model.to(device)\n\n    def _inference(engine, batch):\n        model.eval()\n        with torch.no_grad():\n            x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\n            y_pred = model(x)\n            return y_pred, y\n\n    engine = Engine(_inference)\n\n    for name, metric in metrics.items():\n        metric.attach(engine, name)\n\n    return engine\n", "path": "ignite/engine/__init__.py"}], "after_files": [{"content": "import torch\n\nfrom ignite.engine.engine import Engine, State, Events\nfrom ignite.utils import convert_tensor\n\n\ndef _prepare_batch(batch, device=None, non_blocking=False):\n    \"\"\"Prepare batch for training: pass to a device with options.\n\n    \"\"\"\n    x, y = batch\n    return (convert_tensor(x, device=device, non_blocking=non_blocking),\n            convert_tensor(y, device=device, non_blocking=non_blocking))\n\n\ndef create_supervised_trainer(model, optimizer, loss_fn,\n                              device=None, non_blocking=False,\n                              prepare_batch=_prepare_batch,\n                              output_transform=lambda x, y, y_pred, loss: loss.item()):\n    \"\"\"\n    Factory function for creating a trainer for supervised models.\n\n    Args:\n        model (`torch.nn.Module`): the model to train.\n        optimizer (`torch.optim.Optimizer`): the optimizer to use.\n        loss_fn (torch.nn loss function): the loss function to use.\n        device (str, optional): device type specification (default: None).\n            Applies to both model and batches.\n        non_blocking (bool, optional): if True and this copy is between CPU and GPU, the copy may occur asynchronously\n            with respect to the host. For other cases, this argument has no effect.\n        prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs\n            tuple of tensors `(batch_x, batch_y)`.\n        output_transform (callable, optional): function that receives 'x', 'y', 'y_pred', 'loss' and returns value\n            to be assigned to engine's state.output after each iteration. Default is returning `loss.item()`.\n\n    Note: `engine.state.output` for this engine is defind by `output_transform` parameter and is the loss\n        of the processed batch by default.\n\n    Returns:\n        Engine: a trainer engine with supervised update function.\n    \"\"\"\n    if device:\n        model.to(device)\n\n    def _update(engine, batch):\n        model.train()\n        optimizer.zero_grad()\n        x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\n        y_pred = model(x)\n        loss = loss_fn(y_pred, y)\n        loss.backward()\n        optimizer.step()\n        return output_transform(x, y, y_pred, loss)\n\n    return Engine(_update)\n\n\ndef create_supervised_evaluator(model, metrics={},\n                                device=None, non_blocking=False,\n                                prepare_batch=_prepare_batch,\n                                output_transform=lambda x, y, y_pred: (y_pred, y,)):\n    \"\"\"\n    Factory function for creating an evaluator for supervised models.\n\n    Args:\n        model (`torch.nn.Module`): the model to train.\n        metrics (dict of str - :class:`~ignite.metrics.Metric`): a map of metric names to Metrics.\n        device (str, optional): device type specification (default: None).\n            Applies to both model and batches.\n        non_blocking (bool, optional): if True and this copy is between CPU and GPU, the copy may occur asynchronously\n            with respect to the host. For other cases, this argument has no effect.\n        prepare_batch (callable, optional): function that receives `batch`, `device`, `non_blocking` and outputs\n            tuple of tensors `(batch_x, batch_y)`.\n        output_transform (callable, optional): function that receives 'x', 'y', 'y_pred' and returns value\n            to be assigned to engine's state.output after each iteration. Default is returning `(y_pred, y,)` which fits\n            output expected by metrics. If you change it you should use `output_transform` in metrics.\n\n    Note: `engine.state.output` for this engine is defind by `output_transform` parameter and is\n        a tuple of `(batch_pred, batch_y)` by default.\n\n    Returns:\n        Engine: an evaluator engine with supervised inference function.\n    \"\"\"\n    if device:\n        model.to(device)\n\n    def _inference(engine, batch):\n        model.eval()\n        with torch.no_grad():\n            x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)\n            y_pred = model(x)\n            return output_transform(x, y, y_pred)\n\n    engine = Engine(_inference)\n\n    for name, metric in metrics.items():\n        metric.attach(engine, name)\n\n    return engine\n", "path": "ignite/engine/__init__.py"}]}