Transformers 4.37 中文文档(十九)(6)

简介: Transformers 4.37 中文文档(十九)

Transformers 4.37 中文文档(十九)(5)https://developer.aliyun.com/article/1564926


NVMe 支持

ZeRO-Infinity 通过使用 NVMe 内存扩展 GPU 和 CPU 内存,允许训练非常大的模型。由于智能分区和平铺算法,每个  GPU 在卸载期间需要发送和接收非常少量的数据,因此现代 NVMe 被证明适合允许更大的总内存池可用于您的训练过程。ZeRO-Infinity  需要启用 ZeRO-3。

以下配置示例启用了 NVMe 以卸载优化器状态和参数:

{
    "zero_optimization": {
        "stage": 3,
        "offload_optimizer": {
            "device": "nvme",
            "nvme_path": "/local_nvme",
            "pin_memory": true,
            "buffer_count": 4,
            "fast_init": false
        },
        "offload_param": {
            "device": "nvme",
            "nvme_path": "/local_nvme",
            "pin_memory": true,
            "buffer_count": 5,
            "buffer_size": 1e8,
            "max_in_cpu": 1e9
        },
        "aio": {
            "block_size": 262144,
            "queue_depth": 32,
            "thread_count": 1,
            "single_submit": false,
            "overlap_events": 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
    },
}

您可以选择将优化器状态和参数都卸载到 NVMe,或者只卸载其中一个或两者都不卸载。例如,如果您有大量的 CPU 内存可用,尽管将其仅卸载到 CPU 内存,因为这样会更快(提示:“device”: “cpu”)。

这里是有关卸载优化器状态参数的完整文档。

确保您的nvme_path实际上是一个 NVMe,因为它可以与普通硬盘或固态硬盘一起使用,但速度会慢得多。快速可扩展的训练是根据现代 NVMe 传输速度设计的(截至本文撰写时,读取速度约为 3.5GB/s,写入速度约为 3GB/s)。

为了找出最佳的aio配置块,您必须在目标设置上运行基准测试,如此处所述

ZeRO-2 与 ZeRO-3 性能

如果一切配置相同,ZeRO-3 可能比 ZeRO-2 慢,因为前者需要收集模型权重以外的内容。如果 ZeRO-2  满足您的需求,并且您不需要扩展到几个 GPU 之外,那么您可以选择坚持使用它。重要的是要了解,ZeRO-3  在速度上的代价是实现更高的可伸缩性容量。

可以调整 ZeRO-3 配置,使其性能接近 ZeRO-2:

  • stage3_param_persistence_threshold设置为一个非常大的数字 - 大于最大参数,例如6 * hidden_size * hidden_size。这将使参数保留在 GPU 上。
  • 关闭offload_params,因为 ZeRO-2 没有该选项。

即使您不更改stage3_param_persistence_threshold,只要关闭offload_params,性能可能会显着提高。当然,这些更改将影响您可以训练的模型大小。因此,这些帮助您根据需要在可伸缩性和速度之间进行权衡。

ZeRO-2 示例

这里是一个完整的 ZeRO-2 自动配置文件ds_config_zero2.json

{
    "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
}

这里是一个完整的 ZeRO-2 全启用手动设置的配置文件。这里主要是让您看看典型值是什么样的,但我们强烈建议使用其中带有多个auto设置的配置文件。

{
    "fp16": {
        "enabled": true,
        "loss_scale": 0,
        "loss_scale_window": 1000,
        "initial_scale_power": 16,
        "hysteresis": 2,
        "min_loss_scale": 1
    },
    "optimizer": {
        "type": "AdamW",
        "params": {
            "lr": 3e-5,
            "betas": [0.8, 0.999],
            "eps": 1e-8,
            "weight_decay": 3e-7
        }
    },
    "scheduler": {
        "type": "WarmupLR",
        "params": {
            "warmup_min_lr": 0,
            "warmup_max_lr": 3e-5,
            "warmup_num_steps": 500
        }
    },
    "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
    },
    "steps_per_print": 2000,
    "wall_clock_breakdown": false
}
ZeRO-3 示例

这里是一个完整的 ZeRO-3 自动配置文件ds_config_zero3.json

{
    "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
}

这里是一个完整的 ZeRO-3 全启用手动设置的配置文件。这里主要是让您看看典型值是什么样的,但我们强烈建议使用其中带有多个auto设置的配置文件。

