PyTorch分布式(9) ----- DistributedDataParallel初始化
2024-02-09 06:16:31
如何初始化 PyTorch 中的 DistributedDataParallel
在 PyTorch 中进行分布式训练时,DistributedDataParallel(DDP)是一个不可或缺的工具。它允许我们在多台 GPU 上训练模型,从而显著提高训练速度和吞吐量。本文将深入探讨 DDP 的初始化过程,帮助你理解其内部机制。
一、DDP 初始化概览
1. Python 世界初始化
- 调用
torch.distributed.init_process_group()
初始化分布式进程组。 - 创建
DistributedDataParallel
对象。 - 将模型和优化器包装进
DistributedDataParallel
对象。 - 调用
DistributedDataParallel
对象的train()
方法开始分布式训练。
2. C++ 世界初始化
- 创建
DistributedDataParallel
对象的 C++ 对象。 - 将模型和优化器包装进
DistributedDataParallel
对象的 C++ 对象。 - 调用
DistributedDataParallel
对象的 C++ 对象的train()
方法开始分布式训练。
二、DDP 初始化的关键代码解析
1. Python 世界关键代码
def __init__(self, module, device_ids=None, output_device=None, dim=0, bucket_cap_mb=25):
"""
See :meth:`torch.nn.parallel.DistributedDataParallel` for most of the
arguments' documentation.
Args:
bucket_cap_mb (float, optional): DistributedDataParallel will
bucket parameters into multiple buckets so that each bucket would
be no larger than `bucket_cap_mb` MegaBytes (default: 25)
"""
super(DistributedDataParallel, self).__init__(module, device_ids, output_device, dim)
self.bucket_cap_mb = bucket_cap_mb
self._ddp_init_helper()
此代码片段是 DistributedDataParallel
对象的构造函数,它初始化 DDP 相关属性,如 bucket_cap_mb
,并调用 _ddp_init_helper()
方法进行其他初始化工作。
def _ddp_init_helper(self):
# ...省略其他代码...
# Get a list of all parameters, including the parameters of nested modules.
param_list = get_parameter_list(self.module)
# Determine the bucket size and the number of buckets.
self.bucket_sizes, self.num_buckets = _determine_bucket_sizes_and_num_buckets(
param_list, self.bucket_cap_mb
)
# Create a list of parameter buckets.
self.buckets = [[] for _ in range(self.num_buckets)]
# Assign parameters to buckets.
_assign_parameters_to_buckets(param_list, self.buckets, self.bucket_sizes)
# Create a list of DDP groups, one for each bucket.
self.ddp_groups = [
dist.new_group([rank for rank in self.process_group]) for _ in range(self.num_buckets)
]
# ...省略其他代码...
此代码片段是 _ddp_init_helper()
方法,它获取模型的所有参数,确定桶的大小和数量,并创建桶列表。然后,它将参数分配到桶中,并为每个桶创建一个 DDP 组。
2. C++ 世界关键代码
template <typename param_type>
static void _assign_parameters_to_buckets(
std::vector<param_type>& parameters,
std::vector<std::vector<param_type>>& buckets,
const std::vector<size_t>& bucket_sizes) {
// ...省略其他代码...
for (size_t param_idx = 0; param_idx < parameters.size(); ++param_idx) {
// Get the size of the current parameter.
size_t param_size = _get_parameter_size(parameters[param_idx]);
// Find the smallest bucket that can hold the current parameter.
size_t bucket_idx = 0;
while (bucket_idx < buckets.size() && bucket_sizes[bucket_idx] < param_size) {
++bucket_idx;
}
// Add the current parameter to the selected bucket.
buckets[bucket_idx].push_back(parameters[param_idx]);
// Update the size of the selected bucket.
bucket_sizes[bucket_idx] += param_size;
// ...省略其他代码...
}
}
此代码片段是 _assign_parameters_to_buckets()
方法,它将参数分配到桶中,通过为每个参数找到最小的桶并将其添加到该桶中来实现。
三、结论
DDP 的初始化过程涉及将模型和优化器包装到一个分布式对象中,并为每个 GPU 创建一个 DDP 组。通过对关键代码的分析,我们了解了 DDP 如何实现这些步骤。通过充分利用 PyTorch 提供的工具,我们可以轻松地进行分布式训练,从而提高机器学习模型的训练速度和效率。
常见问题解答
1. DDP 的桶是如何创建的?
桶是根据参数的大小创建的,每个桶的大小不超过指定的 bucket_cap_mb
。
2. 为什么需要将参数分配到桶中?
桶有助于优化参数通信,因为只有属于同一个桶的参数才会在 GPU 之间进行通信。
3. DDP 组的用途是什么?
DDP 组用于在 GPU 之间进行参数和梯度通信。
4. 如何使用 C++ 初始化 DDP?
使用 torch::distributed::DDP
名称空间创建 DDP
对象,并传入模型和优化器等参数。
5. DDP 的好处是什么?
DDP 允许在多台 GPU 上训练模型,提高训练速度和吞吐量。