之前断断续续用deepspeed搞sft,但每次都只关注了一部分,这里再从头捋捋
概念recap
Data parallel DP
- 数据集切分,不同GPU给到不同的batches
- GPUs独立forward-backword
- 最后update参数才allreduce
- 注意提前在loss位置reduce没意义,因为算loss均值也是线性的,因此直接reduce出平均梯度就行
- 当然也不会所有参数backward完才reduce,算完的部分就可以(分bucket)直接开始all reduce了
- 经典的pytorch dp是gpu0分享data到其他卡,然后算梯度也是收回gpu0,这个就是bottleneck
- 现在一般讲DP肯定是指DDP
之前实习是在<2B的embedding LLM上full SFT,数据量极大(>10T,当然其实不会全部用完),因此印象中是A100集群DP,每张卡塞3-4个实例,可以DP把等效batchsize搞得很大
batchsize大除了加速训练,还有一点是embedding最后算InfoNCE是在batch内按照正负例相对值算的,大batchsize噪声小一点,这个和GRPO避免过小的groupsize的道理有些相通之处
(
有点忘记算loss时有没有在DP全局算loss了。。。有的,当时all_gather还调了半天才搞通)
Tensor parallel TP
- 底层矩阵切分,一个Layer分散到多个GPU计算,然后reduce
- 高通信量
Pipeline parallel PP
- 特指按Layer切,一个GPU装几层,然后逻辑上是串行执行
- 当然实际上肯定类似流水线做法
- 特殊的点在于除了forward外还会有个时序相反的backward,和一般的流水线差这了
- 这个东西带来的麻烦很大,比如PP高了之后由于前面forward结果都要存导致显存飙升
Sequence parallel SP
- 每层的input都切分放到不同GPU
- 只是用TP的话,每次attention部分搞完后、产生activation前,都要重新all reduce,然后每个GPU都要算一个一模一样的activation
- 因此all reduce改成reduce scatter,每个GPU只算一段activation,最后all gather
- 通信层面没省,但是显存&计算量节省,对long seq友好
- 因此是TP后的自然结果,一般TP+SP – Megatron
MoE parallel EP
- 不同expert放到不同的GPU去
offload
- 特指显存不够时移到SSD
ZeRO
- 针对的是training state做shard,训练流程(计算)上没有添加并行度,只是优化显存
ZeRO-1
- 切Adam状态,依旧reduce-scatter + all gather
ZeRO-2
- 切Adam和grad
ZeRO-3
- 切Adam,grad和权重
- 注意这不是类似TP/PP那种切法,这里权重切完之后每次forward都要all reduce临时拼一下,计算过程和不使用TP/PP等是一模一样的(所以说ZeRO是纯粹的显存优化)