Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions 各类并行.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# 各类通信方式


| All-to-all | 每个进程 ↔ 所有其他进程交换数据 | MoE、张量并行、数据重分布 | | |
| -------------- | ---------------------------------- | ---------------------------- | - | - |
| All-reduce | 所有进程数据汇总后广播给所有人 | 梯度同步(数据并行训练) | | |
| All-gather | 每个进程数据收集起来,广播给所有人 | 收集各设备结果,拼接完整张量 | | |
| Broadcast | 一个进程数据广播给所有人 | 初始化参数、广播输入 | | |
| Reduce-scatter | 各设备数据汇总后分片返回各设备 | 某些并行策略中的梯度分发 | | |

我们先看一个经典的3D矩阵乘法:
![img.png](img.png)

从这个图中就可以看出针对数据输入和模型参数都有切分规则,接下来我们就从这两个对象的切分维度上进行讲述。

## 数据上下文并行


在切分输入的并行中,我们可以从张量的不同维度进行切分。

* **batch维度:从batch进行切分就是我们熟知的数据并行,即把一个大的batch size切分到多个DP域内并行计算。**
* **sequence维度:由于LLM中一句话会切分成一串sequence,我们可以将sequence切分进行并行计算【Context Parallelism和Sequence Parallelism】**

### 数据并行


数据并行顾名思义就是把Input(batched)分散到不同的计算GPU上进行训练,**每个核心GPU各自完成反向传播计算出此部分数据的梯度,然后利用一个GPU节点接收其他所有GPU计算出的梯度,**

**将其累加求平均,然后再传回各个GPU进行权重更新**

![image.png](assets/image.png)


同步式数据并行的缺点如下:**由于需要一个专门的GPU节点来累加梯度,所以节点就要等到最慢的那个GPU算完梯度之后才能完成累加,然后才能将平均后的梯度传回给各个GPU节点,这就导致了算的快的GPU产生了大量的空闲时间。**

故改进思路便是取消单个参数服务器,将所有GPU都作为参数服务器进行梯度同步。

**梯度累加算法改进(Ring AllReduce):如下图所示,算法将只选择一个节点累加梯度改为所有节点都参与梯度的累加,所有节点采用环状旋转传播梯度。**

### Ring AllReduce算法

算法分为`Reduce-Scatter`和`Allgather`两个部分

#### Reduce-Scatter

![image.png](assets/image2.png)

每个GPU节点的发送和接收端只负责一部分数据(如GPU0只负责发送a数据,接收e数据)

![image.png](assets/imagefdsa.png)

第一个循环结束时GPU1的a数据已经含有自己的a1和从GPU0接收来的a0,即a0+a1

![image.png](assets/imag432e.png)

第四个循环结束时GPU4的a数据已经含有自己的a4和从GPU3接收来的a0+a1+a2+a3,即a0+a1+a2+a3+a4

**此时所有GPU都含有了完整的部分数据,GPU4含有了a的完整数据,GPU0含有b的完整数据.....然后我们就要将这些完整的数据再通过环状传播到所有GPU节点中去**


#### Allgather

![image.png](assets/image2323.png)

GPU节点发送和接收的数据会随循环,GPU接收数据后不再是累加接收到的数据,而是用接收到的数据替换自己原有的数据

![image.png](assets/image222.png)

第一个循环后每个GPU都有了接收到的数据,此后的循环便是将接收到的数据再发送出去的过程



GPU2接收到了在iteration3时接收到了GPU1发送的a数据,然后在iteration4时便将数据a发给GPU3。其在iteration2时接收的其实是b数据,发送给GPU3的是c数据。从此可以看出,Allgather部分的流程中各个GPU节点接收和发送的数据是随循环改变的


经过p-1个循环后所有GPU便拥有了完整的所有数据


### 分布式数据并行(Distributed Data Parallelism):

相较于数据并行, DDP在梯度传播的顺序和时机上做了优化。

![image.png](assets/image222222.png)