如何使用 Megatron-LM 训练语言模型

如何使用 Megatron-LM 训练语言模型

如何使用 Megatron-LM 训练语言模型

原创 Hugging Face  2023年05月29日 17:59 广东

在 PyTorch 中训练大语言模型不仅仅是写一个训练循环这么简单。我们通常需要将模型分布在多个设备上,并使用许多优化技术以实现稳定高效的训练。Hugging Face 🤗 Accelerate 的创建是为了支持跨 GPU 和 TPU 的分布式训练,并使其能够非常容易的集成到训练代码中。🤗 Transformers 还支持使用 Trainer API 来训练,其在 PyTorch 中提供功能完整的训练接口,甚至不需要自己编写训练的代码。

Megatron-LM 是研究人员用于预训练大型 Transformer 模型的另一个流行工具,它是 NVIDIA 应用深度学习研究团队开发的一个强大框架。与 accelerateTrainer 不同,Megatron-LM 使用起来并不简单,对于初学者来说可能难以上手。但它针对 GPU 上的训练进行了高度优化。在这篇文章中,你将学习如何使用 Megatron-LM 框架在 NVIDIA GPU 上训练语言模型,并将其与 transformers 结合。

我们将分解在此框架中训练 GPT2 模型的不同步骤,包括:

环境设置

数据预处理

训练

将模型转化为 🤗 Transformers

为什么选择 Megatron-LM?

在进入训练细节的讲解之前,让我们首先了解是什么让这个框架比其他框架更高效。本节的灵感来自这篇关于使用 Megatron-DeepSpeed 进行 BLOOM 训练的精彩 博客,请参阅该博客以获取更多详细信息,因为该博客旨在对 Megatron-LM 进行详细的介绍。

数据加载

Megatron-LM 带有一个高效的 DataLoader,其中数据在训练前被 tokenize 和 shuffle。它还将数据拆分为带有索引的编号序列,并将索引存储,因此 tokenize 只需要计算一次。为了构建索引,首先根据训练参数计算每个 epoch 的数量,并创建一个排序,然后对数据进行 shuffle 操作。这与大多数情况不同,我们通常迭代整个数据集直到其用尽,然后重复第二个 epoch 。这平滑了学习曲线并节省了训练时间。

融合 CUDA 内核

当一个计算在 GPU 上运行时,必要的数据会从内存中取出并加载到 GPU 上,然后计算结果被保存回内存。简单来说,融合内核的思想是: 将通常由 PyTorch 单独执行的类似操作组合成一个单独的硬件操作。因此可以将多个离散计算合并为一个,从而减少在多个离散计算中的内存移动次数。下图说明了内核融合的思想。它的灵感来自这篇 论文,该论文详细讨论了这个概念。

www.zeeklog.com  - 如何使用 Megatron-LM 训练语言模型

当 f、g 和 h 融合在一个内核中时,f 和 g 的中间结果 x' 和 y' 存储在 GPU 寄存器中并立即被 h 使用。但是如果不融合,x' 和 y' 就需要复制到内存中,然后由 h 加载。因此,融合 CUDA 内核显着加快了计算速度。此外,Megatron-LM 还使用 Apex 的 AdamW 融合实现,它比 PyTorch 实现更快。

虽然我们可以在 transformers 中自定义 Megatron-LM 中的 DataLoader 和 Apex 的融合优化器,但自定义融合 CUDA 内核对新手来说太不友好了。

现在你已经熟悉了该框架及其优势,让我们进入训练细节吧!

如何使用 Megatron-LM 框架训练?

环境设置

设置环境的最简单方法是从 NGC 拉取附带所有所需环境的 NVIDIA PyTorch 容器。有关详细信息,请参阅 文档。如果你不想使用此容器,则需要安装最新的 pytorch、cuda、nccl 和 NVIDIA APEX 版本和 nltk 库。

在安装完 Docker 之后,你可以使用以下命令运行容器 (xx.xx 表示你的 Docker 版本),然后在其中克隆 Megatron-LM 库:

docker run --gpus all -it --rm nvcr.io/nvidia/pytorch:xx.xx-py3
git clone https://github.com/NVIDIA/Megatron-LM

