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()

```

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)

{"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"}]}