# GPT2 ## 论文 `Language Models are Unsupervised Multitask Learners` - [https://d4mucfpksywv.cloudfront.net/better-language-models/language-models.pdf](https://d4mucfpksywv.cloudfront.net/better-language-models/language-models.pdf) ## 模型结构 第二代生成式预训练模型(Generative Pre-Training2),GPT2使用 Transformer 的 Decoder 结构,并对 Transformer Decoder 进行了一些改动,原本的 Decoder 包含了两个 Multi-Head Attention 结构,GPT2 只保留了 Mask Multi-Head Attention。 gpt2模型结构.png 我们为了用户可以使用OneFlow-Libai快速验证GPT2模型预训练,统计性能或验证精度,提供了一个GPT2网络示例,主要网络参数: ``` model.cfg.num_attention_heads = 16 model.cfg.hidden_size = 384 model.cfg.ffn_hidden_size = 1536 model.cfg.hidden_layers = 6 model.cfg.max_seq_length = 1024 ``` 完整的GPT2网络配置在configs/common/model/gpt.py中 同时,我们提供了一个更大的GPT2-13B网络为了用户可以快速在DCU集群上使用OneFlow-Libai进行较大规模的混合并行分布式预训练验证(该网络可能并不具有实际训练价值),该网络结构在GPT2基础上进行扩充,主要网络参数如下,参数量共有13.1B: ``` model.cfg.num_attention_heads = 32 model.cfg.hidden_size = 4096 model.cfg.ffn_hidden_size = 4096*4 model.cfg.hidden_layers = 64 model.cfg.max_seq_length = 1024 ``` ## 算法原理 GPT-2中使用掩模自注意力(masked self-attention),一般的自注意力模块允许某位置右侧的词计算时处于最大值。而掩模自注意力会阻止这种情况发生。 gpt2算法原理.png ## 数据集 我们在libai目录下集成了部分小数据集供用户快速验证: $ tree nlp_data ├── data ├── bert-base-chinese-vocab ├── gpt2-merges └── gpt2-vocab ## 环境配置 ### Docker 提供[光源](https://www.sourcefind.cn/#/service-details)拉取的训练以及推理的docker镜像:image.sourcefind.cn:5000/dcu/admin/base/oneflow:0.9.1-centos7.6-dtk-22.10.1-py39-latest docker pull image.sourcefind.cn:5000/dcu/admin/base/oneflow:0.9.1-centos7.6-dtk-22.10.1-py39-latest # 用上面拉取docker镜像的ID替换 docker run --shm-size 16g --network=host --name=gpt_oneflow --privileged --device=/dev/kfd --device=/dev/dri --group-add video --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v $PWD/GPT:/home/GPT -it bash cd /home/GPT pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple pip3 install pybind11 -i https://mirrors.aliyun.com/pypi/simple pip3 install -e . -i https://mirrors.aliyun.com/pypi/simple ## 训练 该预训练脚本运行环境为1节点,4张DCU-Z100-16G。 并行配置策略在configs/gpt2_pretrain.py中,使用自动混合精度: ``` train.amp.enabled = True train.train_micro_batch_size = 4 train.dist.data_parallel_size = 4 train.dist.tensor_parallel_size = 1 train.dist.pipeline_parallel_size = 1 ``` 预训练命令: bash tools/train.sh tools/train_net.py configs/gpt2_pretrain.py 4 ## result ### 精度 训练数据:[https://oneflow-static.oss-cn-beijing.aliyuncs.com/ci-files/dataset/libai/gpt_dataset](链接) 使用的GPGPU:4张DCU-Z100-16G。 模型精度: | 卡数 | 分布式工具 | 收敛性 | | :--: | :--------: | :---------------------------: | | 4 | Libai-main | total_loss: 4.336/10000 iters | ## 混合并行配置指南 首先,可以在一个节点内的多卡上做模型并行切分。因为模型并行通信开销大(前后向可能都需要all-reduce通信),而节点内设备间带宽高;另外模型并行组大小越大,流水线Stage可以减少,继而可以减少流水线中的气泡;所以一般可以节点内所有设备作为一个模型并行组。 然后,在模型并行组大小确定后,单节点的可以容纳的模型大小基本确定,就可以据此再依次把多层 Layer 的模型分布到多个节点上,形成流水线并行。在实际中,先固定数据并行是1,参考上面总结固定模型并行大小,再加流水线并行的stage,直到模型可以放的下,不出现oom。 最后,情况就变得简单了,继续加节点,使用更高的数据并行规模,把一个模型并行组的模型复制出多个数据并行组的模型,对数据切分,形成更多的数据并行组,如此就可以形成一个3D并行的切分结果。 值得注意的是,在采用以上策略时,核心要素有几点。首先保证流水并行stage数量小,气泡尽可能少,所以有时可能会再扩大模型并行至2节点。其次,可以同时采用zero策略来不增加通信量的前提下减少显存占用,一般zero 1就可以最多减少75%左右的模型状态(下放的是优化器状态),当然使用zero 2也可以,但是需要注意是否会在真实训练场景中造成性能下降。然后,配合设置Gradient Accumulation Step以及Activation Checkpointing技术来进一步减少模型中间状态对显存的占用,一般Gradient Accumulation Step设置为流水并行度的1-2倍。最后,当显存占用优化明显后,就可以在相同规模的节点上放下更大的macro bs,尽量挤满显存,最终带来可观的性能提升。 当然,在不同参数量的网络下,以上配置需要进行调整,但是思路类似。 ## 应用场景 ### 算法类别 `自然语言处理` ### 热点应用行业 `医疗,教育,科研,金融` ## 源码仓库及问题反馈 - https://developer.sourcefind.cn/codes/modelzoo/GPT ## 参考 * https://libai.readthedocs.io/en/latest/tutorials/get_started/quick_run.html * https://github.com/Oneflow-Inc/oneflow * https://github.com/Oneflow-Inc/libai/blob/main/docs/source/notes/FAQ.md