你还需要在容器的 Megatron-LM 文件夹中添加分词器的词汇文件 vocab.json 和合并表 merges.txt。这些文件可以在带有权重的模型仓库中找到,请参阅 GPT2 库。你还可以使用 transformers 训练自己的分词器。你可以查看 CodeParrot 项目 以获取实际示例。现在,如果你想从容器外部复制这些数据,你可以使用以下命令:

sudo docker cp vocab.json CONTAINER_ID:/workspace/Megatron-LM
sudo docker cp merges.txt CONTAINER_ID:/workspace/Megatron-LM

数据预处理

在本教程的其余部分,我们将使用 CodeParrot 模型和数据作为示例。

我们需要对预训练数据进行预处理。首先,你需要将其转换为 json 格式,一个 json 的一行包含一个文本样本。如果你正在使用 🤗 Datasets,这里有一个关于如何做到这一点的例子 (请在 Megatron-LM 文件夹中进行这些操作):

from datasets import load_dataset

train_data = load_dataset('codeparrot/codeparrot-clean-train', split='train')
train_data.to_json("codeparrot_data.json", lines=True)

然后使用以下命令将数据 tokenize、shuffle 并处理成二进制格式以进行训练:

#if nltk isn't installed
pip install nltk
python tools/preprocess_data.py \
       --input codeparrot_data.json \
       --output-prefix codeparrot \
       --vocab vocab.json \
       --dataset-impl mmap \
       --tokenizer-type GPT2BPETokenizer \
       --merge-file merges.txt \
       --json-keys content \
       --workers 32 \
       --chunk-size 25 \
       --append-eod

workerschunk_size 选项指的是预处理中使用的线程数量和分配给每个线程的数据块大小。dataset-impl 指的是索引数据集的实现方式,包括 ['lazy', 'cached', 'mmap']。这将输出 codeparrot_content_document.idx 和  codeparrot_content_document.bin 两个文件用于训练。

训练

你可以使用如下所示配置模型架构和训练参数,或将其放入你将运行的 bash 脚本中。该命令在 8 个 GPU 上参数为 110M 的 CodeParrot 模型进行预训练。请注意,数据默认按 969:30:1 的比例划分为训练/验证/测试集。

GPUS_PER_NODE=8
MASTER_ADDR=localhost
MASTER_PORT=6001
NNODES=1
NODE_RANK=0
WORLD_SIZE=$(($GPUS_PER_NODE*$NNODES))
DISTRIBUTED_ARGS="--nproc_per_node $GPUS_PER_NODE --nnodes $NNODES --node_rank $NODE_RANK --master_addr $MASTER_ADDR --master_port $MASTER_PORT"
CHECKPOINT_PATH=/workspace/Megatron-LM/experiments/codeparrot-small
VOCAB_FILE=vocab.json
MERGE_FILE=merges.txt
DATA_PATH=codeparrot_content_document
GPT_ARGS="--num-layers 12
--hidden-size 768
--num-attention-heads 12
--seq-length 1024
--max-position-embeddings 1024
--micro-batch-size 12
--global-batch-size 192
--lr 0.0005
--train-iters 150000
--lr-decay-iters 150000
--lr-decay-style cosine
--lr-warmup-iters 2000
--weight-decay .1
--adam-beta2 .999
--fp16
--log-interval 10
--save-interval 2000
--eval-interval 200
--eval-iters 10
"
TENSORBOARD_ARGS="--tensorboard-dir experiments/tensorboard"
python3 -m torch.distributed.launch $DISTRIBUTED_ARGS \
        pretrain_gpt.py \
        --tensor-model-parallel-size 1 \
        --pipeline-model-parallel-size 1 \
        $GPT_ARGS \
        --vocab-file $VOCAB_FILE \
        --merge-file $MERGE_FILE \
        --save $CHECKPOINT_PATH \
        --load $CHECKPOINT_PATH \
        --data-path $DATA_PATH \
        $TENSORBOARD_ARGS

使用以上设置,训练大约需要 12 个小时。