{
    "fp16": {
        "enabled": true,
        "loss_scale": 0,
        "loss_scale_window": 1000,
        "initial_scale_power": 16,
        "hysteresis": 2,
        "min_loss_scale": 1
    },
    "optimizer": {
        "type": "AdamW",
        "params": {
            "lr": 3e-5,
            "betas": [0.8, 0.999],
            "eps": 1e-8,
            "weight_decay": 3e-7
        }
    },
    "scheduler": {
        "type": "WarmupLR",
        "params": {
            "warmup_min_lr": 0,
            "warmup_max_lr": 3e-5,
            "warmup_num_steps": 500
        }
    },
    "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": 1e6,
        "stage3_prefetch_bucket_size": 0.94e6,
        "stage3_param_persistence_threshold": 1e4,
        "stage3_max_live_parameters": 1e9,
        "stage3_max_reuse_distance": 1e9,
        "stage3_gather_16bit_weights_on_model_save": true
    },
    "steps_per_print": 2000,
    "wall_clock_breakdown": false
}
如何选择最佳性能的 ZeRO 阶段和卸载方式

现在您知道有所有这些不同的阶段。如何决定使用其中哪一个?本节将尝试回答这个问题。

一般来说,以下内容适用:

  • 速度方面(左边比右边快)

阶段 0(DDP)> 阶段 1 > 阶段 2 > 阶段 2 + 卸载 > 阶段 3 > 阶段 3 + 卸载

  • GPU 内存使用方面(右侧比左侧更节省 GPU 内存)

阶段 0(DDP)<阶段 1<阶段 2<阶段 2 +卸载<阶段 3<阶段 3 +卸载

因此,当您希望在最少数量的 GPU 中获得最快的执行时,请按照以下过程进行。我们从最快的方法开始,如果遇到 GPU OOM,则转向下一个较慢的方法,但将使用更少的 GPU 内存。依此类推。

首先将批处理大小设置为 1(您始终可以使用梯度累积来获得任何所需的有效批处理大小)。

  1. 启用--gradient_checkpointing 1(HF Trainer)或直接model.gradient_checkpointing_enable()-如果 OOM,则
  2. 首先尝试 ZeRO 阶段 2。如果 OOM,则
  3. 尝试 ZeRO 阶段 2 + offload_optimizer-如果 OOM,则
  4. 切换到 ZeRO 阶段 3-如果 OOM,则
  5. 启用offload_paramcpu-如果 OOM,则
  6. 启用offload_optimizercpu-如果 OOM,则
  7. 如果您仍然无法适应批处理大小为 1,请首先检查各种默认值,并在可能的情况下将其降低。例如,如果您使用generate,并且不使用宽搜索光束,请将其变窄,因为这将占用大量内存。
  8. 绝对使用混合半精度而不是 fp32-因此在 Ampere 及更高 GPU 上使用 bf16,在旧的 GPU 架构上使用 fp16。
  9. 如果您仍然 OOM,您可以添加更多硬件或启用 ZeRO-Infinity-即切换卸载offload_paramoffload_optimizernvme。您需要确保它是一个非常快速的 nvme。作为一个轶事,我能够在一个小型 GPU 上推断 BLOOM-176B,使用 ZeRO-Infinity,只是速度极慢。但它有效!

当然,您可以通过从最 GPU 内存高效的配置开始,然后向后进行,或者尝试二分法来逆向执行这些步骤。

一旦您的批处理大小为 1 不会导致 OOM,请测量您的有效吞吐量。

接下来尝试将批处理大小增加到尽可能大,因为批处理大小越大,GPU 的效率就越高,因为它们在乘法矩阵很大时表现最佳。

现在性能优化游戏开始了。您可以关闭一些卸载功能或降低 ZeRO 阶段,并增加/减少批处理大小,然后再测量您的有效吞吐量。反复进行,直到满意为止。

不要花太多时间在上面,但如果您即将开始为期 3  个月的培训-请花几天时间找到最有效的吞吐量设置。这样,您的培训成本将最低,您将更快地完成培训。在当前快节奏的 ML  世界中,如果您需要额外一个月来训练某些内容,您很可能会错过一个绝佳的机会。当然,这只是我分享的一个观察,我绝不会催促您。在开始训练  BLOOM-176B 之前,我花了 2 天时间进行这个过程,并且能够将吞吐量从 90 提高到 150  TFLOPs!这一努力为我们节省了一个多月的培训时间。

这些注意事项主要是针对训练模式编写的,但它们在推断方面也应该大多适用。例如,在推断期间,梯度检查点是无效的,因为它只在训练期间有用。此外,我们发现,如果您正在进行多 GPU 推断并且不使用DeepSpeed-InferenceAccelerate应该提供更优越的性能。

其他快速相关的性能注意事项:

  • 如果您正在从头开始训练某些内容,请始终尝试具有可被 16 整除的张量形状(例如隐藏大小)。对于批处理大小,请至少尝试可被 2 整除。如果您想从 GPU 中挤取更高的性能,则有硬件特定的波和瓷砖量化可被整除。

激活检查点或梯度检查点

激活检查点和梯度检查点是指同一方法的两个不同术语。这很令人困惑,但事实就是如此。

梯度检查点允许将速度换成 GPU 内存,这样可以克服 GPU OOM,或者增加批量大小,通常会带来更好的性能。

