prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  AttributeError: Can't pickle local object 'build_dataloader.<locals>.worker_init_fn'
  Recently, I update pytorch to 1.4. When running `tools/dist_train.sh submitted/faster_giou_train_config.py 1 --validate --autoscale-lr --seed 512`, one error raised: "AttributeError: Can't pickle local object 'build_dataloader.<locals>.worker_init_fn'". I found random seed caused this error, when running without `--seed`, it's ok.
  
  I haven't ran script with `--seed` option in pytorch 1.3, so i don't know if it's the pytorch verion.
  
  I wonder if this is a bug or a feature, Thank you in advance!
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `mmdet/datasets/loader/build_loader.py`
  Content:
  ```
  1 import platform
  2 import random
  3 from functools import partial
  4 
  5 import numpy as np
  6 from mmcv.parallel import collate
  7 from mmcv.runner import get_dist_info
  8 from torch.utils.data import DataLoader
  9 
  10 from .sampler import DistributedGroupSampler, DistributedSampler, GroupSampler
  11 
  12 if platform.system() != 'Windows':
  13     # https://github.com/pytorch/pytorch/issues/973
  14     import resource
  15     rlimit = resource.getrlimit(resource.RLIMIT_NOFILE)
  16     resource.setrlimit(resource.RLIMIT_NOFILE, (4096, rlimit[1]))
  17 
  18 
  19 def build_dataloader(dataset,
  20                      imgs_per_gpu,
  21                      workers_per_gpu,
  22                      num_gpus=1,
  23                      dist=True,
  24                      shuffle=True,
  25                      seed=None,
  26                      **kwargs):
  27     """Build PyTorch DataLoader.
  28 
  29     In distributed training, each GPU/process has a dataloader.
  30     In non-distributed training, there is only one dataloader for all GPUs.
  31 
  32     Args:
  33         dataset (Dataset): A PyTorch dataset.
  34         imgs_per_gpu (int): Number of images on each GPU, i.e., batch size of
  35             each GPU.
  36         workers_per_gpu (int): How many subprocesses to use for data loading
  37             for each GPU.
  38         num_gpus (int): Number of GPUs. Only used in non-distributed training.
  39         dist (bool): Distributed training/test or not. Default: True.
  40         shuffle (bool): Whether to shuffle the data at every epoch.
  41             Default: True.
  42         kwargs: any keyword argument to be used to initialize DataLoader
  43 
  44     Returns:
  45         DataLoader: A PyTorch dataloader.
  46     """
  47     rank, world_size = get_dist_info()
  48     if dist:
  49         # DistributedGroupSampler will definitely shuffle the data to satisfy
  50         # that images on each GPU are in the same group
  51         if shuffle:
  52             sampler = DistributedGroupSampler(dataset, imgs_per_gpu,
  53                                               world_size, rank)
  54         else:
  55             sampler = DistributedSampler(
  56                 dataset, world_size, rank, shuffle=False)
  57         batch_size = imgs_per_gpu
  58         num_workers = workers_per_gpu
  59     else:
  60         sampler = GroupSampler(dataset, imgs_per_gpu) if shuffle else None
  61         batch_size = num_gpus * imgs_per_gpu
  62         num_workers = num_gpus * workers_per_gpu
  63 
  64     def worker_init_fn(worker_id):
  65         # The seed of each worker equals to
  66         # num_worker * rank + worker_id + user_seed
  67         worker_seed = num_workers * rank + worker_id + seed
  68         np.random.seed(worker_seed)
  69         random.seed(worker_seed)
  70 
  71     data_loader = DataLoader(
  72         dataset,
  73         batch_size=batch_size,
  74         sampler=sampler,
  75         num_workers=num_workers,
  76         collate_fn=partial(collate, samples_per_gpu=imgs_per_gpu),
  77         pin_memory=False,
  78         worker_init_fn=worker_init_fn if seed is not None else None,
  79         **kwargs)
  80 
  81     return data_loader
  82
  ```
  --- 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/mmdet/datasets/loader/build_loader.py b/mmdet/datasets/loader/build_loader.py
  --- a/mmdet/datasets/loader/build_loader.py
  +++ b/mmdet/datasets/loader/build_loader.py
  @@ -61,12 +61,9 @@
           batch_size = num_gpus * imgs_per_gpu
           num_workers = num_gpus * workers_per_gpu
   
  -    def worker_init_fn(worker_id):
  -        # The seed of each worker equals to
  -        # num_worker * rank + worker_id + user_seed
  -        worker_seed = num_workers * rank + worker_id + seed
  -        np.random.seed(worker_seed)
  -        random.seed(worker_seed)
  +    init_fn = partial(
  +        worker_init_fn, num_workers=num_workers, rank=rank,
  +        seed=seed) if seed is not None else None
   
       data_loader = DataLoader(
           dataset,
  @@ -75,7 +72,15 @@
           num_workers=num_workers,
           collate_fn=partial(collate, samples_per_gpu=imgs_per_gpu),
           pin_memory=False,
  -        worker_init_fn=worker_init_fn if seed is not None else None,
  +        worker_init_fn=init_fn,
           **kwargs)
   
       return data_loader
  +
  +
  +def worker_init_fn(worker_id, num_workers, rank, seed):
  +    # The seed of each worker equals to
  +    # num_worker * rank + worker_id + user_seed
  +    worker_seed = num_workers * rank + worker_id + seed
  +    np.random.seed(worker_seed)
  +    random.seed(worker_seed)
  
