LLM-分布式训练工具(一):DeepSpeed【微软】【大模型分布式训练工具,实现ZeRO并行训练算法】【zero3配置将模型参数切分后分配到不同的显卡中,突破单张显卡容量不足以加载模型参数的限制】

这篇具有很好参考价值的文章主要介绍了LLM-分布式训练工具(一):DeepSpeed【微软】【大模型分布式训练工具,实现ZeRO并行训练算法】【zero3配置将模型参数切分后分配到不同的显卡中,突破单张显卡容量不足以加载模型参数的限制】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

DeepSpeed是微软推出的大规模模型分布式训练的工具,主要实现了ZeRO并行训练算法。

原始文档链接:

DeepSpeed

一、DeepSpeed目前支持的功能

  1. Optimizer state partitioning (ZeRO stage 1)
  2. Gradient partitioning (ZeRO stage 2)
  3. Parameter partitioning (ZeRO stage 3)
  4. Custom mixed precision training handling
  5. A range of fast CUDA-extension-based optimizers
  6. ZeRO-Offload to CPU and NVMe

二、DeepSpeed的使用

2.1 调用方法

# 单卡的使用方法
deepspeed --num_gpus=1 examples/pytorch/translation/run_translation.py ...
# 单卡,并指定对应的GPU
deepspeed --include localhost:1 examples/pytorch/translation/run_translation.py ...
​
# 多GPU的使用方法1
torch.distributed.run --nproc_per_node=2 your_program.py <normal cl args> --deepspeed ds_config.json
# 多GPU的使用方法2
deepspeed --num_gpus=2 your_program.py <normal cl args> --deepspeed ds_config.json
​
# 多节点多卡方法1,需要在多个节点上手动启动
python -m torch.distributed.run --nproc_per_node=8 --nnode=2 --node_rank=0 --master_addr=hostname1 --master_port=9901 your_program.py <normal cl args> --deepspeed ds_config.json
# 多节点多卡方法2,需要创建一个 hostfile 文件,只需在一个节点上启动
hostname1 slots=8
hostname2 slots=8
# 然后运行
deepspeed --num_gpus 8 --num_nodes 2 --hostfile hostfile --master_addr hostname1 --master_port=9901 your_program.py <normal cl args> --deepspeed ds_config.json
​
# 在SLURM上运行,略,参见原始文档
# 在jupyter中运行,略,参见原始文档

2.2 为什么单卡的情况,也可以使用deepspeed?

  1. 使用ZeRO-offload,将部分数据offload到CPU,降低对显存的需求
  2. 提供了对显存的管理,减少显存中的碎片

2.3 传递参数

TrainingArguments(..., deepspeed="/path/to/ds_config.json")
​
# or
ds_config_dict = dict(scheduler=scheduler_params, optimizer=optimizer_params)
TrainingArguments(..., deepspeed=ds_config_dict)

三、ZeRO中的配置

