DeepSpeed 数据效率:一个可组合的库,可以更好地利用数据,提高训练效率并改善模型质量

什么是 DeepSpeed 数据效率:DeepSpeed 数据效率是一个专门构建的库,可以更好地利用数据,提高训练效率并改善模型质量。

为什么要使用 DeepSpeed 数据效率:DeepSpeed 数据效率提供新颖的数据效率技术,以实现更好的训练效率和/或更好的模型质量。DeepSpeed 数据效率考虑了可扩展性、灵活性,可组合性,这使得自定义技术、将技术应用于各种训练任务以及将多种技术组合在一起变得更容易。我们强烈建议您还阅读 我们的博客 以了解有关(高级)我们构建 DeepSpeed 数据效率的原因以及它为用户提供的哪些好处。其他技术细节可以在我们的论文中找到,“Random-LTD: Random and Layerwise Token Dropping Brings Efficient Training for Large-scale Transformers” 描述了 random-LTD 技术,以及 “DeepSpeed Data Efficiency: Improving Deep Learning Model Quality and Training Efficiency via Efficient Data Sampling and Routing” 描述了课程学习技术和整体 DeepSpeed 数据效率框架。

如何使用 DeepSpeed 数据效率:在以下教程中,前两个部分将描述库支持的数据效率技术。第三部分将描述如何组合两种技术以实现更高的训练效率/模型质量。

1. 课程学习

1.1 什么是课程学习

课程学习(由 Yoshua Bengio 等人 提出)旨在通过在训练早期展示相对更容易或更简单的示例来提高训练收敛速度。构建课程学习解决方案通常需要两个组件:难度指标(即如何量化每个数据样本的难度)和步调函数(即如何决定采样下一个训练数据批次时的课程难度范围)。

1.2 何时使用课程学习

课程学习已成功应用于各种训练任务(例如,请参阅 这篇综述论文),去年,我们还发布了一种针对 GPT 样式模型预训练的特定课程学习技术(序列长度预热)(有关技术细节,请参阅我们发表在 NeurIPS 2022 上的论文 “The Stability-Efficiency Dilemma: Investigating Sequence Length Warmup for Training GPT Models” 以及 此旧版课程学习功能的教程)。DeepSpeed 数据效率中的这个新的通用课程学习库使用户能够以最大可扩展性的方式将课程学习应用于他们的模型:用户可以轻松地根据各种可定制策略分析、索引和采样他们的训练数据。使用这个库,我们能够探索用于 GPT-3 和 BERT 预训练的不同 CL 策略,并确定最佳解决方案,该解决方案可以提供高达1.5 倍的数据节省,同时仍然保持相似的模型质量。

1.3 如何使用课程学习

1.3.1 GPT-3 和 BERT 预训练

我们 Megatron-DeepSpeed 仓库 中的 examples_deepspeed/data_efficiency 目录包含我们如何将课程学习应用于 GPT-3 和 BERT 预训练的示例。共有 3 个步骤:数据分析、预训练和评估/微调。

数据分析:课程学习需要在预训练之前进行数据分析,以计算每个数据样本的难度(基于用户提供的指标),并构建一个索引,将难度值映射到相应的数据样本。(存在例外:例如,基于截断的序列长度指标可以通过数据后处理来实现,无需数据分析。)我们提供了一个数据分析器来执行脱机 CPU 仅数据分析。

examples_deepspeed/data_efficiency/gpt/ds_analyze_*.shexamples_deepspeed/data_efficiency/bert/ds_analyze_*.sh 是 GPT-3 和 BERT 数据分析的示例脚本。我们的数据分析器采用简单的 Map-Reduce 方案。首先,在 Map 阶段,使用 ds_analyze_*_data_map.sh 拆分数据集并计算每个数据样本的难度值。用户需要提供一个函数来计算指标(我们在 examples_deepspeed/data_efficiency/analyze_data.py 中实现了我们的指标),原始训练数据集以及其他配置,例如 CPU 节点数和每个节点的线程数。然后,数据分析器将自动根据工作程序数量拆分数据集,以批处理方式计算难度值,并将结果写入两个索引:一个索引将每个数据样本映射到其难度值,另一个索引将每个不同的难度值映射到相应的样本。其次,在 Reduce 阶段,使用 ds_analyze_*_data_reduce.sh 合并所有工作程序生成的索引文件。需要注意的是,为了通过分布式方式实现加速,但仍然能够合并所有输出,Map 阶段可能会生成很多输出文件,这与 CPU 节点数、每个节点的线程数以及可能的指标值数量成正比。因此,为了避免生成过多的输出文件,我们建议从更少的节点/线程数开始(在输出日志中,我们提供了一个估计所需时间,供用户判断他们是否想要增加工作程序数量),我们建议在设计难度指标时限制可能的难度值数量(我们的经验表明,几千个不同的值已经足以享受课程学习的好处)。