HF Transformers 模型对 DeepSpeed 的激活检查点一无所知,因此如果您尝试在 DeepSpeed 配置文件中启用该功能,将不会发生任何事情。

因此,您有两种方法可以利用这个非常有益的功能:

  1. 如果您想使用 HF Transformers 模型,可以使用 model.gradient_checkpointing_enable() 或在 HF Trainer 中使用 --gradient_checkpointing,这将自动为您启用此功能。在那里使用 torch.utils.checkpoint
  2. 如果您编写自己的模型并希望使用 DeepSpeed 的激活检查点,可以使用那里规定的 API。您还可以使用 HF Transformers 建模代码,并将 torch.utils.checkpoint 替换为 DeepSpeed 的 API。后者更灵活,因为它允许您将前向激活卸载到 CPU 内存,而不是重新计算它们。

优化器和调度器

只要不启用 offload_optimizer,您可以混合使用 DeepSpeed 和 HuggingFace 调度器和优化器。

在启用 offload_optimizer 时,可以使用非 DeepSpeed 优化器,只要它具有 CPU 和 GPU 实现(除了 LAMB)。

优化器

DeepSpeed 的主要优化器是 Adam、AdamW、OneBitAdam 和 Lamb。这些已经通过 ZeRO 进行了彻底测试,因此建议使用它们。但是,它可以从 torch 导入其他优化器。完整文档在这里

如果您在配置文件中不配置 optimizer 条目,Trainer 将自动将其设置为 AdamW,并将使用提供的值或以下命令行参数的默认值:--learning_rate--adam_beta1--adam_beta2--adam_epsilon--weight_decay

这是 AdamW 的自动配置的 optimizer 条目的示例:

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

请注意,命令行参数将设置配置文件中的值。这样一来,就有了一个明确的值来源,避免了例如学习率在不同地方设置为不同值时难以找到的错误。命令行规则。被覆盖的值包括:

  • lr 的值为 --learning_rate
  • betas 的值为 --adam_beta1 --adam_beta2
  • eps 的值为 --adam_epsilon
  • weight_decay 的值为 --weight_decay

因此,请记住在命令行上调整共享的超参数。

您还可以显式设置这些值:

{
   "optimizer": {
       "type": "AdamW",
       "params": {
         "lr": 0.001,
         "betas": [0.8, 0.999],
         "eps": 1e-8,
         "weight_decay": 3e-7
       }
   }
}

但是,您需要自行同步 Trainer 命令行参数和 DeepSpeed 配置。

如果要使用上面未列出的其他优化器,则必须添加到顶级配置。

{
   "zero_allow_untested_optimizer": true
}

AdamW 类似,您可以配置其他官方支持的优化器。只需记住,这些可能具有不同的配置值。例如,对于 Adam,您将希望 weight_decay 大约为 0.01

此外,当与 Deepspeed 的 CPU Adam 优化器一起使用时,卸载效果最佳。如果要使用不同的优化器进行卸载,自 deepspeed==0.8.3 以来,您还需要添加:

{
   "zero_force_ds_cpu_optimizer": false
}

到顶级配置。


Transformers 4.37 中文文档(十九)(7)https://developer.aliyun.com/article/1564928

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
5月前
|
存储 PyTorch 算法框架/工具
Transformers 4.37 中文文档(十九)(4)
Transformers 4.37 中文文档(十九)
273 2
|
5月前
|
存储 PyTorch 网络安全
Transformers 4.37 中文文档(十九)(5)
Transformers 4.37 中文文档(十九)
95 2
|
5月前
|
存储 机器学习/深度学习 异构计算
Transformers 4.37 中文文档(十九)(8)
Transformers 4.37 中文文档(十九)
195 2
|
5月前
|
存储 PyTorch API
Transformers 4.37 中文文档(十九)(2)
Transformers 4.37 中文文档(十九)
340 1
|
5月前
|
存储 PyTorch 算法框架/工具
Transformers 4.37 中文文档(十九)(3)
Transformers 4.37 中文文档(十九)
44 1
|
5月前
|
并行计算 PyTorch 调度
Transformers 4.37 中文文档(十九)(1)
Transformers 4.37 中文文档(十九)
122 1
|
5月前
|
存储
Transformers 4.37 中文文档(十五)(2)
Transformers 4.37 中文文档(十五)
71 1
|
5月前
|
存储 自然语言处理
Transformers 4.37 中文文档(十五)(3)
Transformers 4.37 中文文档(十五)
81 1
|
5月前
|
存储 PyTorch TensorFlow
Transformers 4.37 中文文档(二十)(1)
Transformers 4.37 中文文档(二十)
86 2
|
5月前
|
PyTorch 算法框架/工具 异构计算
Transformers 4.37 中文文档(二十)(5)
Transformers 4.37 中文文档(二十)
39 2