ZeRO-2

  • 一个配置示例
{
    "fp16": {
        "enabled": "auto",
        "loss_scale": 0,
        "loss_scale_window": 1000,
        "initial_scale_power": 16,
        "hysteresis": 2,
        "min_loss_scale": 1
    },

    "optimizer": {
        "type": "AdamW",
        "params": {
            "lr": "auto",
            "betas": "auto",
            "eps": "auto",
            "weight_decay": "auto"
        }
    },

    "scheduler": {
        "type": "WarmupLR",
        "params": {
            "warmup_min_lr": "auto",
            "warmup_max_lr": "auto",
            "warmup_num_steps": "auto"
        }
    },

    "zero_optimization": {
        "stage": 2,
        "offload_optimizer": {
            "device": "cpu",
            "pin_memory": true
        },
        "allgather_partitions": true,
        "allgather_bucket_size": 2e8,
        "overlap_comm": true,
        "reduce_scatter": true,
        "reduce_bucket_size": 2e8,
        "contiguous_gradients": true
    },

    "gradient_accumulation_steps": "auto",
    "gradient_clipping": "auto",
    "steps_per_print": 2000,
    "train_batch_size": "auto",
    "train_micro_batch_size_per_gpu": "auto",
    "wall_clock_breakdown": false
}
  • overlap_comm:控制是否使用通信与计算的重叠。当设置为True时,DeepSpeed将在梯度计算时尝试并行执行梯度通信。可以有效地减少通信时间,从而加速整个训练过程。
  • allgather_bucket_size:用于控制Allgather操作的分桶大小。Allgather操作是指在分布式训练中,每个进程收集其他所有进程的张量,并将这些张量按顺序拼接起来。通过将张量划分为较小的桶(buckets),可以在通信过程中更高效地传输数据。allgather_bucket_size值越大,每个桶的大小越大,通信操作可能会变得更快,但也需要更多的内存来存储中间结果。合适的桶大小要根据实际情况调整。
  • reduce_bucket_size:类似于allgather_bucket_size,用于控制Allreduce操作的分桶大小。Allreduce操作是将所有进程的某个张量进行规约(例如求和),并将结果广播回所有进程。通过将张量划分为较小的桶,可以更高效地传输数据。reduce_bucket_size值越大,每个桶的大小越大,通信操作可能会变得更快,但同时也需要更多的内存来存储中间结果。合适的桶大小需要根据实际情况进行调整。
  • overlap_comm使用的是allgather_bucket_sizereduce_bucket_size值的4.5倍。如果它们被设置为5e8,需要9GB显存(5e8 x 2Bytes x 2 x 4.5)。如果内存大小是8GB或更小,需要将这些参数减少到约2e8,从而避免OOM,这需要3.6GB显存。如果在大容量GPU上也出现OOM,也需要做同样的调整。
  • 在deepspeed==0.4.4中新增了 round_robin_gradients 选项,可以并行化CPU的offload。当梯度累积的步数增加,或者GPU数量增加时,会有更好的性能优势。

ZeRO-3

  • 一个配置示例
{
    "fp16": {
        "enabled": "auto",
        "loss_scale": 0,
        "loss_scale_window": 1000,
        "initial_scale_power": 16,
        "hysteresis": 2,
        "min_loss_scale": 1
    },

    "optimizer": {
        "type": "AdamW",
        "params": {
            "lr": "auto",
            "betas": "auto",
            "eps": "auto",
            "weight_decay": "auto"
        }
    },

    "scheduler": {
        "type": "WarmupLR",
        "params": {
            "warmup_min_lr": "auto",
            "warmup_max_lr": "auto",
            "warmup_num_steps": "auto"
        }
    },

    "zero_optimization": {
        "stage": 3,
        "offload_optimizer": {
            "device": "cpu",
            "pin_memory": true
        },
        "offload_param": {
            "device": "cpu",
            "pin_memory": true
        },
        "overlap_comm": true,
        "contiguous_gradients": true,
        "sub_group_size": 1e9,
        "reduce_bucket_size": "auto",
        "stage3_prefetch_bucket_size": "auto",
        "stage3_param_persistence_threshold": "auto",
        "stage3_max_live_parameters": 1e9,
        "stage3_max_reuse_distance": 1e9,
        "stage3_gather_16bit_weights_on_model_save": true
    },

    "gradient_accumulation_steps": "auto",
    "gradient_clipping": "auto",
    "steps_per_print": 2000,
    "train_batch_size": "auto",
    "train_micro_batch_size_per_gpu": "auto",
    "wall_clock_breakdown": false
}
  • stage3_max_live_parameters 是保留在 GPU 上的完整参数数量的上限。
  • stage3_max_reuse_distance 是指将来何时再次使用参数的指标,从而决定是丢弃参数还是保留参数。 如果一个参数在不久的将来要再次使用(小于 stage3_max_reuse_distance),可以保留以减少通信开销。 使用activation checkpointing时,这一点非常有用。
  • 如果遇到 OOM,可以减少 stage3_max_live_parameters 和 stage3_max_reuse_distance。 除非正在使用activation checkpointing,否则它们对性能的影响应该很小。 1e9 会消耗 ~2GB。 内存由 stage3_max_live_parameters 和 stage3_max_reuse_distance 共享,所以不是相加的,一共 2GB。
  • stage3_gather_16bit_weights_on_model_save 在保存模型时启用模型 fp16 权重合并。 对大型模型和多GPU,在内存和速度方面都是一项昂贵的操作。 如果打算恢复训练,目前需要使用它。 未来的更新将消除此限制。
  • sub_group_size 控制在optimizer steps中更新参数的粒度。 参数被分组到 sub_group_size 的桶中,每个桶一次更新一个。 当与 ZeRO-Infinity 中的 NVMe offload一起使用时,sub_group_size 控制模型状态在optimizer steps期间从 NVMe 移入和移出 CPU 内存的粒度。 防止超大模型耗尽 CPU 内存。不使用NVMe offload时,使其保持默认值。出现OOM时,减小sub_group_size。当优化器迭代很慢时,可以增大sub_group_size 。
  • ZeRO-3 中未使用 allgather_partitionsallgather_bucket_size 和 reduce_scatter 配置参数

