假设读者熟知尺度的随机梯度降落算法(SGD),该算法常用于实习深度进修模子。我们此刻看到的是 SGD 的一个变体——同步 SGD(synchronous SGD),它操作 all-reduce collective 来举办扩展。我们先从尺度 SGD 的数学公式开始吧。
个中 D 是一个样本荟萃(mini-batch),θ 是全部参数的荟萃,λ 是进修率,Loss(X, y) 是某个丧失函数在 D 中全部样本上的均值。
同步 SGD 所依靠的焦点能力是将更新法则中的求和在更小的 (mini)batch 子集长举办支解。D 被支解成 R 个子集 D₁, D₂, . .(保举每个子集具有沟通数目的样本),以是 将尺度的 SGD 更新公式中的求和举办支解,获得:
此刻,由于梯度算子在求和算子上是漫衍式的,以是我们获得:
我们从中获得了什么?
看一下上面方程中单独的梯度项(方括号内里)。它们此刻可以被独立地计较,然后加起来获得原始的梯度,并且没有任何丧失/近似。这就是数据并行。下面是整个进程:
- 将整个数据集分成 R 个等大的数据块(子集)。这里的字母 R 代表的是 replica(副本)。
- 行使 MPI 启动 R 个历程/rank,将每个历程绑定到一个数据块上。
- 让每个 rank 行使巨细为 B 的 mini-batch(dᵣ)(dᵣ来自该 rank 分派到的数据块 D_r)计较梯度,即 rank r 计较
。
- 将全部 rank 的梯度举办求和,然后将获得的梯度对每个 rank 可见,再举办进一步处理赏罚。
最后一点就是 all-reduce 算法。以是,每次在全部 rank 行使巨细为 B 的 mini-batch(dᵣ)计较完梯度往后,都必需执行 all-reduce。必要留意的一点是,将所有 R 个 rank(行使巨细为 B 的 mini-batch 计较出)的梯度相加之后会获得一个有用的批巨细:
下面是实现的要害部门(没有展示样板代码):
- model = LeNet()
- # first synchronization of initial weights
- sync_initial_weights(model, rank, world_size)
-
- optimoptimizer = optim.SGD(model.parameters(), lr=1e-3, momentum=0.85)
-
- model.train()
- for epoch in range(1, epochs + 1):
- for data, target in train_loader:
- optimizer.zero_grad()
- output = model(data)
- loss = F.nll_loss(output, target)
- loss.backward()
-
- # The all-reduce on gradients
- sync_gradients(model, rank, world_size)
-
- optimizer.step()
-
- def sync_initial_weights(model, rank, world_size):
- for param in model.parameters():
- if rank == 0:
- # Rank 0 is sending it's own weight
- # to all it's siblings (1 to world_size)
- for sibling in range(1, world_size):
- dist.send(param.data, dst=sibling)
- else:
- # Siblings must recieve the parameters
- dist.recv(param.data, src=0)
-
-
- def sync_gradients(model, rank, world_size):
- for param in model.parameters():
- dist.all_reduce(param.grad.data, op=dist.reduce_op.SUM)
- 所有 R 个 rank 都行使随机权重建设本身的模子副本。
- 单个具有随机权重的副本也许导致在初始的时辰差异步。保举在全部的副本上同步初始权重,sync_initial_weights(..) 就是在做这件事。让任何一个 rank 将本身的权重发送到它的兄弟 rank,兄弟 rank 必需吸取这些权重并用来初始化它们自身。
- 从每个 rank 对应的数据部门取出一个 mini-batch(巨细为 B),计较前向和反向转达(梯度)。作为设置的一部门,这里必要重点留意的一点是:全部的历程/rank 应该让本身那部门数据可见(凡是是在本身的硬盘上可能在共享文件体系中)。
- 把求和作为 reduction 运算,对每一个副本上的梯度执行 all-reduce 集团。sync_gradients(..) 会完成梯度同步。
- 梯度同步之后,每个副本可以或许在本身的权重上独立地执行尺度的 SGD 更新。optimizer.step() 正常运行。
此刻题目来了:我们怎样确保独立的更新保持同步? (编辑:湖南网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|