Deepspeed、ZeRO、FSDP、ZeRO-Offload、all reduce、reduce-scatter

2024-03-30 05:12

本文主要是介绍Deepspeed、ZeRO、FSDP、ZeRO-Offload、all reduce、reduce-scatter,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Transformer为基础的大模型应该如何并行

  • 数据并行。但是如果模型太大放不到一块卡上就没用了。为了解决把参数放到一块卡上的问题,演进出了论文Zero的思想,分为Zero-DP和Zero-R两部分。Zero-DP是解决Data parallel的问题,并行过程中内容不够,解决思路也比较简单,模型参数w只存在一台机器上,剩下的部分等用的时候找某台机器通过all-reduce请求就可以了。Zero-R是在每一层输入存不下,解决思想是带宽换内存。由Zero论文演进的Deep-speed框架影响了pytorch分布式计算的接口。
  • 模型并行。典型的是按照GPipe的思路,将模型按层切开,这样会实现像CPU流水线一样并行的设计。
  • 张量并行。典型的是Megatron LM,其实就是将矩阵乘法切开,参考下图:
    在这里插入图片描述

DeepSpeed中参数量的估计

  • 基本问题:在理解ZeRO前需要先理解一个基本问题,对于一个参数量为 Φ \Phi Φ的模型,使用Adam优化器单卡进行混合精度训练过程中至少占多大显存?结果是16* Φ \Phi Φ,分为以下两个部分:

    • 模型参数、模型梯度使用半精度FP16进行保存,模型迭代前向反向过程使用的都是FP16,因此对于模型参数、模型梯度的存储需要2* Φ \Phi Φ+2* Φ \Phi Φ个字节(半精度FP16或者BF16占用两个字节所以*2),也就是下图红框中的2+2
    • 在optimizer进行模型参数更新时,由于需要大量的累加和乘运算,半精度在这时经常出现精度溢出的情况,因此这时还是换回用FP32来优化,这也是混合精度计算命名的由来。在Adam更新时,原来FP16保存的模型参数会转换成FP32,占用4个字节。Adam中存在一阶矩和二阶矩两个Optimizer state,各占4个字节,也就是8个字节。因此这部分一共需要12个字节,也就是下图蓝框中的K=12(当然使用不同优化器这部分占用的显存是不一样的,这里就不展开了)。
      在这里插入图片描述
  • 核心想法:ZeRO的贡献分为ZeRO-DP(Data Parallel)和ZeRO-R(Residual State Memory)两部分优化思路:

    • ZeRO-DP实际上是利用参数服务器all reduce的思想把数据分到Nd块卡上,减少平均到每一块卡上的显存占用。DeepSpeed在实际使用中需要预先配置使用stage1(只数据并行上述K=12优化器状态部分的显存)或者stage2(数据并行上述K=12优化器状态部分+梯度部分的显存)或者stage3(数据并行上述K=12优化器状态部分+梯度部分+模型参数部分的显存),理解上图就理解了Zero工作的核心思想
    • ZeRO-R(Residual State Memory),这里Residual State Memory主要几个trick的叠加:1. 神经网络或者多层Transformers总依赖前一层算完才能再算下一层,保存前一层的结果会也会占用显存,ZeRO-R这里采用的是时间换空间通过合理并行来减少显存的想法;2. Constant Size Buffers,多卡通信中如果数据包太大或者太小都不利于整体效率,作者这里做了合理的tradeoff
  • 实际操作:由HuggingFace出的accelerate(https://huggingface.co/docs/accelerate/usage_guides/deepspeed)本身可以简化DeepSpeed的配置。DeepSpeed的配置项非常多,手动配置较容易出错,建议使用accelerate config完成初始配置后直接用accelerate launch不带其他accelerate参数启动code

  • 视频讲解: 来自李沐老师对这篇文章的精读(https://www.bilibili.com/video/BV1tY411g7ZT?vd_source=e260233b721e72ff23328d5f4188b304)强烈推荐,文章本身写的啰里啰嗦的

  • 论文地址: https://arxiv.org/pdf/1910.02054.pdf

Fully Sharded Data Parallel (FSDP)

FSDP来自facebook,对标微软在DeepSpeed中提出的Zero。FSDP可以看成PyTorch中的DDP优化版本,本身也是数据并行,但是和DDP不同的是,FSDP采用了parameter sharding,所谓的parameter sharding就是将模型参数也切分到各个GPUs上,而DDP每个GPU都要保存一份parameter,FSDP可以实现更好的训练效率(速度和显存使用),FSDP其实是和ZeRO-3更加接近

all-reduce=reduce-scatter+all-gather

在DDP中的操作是all-reduce,但是在FSDP中换成了reduce-scatter和all-gather,如下图
在这里插入图片描述
关于为什么all-reduce=reduce-scatter+all-gather?其实下面一张图解释的很清楚,引用https://engineering.fb.com/2021/07/15/open-source/fsdp/attachment/fsdp-graph-2a/的文字来说就是“All-reduce as a combination of reduce-scatter and all-gather. The standard all-reduce operation to aggregate gradients can be decomposed into two separate phases: reduce-scatter and all-gather. During the reduce-scatter phase, the gradients are summed in equal blocks among ranks on each GPU based on their rank index. During the all-gather phase, the sharded portion of aggregated gradients available on each GPU are made available to all GPUs (see here for details on those operators).” 简单来说就是把All Reduce这一步给打碎(scatter掉),如果直接all reduce,会存在广播的问题,带来的问题是带宽是瓶颈
在这里插入图片描述
为什么带宽会成为瓶颈,可以参考一流科技的文章https://juejin.cn/post/7090798853711986695:
在这里插入图片描述
关于reduce-scatter这几个操作的定义可以参考英伟达的文档https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/usage/collectives.html:
在这里插入图片描述

Zero-Offload

Zero-offload,也有被称为Zero4的, 这个甚至是一张卡都可以,Zero-offload就是针对GPU显存不够,甚至单卡的场景设计出来的。Zero-offload,为了优化各种算子的执行,把复杂的FWD和BWD放在了GPU上执行,而相对固定可控的算子param update和float2half就放在了CPU上进行运算,而这一部分除了相对算子简单以外,最重要的是Adam优化器本身是32bit的,把它放在CPU的内存上,会极大的节省GPU的显存。

这部分转载自:

  1. https://zhuanlan.zhihu.com/p/402232568
  2. https://www.zhihu.com/question/453941150/answer/3443788295

这篇关于Deepspeed、ZeRO、FSDP、ZeRO-Offload、all reduce、reduce-scatter的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/860564

相关文章

uva 10061 How many zero's and how many digits ?(不同进制阶乘末尾几个0)+poj 1401

题意是求在base进制下的 n!的结果有几位数,末尾有几个0。 想起刚开始的时候做的一道10进制下的n阶乘末尾有几个零,以及之前有做过的一道n阶乘的位数。 当时都是在10进制下的。 10进制下的做法是: 1. n阶位数:直接 lg(n!)就是得数的位数。 2. n阶末尾0的个数:由于2 * 5 将会在得数中以0的形式存在,所以计算2或者计算5,由于因子中出现5必然出现2,所以直接一

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT,这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频,并利用 SAM 2 进行 3D 空间分割,无需进一步训练或 2D-3D 投影。 我们的框架支持各种提示类型,包括 3D 点、框和掩模,并且可以泛化到不同的场景,例如 3D 对象、室

《Zero-Shot Object Counting》CVPR2023

摘要 论文提出了一种新的计数设置,称为零样本对象计数(Zero-Shot Object Counting, ZSC),旨在测试时对任意类别的对象实例进行计数,而只需在测试时提供类别名称。现有的类无关计数方法需要人类标注的示例作为输入,这在许多实际应用中是不切实际的。ZSC方法不依赖于人类标注者,可以自动操作。研究者们提出了一种方法,可以从类别名称开始,准确识别出最佳的图像块(patches),用

class _ContiguousArrayStorage deallocated with non-zero retain count

Xcode报错 : Object 0x11c614000 of class _ContiguousArrayStorage deallocated with non-zero retain count 2. This object's deinit, or something called from it, may have created a strong reference to self w

零样本学习(zero-shot learning)——综述

-------本文内容来自对论文A Survey of Zero-Shot Learning: Settings, Methods, and Applications 的理解和整理,这里省去了众多的数学符号,以比较通俗的语言对零样本学习做一个简单的入门介绍,用词上可能缺乏一定的严谨性。一些图和公式直接来自于论文,并且省略了论文中讲的比较细的东西,如果感兴趣建议还是去通读论文 注1:为了方便,文中

【go-zero】win启动rpc服务报错 panic: context deadline exceeded

win启动rpc服务报错 panic: context deadline exceeded 问题来源 在使用go-zero生成的rpc项目后 启动不起来 原因 这个问题原因是wndows没有启动etcd 官方文档是删除了etcd配置 而我自己的测试yaml配置有etcd,所以需要启动etcd 下载安装好etcd后,在etcd的安装目录下,打开cmd,.\etcd 启动 然后

Python map以及reduce函数

# -*- coding: utf-8 -*-# 函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式from functools import reducedef normalize(name):name = str.capitalize(name)return namel1 = ['adam', 'LISA', 'barTa']l2 = list(map(no

【Python报错已解决】“ModuleNotFoundError: No module named ‘torch_scatter‘”

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 文章目录 引言:一、问题描述1.1 报错示例:1.2 报错分析:1.3 解决思路: 二、解决方法2.1 方法一:使用pip安装torch_scatter2.2 步骤二:使用conda安装torch_scatter(如果适用) 三、其

Python基础知识(十):高阶函数【map()、reduce()、filter()、lambda、sorted】【高阶函数:可接收其他函数作为参数的函数】

高阶函数:一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归),满足其一则为高阶函数。 一、map函数 map函数接收的是两个参数,一个函数,一个序列,其功能是将序列中的值处理再依次返回至列表内。其返回值为一个迭代器对象–》例如:<map object at 0x00000214EEF40BA8>。其用法如图: 接下来我们看一下map函数

Pytorch:Tensor的高阶操作【where(按条件取元素)、gather(查表取元素)、scatter_(查表取元素)】【可并行计算,提高速度】

一、where:逐个元素按条件选取【并行计算,速度快】 torch.where(condition,x,y) #condition必须是tensor类型 condition的维度和x,y一致,用1和0分别表示该位置的取值 import torchcond = torch.tensor([[0.6, 0.7],[0.3, 0.6]])a = torch.tensor([[1., 1.],[