ZeRO-stage-0

  • stage 0会禁用所有的分片,然后把DeepSpeed当作时DDP来使用。
{
    "zero_optimization": {
        "stage": 0
    }
}

ZeRO-stage-1

  • 只对优化器参数进行分片,可以加速一丢丢
{
    "zero_optimization": {
        "stage": 1
    }
}

NVMe Support

  • ZeRO-Infinity 需要使用 ZeRO-3
  • ZeRO-3 会比 ZeRO-2 慢很多。使用以下策略,可以使得ZeRO-3 的速度更接近ZeRO-2
    • stage3_param_persistence_threshold参数设置的很大,比如6 * hidden_size * hidden_size
    • offload_params参数关闭(可以极大改善性能)

如何选择不同的Zero stage和offload

  • 从左到右,越来越慢
    Stage 0 (DDP) > Stage 1 > Stage 2 > Stage 2 + offload > Stage 3 > Stage 3 + offloads
  • 从左到右,所需GPU显存越来越少
    Stage 0 (DDP) < Stage 1 < Stage 2 < Stage 2 + offload < Stage 3 < Stage 3 + offloads

四、调参步骤

  1. batch_size设置为1,通过梯度累积实现任意的有效batch_size
  2. 如果OOM则,设置--gradient_checkpointing 1 (HF Trainer),或者 model.gradient_checkpointing_enable()
  3. 如果OOM则,尝试ZeRO stage 2
  4. 如果OOM则,尝试ZeRO stage 2 + offload_optimizer
  5. 如果OOM则,尝试ZeRO stage 3
  6. 如果OOM则,尝试offload_param到CPU
  7. 如果OOM则,尝试offload_optimizer到CPU
  8. 如果OOM则,尝试降低一些默认参数。比如使用generate时,减小beam search的搜索范围
  9. 如果OOM则,使用混合精度训练,在Ampere的GPU上使用bf16,在旧版本GPU上使用fp16
  10. 如果仍然OOM,则使用ZeRO-Infinity ,使用offload_param和offload_optimizer到NVME
  11. 一旦使用batch_size=1时,没有导致OOM,测量此时的有效吞吐量,然后尽可能增大batch_size
  12. 开始优化参数,可以关闭offload参数,或者降低ZeRO stage,然后调整batch_size,然后继续测量吞吐量,直到性能比较满意(调参可以增加66%的性能)

一些其他建议

    • 如果训模型from scratch,hidden size最好可以被16整除
    • batch size最好可以被2整除