verification_info: {"golden_diff": "diff --git a/mmdet/datasets/loader/build_loader.py b/mmdet/datasets/loader/build_loader.py\n--- a/mmdet/datasets/loader/build_loader.py\n+++ b/mmdet/datasets/loader/build_loader.py\n@@ -61,12 +61,9 @@\n         batch_size = num_gpus * imgs_per_gpu\n         num_workers = num_gpus * workers_per_gpu\n \n-    def worker_init_fn(worker_id):\n-        # The seed of each worker equals to\n-        # num_worker * rank + worker_id + user_seed\n-        worker_seed = num_workers * rank + worker_id + seed\n-        np.random.seed(worker_seed)\n-        random.seed(worker_seed)\n+    init_fn = partial(\n+        worker_init_fn, num_workers=num_workers, rank=rank,\n+        seed=seed) if seed is not None else None\n \n     data_loader = DataLoader(\n         dataset,\n@@ -75,7 +72,15 @@\n         num_workers=num_workers,\n         collate_fn=partial(collate, samples_per_gpu=imgs_per_gpu),\n         pin_memory=False,\n-        worker_init_fn=worker_init_fn if seed is not None else None,\n+        worker_init_fn=init_fn,\n         **kwargs)\n \n     return data_loader\n+\n+\n+def worker_init_fn(worker_id, num_workers, rank, seed):\n+    # The seed of each worker equals to\n+    # num_worker * rank + worker_id + user_seed\n+    worker_seed = num_workers * rank + worker_id + seed\n+    np.random.seed(worker_seed)\n+    random.seed(worker_seed)\n", "issue": "AttributeError: Can't pickle local object 'build_dataloader.<locals>.worker_init_fn'\nRecently, I update pytorch to 1.4. When running `tools/dist_train.sh submitted/faster_giou_train_config.py 1 --validate --autoscale-lr --seed 512`, one error raised: \"AttributeError: Can't pickle local object 'build_dataloader.<locals>.worker_init_fn'\". I found random seed caused this error, when running without `--seed`, it's ok.\r\n\r\nI haven't ran script with `--seed` option in pytorch 1.3, so i don't know if it's the pytorch verion.\r\n\r\nI wonder if this is a bug or a feature, Thank you in advance!\n", "before_files": [{"content": "import platform\nimport random\nfrom functools import partial\n\nimport numpy as np\nfrom mmcv.parallel import collate\nfrom mmcv.runner import get_dist_info\nfrom torch.utils.data import DataLoader\n\nfrom .sampler import DistributedGroupSampler, DistributedSampler, GroupSampler\n\nif platform.system() != 'Windows':\n    # https://github.com/pytorch/pytorch/issues/973\n    import resource\n    rlimit = resource.getrlimit(resource.RLIMIT_NOFILE)\n    resource.setrlimit(resource.RLIMIT_NOFILE, (4096, rlimit[1]))\n\n\ndef build_dataloader(dataset,\n                     imgs_per_gpu,\n                     workers_per_gpu,\n                     num_gpus=1,\n                     dist=True,\n                     shuffle=True,\n                     seed=None,\n                     **kwargs):\n    \"\"\"Build PyTorch DataLoader.\n\n    In distributed training, each GPU/process has a dataloader.\n    In non-distributed training, there is only one dataloader for all GPUs.\n\n    Args:\n        dataset (Dataset): A PyTorch dataset.\n        imgs_per_gpu (int): Number of images on each GPU, i.e., batch size of\n            each GPU.\n        workers_per_gpu (int): How many subprocesses to use for data loading\n            for each GPU.\n        num_gpus (int): Number of GPUs. Only used in non-distributed training.\n        dist (bool): Distributed training/test or not. Default: True.\n        shuffle (bool): Whether to shuffle the data at every epoch.\n            Default: True.\n        kwargs: any keyword argument to be used to initialize DataLoader\n\n    Returns:\n        DataLoader: A PyTorch dataloader.\n    \"\"\"\n    rank, world_size = get_dist_info()\n    if dist:\n        # DistributedGroupSampler will definitely shuffle the data to satisfy\n        # that images on each GPU are in the same group\n        if shuffle:\n            sampler = DistributedGroupSampler(dataset, imgs_per_gpu,\n                                              world_size, rank)\n        else:\n            sampler = DistributedSampler(\n                dataset, world_size, rank, shuffle=False)\n        batch_size = imgs_per_gpu\n        num_workers = workers_per_gpu\n    else:\n        sampler = GroupSampler(dataset, imgs_per_gpu) if shuffle else None\n        batch_size = num_gpus * imgs_per_gpu\n        num_workers = num_gpus * workers_per_gpu\n\n    def worker_init_fn(worker_id):\n        # The seed of each worker equals to\n        # num_worker * rank + worker_id + user_seed\n        worker_seed = num_workers * rank + worker_id + seed\n        np.random.seed(worker_seed)\n        random.seed(worker_seed)\n\n    data_loader = DataLoader(\n        dataset,\n        batch_size=batch_size,\n        sampler=sampler,\n        num_workers=num_workers,\n        collate_fn=partial(collate, samples_per_gpu=imgs_per_gpu),\n        pin_memory=False,\n        worker_init_fn=worker_init_fn if seed is not None else None,\n        **kwargs)\n\n    return data_loader\n", "path": "mmdet/datasets/loader/build_loader.py"}], "after_files": [{"content": "import platform\nimport random\nfrom functools import partial\n\nimport numpy as np\nfrom mmcv.parallel import collate\nfrom mmcv.runner import get_dist_info\nfrom torch.utils.data import DataLoader\n\nfrom .sampler import DistributedGroupSampler, DistributedSampler, GroupSampler\n\nif platform.system() != 'Windows':\n    # https://github.com/pytorch/pytorch/issues/973\n    import resource\n    rlimit = resource.getrlimit(resource.RLIMIT_NOFILE)\n    resource.setrlimit(resource.RLIMIT_NOFILE, (4096, rlimit[1]))\n\n\ndef build_dataloader(dataset,\n                     imgs_per_gpu,\n                     workers_per_gpu,\n                     num_gpus=1,\n                     dist=True,\n                     shuffle=True,\n                     seed=None,\n                     **kwargs):\n    \"\"\"Build PyTorch DataLoader.\n\n    In distributed training, each GPU/process has a dataloader.\n    In non-distributed training, there is only one dataloader for all GPUs.\n\n    Args:\n        dataset (Dataset): A PyTorch dataset.\n        imgs_per_gpu (int): Number of images on each GPU, i.e., batch size of\n            each GPU.\n        workers_per_gpu (int): How many subprocesses to use for data loading\n            for each GPU.\n        num_gpus (int): Number of GPUs. Only used in non-distributed training.\n        dist (bool): Distributed training/test or not. Default: True.\n        shuffle (bool): Whether to shuffle the data at every epoch.\n            Default: True.\n        kwargs: any keyword argument to be used to initialize DataLoader\n\n    Returns:\n        DataLoader: A PyTorch dataloader.\n    \"\"\"\n    rank, world_size = get_dist_info()\n    if dist:\n        # DistributedGroupSampler will definitely shuffle the data to satisfy\n        # that images on each GPU are in the same group\n        if shuffle:\n            sampler = DistributedGroupSampler(dataset, imgs_per_gpu,\n                                              world_size, rank)\n        else:\n            sampler = DistributedSampler(\n                dataset, world_size, rank, shuffle=False)\n        batch_size = imgs_per_gpu\n        num_workers = workers_per_gpu\n    else:\n        sampler = GroupSampler(dataset, imgs_per_gpu) if shuffle else None\n        batch_size = num_gpus * imgs_per_gpu\n        num_workers = num_gpus * workers_per_gpu\n\n    init_fn = partial(\n        worker_init_fn, num_workers=num_workers, rank=rank,\n        seed=seed) if seed is not None else None\n\n    data_loader = DataLoader(\n        dataset,\n        batch_size=batch_size,\n        sampler=sampler,\n        num_workers=num_workers,\n        collate_fn=partial(collate, samples_per_gpu=imgs_per_gpu),\n        pin_memory=False,\n        worker_init_fn=init_fn,\n        **kwargs)\n\n    return data_loader\n\n\ndef worker_init_fn(worker_id, num_workers, rank, seed):\n    # The seed of each worker equals to\n    # num_worker * rank + worker_id + user_seed\n    worker_seed = num_workers * rank + worker_id + seed\n    np.random.seed(worker_seed)\n    random.seed(worker_seed)\n", "path": "mmdet/datasets/loader/build_loader.py"}]}