预训练 examples_deepspeed/data_efficiency/gpt/pretrainexamples_deepspeed/data_efficiency/bert/pretrain 包含使用课程学习功能的示例预训练脚本。要启用预训练期间的课程学习,需要进行几项更改:(1)用户需要提供一个 DeepSpeed json 配置文件,其中包含课程学习的配置(有关详细信息,请参阅 配置列表)。我们在 examples_deepspeed/data_efficiency/gpt/pretrain/ds_pretrain_gpt_1.3B_dense_run.shexamples_deepspeed/data_efficiency/bert/pretrain/ds_pretrain_bert_336M_run.sh 中提供了经过测试的示例配置。(2)在通过 deepspeed.initialize 初始化 DeepSpeed 引擎时,用户需要提供训练数据集并使用初始化返回的数据加载器(此数据加载器包含课程学习功能)。我们在 megatron/training.py 函数 setup_model_and_optimizer 中提供了此更改的示例实现。(3)如果课程学习指标需要数据后处理(例如基于截断的序列长度),用户需要使用 DeepSpeed 引擎的 set_data_post_process_func API 提供后处理函数。我们在 megatron/training.pypretrain_bert.pypretrain_gpt.py 中提供了此更改的示例实现。(4)如果课程学习指标需要自定义调度策略(步调函数),用户需要使用 DeepSpeed 引擎的 set_custom_curriculum_learning_schedule API 提供一个函数来更新训练期间的最大可接受难度。DeepSpeed 引擎将向此回调函数提供一个全局训练步骤输入。

评估/微调 examples_deepspeed/data_efficiency/gpt/eval/examples_deepspeed/data_efficiency/bert/finetune 包含 GPT-3 模型的零/少样本评估和 BERT 模型的微调示例脚本。我们的 论文 包含参考评估/微调结果,如果您按照我们的示例脚本执行预训练/评估/微调,则会得到这些结果。

1.3.2 GPT-2 微调

我们 DeepSpeedExamples 仓库 中的 data_efficiency/gpt_finetuning 目录包含我们如何将课程学习应用于 GPT-2 微调的示例。 data_efficiency/gpt_finetuning/finetune/ds_finetune_gpt2_run.sh 是示例微调脚本。对于需要数据分析的 CL 指标(例如词汇表稀有性指标),您需要首先使用 data_efficiency/gpt_finetuning/finetune/ds_analyze_gpt_data_* 分析和索引数据集,类似于上面 1.3.1 中描述的 GPT-3 预训练案例。

2. 随机层级标记丢弃 (random-LTD)

2.1 什么是 random-LTD

Random-LTD 是一种高效的标记丢弃方法,应用于每个层,并进行随机分配。准确地说,对于每一层,与基线相比,random-LTD 随机选择标记的子集并将它们馈送到 Transformer 层。之后,我们将 Transformer 层的输出与丢弃的标记组合在一起,以恢复完整的序列长度。因此,下一层仍然接收完整的序列,并可以重复此过程。有关更多技术细节,请阅读 我们的 random-LTD 论文

2.2 何时使用 random-LTD

当您想要对基于 Transformer 的模型进行预训练/微调时,尝试 random-LTD 总是一个好主意,因为它可以在相同计算成本的情况下比标准基线训练实现更好的性能。如果您资源有限,random-LTD 可以在理论上节省高达 33.3% 的成本,并在实际运行时节省高达 25.6% 的时间,并获得与原始基线方法相似的准确性。特别地,如果您需要训练一个具有 >=24 层和 >=2048 序列长度的更大模型,我们的方法将比基线方法效率更高。

2.3 如何使用 random-LTD

2.3.1 GPT-3 和 BERT 预训练

我们 Megatron-DeepSpeed 仓库 中的 examples_deepspeed/data_efficiency 目录包含我们如何将 random-LTD 应用于 GPT-3 和 BERT 预训练的示例。

