prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  utils.convert_tensor considers `device = 0` to be no device
  ## 🐛 Bug description
  In utils.convert_tensor, this line appears:
  `return tensor.to(device=device, non_blocking=non_blocking) if device else tensor`
  
  This means that for `device = 0` (as returned from `torch.cuda.current_device`) no conversion is applied, which can be very confusing. I might add a PR for that tomorrow, unless people tell me there's a reason to leave that line as it is.
  
  For reproduction:
  ```python
  import torch
  from ignite.utils import convert_tensor
  
  mytens = torch.zeros(2)
  device = torch.cuda.current_device()
  converted_tens = convert_tensor(mytens, device)
  assert converted_tens.device == device
  ```
  
  ## Environment
  
   - PyTorch Version (e.g., 1.4): 1.4
   - Ignite Version (e.g., 0.3.0): 0.3
   - OS (e.g., Linux): Windows 10
   - How you installed Ignite (`conda`, `pip`, source): conda
   - Python version: 3.7.6
  
  
  
  --- 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/utils.py`
  Content:
  ```
  1 import collections.abc as collections
  2 import logging
  3 from typing import Union, Optional, Callable, Any, Type, Tuple
  4 
  5 import torch
  6 
  7 __all__ = ["convert_tensor", "apply_to_tensor", "apply_to_type", "to_onehot", "setup_logger"]
  8 
  9 
  10 def convert_tensor(
  11     input_: Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes],
  12     device: Optional[Union[str, torch.device]] = None,
  13     non_blocking: bool = False,
  14 ) -> Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes]:
  15     """Move tensors to relevant device."""
  16 
  17     def _func(tensor: torch.Tensor) -> torch.Tensor:
  18         return tensor.to(device=device, non_blocking=non_blocking) if device else tensor
  19 
  20     return apply_to_tensor(input_, _func)
  21 
  22 
  23 def apply_to_tensor(
  24     input_: Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes], func: Callable
  25 ) -> Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes]:
  26     """Apply a function on a tensor or mapping, or sequence of tensors.
  27     """
  28     return apply_to_type(input_, torch.Tensor, func)
  29 
  30 
  31 def apply_to_type(
  32     input_: Union[Any, collections.Sequence, collections.Mapping, str, bytes],
  33     input_type: Union[Type, Tuple[Type[Any], Any]],
  34     func: Callable,
  35 ) -> Union[Any, collections.Sequence, collections.Mapping, str, bytes]:
  36     """Apply a function on a object of `input_type` or mapping, or sequence of objects of `input_type`.
  37     """
  38     if isinstance(input_, input_type):
  39         return func(input_)
  40     elif isinstance(input_, (str, bytes)):
  41         return input_
  42     elif isinstance(input_, collections.Mapping):
  43         return type(input_)({k: apply_to_type(sample, input_type, func) for k, sample in input_.items()})
  44     elif isinstance(input_, tuple) and hasattr(input_, "_fields"):  # namedtuple
  45         return type(input_)(*(apply_to_type(sample, input_type, func) for sample in input_))
  46     elif isinstance(input_, collections.Sequence):
  47         return type(input_)([apply_to_type(sample, input_type, func) for sample in input_])
  48     else:
  49         raise TypeError(("input must contain {}, dicts or lists; found {}".format(input_type, type(input_))))
  50 
  51 
  52 def to_onehot(indices: torch.Tensor, num_classes: int) -> torch.Tensor:
  53     """Convert a tensor of indices of any shape `(N, ...)` to a
  54     tensor of one-hot indicators of shape `(N, num_classes, ...) and of type uint8. Output's device is equal to the
  55     input's device`.
  56     """
  57     onehot = torch.zeros(indices.shape[0], num_classes, *indices.shape[1:], dtype=torch.uint8, device=indices.device)
  58     return onehot.scatter_(1, indices.unsqueeze(1), 1)
  59 
  60 
  61 def setup_logger(
  62     name: str,
  63     level: int = logging.INFO,
  64     format: str = "%(asctime)s %(name)s %(levelname)s: %(message)s",
  65     filepath: Optional[str] = None,
  66     distributed_rank: int = 0,
  67 ) -> logging.Logger:
  68     """Setups logger: name, level, format etc.
  69 
  70     Args:
  71         name (str): new name for the logger.
  72         level (int): logging level, e.g. CRITICAL, ERROR, WARNING, INFO, DEBUG
  73         format (str): logging format. By default, `%(asctime)s %(name)s %(levelname)s: %(message)s`
  74         filepath (str, optional): Optional logging file path. If not None, logs are written to the file.
  75         distributed_rank (int, optional): Optional, rank in distributed configuration to avoid logger setup for workers.
  76 
  77     Returns:
  78         logging.Logger
  79 
  80     For example, to improve logs readability when training with a trainer and evaluator:
  81 
  82     .. code-block:: python
  83 
  84         from ignite.utils import setup_logger
  85 
  86         trainer = ...
  87         evaluator = ...
  88 
  89         trainer.logger = setup_logger("trainer")
  90         evaluator.logger = setup_logger("evaluator")
  91 
  92         trainer.run(data, max_epochs=10)
  93 
  94         # Logs will look like
  95         # 2020-01-21 12:46:07,356 trainer INFO: Engine run starting with max_epochs=5.
  96         # 2020-01-21 12:46:07,358 trainer INFO: Epoch[1] Complete. Time taken: 00:5:23
  97         # 2020-01-21 12:46:07,358 evaluator INFO: Engine run starting with max_epochs=1.
  98         # 2020-01-21 12:46:07,358 evaluator INFO: Epoch[1] Complete. Time taken: 00:01:02
  99         # ...
  100 
  101     """
  102     logger = logging.getLogger(name)
  103 
  104     if distributed_rank > 0:
  105         return logger
  106 
  107     logger.setLevel(level)
  108 
  109     # Remove previous handlers
  110     if logger.hasHandlers():
  111         for h in list(logger.handlers):
  112             logger.removeHandler(h)
  113 
  114     formatter = logging.Formatter(format)
  115 
  116     ch = logging.StreamHandler()
  117     ch.setLevel(level)
  118     ch.setFormatter(formatter)
  119     logger.addHandler(ch)
  120 
  121     if filepath is not None:
  122         fh = logging.FileHandler(filepath)
  123         fh.setLevel(level)
  124         fh.setFormatter(formatter)
  125         logger.addHandler(fh)
  126 
  127     return logger
  128
  ```
  --- 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/utils.py b/ignite/utils.py
  --- a/ignite/utils.py
  +++ b/ignite/utils.py
  @@ -15,7 +15,7 @@
       """Move tensors to relevant device."""
   
       def _func(tensor: torch.Tensor) -> torch.Tensor:
  -        return tensor.to(device=device, non_blocking=non_blocking) if device else tensor
  +        return tensor.to(device=device, non_blocking=non_blocking) if device is not None else tensor
   
       return apply_to_tensor(input_, _func)
  
verification_info: {"golden_diff": "diff --git a/ignite/utils.py b/ignite/utils.py\n--- a/ignite/utils.py\n+++ b/ignite/utils.py\n@@ -15,7 +15,7 @@\n     \"\"\"Move tensors to relevant device.\"\"\"\n \n     def _func(tensor: torch.Tensor) -> torch.Tensor:\n-        return tensor.to(device=device, non_blocking=non_blocking) if device else tensor\n+        return tensor.to(device=device, non_blocking=non_blocking) if device is not None else tensor\n \n     return apply_to_tensor(input_, _func)\n", "issue": "utils.convert_tensor considers `device = 0` to be no device\n## \ud83d\udc1b Bug description\r\nIn utils.convert_tensor, this line appears:\r\n`return tensor.to(device=device, non_blocking=non_blocking) if device else tensor`\r\n\r\nThis means that for `device = 0` (as returned from `torch.cuda.current_device`) no conversion is applied, which can be very confusing. I might add a PR for that tomorrow, unless people tell me there's a reason to leave that line as it is.\r\n\r\nFor reproduction:\r\n```python\r\nimport torch\r\nfrom ignite.utils import convert_tensor\r\n\r\nmytens = torch.zeros(2)\r\ndevice = torch.cuda.current_device()\r\nconverted_tens = convert_tensor(mytens, device)\r\nassert converted_tens.device == device\r\n```\r\n\r\n## Environment\r\n\r\n - PyTorch Version (e.g., 1.4): 1.4\r\n - Ignite Version (e.g., 0.3.0): 0.3\r\n - OS (e.g., Linux): Windows 10\r\n - How you installed Ignite (`conda`, `pip`, source): conda\r\n - Python version: 3.7.6\r\n\r\n\n", "before_files": [{"content": "import collections.abc as collections\nimport logging\nfrom typing import Union, Optional, Callable, Any, Type, Tuple\n\nimport torch\n\n__all__ = [\"convert_tensor\", \"apply_to_tensor\", \"apply_to_type\", \"to_onehot\", \"setup_logger\"]\n\n\ndef convert_tensor(\n    input_: Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes],\n    device: Optional[Union[str, torch.device]] = None,\n    non_blocking: bool = False,\n) -> Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes]:\n    \"\"\"Move tensors to relevant device.\"\"\"\n\n    def _func(tensor: torch.Tensor) -> torch.Tensor:\n        return tensor.to(device=device, non_blocking=non_blocking) if device else tensor\n\n    return apply_to_tensor(input_, _func)\n\n\ndef apply_to_tensor(\n    input_: Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes], func: Callable\n) -> Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes]:\n    \"\"\"Apply a function on a tensor or mapping, or sequence of tensors.\n    \"\"\"\n    return apply_to_type(input_, torch.Tensor, func)\n\n\ndef apply_to_type(\n    input_: Union[Any, collections.Sequence, collections.Mapping, str, bytes],\n    input_type: Union[Type, Tuple[Type[Any], Any]],\n    func: Callable,\n) -> Union[Any, collections.Sequence, collections.Mapping, str, bytes]:\n    \"\"\"Apply a function on a object of `input_type` or mapping, or sequence of objects of `input_type`.\n    \"\"\"\n    if isinstance(input_, input_type):\n        return func(input_)\n    elif isinstance(input_, (str, bytes)):\n        return input_\n    elif isinstance(input_, collections.Mapping):\n        return type(input_)({k: apply_to_type(sample, input_type, func) for k, sample in input_.items()})\n    elif isinstance(input_, tuple) and hasattr(input_, \"_fields\"):  # namedtuple\n        return type(input_)(*(apply_to_type(sample, input_type, func) for sample in input_))\n    elif isinstance(input_, collections.Sequence):\n        return type(input_)([apply_to_type(sample, input_type, func) for sample in input_])\n    else:\n        raise TypeError((\"input must contain {}, dicts or lists; found {}\".format(input_type, type(input_))))\n\n\ndef to_onehot(indices: torch.Tensor, num_classes: int) -> torch.Tensor:\n    \"\"\"Convert a tensor of indices of any shape `(N, ...)` to a\n    tensor of one-hot indicators of shape `(N, num_classes, ...) and of type uint8. Output's device is equal to the\n    input's device`.\n    \"\"\"\n    onehot = torch.zeros(indices.shape[0], num_classes, *indices.shape[1:], dtype=torch.uint8, device=indices.device)\n    return onehot.scatter_(1, indices.unsqueeze(1), 1)\n\n\ndef setup_logger(\n    name: str,\n    level: int = logging.INFO,\n    format: str = \"%(asctime)s %(name)s %(levelname)s: %(message)s\",\n    filepath: Optional[str] = None,\n    distributed_rank: int = 0,\n) -> logging.Logger:\n    \"\"\"Setups logger: name, level, format etc.\n\n    Args:\n        name (str): new name for the logger.\n        level (int): logging level, e.g. CRITICAL, ERROR, WARNING, INFO, DEBUG\n        format (str): logging format. By default, `%(asctime)s %(name)s %(levelname)s: %(message)s`\n        filepath (str, optional): Optional logging file path. If not None, logs are written to the file.\n        distributed_rank (int, optional): Optional, rank in distributed configuration to avoid logger setup for workers.\n\n    Returns:\n        logging.Logger\n\n    For example, to improve logs readability when training with a trainer and evaluator:\n\n    .. code-block:: python\n\n        from ignite.utils import setup_logger\n\n        trainer = ...\n        evaluator = ...\n\n        trainer.logger = setup_logger(\"trainer\")\n        evaluator.logger = setup_logger(\"evaluator\")\n\n        trainer.run(data, max_epochs=10)\n\n        # Logs will look like\n        # 2020-01-21 12:46:07,356 trainer INFO: Engine run starting with max_epochs=5.\n        # 2020-01-21 12:46:07,358 trainer INFO: Epoch[1] Complete. Time taken: 00:5:23\n        # 2020-01-21 12:46:07,358 evaluator INFO: Engine run starting with max_epochs=1.\n        # 2020-01-21 12:46:07,358 evaluator INFO: Epoch[1] Complete. Time taken: 00:01:02\n        # ...\n\n    \"\"\"\n    logger = logging.getLogger(name)\n\n    if distributed_rank > 0:\n        return logger\n\n    logger.setLevel(level)\n\n    # Remove previous handlers\n    if logger.hasHandlers():\n        for h in list(logger.handlers):\n            logger.removeHandler(h)\n\n    formatter = logging.Formatter(format)\n\n    ch = logging.StreamHandler()\n    ch.setLevel(level)\n    ch.setFormatter(formatter)\n    logger.addHandler(ch)\n\n    if filepath is not None:\n        fh = logging.FileHandler(filepath)\n        fh.setLevel(level)\n        fh.setFormatter(formatter)\n        logger.addHandler(fh)\n\n    return logger\n", "path": "ignite/utils.py"}], "after_files": [{"content": "import collections.abc as collections\nimport logging\nfrom typing import Union, Optional, Callable, Any, Type, Tuple\n\nimport torch\n\n__all__ = [\"convert_tensor\", \"apply_to_tensor\", \"apply_to_type\", \"to_onehot\", \"setup_logger\"]\n\n\ndef convert_tensor(\n    input_: Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes],\n    device: Optional[Union[str, torch.device]] = None,\n    non_blocking: bool = False,\n) -> Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes]:\n    \"\"\"Move tensors to relevant device.\"\"\"\n\n    def _func(tensor: torch.Tensor) -> torch.Tensor:\n        return tensor.to(device=device, non_blocking=non_blocking) if device is not None else tensor\n\n    return apply_to_tensor(input_, _func)\n\n\ndef apply_to_tensor(\n    input_: Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes], func: Callable\n) -> Union[torch.Tensor, collections.Sequence, collections.Mapping, str, bytes]:\n    \"\"\"Apply a function on a tensor or mapping, or sequence of tensors.\n    \"\"\"\n    return apply_to_type(input_, torch.Tensor, func)\n\n\ndef apply_to_type(\n    input_: Union[Any, collections.Sequence, collections.Mapping, str, bytes],\n    input_type: Union[Type, Tuple[Type[Any], Any]],\n    func: Callable,\n) -> Union[Any, collections.Sequence, collections.Mapping, str, bytes]:\n    \"\"\"Apply a function on a object of `input_type` or mapping, or sequence of objects of `input_type`.\n    \"\"\"\n    if isinstance(input_, input_type):\n        return func(input_)\n    elif isinstance(input_, (str, bytes)):\n        return input_\n    elif isinstance(input_, collections.Mapping):\n        return type(input_)({k: apply_to_type(sample, input_type, func) for k, sample in input_.items()})\n    elif isinstance(input_, tuple) and hasattr(input_, \"_fields\"):  # namedtuple\n        return type(input_)(*(apply_to_type(sample, input_type, func) for sample in input_))\n    elif isinstance(input_, collections.Sequence):\n        return type(input_)([apply_to_type(sample, input_type, func) for sample in input_])\n    else:\n        raise TypeError((\"input must contain {}, dicts or lists; found {}\".format(input_type, type(input_))))\n\n\ndef to_onehot(indices: torch.Tensor, num_classes: int) -> torch.Tensor:\n    \"\"\"Convert a tensor of indices of any shape `(N, ...)` to a\n    tensor of one-hot indicators of shape `(N, num_classes, ...) and of type uint8. Output's device is equal to the\n    input's device`.\n    \"\"\"\n    onehot = torch.zeros(indices.shape[0], num_classes, *indices.shape[1:], dtype=torch.uint8, device=indices.device)\n    return onehot.scatter_(1, indices.unsqueeze(1), 1)\n\n\ndef setup_logger(\n    name: str,\n    level: int = logging.INFO,\n    format: str = \"%(asctime)s %(name)s %(levelname)s: %(message)s\",\n    filepath: Optional[str] = None,\n    distributed_rank: int = 0,\n) -> logging.Logger:\n    \"\"\"Setups logger: name, level, format etc.\n\n    Args:\n        name (str): new name for the logger.\n        level (int): logging level, e.g. CRITICAL, ERROR, WARNING, INFO, DEBUG\n        format (str): logging format. By default, `%(asctime)s %(name)s %(levelname)s: %(message)s`\n        filepath (str, optional): Optional logging file path. If not None, logs are written to the file.\n        distributed_rank (int, optional): Optional, rank in distributed configuration to avoid logger setup for workers.\n\n    Returns:\n        logging.Logger\n\n    For example, to improve logs readability when training with a trainer and evaluator:\n\n    .. code-block:: python\n\n        from ignite.utils import setup_logger\n\n        trainer = ...\n        evaluator = ...\n\n        trainer.logger = setup_logger(\"trainer\")\n        evaluator.logger = setup_logger(\"evaluator\")\n\n        trainer.run(data, max_epochs=10)\n\n        # Logs will look like\n        # 2020-01-21 12:46:07,356 trainer INFO: Engine run starting with max_epochs=5.\n        # 2020-01-21 12:46:07,358 trainer INFO: Epoch[1] Complete. Time taken: 00:5:23\n        # 2020-01-21 12:46:07,358 evaluator INFO: Engine run starting with max_epochs=1.\n        # 2020-01-21 12:46:07,358 evaluator INFO: Epoch[1] Complete. Time taken: 00:01:02\n        # ...\n\n    \"\"\"\n    logger = logging.getLogger(name)\n\n    if distributed_rank > 0:\n        return logger\n\n    logger.setLevel(level)\n\n    # Remove previous handlers\n    if logger.hasHandlers():\n        for h in list(logger.handlers):\n            logger.removeHandler(h)\n\n    formatter = logging.Formatter(format)\n\n    ch = logging.StreamHandler()\n    ch.setLevel(level)\n    ch.setFormatter(formatter)\n    logger.addHandler(ch)\n\n    if filepath is not None:\n        fh = logging.FileHandler(filepath)\n        fh.setLevel(level)\n        fh.setFormatter(formatter)\n        logger.addHandler(fh)\n\n    return logger\n", "path": "ignite/utils.py"}]}