该设置使用数据并行,但也可以对无法放在单个 GPU 的超大模型使用模型并行。第一种选择是设置张量并行,它将模型中的张量拆分到多个 GPU 上并行运算,你需要将 tensor-model-parallel-size 参数更改为所需的 GPU 数量。第二种选择是流水线并行,它将模型按层分成大小相等的几块。参数 pipeline-model-parallel-size 表示将模型分成的块数。有关详细信息,请参阅此 博客

将模型转换为 🤗 Transformers

训练结束后,我们希望使用 transformers 库对该模型进行评估或将其部署到生产环境中。你可以按照 教程 将其转换为 transformers 模型。例如,在训练完成后,你可以复制第 150k 次迭代的权重,并使用以下命令将文件 model_optim_rng.pt 转换为 transformers 支持的 pytorch_model.bin 文件:

# to execute outside the container:
mkdir -p nvidia/megatron-codeparrot-small
# copy the weights from the container
sudo docker cp CONTAINER_ID:/workspace/Megatron-LM/experiments/codeparrot-small/iter_0150000/mp_rank_00/model_optim_rng.pt nvidia/megatron-codeparrot-small
git clone https://github.com/huggingface/transformers.git
git clone https://github.com/NVIDIA/Megatron-LM.git
export PYTHONPATH=Megatron-LM
python transformers/src/transformers/models/megatron_gpt2/convert_megatron_gpt2_checkpoint.py nvidia/megatron-codeparrot-small/model_optim_rng.pt

请注意,如果你打算使用原始的分词器,你将需要在转换后将生成的词汇文件和合并表替换为我们之前介绍的原始文件。

不要忘记将你的模型推送到 hub 并与社区分享,只需三行代码 🤗:

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("nvidia/megatron-codeparrot-small")
# this creates a repository under your username with the model name codeparrot-small
model.push_to_hub("codeparrot-small")

你还可以轻松地使用它来生成文本:

from transformers import pipeline

pipe = pipeline("text-generation", model="your_username/codeparrot-small")
outputs = pipe("def hello_world():")
print(outputs[0]["generated_text"])
 def hello_world():
    print("Hello World!")

Transformers 还可以有效地处理大模型推理。如果你训练了一个非常大的模型 (例如训练时使用了模型并行),你可以通过以下命令轻松地进行推理:

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("your_username/codeparrot-large", device_map="auto")

这将在内部调用 accelerate 库 自动在你可用的设备 (GPU、CPU RAM) 之间分配模型权重。

免责声明: 我们已经证明任何人都可以使用 Megatron-LM 来训练语言模型。问题是我们需要考虑什么时候使用它。由于额外的预处理和转换步骤,这个框架显然增加了一些时间开销。因此,重要的是你要考虑哪个框架更适合你的需求和模型大小。我们建议将其用于预训练模型或微调,但可能不适用于中型模型的微调。APITraineraccelerate 库对于模型训练同样也非常方便,并且它们与设备无关,为用户提供了极大的灵活性。

恭喜 🎉 现在你学会了如何在 Megatron-LM 框架中训练 GPT2 模型并使其支持 transformers

文中提到的链接请访问 阅读原文 查看哦~


英文原文: https://hf.co/blog/megatron-training
作者: Loubna Ben Allal
译者: gxy-gxy
审校/排版: zhongdongy (阿东)

Read more

Python内置函数input()——《Python内置函数手册》Python老吕编著

Python内置函数input()——《Python内置函数手册》Python老吕编著

Python内置函数input——《Python内置函数手册》Python老吕编著 * * * * * * * * * * Python内置函数input() 1. 引言 1.1 用户输入在Python中的作用 用户输入是Python程序与用户进行交互的一种方式,允许程序根据用户的实时输入做出响应。这种交互性使得程序更加灵活和动态,能够适应不同的用户需求和场景。用户输入可以用于收集数据、控制程序流程、实现个性化设置等,是构建交互式应用的基础。 1.2 input()函数概述 input()函数是Python中用于接收用户输入的内置函数。当程序调用input()时,它会暂停执行,等待用户在控制台输入文本,并按下回车键。用户输入的文本将作为字符串返回给程序,供进一步处理和使用。input()函数可以提高程序的用户体验,使其能够根据用户的指令或数据进行操作。 此外,input()函数还可以接受一个可选的prompt参数,该参数用于在用户输入前显示提示信息,帮助用户了解需要输入什么类型的数据。例如,input("请输入您的名字:")会