五、优化器和调度器

  • 当不使用offload_optimizer 时,可以按照下表,混合使用HF和DS的优化器和迭代器,除了HF Scheduler和DS Optimizer这一种情况。
Combos HF Scheduler DS Scheduler
HF Optimizer Yes Yes
DS Optimizer No Yes

5.1 优化器

  • 启用 offload_optimizer 时可以使用非 DeepSpeed 的优化器,只要它同时具有 CPU 和 GPU 的实现(LAMB 除外)。
  • DeepSpeed 的主要优化器是 Adam、AdamW、OneBitAdam 和 Lamb。 这些已通过 ZeRO 进行了彻底测试,建议使用。
  • 如果没有在配置文件中配置优化器参数,Trainer 将自动将其设置为 AdamW,并将使用命令行参数的默认值:--learning_rate、--adam_beta1、--adam_beta2、 --adam_epsilon 和 --weight_decay。
  • 与 AdamW 类似,可以配置其他官方支持的优化器。 请记住,它们可能具有不同的配置值。 例如 对于 Adam,需要将 weight_decay 设置为 0.01 左右。
  • 此外,offload在与 Deepspeed 的 CPU Adam 优化器一起使用时效果最佳。 如果想对offload使用不同的优化器,deepspeed==0.8.3 以后的版本,还需要添加:
{
    "zero_force_ds_cpu_optimizer": false
}

5.2 调度器

  • DeepSpeed 支持 LRRangeTest、OneCycle、WarmupLR 和 WarmupDecayLR 学习率调度器。
  • Transformers和DeepSpeed中调度器的overlap
WarmupLR 使用 --lr_scheduler_type constant_with_warmup
WarmupDecayLR 使用 --lr_scheduler_type linear

六、训练精度

  • 由于 fp16 混合精度大大减少了内存需求,并可以实现更快的速度,因此只有在在此训练模式下表现不佳时,才考虑不使用混合精度训练。 通常,当模型未在 fp16 混合精度中进行预训练时,会出现这种情况(例如,使用 bf16 预训练的模型)。 这样的模型可能会溢出,导致loss为NaN。 如果是这种情况,使用完整的 fp32 模式。
  • 如果是基于 Ampere 架构的 GPU,pytorch 1.7 及更高版本将自动切换为使用更高效的 tf32 格式进行某些操作,但结果仍将采用 fp32。
  • 使用 Trainer,可以使用 --tf32 启用它,或使用 --tf32 0 或 --no_tf32 禁用它。 PyTorch 默认值是使用tf32。

自动混合精度

  • fp16
    • 可以使用 pytorch-like AMP 方式或者 apex-like 方式
    • 使用 --fp16--fp16_backend amp 或 --fp16_full_eval 命令行参数时启用此模式
  • bf16
    • 使用--bf16 or --bf16_full_eval 命令行参数时启用此模式

NCCL

  • 通讯会采用一种单独的数据类型
  • 默认情况下,半精度训练使用 fp16 作为reduction操作的默认值
  • 可以增加一个小的开销并确保reduction将使用 fp32 作为累积数据类型
{
    "communication_data_type": "fp32"
}

apex

  • Apex 是一个在 PyTorch 深度学习框架下用于加速训练和提高性能的库。Apex 提供了混合精度训练、分布式训练和内存优化等功能,帮助用户提高训练速度、扩展训练规模以及优化 GPU 资源利用率。
  • 使用--fp16、 --fp16_backend apex、 --fp16_opt_level 01 命令行参数时启用此模式
"amp": {
     "enabled": "auto",
     "opt_level": "auto"
}

