A DistributedDataParallel wrapper for models in 3D mesh estimation task. In 3D mesh estimation task, there is a need to wrap different modules in the models with separate DistributedDataParallel. Otherwise, it will cause errors for GAN training. More specific, the GAN model, usuall
| 8 | |
| 9 | @MODULE_WRAPPERS.register_module() |
| 10 | class DistributedDataParallelWrapper(nn.Module): |
| 11 | """A DistributedDataParallel wrapper for models in 3D mesh estimation task. |
| 12 | |
| 13 | In 3D mesh estimation task, there is a need to wrap different modules in |
| 14 | the models with separate DistributedDataParallel. Otherwise, it will cause |
| 15 | errors for GAN training. |
| 16 | More specific, the GAN model, usually has two sub-modules: |
| 17 | generator and discriminator. If we wrap both of them in one |
| 18 | standard DistributedDataParallel, it will cause errors during training, |
| 19 | because when we update the parameters of the generator (or discriminator), |
| 20 | the parameters of the discriminator (or generator) is not updated, which is |
| 21 | not allowed for DistributedDataParallel. |
| 22 | So we design this wrapper to separately wrap DistributedDataParallel |
| 23 | for generator and discriminator. |
| 24 | In this wrapper, we perform two operations: |
| 25 | 1. Wrap the modules in the models with separate MMDistributedDataParallel. |
| 26 | Note that only modules with parameters will be wrapped. |
| 27 | 2. Do scatter operation for 'forward', 'train_step' and 'val_step'. |
| 28 | Note that the arguments of this wrapper is the same as those in |
| 29 | `torch.nn.parallel.distributed.DistributedDataParallel`. |
| 30 | Args: |
| 31 | module (nn.Module): Module that needs to be wrapped. |
| 32 | device_ids (list[int | `torch.device`]): Same as that in |
| 33 | `torch.nn.parallel.distributed.DistributedDataParallel`. |
| 34 | dim (int, optional): Same as that in the official scatter function in |
| 35 | pytorch. Defaults to 0. |
| 36 | broadcast_buffers (bool): Same as that in |
| 37 | `torch.nn.parallel.distributed.DistributedDataParallel`. |
| 38 | Defaults to False. |
| 39 | find_unused_parameters (bool, optional): Same as that in |
| 40 | `torch.nn.parallel.distributed.DistributedDataParallel`. |
| 41 | Traverse the autograd graph of all tensors contained in returned |
| 42 | value of the wrapped module’s forward function. Defaults to False. |
| 43 | kwargs (dict): Other arguments used in |
| 44 | `torch.nn.parallel.distributed.DistributedDataParallel`. |
| 45 | """ |
| 46 | |
| 47 | def __init__(self, |
| 48 | module, |
| 49 | device_ids, |
| 50 | dim=0, |
| 51 | broadcast_buffers=False, |
| 52 | find_unused_parameters=False, |
| 53 | **kwargs): |
| 54 | super().__init__() |
| 55 | assert len(device_ids) == 1, ( |
| 56 | 'Currently, DistributedDataParallelWrapper only supports one' |
| 57 | 'single CUDA device for each process.' |
| 58 | f'The length of device_ids must be 1, but got {len(device_ids)}.') |
| 59 | self.module = module |
| 60 | self.dim = dim |
| 61 | self.to_ddp( |
| 62 | device_ids=device_ids, |
| 63 | dim=dim, |
| 64 | broadcast_buffers=broadcast_buffers, |
| 65 | find_unused_parameters=find_unused_parameters, |
| 66 | **kwargs) |
| 67 | self.output_device = _get_device_index(device_ids[0], True) |