examples_deepspeed/data_efficiency/gpt/pretrainexamples_deepspeed/data_efficiency/bert/pretrain 包含带有随机-LTD功能的预训练示例脚本。要启用预训练过程中的随机-LTD,需要进行以下更改: (1) 用户需要提供包含随机-LTD配置的 DeepSpeed json 配置文件(有关详细信息,请参阅 配置列表)。我们在 examples_deepspeed/data_efficiency/gpt/pretrain/ds_pretrain_gpt_1.3B_dense_run.shexamples_deepspeed/data_efficiency/bert/pretrain/ds_pretrain_bert_336M_run.sh 中提供了经过测试的示例配置。 (2) 通过 deepspeed.initialize 初始化 DeepSpeed 引擎后,用户需要使用 convert_to_random_ltd API 转换并包装模型层,以启用随机-LTD 功能。我们在 megatron/training.py 函数 setup_model_and_optimizer 中提供了此更改的示例实现。(3) 为了使随机-LTD 能够理解前向函数的输入参数映射,用户需要将所有输入参数(除了 hidden_states 输入)更改为关键字/命名参数。例如,在 megatron/model/transformer.py 中,我们将前向函数从 def forward(self, hidden_states, attention_mask, encoder_output=None, enc_dec_attn_mask=None, layer_past=None, get_key_value=False): 更改为 def forward(self, hidden_states, attention_mask=None, encoder_output=None, enc_dec_attn_mask=None, layer_past=None, get_key_value=False):。(4) 保存模型检查点时(尤其是当状态字典具有非传统结构时),用户需要使用 remove_random_ltd_state_dict API 将随机-LTD 包装的层转换回原始模型层。我们在 megatron/model/language_model.py 中提供了此更改的示例实现。

有关预训练模型的评估/微调,请参阅 上一节,了解如何使用我们的示例脚本。

2.3.2 GPT-2 和 ViT 微调

我们 DeepSpeedExamples 仓库 中的 data_efficiency 目录包含我们如何将随机-LTD 应用于 GPT-2 和 ViT 微调的示例。

与预训练情况类似,启用微调的随机-LTD 也需要类似的更改: (1) DeepSpeed json 配置文件。 (2) 使用 convert_to_random_ltd API 转换并包装模型层。(3) 保存模型检查点时,使用 remove_random_ltd_state_dict API 将随机-LTD 包装的层转换回原始模型层。

您可以通过以下方法运行我们的 GPT 微调示例:

DeepSpeedExamples/data_efficiency/gpt_finetuning$ pip install -r requirement.txt
DeepSpeedExamples/data_efficiency/gpt_finetuning$ bash ./bash_script/run_base_random_ltd.sh
DeepSpeedExamples/data_efficiency/gpt_finetuning$ bash ./bash_script/run_medium_random_ltd.sh

参考最终结果是:

For run_base_random_ltd.sh:
End of training epoch 3 step 1344 consumed_token 2148032 best perplexity 22.552324221233757 time 0.17486039188173083 hr

For run_medium_random_ltd.sh:
End of training epoch 3 step 1373 consumed_token 2147024 best perplexity 17.332243199130996 time 0.4661190489927928 hr

您可以通过以下方法运行我们的 ViT 微调示例:

DeepSpeedExamples/data_efficiency/vit_finetuning$ pip install -r requirement.txt
DeepSpeedExamples/data_efficiency/vit_finetuning$ bash ./bash_script/run_cifar.sh
DeepSpeedExamples/data_efficiency/vit_finetuning$ bash ./bash_script/run_imagenet.sh

参考最终结果是:

For run_cifar.sh:
13 epoch at time 480.6546013355255s | reserved_length 197
iter 5474 | LR [0.0001]| val_acc 97.97000122070312 | layer_token 305784192

3. 将课程学习和 random-LTD 组合起来以实现更多

3.1 GPT-3 和 BERT 预训练

我们 Megatron-DeepSpeed 仓库 中的 examples_deepspeed/data_efficiency 目录包含我们如何组合课程学习随机-LTD 并将其应用于 GPT-3 和 BERT 预训练的示例。

由于 DeepSpeed 数据效率已经处理了组合两种技术的复杂性,因此所需的更改与前两节中描述的相同。但是,需要注意的是,由于随机-LTD 和一些课程学习指标会更改序列长度,因此可能需要一些额外的代码来计算每个步骤的有效序列长度。我们在 megatron/training.py 函数 train 中提供了此更改的示例实现,我们在其中计算了 actual_seq_length

3.2 GPT-2 微调

我们 DeepSpeedExamples 仓库 中的 data_efficiency/gpt_finetuning 目录包含我们如何将课程学习随机-LTD 组合用于 GPT-2 微调的示例。 data_efficiency/gpt_finetuning/finetune/ds_finetune_gpt2_run.sh 是微调示例脚本。

更新: