Accelerate 文档
FSDP vs DeepSpeed
并获得增强的文档体验
开始使用
FSDP vs DeepSpeed
Accelerate 通过集成两个极其强大的分布式训练工具(即 Pytorch FSDP 和 Microsoft DeepSpeed)提供了训练框架的灵活性。本教程旨在对比和概述潜在的差异,使用户能够在这两个框架之间无缝切换。
为了在这两个框架之间切换,我们建议启动代码 accelerate launch
,并通过 --config_file
传入正确的配置文件,或者直接为 FSDP 和 DeepSpeed 传入相应的参数。
Accelerate 配置示例可以在 DeepSpeed 和 FSDP 的文档中找到,或者在 示例库的“启动配置” 下找到。
本教程仅适用于单节点、多 GPU 场景。
配置功能
模型张量被拆分到不同的 GPU 中,以尝试扩大模型尺寸;这在 FSDP 中称为分片,在 DeepSpeed 中称为分区。FSDP 分片和 DeepSpeed ZeRO(分区)阶段分别通过 --fsdp_sharding_strategy
和 --zero_stage
进行配置。特别是,FSDP FULL_SHARD
映射到 DeepSpeed ZeRO 阶段 3
;请参阅 FSDP 分片和 DeepSpeed ZeRO 设置之间的全面映射。下表总结并分组了相似的设置
组 | 框架 | 配置 | 示例 | 限制(如果有) |
---|---|---|---|---|
分片/分区 | FSDP DeepSpeed | --fsdp_sharding_strategy --zero_stage | 1 (FULL_SHARD )3 | |
卸载 | FSDP DeepSpeed | --fsdp_offload_params --offload_param_device --offload_optimizer_device | true cpu cpu | 全部或全无 |
模型加载 | FSDP DeepSpeed | --fsdp_cpu_ram_efficient_loading --zero3_init_flag | true true | 仅 ZeRO 3 |
高效检查点 | FSDP DeepSpeed | --fsdp_state_dict_type --zero3_save_16bit_model | SHARDED_STATE_DICT true | 仅 ZeRO 3 |
权重预取 | FSDP DeepSpeed | --fsdp_forward_prefetch --fsdp_backward_prefetch None | true BACKWARD_PRE | |
模型 | FSDP DeepSpeed | --fsdp_auto_wrap_policy --fsdp_transformer_layer_cls_to_wrap None | TRANSFORMER_BASED_WRAP <层类> | 通常不需要 对用户透明。 |
参数召唤 | FSDP DeepSpeed | --fsdp_use_orig_params None | true | torch.compile 所需对用户透明 |
参数同步 | FSDP DeepSpeed | --fsdp_sync_module_states None | true | |
训练 | FSDP DeepSpeed | None--gradient_accumulation_steps --gradient_clipping | auto auto | 对用户透明 |
有关上述内容的详细描述,请参阅 Accelerate
启动文档。
要访问其他 DeepSpeed 配置,例如混合精度设置,您需要传入 --deepspeed_config_file
,请参阅文档。
DeepSpeed 也可以通过 DeepSpeedPlugin 进行配置,例如,DeepSpeedPlugin.zero_stage
等效于 --zero_stage
,DeepSpeedPlugin.hf_ds_config
可用于传递 --deepeed_config_file.
。
FSDP 也可以通过 FullyShardedDataParallelPlugin 进行配置,例如,FullyShardedDataParallelPlugin.sharding_strategy
等效于 --fsdp_sharding_strategy
。
检查点
请注意,虽然可以通过 --fsdp_state_dict_type
配置 FSDP 以保存完整/分片检查点。
对于 DeepSpeed Zero3,可以传递 --zero3_save_16bit_model true
,这将方便地将模型整合到单个 rank 并保存;这相当于 FSDP 的 fsdp_state_dict_type: FULL_STATE_DICT
。
对于大型模型,将模型整合到单个 rank 可能会非常慢。
为了更快地进行检查点,对于 FSDP,请使用 fsdp_state_dict_type: SHARDED_STATE_DICT
,对于 DeepSpeed Zero3,请使用 zero_to_fp32.py
脚本来后转换分片检查点。
卸载
FSDP 仅允许全部或全无卸载(即,要么卸载参数、梯度和优化器,要么将它们全部保留在 GPU 中),但 DeepSpeed 可以不同地卸载参数和优化器。此外,DeepSpeed 还支持 卸载到 NVME。
预取
FSDP 允许两种预取配置 --fsdp_forward_prefetch
和 --fsdp_backward_prefetch
,以改善通信/计算的重叠,但会以额外的内存为代价,请参阅 FSDP 文档。对于 DeepSpeed,预取将在需要时开启,并且它会根据某些超参数(如 stage3_param_persistence_threshold
、stage3_max_reuse_distance
等)开启,这些超参数可以为 Zero3 配置;如果您没有在 DeepSpeed 配置文件中显式设置这些超参数,则 accelerate
可能会自动设置它们。
对于 FSDP,如果内存允许,请设置 fsdp_backward_prefetch: BACKWARD_PRE
以提高吞吐量。
模型加载
虽然 FSDP 需要显式的 --fsdp_cpu_ram_efficient_loading true
来激活高效的模型加载,但只要使用 DeepSpeed Zero3,transformers
就会激活类似的功能。
对于 FSDP,每当设置 --fsdp_cpu_ram_efficient_loading true
时,accelerate
将自动将 sync_module_states
设置为 true。对于 RAM 高效加载,权重将仅在单个 rank 中加载,因此需要 sync_module_states
将权重广播到其他 rank。
模型
FSDP 需要显式的 --fsdp_auto_wrap_policy
,以便算法决定如何调度 all-gather 和 reduce-scatter 操作。但对于 DeepSpeed,这对用户是透明的。
对于 FSDP,只需设置 fsdp_auto_wrap_policy: TRANSFORMER_BASED_WRAP
。在最新的 transformers
版本中,我们尽力找出适用于 HF transformers 模型的 fsdp_transformer_layer_cls_to_wrap
。但是,如果您收到有关它的错误,请指定此项。
参数召唤
如果使用 torch.compile
,FSDP 需要显式的 --fsdp_use_orig_params
标志,请参阅 pytorch 文档。对于 DeepSpeed,这对用户是透明的。
对于 FSDP,当使用 torch.compile
时,请设置 fsdp_use_orig_params: True
。
训练
Deepspeed 需要显式的 --gradient_accumulation_steps
和 --gradient_clipping
标志。对于 FSDP,这对用户是透明的。
当使用 DeepSpeed 时,设置 gradient_accumulation_steps: "auto"
和 gradient_clipping: "auto"
以自动拾取在 加速器 (Accelerator) 或 TrainingArguments
(如果使用 transformers
)中设置的值。
关于数据精度处理的差异
为了讨论 FSDP 和 DeepSpeed 中如何处理数据精度,首先概述这些框架中如何处理模型参数是有益的。在模型/优化器参数跨 GPU 分布之前,需要进行参数准备,首先将它们“展平”为一维 torch.Tensor
。FSDP/DeepSpeed 的实现在存储这些“展平”参数的 dtype
方面有所不同,并且在 torch.Optimizer
如何分配其 dtype
方面存在影响。下表概述了这两个框架的过程;“本地”列指示每个 GPU 级别发生的过程,因此,通过向上转换引起的任何内存开销都应理解为通过使用的 GPU 数量来摊销。
根据经验,为了使用自动混合精度进行稳定训练,所有可训练参数都必须在 torch.float32
中。
过程 | 本地 | 框架 | 详情 |
---|---|---|---|
加载,即 AutoModel.from_pretrained(..., torch_dtype=torch_dtype) | |||
准备,即创建“展平参数” | ✅ | FSDP DeepSpeed | 在 torch_dtype 中创建。忽略 torch_dtype ,在 float32 中创建。 |
优化器初始化 | ✅ | FSDP DeepSpeed | 在 torch_dtype 中创建参数在 float32 中创建参数 |
训练步骤,即前向、后向、缩减 | FSDP DeepSpeed | 遵循 MixedPrecision 遵循 deepspeed_config_file 混合精度设置。 | |
优化器(预步骤) | ✅ | FSDP DeepSpeed | 向上转换(如果有)到 torch_dtype 向上转换为 float32 |
优化器(实际步骤) | ✅ | FSDP DeepSpeed | 在 torch_dtype 中发生在 float32 中发生。 |
因此,当使用 DeepSpeed 且 GPU 数量较少时,请注意由于准备期间的向上转换而可能产生的显著内存开销。
使用 FSDP,在没有混合精度的情况下,可以在低精度 torch_dtype
中操作 torch.Optimizer
,这在使用少量 GPU 时可能很有用。
使用混合精度时,FSDP 和 DeepSpeed 将在模型准备步骤中进行向上转换(参见上表)。但请注意,FSDP 随后将以向上转换的精度保存检查点;如果指定了 --zero3_save_16bit_model
,DeepSpeed 仍可能保存低精度检查点。
为了澄清上表,请考虑以下具体示例;为简洁起见,优化器预步骤和实际步骤合并在一起。使用 FSDP 可以在下面显示的两种模式下运行,但 DeepSpeed 只能在一种模式下运行。
框架 | 模型加载 (torch_dtype ) | 混合精度 | 准备(本地) | 训练 | 优化器(本地) |
---|---|---|---|---|---|
FSDP | bf16 | 默认(无) | bf16 | bf16 | bf16 |
FSDP | bf16 | bf16 | fp32 | bf16 | fp32 |
DeepSpeed | bf16 | bf16 | fp32 | bf16 | fp32 |