By Ne0inhk
阿里巴巴大牛是怎么写数据分析报告的?

阿里巴巴大牛是怎么写数据分析报告的?

DeeperMan | 作者 InfoQ | 来源 https://xie.infoq.cn/article/7c2951aeebab01a95b03341bf 1 写在前面的话 在当今企业纷纷推动数字化运营的背景下,“No Data, No BB”成了职场人的口头禅。做一份好的数据分析报告,大到成为能否帮助企业做出正确的商业决策,小到成为能否说服老板获取业务资源的关键因素。因此做出一份高质量的数据分析报告是一个职场人必备的利器。 有人说,数据分析报告,不就是一堆的饼图、柱状图、散点图放到PPT上吗?在阿里巴巴工作,经常会需要撰写数据分析报告,我也积累了很多这方面的经验,今天想尝试从这个人人习以为常的操作中看看是否有不变的门道。 1. 表达主题决定了我们的图表形式 决定分析报告图表形式的并不是拥有的数据是什么,而是你所需要表达的主题是什么。 图1和图2是根据一份相同的数据,展现的2个不同的图表: 上图可以发现对于相同的数据,因为我们所需表达的主题的差异,也将呈现完全不同的展现方式。图1表达的主题是爽肤水和沐浴露两个品类在不同城市的销量排名,图2主要表达的主题是

By Ne0inhk
炎炎夏日,漂流去哪漂?评论情感分析告诉你

炎炎夏日,漂流去哪漂?评论情感分析告诉你

作者|木下瞳 来源|木下学Python 前言 炎炎夏日,在这酷暑的天气,玩水,游泳等接触水的活动成了大家都想体验的活动,以此来降低一下温度,小编也准备水上活动,去漂流,但那景点没去过,不知道好不好玩,于是乎,爬取了美团上此漂流景点的评论数据,来分析一下大家的体验是怎么样的,作为一个参考。 小编使用爬虫从美团上采集数据,在对数据中的评论星级,评论时间做一个数据探索,再清洗评论数据,绘制综合评论词云,正负情感词云,最后使用 LDA 主题模型进行评论主题的探索。 数据获取 对数据获取不感兴趣的伙伴可以跳过直接阅读分析部分。 打开美团,搜索漂流,找到要去的目的地,小编是高过河,可见有 1681 条评论: 点进去查看评论,打开开发者工具,翻两页发现是异步加载的,并且可以看到数据源是在哪个包: 查看此包的请求头及参数部分,使用的 get 方法请求,url 中 offset 是控制页数的参数步数为 10,以此可以根据总评论数构造请求链接,

By Ne0inhk
用Scipy求解单个正态总体的置信区间

用Scipy求解单个正态总体的置信区间

少年吉 | 作者 数据科学CLUB | 来源 区间估计简介 假定参数是射击靶上 10 环的位置,作一次射击,打在靶心 10 环的位置上的可能性很小,但打在靶子上的可能性就很大,用打在靶上的这个点画出一个区间,这个区间包含靶心的可能性就很大,这就是区间估计的基本思想。 在区间估计中,由样本统计量所构造的总体参数的估计区间称为置信区间, 其中区间的最小值称为置信下限,最大值称为置信上限。由于统计 学家在某种程度.上确信这个区间会包含真正的总体参数,所以给它取名为置信区间。原因是,如果抽取了许多不同的样本,比如说抽取 100 个样本,根据每一个样本构造一个置信区间,这样,由 100 个样本构造的总体参数的 100 个置信区间中,有 95%的区间包含了总体参数的真值,而 5%则没包含,则 95%这个值称为置信水平。一般地,如果将构造置信区间的步骤重复多次,置信区间中包含总体参数真值的次数所占的比例称为置信水平。 从上图不难看出,当样本量给定时,

By Ne0inhk