七、获取模型参数

  • deepspeed会在优化器参数中存储模型的主参数,存储在global_step*/*optim_states.pt 文件中,数据类型为fp32。因此,想要从checkpoint中恢复训练,则保持默认即可
  • 如果模型是在ZeRO-2模式下保存的,模型参数会以fp16的形式存储在pytorch_model.bin
  • 如果模型是在ZeRO-3模式下保存的,需要如下所示设置参数,否则pytorch_model.bin将不会被创建
{
  "zero_optimization": {
         "stage3_gather_16bit_weights_on_model_save": true
    }
}
  • 在线fp32权重恢复(需要很多的RAM)略
  • 离线获取fp32权重
python zero_to_fp32.py . pytorch_model.bin

ZeRO-3 and Infinity Nuances

  • 构造超大模型(略)
  • 搜集参数(略)

八、ZeRO inference

只有ZeRO-3是有意义的,因为可以将参数分片:

deepspeed --num_gpus=2 your_program.py <normal cl args> --do_eval --deepspeed ds_config.json

九、估算需要的显存

可以通过下面的代码,先估算不同配置需要的显存数量,从而决定开始尝试的ZeRO stage。

python -c 'from transformers import AutoModel; \
from deepspeed.runtime.zero.stage3 import estimate_zero3_model_states_mem_needs_all_live; \
model = AutoModel.from_pretrained("bigscience/T0_3B"); \
estimate_zero3_model_states_mem_needs_all_live(model, num_gpus_per_node=2, num_nodes=1)'
[...]
Estimated memory needed for params, optim states and gradients for a:
HW: Setup with 1 node, 2 GPUs per node.
SW: Model with 2783M total params, 65M largest layer params.
  per CPU  |  per GPU |   Options
 70.00GB |   0.25GB | offload_param=cpu , offload_optimizer=cpu , zero_init=1
 70.00GB |   0.25GB | offload_param=cpu , offload_optimizer=cpu , zero_init=0
 62.23GB |   2.84GB | offload_param=none, offload_optimizer=cpu , zero_init=1
 62.23GB |   2.84GB | offload_param=none, offload_optimizer=cpu , zero_init=0
 0.74GB |  23.58GB | offload_param=none, offload_optimizer=none, zero_init=1
 31.11GB |  23.58GB | offload_param=none, offload_optimizer=none, zero_init=0

十、可能遇到的问题

  • 启动时,进程被杀死,并且没有打印出traceback:CPU显存不够
  • loss是NaN:训练时用的是bf16,使用时是fp16。常常发生于google在TPU上train的模型,如T5。此时需要使用fp32或者bf16。

如果觉得本文有帮助,欢迎点赞收藏评论转发。也欢迎关注同名公众号【JOYWIN】,获取第一手更新文章。




deepspeed入门教程 - 知乎

微软DeepSpeed Chat,人人可快速训练百亿、千亿级ChatGPT大模型

【自然语言处理】【大模型】DeepSpeed+Transformers:简单快捷上手百亿参数模型微调 - 知乎文章来源地址https://www.toymoban.com/news/detail-589181.html

到了这里,关于LLM-分布式训练工具(一):DeepSpeed【微软】【大模型分布式训练工具,实现ZeRO并行训练算法】【zero3配置将模型参数切分后分配到不同的显卡中,突破单张显卡容量不足以加载模型参数的限制】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 大模型学习笔记08——分布式训练

    模型规模的扩大,对硬件(算力、内存)的发展提出要求。然而,因为内存墙的存在,单一设备的算力及容量,受限于物理定律,持续提高芯片的集成越来越困难,难以跟上模型扩大的需求。 为了解决算力增速不足的问题,人们考虑用多节点集群进行分布式训练,以提升算力

    2024年01月23日
    浏览(46)
  • 语言大模型的分布式训练与高效微调指南

    原文:语言大模型的分布式训练与高效微调指南 - 知乎 目录 收起 1 分布式训练 2 ZeRO驱动的数据并行 3 全分片数据并行 4 实现 5 高效微调 6 实践指南 7 关于DeepSpeed和FSDP的更多内容 OneFlow编译 翻译|杨婷、宛子琳 最近语言大模型(LLM)异常火爆,一个非常特别的开源社区正在

    2024年01月18日
    浏览(51)
  • LLMs开源模型们的分布式训练和量化

    前一篇博文整理了: LLMs开源模型们和数据集简介 这篇博文主要整理一下目前流行的训练方法和量化。 (图自Towards a Unified View of Parameter-Efficient Transfer Learning) 使通用LLMs适应下游任务的最常见方法是微调所有模型参数或微调尾层参数(Freeze)。然而这会导致每个任务都有一

    2024年02月07日
    浏览(48)
  • 如何借助分布式存储 JuiceFS 加速 AI 模型训练

    传统的机器学习模型,数据集比较小,模型的算法也比较简单,使用单机存储,或者本地硬盘就足够了,像 JuiceFS 这样的分布式存储并不是必需品。 随着近几年深度学习的蓬勃发展,越来越多的团队开始遇到了单机存储的瓶颈,分布式存储在 AI 领域的重要性不断凸显。AI 团

    2023年04月26日
    浏览(42)
  • TensorFlow 高级技巧:自定义模型保存、加载和分布式训练

    本篇文章将涵盖 TensorFlow 的高级应用,包括如何自定义模型的保存和加载过程,以及如何进行分布式训练。 在 TensorFlow 中,我们可以通过继承 tf.train.Checkpoint 来自定义模型的保存和加载过程。 以下是一个例子: TensorFlow 提供了 tf.distribute.Strategy API,让我们可以在不同的设备

    2024年02月15日
    浏览(37)
  • 用通俗易懂的方式讲解大模型分布式训练并行技术:MOE并行

    前面的文章中讲述了数据并行、流水线并行、张量并行、序列并行、自动并行等多种并行技术。但现在的模型越来越大,训练样本越来越多,每个样本都需要经过模型的全部计算,这就导致了训练成本的平方级增长。 而当我们希望在牺牲极少的计算效率的情况下,把模型规模

    2024年02月02日
    浏览(67)
  • 工具系列:PyCaret介绍_Fugue 集成_Spark、Dask分布式训练

    Fugue 是一个低代码的统一接口,用于不同的计算框架,如 Spark、Dask。PyCaret 使用 Fugue 来支持分布式计算场景。 让我们从最标准的例子开始,代码与本地版本完全相同,没有任何魔法。 compare_model 如果您不想使用分布式系统,也完全相同。 现在让我们将其分布式,作为一个玩

    2024年02月04日
    浏览(51)
  • 【深入了解PyTorch】PyTorch分布式训练:多GPU、数据并行与模型并行

    在深度学习领域,模型的复杂性和数据集的巨大规模使得训练过程变得极具挑战性。为了加速训练过程,利用多个GPU进行并行计算是一种常见的方法。PyTorch作为一种流行的深度学习框架,提供了强大的分布式训练工具,使得多GPU、数据并行和模型并行等技术变得更加容易实现

    2024年02月12日
    浏览(42)
  • 【金猿案例展】智谱AI——基于全闪分布式并行文件存储打造高速大模型训练平台...

    ‍ 焱融科技案例 本项目案例由焱融科技投递并参与“数据猿年度金猿策划活动——2023大数据产业年度创新服务企业榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 · 改变商业 自 ChatGPT 爆火以来,中国的 AI 产业已经进入名副其实的“百模大战”。《中国人工智能

    2024年02月02日
    浏览(51)
  • 【分布式·大数据】大模型赛道如何实现华丽的弯道超车 —— AI/ML训练赋能解决方案

    导读 :Alluxio作为一款强大的分布式统一大数据虚拟文件系统,已经在众多领域展现出了其卓越的应用价值,并且为AI/ML训练赋能提供了一个全新的解决方案。 在人工智能(AI)和机器学习(ML)领域,数据驱动的决策和模型训练已成为现代应用和研究的核心。伴随大模型技术

    2024年02月08日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包