# DeepSpeed
## 目录
* 以下给出[DeepSpeed官方](https://www.deepspeed.ai/training/)所总结的training feature
* Distributed Training with Mixed Precision
* 16-bit mixed precision
* Single-GPU/Multi-GPU/Multi-Node
* Model Parallelism
* Support for Custom Model Parallelism
* Integration with Megatron-LM
* Pipeline Parallelism
* 3D Parallelism
* The Zero Redundancy Optimizer
* Optimizer State and Gradient Partitioning
* Activation Partitioning
* Constant Buffer Optimization
* Contiguous Memory Optimization
* ZeRO-Offload
* Leverage both CPU/GPU memory for model training
* Support 10B model training on a single GPU
* Ultra-fast dense transformer kernels
* Sparse attention
* Memory- and compute-efficient sparse kernels
* Support 10x long sequences than dense
* Flexible support to different sparse structures
* 1-bit Adam, 0/1 Adam and 1-bit LAMB
* Custom communication collective
* Up to 26x communication volume saving
* Additional Memory and Bandwidth Optimizations
* Smart Gradient Accumulation
* Communication/Computation Overlap
* Training Features
* Simplified training API
* Gradient Clipping
* Automatic loss scaling with mixed precision
* Training Optimizers
* Fused Adam optimizer and arbitrary torch.optim.Optimizer
* Memory bandwidth optimized FP16 Optimizer
* Large Batch Training with LAMB Optimizer
* Memory efficient Training with ZeRO Optimizer
* CPU-Adam
* Training Agnostic Checkpointing
* Advanced Parameter Search
* Learning Rate Range Test
* 1Cycle Learning Rate Schedule
* Simplified Data Loader
* Data Efficiency
* Efficient data sampling via curriculum learning and efficient data routing via random layerwise token dropping
* Up to 2x data and 2x time saving during GPT-3/BERT pretraining and GPT/ViT finetuning
* Or further improve model quality under the same data/time
* Curriculum Learning
* A curriculum learning-based data pipeline that presents easier or simpler examples earlier during training
* Stable and 3.3x faster GPT-2 pre-training with 8x/4x larger batch size/learning rate while maintaining token-wise convergence speed
* Complementary to many other DeepSpeed features
* Note that the Data Efficiency Library above provides more general curriculum learning support. This legacy curriculum learning feature is still supported but we recommend to use the Data Efficiency Library.
* Progressive Layer Dropping
* Efficient and robust compressed training
* Up to 2.5x convergence speedup for pre-training
* Performance Analysis and Debugging
* Mixture of Experts (MoE)
* 以下给出[DeepSpeed官方](https://www.microsoft.com/en-us/research/blog/deepspeed-accelerating-large-scale-model-inference-and-training-via-system-optimizations-and-compression/)所总结的inference feature
* Inference-adapted parallelism
* Inference-optimized CUDA kernels
* Effective quantize-aware training
* 此外,DeepSpeed还支持模型压缩功能
## Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism
* 概述: 针对transformer结构设计模型切分方法,将切分后的模型分发到多张卡上并行加速
* 方法:
* 切分MLP
* $Y = GeLU(XA)$, $Z = YB$
* $A = \begin{bmatrix}A_1 & A_2\end{bmatrix} B=\begin{bmatrix}B_1 \\ B_2\end{bmatrix}$
* $\begin{bmatrix}Y_1 & Y_2\end{bmatrix} = [GeLU(XA_1), GeLU(XA_2)]$
* $Z = Y_1B_1 + Y_2B_2$
> 下标代表所在的GPU编号,最后计算Z时用all-reduce求和
* 切分self-attention
* 利用self-attention中多头的特性,将每个头平均分配给多个卡即可
*
| MLP切分方式 | self-attension切分方式 |
| -------- | -------- |
|  |  |
* 切分输出层
* 到输出层时,向量大小为$b$x$l$x$v$,其中$b$是batch-size, $l$是输入语句长度,$v$是单字表大小
* 因为$v$非常大,如果直接通信会造成通信量过大,先算softmax再传$b$x$l$结果即可(如果要entropy呢?)
* 参考资料
* paper: https://arxiv.org/pdf/1909.08053.pdf
* https://www.youtube.com/watch?v=mk8FuiDmf0I
## ZeRO: Memory Optimizations Toward Training Trillion Parameter Models
* 背景一: 如何提速? 当拥有多张卡的时候,直觉上有以下几种方法提速
* 数据并行(data parallelism): 将整个batch的数据切分为多个min-batch,每张卡上跑一个mini-batch,计算结束后将各个mini-batch的梯度求平均即可得到整体的梯度
* 优点: 实现简单、计算与通信量低
* 缺点: 每个节点都要维护一份一模一样的模型,浪费显存
* 模型并行(model parallelism): 将模型的每一层都切分为多个tensor,每张卡上计算一部份,每计算完一层都需要进行整合
* 优点: 节省显存
* 缺点: 每计算完一层都需要跟其他卡沟通、通信量大。切分后的模型粒度过小,将影响计算速度。
* 流水并行(pipeline parallelism): 将模型按层切割,每张卡上计算其中n层,可以通过流水线的方式实现以加速
* 优点: 节省显存
* 缺点:
* 为了使用流水线,通常会拆分为多个mini-batch,使得batch norm等操作困难(mini-batch间有时序关系)
* 尽管使用流水线,仍然会使效率降低(pipeline bubble),通常mini batch数量越多,效率降低的越不显著
> ZeRO 希望同时具有DP通信量低与MP/PP节省内存的优点
* 背景二: 如何降显存? 通常显存因为以下几种原因被占用
* 模型参数、梯度与优化器参数:
* 若使用混合精度训练,并使用Adam优化器,且模型参数数量为$\Phi$,则该模型在训练时总共需要占用16$\Phi$ bytes的显存,包含:
* 参数(fp16, $2\Phi$)、
* 梯度(fp16, $2\Phi$)
* 优化器状态: 参数(fp32, $4\Phi$), Adam's momentum(fp32, $4\Phi$), Adam's variance(fp32, $4\Phi$)
> 可以看到优化器状态是占用显存的主要因素,ZeRO-DP通过将优化器状态切割成多份后,分别记录在多张卡上达到降低显存占用的效果。
* 激活值(Activations):
* 
> source gif: https://siboehm.com/articles/22/data-parallel-training
* Activations即上图中的cache,在前向传播时被保留,用以计算反向传播
* Activation checkpointing: 可以适当丢弃部份activations,需要时重新前向计算即可,以增加33%计算量为代价能够节省8x的内存。
> ZeRO-R 通过将Activation checkpointing切割成多份后,分别记录在多张卡上达到降低显存占用的效果
* 缓存(Temporary buffers):
* 模型在执行gradient all-reduce或gradient norm等操作时,可能会开启过大的缓存
> ZeRO-R 通过固定临时缓存大小,避免此问题
* 不连续的显存(Memory Fragmentation):
* 尽管显存足够,若找不到连续且足够大的显存空间,也会有out of memory的问题
* 造成显存不连续的主要原因是不同向量生命周期不同,如activation checkpoint与梯度会被长期保留,而其余activation将在使用后被销毁
> ZeRO-R 通过开辟固定的显存空间来存放会被长期保留的向量,避免此问题
* 算法细节 ZeRO-DP(data parallelism)
> ZeRO-DP是以DP为基础改进而得的算法,以下先介绍all-reduce一种集群通信的方法,接着介绍传统DP方法,最后介绍ZeRO-DP算法的两个变体
* all-reduce:

> source image: https://zhuanlan.zhihu.com/p/504957661
* 概述: 通过环形通信,将不同节点上的数相加,并将结果更新到所有结点
* 分为两个部份reduce-scatter与all-gather (节点数=n, 单笔数据$a_1,b_1...$大小=$\Phi$)
* reduce-scatter: 每个节点每一步都加上自己右手边节点的数,重复n次即可
* all-gather: 将蓝色部份内容依次向左传递,重复n次即可
* reduce-scatter与all-gather每步传递与接收的总数据量都是$\Phi$
* 称all-reduce通信量为2$\Phi$ (实际上要传n-1次,可以使用流水线加速)
* DP(data parallelism)
* 每个节点都要维护一个一模一样的模型,将数据分为多个mini-batch
* 每个节点计算出该mini-batch的梯度,$w_i, i=1,..,n$, 其显存占用大小为$\Phi$
* 用all-reduce将所有mini-batch的梯度求和,并在各自节点上更新模型
> 注意: 理论上reduce-scatter后,每个节点就可以得到求和后的总梯度,只是求和的顺序不同,但由于计算机上浮点数加法不满足交换率,为了确保所有结点模型更新后参数完全相同,因此还是需要进行all-gather步骤 [[1]](https://siboehm.com/articles/22/data-parallel-training)
* ZeRO-DP ($P_{os+g}$)
* 将模型梯度与优化器状态分成$n$份,分别记录在$n$个节点上
* 每个节点计算出自己mini-batch的梯度,用reduce-scatter把所有结点的梯度相加
* 更新模型参数,用all-gather将更新后参数传给其他节点
> 此处求和顺序不同没有关系,只要确保更新后所有结点模型参数相同即可
* 通信量与传统DP相同、显存占用变为: $2+\frac{2+4+4+4}{n}$ (n很大时为8x)
* ZeRO-DP ($P_{os+g+p}$)
* 将模型参数也分成$n$份,分别记录在$n$个节点上
* 前向传播:通过广播从其他节点取得其他部份的结果,计算自己负责的mini-batch
* 反向传播:通过广播从其他节点取得其他部份的结果,计算自己负责的mini-batch
* 得到梯度后用reduce-scatter把所有结点的梯度相加
* 直接更新自己那部份参数就可以
* 通信量是传统DP 1.5倍(前向、反向、reduce-scatter)且需要广播,显存占用变为$\frac{16}{n}$
* 算法细节 ZeRO-R: Optimizing Residual State Memory
* 使用Activation checkpointing
* 将Activation checkpointing切割成多份后,分别记录在多张卡(类似ZeRO-DP)
* 固定临时缓存大小
* 开辟固定的显存空间来存放会被长期保留的向量(包含: activation checkpoints与梯度)
> 问题:
> 1. 并且不懂通信的细节,感觉通信过程中也会占用到很多的缓存,不知道为啥并没有讨论。
> 2. $P_{os+g+p}$要求节点能广播,理论上广播是环状传递效率的一半,这点应该纳入考虑。
> 3. $P_{os+g+p}$与MP的区别?
> 4. Activation checkpoint是需要人工选择哪些参数被保留,才能够最大化效率吗,还是有标准的选择方法($P_p$中模型的切分方法同理)。
> 5. 流水线加速: 为了流水线切割为多个mini-batch会影响性能很多吗,要切割成多少个mini-batch对性能才不会有影响?
* 参考资料
* paper: https://arxiv.org/pdf/1910.02054.pdf
* https://basicv8vc.github.io/posts/zero/
* https://siboehm.com/articles/22/data-parallel-training
* https://zhuanlan.zhihu.com/p/504957661
## ZeRO-Offload Democratizing Billion-Scale Model Training
* 概述: 将优化器状态与梯度传到CPU以降低显存占用
* 方法
* 模型流程设计

* 设计思路
* 上左图是混合精度训练流程图,箭头上代表通信数据量
* $M$为模型参数量,$B$为batch-size
* 首先,计算量来说前向与反向传播都是$O(MB)$,参数更新则是$O(M)$
* 因此,只要$B$不是太小,将参数更新放在CPU上运行不太影响效率
* 并且,前向与反向传播都必须在GPU上运行
* 需要在这两组操作中间切一刀,使得通信量最小,得到应该切过两个2M的箭头
* 考虑到CPU上放尽可能多的操作/数据,最终切分方式如上右图所示
> 
> 事实上,GPU与CPU之间通信所花的时间比想象来说少的多,因为计算反向传播需要时间,后面的层算完后该层梯度就可以开始先往CPU传了,参数更新时同理,如上图所示
* 多卡场景
* 当有n张卡时,与ZeRO-DP的$P_{os+g}$同理,可以将梯度与模型状态分为n等份,分别存在n张卡中,更进一步,offload到CPU上
* 优化CPU优化器
* 通过SIMD vector instruction, Loop unrolling, OMP multithreading优化,没有深入研究
* One-Step Delayed Parameter Update
* 当$B$不是太大时,CPU上做参数更新可能影响性能
* 前N步正常训练,N+1步以后延迟一步更新
* 对性能存在负面影响,看起来不适合直接加入RL训练中
* 参考资料
* paper: https://arxiv.org/pdf/2101.06840.pdf
* https://zhuanlan.zhihu.com/p/513571706
## Ultra-fast dense transformer kernels
* 参考资料: https://www.deepspeed.ai/2020/05/27/fastest-bert-training.html#a-advanced-fused-kernels-to-reduce-data-movement
## Sparse attention
* 参考资料: https://www.deepspeed.ai/2020/09/08/sparse-attention.html
## 1-bit Adam
* 概述: 通过压缩梯度的方式,降低通信开销
* 方法
* 以SGD为例:
* $x_t$为$t$时刻模型参数,$g_t$为$t$时刻梯度,$e_t$为截至$t$时刻为止的累积误差,$C(\cdot)$为压缩函数
* 更新方式: $x_{t+1} = x_t - \gamma C[g_{t+1} + e_t]$
* 这样方法能够保证误差不会累积,不影响收敛性
<!-- * 此时: $e_0 = 0$, $e_{t+1} = e_t + \gamma(g_{t+1} - C[g_{t+1} + e_t])$
* 将误差带入更新公式得: $x_{t+1} = x_t - \gamma g_{t+1} + (e_t-e_{t+1})$
* 由此可知误差不会累积,算法能够收敛
* Adam
* Adam更新方向与梯度非线性关系,不能用上面的方法
* 原本更新公式
$\begin{cases}m_{t+1} = \beta_1m_t + (1-\beta_1)g_t\\v_{t+1} = \beta_2v_t + (1-\beta_2)v_t\\x_{t+1} = x_t\frac{m_{t+1}}{\sqrt{v_{t+1}}+\eta}\end{cases}$
* -->
* 参考资料
* paper: https://arxiv.org/pdf/2108.02102.pdf
* https://www.deepspeed.ai/2020/09/08/onebit-adam-blog-post.html
## Inference
* 概述
* 多卡并行将造成通信增加与计算粒度下降等问题
* 多卡并行效率通过模型并行解决
* 计算粒度下降通过kernel优化解决
* 需要用户自行选用合适并行程度
* 多卡并行推断
* DeepSpeed支持transformer类模型的自动切分(model parallelism)
* 针对推断设计的kernel
* Deep fusion:
* 合并多个操作到同个kernel以加速
* 包含: 算子优化、针对Transformer结构的优化
* Inference-customized GeMM(General Matrix Multiplication):
* batch-size过小,导致模型加载的时间远大于计算的时间
* DeepSpeed优化kernel,使其模型加载速率增大
* 当batch_size介于1到10时,效率高20%
<!-- * Flexible quantization support
* Mixture of Quantization (用于训练)
* quantization-aware training (QAT):
* 从高精度开始,逐渐加大量化程度
* 反馈动态调整精度
* 参考资料: https://www.deepspeed.ai/2021/05/04/MoQ.html
* INT8 inference kernels -->
## ZeroQuant Efficient and Affordable Post-Training Quantization for Large-Scale Transformers
* 方法
* 分组量化:
* 大模型参数,同一行参数对应同一个输入特征维度,因此数值上接近
* 反之,不同行间数值差距极大,因此不能用一个固定范围来做量化
* 采用分组量化,将一层参数(共$n$行)分为$g$组,$n\geq g$
* Token-wise量化:
* 对于不同的token,activation会很不一样
* 采用Token-wise量化,对于每组token都动态计算其范围
* kernel融合:
* 量化与反量化操作耗时
* 通过kernel融合加速,如: BN与量化融合
* 参考资料
* paper: https://arxiv.org/pdf/2206.01861.pdf
* https://mp.weixin.qq.com/s/iWEGUYOe32bqxxGohjqIhw
<!-- * [XTC](https://www.microsoft.com/en-us/research/publication/extreme-compression-for-pre-trained-transformers-made-simple-and-efficient/): 二元量化 -->