作者:李鹏,王玮,陈嘉乐,黄松芳,黄俊 单位:阿里云智能机器学习平台 PAI & 达摩院自然语言基础技术

  概述

GPT 模型能较好的处理文本生成领域的各种任务,比如文本补全,自由问答,完形填空,写作文,写摘要,写小说,写诗歌等等。最近火爆全网的人工智能产品 ChatGPT 也是以 GPT 文本生成模型为底座。虽然 GPT 大模型作用在这些应用领域的效果很好,但是训练成本非常高。以 OpenAI 推出的 1750 亿的 GPT-3 为例,在 1024 张 A100GPU 上预估需要 34 天,一万亿参数的 GPT-3 在 3072 张 A100 显卡上也至少需要 84 天;微软 / 英伟达联合推出的 5300 亿的 NLG 模型,在 2048 张 A100 显卡上耗时了 3 个月的训练时间才能达到比较好的收敛效果。
b399178293d9427294ede67fdf37810d~tplv-k3u1fbpfcp-zoom-1.jpg
针对 GPT 基础模型参数量大,训练 & 推理硬件资源消耗过高等问题,基于 MoE 的稀疏化训练是目前最具竞争力的降本增效途径。MoE 的全称是 Mixture of Experts,其中的 Expert 对应的是 Transfomrer 模型的 MLP 层,在训练的时候从多个 MLP 中选取一个 MLP 进行激活(如下图所示)。这意味着模型可以在不增加计算强度(FLOPS/Bytes)的情况下,通过增加 MLP 模块的数量来增加模型参数量级,进而提升模型在下游任务上的泛化性能。采用 MoE 后的稀疏 Transformer 模型和同等质量(验证集 loss 以及 zeroshot nlu 下游任务性能)的稠密模型相比有将近 1.2 倍的训练吞吐性能提升,1.3 倍的推理吞吐性能提升。我们在稀疏架构总体设计的时候,选择让 MoE 跟纯 Transformer Decoder 架构的 GPT 进行有机结合。原因是 MoE 跟 Decoder 结合效果通常会好于跟 Encoder 的结合效果。具体来讲,Encoder 是通过随机 masking 的方式学习语言模型,而这种被随机 masked 的 token 会让 expert 的路由选择出现不均衡。另一方面,考虑到 Decoder 类的 GPT 模型比 Encoder 类的 Bert 模型有更广泛使用场景,因此我们采用 GPT+MoE 的技术架构路线,探索单机最高能效的绿色低碳 GPT 大模型训练 & 推理软硬一体化适配技术在中文文本生成场景的落地可行性。
基于当前比较成熟的分布式 MoE 专家路由选择技术,采用 Switch Transformer [2] 中的 top-1 路由机制。每个 Expert 根据如下的 softmax 函数被赋予一个概率值,取概率最高(top-1)的那个 Expert 当作网络的 FFN 层。其中 W_r 是做路由选择时需要学习的参数。
8b7e84ca51204595b8c725464a6e597b~tplv-k3u1fbpfcp-zoom-1.jpg

  GPT-MoE 训练 & 推理能效分析
  基础预训练模型训练 & 推理性能分析
任何一种稠密(Dense)的 GPT 模型,都有一种效果与之对应的训练 & 推理速度更快的稀疏(MoE)GPT 模型。我们的目标是在受限硬件比如单机条件下找到这种 GPT-MoE 模型配置,然后通过对 MoE 算法进行改进来进一步提升它的训练能效。我们通过对比稠密 & 稀疏模型的训练 & 推理性能,来发现与稠密模型等价的高能效稀疏模型。
8 种 GPT 模型的参数量,模型结构,训练超参数如下表所示:
acd5bf5a2c234f59a7cccbc49de08dd0~tplv-k3u1fbpfcp-zoom-1.jpg
如下图所示,1.3B+MoE32/64 模型在相同的 step 下对比 1.3B dense 表现出更低的验证集 loss,其中 1.3B+MoE-64 模型的 loss 甚至低于 2.7B dense 模型
cf18044514f5442980ea1d33ecc3634d~tplv-k3u1fbpfcp-zoom-1.jpg
e8d0e84daeac46818fd7d89161395c8b~tplv-k3u1fbpfcp-zoom-1.jpg
5 个模型中,0.35B+MoE-64 的训练吞吐速度最快,是其他模型的 2 倍左右。其余四个模型中,吞吐速度较高的是 1.3B dense 和 1.3B+MoE-32,1.3B+MoE-64 和 2.7B dense 的速度相近。如下图所示:
v2-8eeb92b9a3c0c7f4becf35bd1ae1cb73_720w.jpg
推理吞吐速度方面,1.3B Dense 的显存消耗最少,0.35B+MoE64 的延迟最低。
input_len = 20
output_len = 128
batch_size = 1
e9b175ab33374058b6f5e3debb4c5aa2~tplv-k3u1fbpfcp-zoom-1.jpg
通过以上的图表分析,我们能大致判断出 2.7B-Dense 模型对应的高能效的稀疏模型是以 1.3B 的 dense 模型为底座,同时配置 32 或者 64 个专家的 MoE 模型。下面我们重点分析下 1.3B+MoE-32/64 和 2.7B dense 模型的性价比。在单机 A100 上预训练 200 个小时后,借助 Tensorboard 画出预训练验证集 loss 曲线。我们发现在验证集 loss 到达 2.16 时,1.3B+MoE-64 模型的收敛速度是 2.7B dense 的 1.17,1.3B+MoE-32 的收敛速度落后于 2.7B dense 模型 15%,如下图所示:
5d5036596b404f299a38beddb0ce2618~tplv-k3u1fbpfcp-zoom-1.jpg
从下图中的基于 Faster Transformer 的单级单卡推理性能上看。1.3B+MoE-32 和 1.3B+MoE64 的吞吐速度差不多且都高于 2.6B dense 模型,这是符合预期的,因为他们的底座大小都只有 1.3B。
1671786576245-e7d6755e-b8ac-4b07-980e-32a73973bc54.png
  中文 ZeroShot-NLU 效果评测
0d5bdb6d702d4aa6834d7effb855d0b4~tplv-k3u1fbpfcp-zoom-1.jpg

  中文文本生成效果评测
文本补全
7028c141b0c548fbb740f1ea8e2b40b8~tplv-k3u1fbpfcp-zoom-1.jpg
诗歌生成
在线体验地址:https://www.modelscope.cn/models/PAI/nlp_gpt3_text-generation_0.35B_MoE-64/summary
9e75258d6504476aab0f6ad2609320d0~tplv-k3u1fbpfcp-zoom-1.jpg
广告文案生成
在线体验地址:https://www.modelscope.cn/models/PAI/nlp_gpt3_text-generation_1.3B_MoE-32/summary
输入 prompt类型 #裙颜色 #白色风格 #清新图案 #刺绣裙下摆 #花边裙长 #连衣裙裙领型 #v 领 * 裙款式 #抽褶类型 #裤 * 材质 #羊毛
达摩院 1.3B Dense (51200)这款连衣裙采用了清新的白色调,给人一种清爽的感觉,同时,还带来了清爽的视觉感。裙身上的刺绣图案,精致美观,尽显浪漫的气息。而 v 领的设计,则为其增添了几分优雅的气息。再加上褶皱的裙摆,更是增添了灵动的感觉。这款羊毛裤,采用了羊毛的材质,手感柔软,穿着舒适,且不易变形,且不易变形,耐穿性强。裤子的版型是有点微微的,可以很好的修饰腿型,拉长腿部比例,显得腿部更加修长。
达摩院 2.7B Dense (51200)连衣裙是每个女们的必备,这款连衣裙采用了清新的绿色调,带来一种清新淡淡雅的气质,同时也带来清新的视觉效果。v 领的设计,更能衬托出优美的天鹅颈,还可以很好的修饰脸型和脸型,更好的展现出女性的柔美。> 裙子上的花朵刺绣花边装饰,更具时尚气息,更是让人眼前一亮。针织衫采用优质的纯棉,手感柔软,穿着舒适透气,穿上身不勒身形。裤身采用了弹力的针织面料,手感舒适,穿着舒适亲肤。裤腿处的侧边采用的开口设计,不仅可以起到修饰腿部的作用,又能够更加的显腿长,同时也能让你轻松拥有型。
PAI 0.35B+MoE-64 (70k)这款连衣裙采用了清新的白色调,搭配精致的刺绣花边,尽显甜美气质。v 领的设计,修饰脸型,衬托出精致的脸庞。褶皱花边的袖口,更显甜美气质。这款裤子采用了羊毛的面料,具有较好的弹性和透气性,穿着起来舒适。裤子的版型设计,能够很好的修饰腿型,让你看起来更加的修长。裤子的版型设计,能够很好的修饰腿型,让你的腿部看起来更加的修长。
PAI 1.3B+MoE-32 (70k)这一款碎花连衣裙采用了精致的刺绣花朵,清新的气息。清新的花边,更加的清新颖,让你在春季节的感觉。经典百搭的一款针织衫,在视觉上的设计,让你的同时也很好的穿搭。这款牛仔裤子的裤子采用了经过的设计,更是很好的修饰身体的腿型,穿着舒适又不紧。
PAI 1.3B+MoE-64 (70k)清新的粉红色连衣裙,穿上身后能够衬托出女性的柔美。领口处采用的是花边的设计,让整体的层次感更加的精致,更能凸显甜美。圆领的领口设计,更加的修饰脸型,更显精致,而且不挑人的脸蛋糕裙摆,更能凸显女性的精致魅力这款裤子的版型设计,可以说是腿部的位置,可以很好的拉长了身材比例,而且不会有紧绷的效果,让人看起来更加的有型。而且有着很高的剪裁设计,能够很好的修饰腿型,还能很好的遮肉,让腿部的肉肉,还能很好的展现你的腿部的曲线。
作文生成
在线体验地址:https://www.modelscope.cn/models/PAI/nlp_gpt3_text-generation_1.3B_MoE-64/summary
输入 prompt信任老板商店还给气喘吁吁美丽成为现实忘不了逼真
达摩院 1.3B Dense (51200)回到家,我和老妈气喘吁吁地赶到附近的小店去买了一张贺卡。我把写得一片 “对联” 的纸贴在 “商店” 的墙上,还给老板 20 元钱。老板还给我做了一个 “会飞” 的邮局董事长呢!我还在纸上写了一些祝福语。老板还夸我是一个诚实的好孩子呢!最后,我还当上了董事谁不曾有过那种梦呢?谁不曾有过那种美丽,让人向往的美丽呢?当你忘不了那些令人向往的梦时,那是一种多么诱惑而又美丽的梦啊!在那里人们可以大肆的陶醉一番,而在那里人们也可以过目不忘,可为什么呢?梦总是那么深远大,而又有多远大的吸引力。
达摩院 2.7B Dense (51200)回到家,我急不可待地把这件事说给了他们,他们听,我刚说完还感动万分,立刻向商店去买了盒方便面。谁知 > 商店里的老板娘火冒三丈,拿起了那盒快就准备好的方便面。“还给?” 我急得心都快跳了出来。这时,走进商店,妈妈拿起一件外套心仪已是生了。谁不曾有过那样的梦呢?谁不曾有过那样的理想呢?这毕竟是过去,而将来又会成为现实,忘不了的事,成为记忆中的一页记忆。这其中当然包含了许多道理,也有很多无法用言的东西,但它们都会成为我心中最美丽的梦境,我迷恋着美丽而令我向往的梦!
PAI 0.35B+MoE-64 (70k)回到家,我把我做的手工事一五一十地告诉了他,老板气喘吁吁地说:“你怎么可以这样做!你这样做是不对的,我们应该把你的信任还给你,你看行不行?” 听完后,我心情舒畅多了,心想:我以后做事一定要细心。于是,我便把信任还给店里,到了商店,把我买下的信谁不曾有过美丽的梦?谁不曾有过梦的历险?谁不曾有过美丽的梦?谁不曾有过梦的迷茫?谁都不曾有过梦的逼真?我忘不了我的梦,我的梦是成为一名画家;我忘不了我伟大的梦:成为一名作家;我忘不了我的梦是成为一名画家;我更忘不了我的美丽中国
PAI 1.3B+MoE-32 (70k)回到家,我便气喘吁吁地冲到商店,把钱还给老板说:“老板,你,你,我说话算数,还剩 15 元钱,够本就行了!” 老板仍然不信任我,问道:“怎么回事?”“把钱拿去还给老板。” 我只好硬着头皮罢了。谁不曾有过这样的梦呢?似乎很逼真,让人忘不了,也很难想象;似乎很难想象,但它终究是现实,梦终究是美丽的,即使梦不是想象,它终究是逼真,因为美丽的事物总有被我们忽略的一面而不被我们忽略存而已。梦永远在身边,却不在身边,只要随心走
PAI 1.3B+MoE-64 (70k)回到家,老板气喘吁吁地说:“我还给你买了一件衣服,你快去商店给老板买一件衣服吧!我还给你买了一件衣服,你快去商店吧!” 老板还不停地点着头。老板不信任他,他就把钱还给了老板。谁不曾有过那种梦呢?我想,那一定是美丽的梦,可是现实却逼真的梦,成为了现实中真实的梦,让人难以忘却。我想,这就是我梦中的美丽梦。我的梦,成真而又真实的梦,让人忘不了。
  

自研 GPT-MoE 算法创新 & 实验分析

  背景
Top-1 Gating 是目前最主流也最有效的 Routing 算法,但是也有着明显的缺点。例如,在 Top-1 Gating 中,每一个 Token 仅会被交给一个 expert 处理,因此,时常会出现某些 expert 需要处理很多 token,而有些 expert 仅需处理极少数量的 token 的情况,这导致处理极少 token 的 expert 无法获得足够多的信息,无法得到充分的利用。

  高能效专家路由选择
因此,我们自研了新的路由算法,如下图所示。我们的算法让 expert 主动选择固定数量(capacity)的 token,同一个 token 可以同时被不同的 expert 处理,从而使每一个 expert 都能得到充分的训练。
最后生成的 token 的表示,则采用 weighted sum 的方式,将来自不同 expert 生成的表示加权求和并经过 Expert Residual 模块,以获得最终的 token 表示。这样的表示,由于有多个 expert 的共同作用,因此更加鲁棒。
945c7ece269b40d39f13eb43910104b0~tplv-k3u1fbpfcp-zoom-1.jpg

  • 计算 expert 对 token 的偏好:
<span class="MathJax" id="MathJax-Element-1-Frame" tabindex="0" style="position: relative;" data-mathml="S=X&#x2217;We" role="presentation">S=X∗We

其中 <span class="MathJax" id="MathJax-Element-2-Frame" tabindex="0" style="position: relative;" data-mathml="X&#x2208;Rnd" role="presentation">X∈Rnd
是输入的 tokens 的表示, <span class="MathJax" id="MathJax-Element-3-Frame" tabindex="0" style="position: relative;" data-mathml="We&#x2208;Rde" role="presentation">We∈Rde 是 experts 的权重,<span class="MathJax" id="MathJax-Element-4-Frame" tabindex="0" style="position: relative;" data-mathml="n" role="presentation">n 表示输入 token 的数量,<span class="MathJax" id="MathJax-Element-5-Frame" tabindex="0" style="position: relative;" data-mathml="e" role="presentation">e 表示 expert 的数量,<span class="MathJax" id="MathJax-Element-6-Frame" tabindex="0" style="position: relative;" data-mathml="d" role="presentation">d 表示隐藏特征的维度,<span class="MathJax" id="MathJax-Element-7-Frame" tabindex="0" style="position: relative;" data-mathml="S&#x2208;Rn&#x2217;e" role="presentation">S∈Rn∗e 为每一个 expert 对输入的每一个 token 的偏好程度;

  • L-Softmax 算法训练 expert 权重
训练过程中利用 L-Softmax loss 优化 experts 的权重 <span class="MathJax" id="MathJax-Element-8-Frame" tabindex="0" style="position: relative;" data-mathml="We" role="presentation">We
,实现每一个 expert 对 token 都具有可区分的的偏好。

  • 每个 expert 选取固定数量的 token:
<span class="MathJax" id="MathJax-Element-9-Frame" tabindex="0" style="position: relative;" data-mathml="I=Topk(S,k)" role="presentation">I=Topk(S,k)

其中,<span class="MathJax" id="MathJax-Element-10-Frame" tabindex="0" style="position: relative;" data-mathml="k" role="presentation">k
就是我们预先确定的,每个 expert 可以处理的最多 token 的数量,<span class="MathJax" id="MathJax-Element-11-Frame" tabindex="0" style="position: relative;" data-mathml="I&#x2208;Re&#x2217;k" role="presentation">I∈Re∗k 记录了每个 expert 需要处理的 tokens 的索引;
4. 计算最后的输出:
<span class="MathJax" id="MathJax-Element-12-Frame" tabindex="0" style="position: relative;" data-mathml="Xout=a&#x2217;ExpertResidual(Experts(X,I))+(1&#x2212;a)&#x2217;Experts(X,I)" role="presentation">Xout=a∗ExpertResidual(Experts(X,I))+(1−a)∗Experts(X,I)

每一个 expert 根据索引计算出对应 tokens 的表示,并将不同 expert 对同一 token 生成的表示加权求和,最后通过 Expert Residual 模块生成最终的输出 <span class="MathJax" id="MathJax-Element-13-Frame" tabindex="0" style="position: relative;" data-mathml="Xout" role="presentation">Xout



  实验分析
下图是采用自研算法与 Top-1 Gating、s-BASE 算法的验证集 loss 随训练 step 变化的曲线图,我们可以发现,采用自研算法的验证集 loss 始终低于 top-1 gating 和 s-BASE 算法的验证集 loss,证明了我们自研算法的有效性。
52386e63c9064ffbab7f3dedc381d374~tplv-k3u1fbpfcp-watermark.jpg
同时,我们观察到,验证集 loss 首次低于 2.7 的时间,自研算法的速度是 s-BASE 的 1.48 倍,极大的减少了模型训练的开销。
78686556f6c94a81affb7c5fff2d460f~tplv-k3u1fbpfcp-watermark.jpg
此外,我们也分析了自研算法和 Top-1 Gating、s-BASE 的训练吞吐,如下图所示,采用自研算法相比于 s-BASE 的训练吞吐提升了 1.17 倍。
d0279c22132c4875863154b333f3c575~tplv-k3u1fbpfcp-watermark.jpg

  基于 PAI DLC 的 GPT-MoE 预训练
Rapidformer 为 EasyNLP 中各种 Transformer 模型提供训练加速能力,这是通过有机整合微软的 DeepSpeed,英伟达的 Megatron 来做到的,如下图所示:
f03205319517411284dde76106eaa3a9~tplv-k3u1fbpfcp-zoom-1.jpg
在 GPT-MoE 大模型的预训练中,我们用到的主要训练加速核心技术包括:
混合精度训练(Mixed Precision Training) 采用混合精度训练的好处主要有以下两点:1. 减少显存占用,由于 FP16 的内存占用只有 FP32 的一半,自然地就可以帮助训练过程节省一半的显存空间。2. 加快训练和推断的计算,FP16 除了能节约内存,还能同时节省模型的训练时间。具体原理如下图所示,核心是在反向传播参数更新的时候需要维护一个 FP32 的备份来避免舍入误差,另外会通过 Loss Scaling 来缓解溢出错误。
选择性激活重算(Selective Activation Recomputation)在神经网络中间设置若干个检查点 (checkpoint),检查点以外的中间结果全部舍弃,反向传播求导数的时间,需要某个中间结果就从最近的检查点开始计算,这样既节省了显存,又避免了从头计算的繁琐过程。实际使用时,有些 layers 产生的激活值大但是计算量小,需要选择性的过滤掉这一部分的激活值,保留重要的激活值,以节省重计算量。
Zero 优化器状态切分The Zero Redundancy Optimizer)是一种用于大规模分布式深度学习的新型内存优化技术。ZeRO 具有三个主要的优化阶段分别对应于优化器状态,梯度和参数的划分。我们这里使用的是 Zero-1 优化器状态分区。
序列并行Sequence Parallelism)是一种对长序列进行切分从而加速训练的技术,在 Tensor Parallelism 的基础上,将 Transformer 核的 LayerNorm 以及 Dropout 层的输入按 Sequence Length 维度进行了切分,使得各个设备上面只需要做一部分的 Dropout 和 LayerNorm 即可。这样做的好处有两个:1. LayerNorm 和 Dropout 的计算被平摊到了各个设备上,减少了计算资源的浪费;2. LayerNorm 和 Dropout 所产生的激活值也被平摊到了各个设备上,进一步降低了显存开销。
接下来我们通过 PAI-DLC 产品来演示如何执行 GPT-MoE 的基础预训练。
  环境准备 首先通过阿里云产品机器学习平台 PAI 页进入容器训练 DLC 创建新的训练任务,如下图所示。
有三个关键的地方需要配置,分别是专属镜像,数据集以及执行命令。节点镜像地址配置为:http://pai-image-manage-registry.cn-shanghai.cr.aliyuncs.com/pai/pai-rf-image-poc-moe:0.2。执行命令配置为:
cd /workspace/RapidformerPro/examples/megatron &&
  • bash dlc_run_pretrain_megatron_gpt.sh run 1 jiebabpe 0.125B 8 0 1 1 sel none 10000
  • 复制代码
    其中 dlc_run_pretrain_megatron_gpt.sh 可以从 EasyNLP 的 github 中获取:https://github.com/alibaba/EasyNLP/blob/master/examples/rapidformer/gpt_moe/run_pretrain_megatron_gpt.sh 传递给 dlc_run_pretrain_megatron_gpt.sh 的主要有以下 11 个参数,分别是:
    MODE=$1                     #run or debugGPUS_PER_NODE=$2            #申请的卡数TOKENIZER=$3                #中文jiebabpe,英文gpt2bpeMODEL_SIZE=$4               #0.125B, 0.35B, 1.3B, 3.6B 等等MOE=$5                      #专家数量RT=$6                       #路由类型BATCH_SIZE=$7               #batch sizeTP=$8                       #模型并行度AC=$9                       #激活检查点类型ZERO=${10}                  #是否打开zero-1SAVE_INTERVAL=${11}         #报错ckpt的step数
    5ceec88a266e4f6f911bcaefc240b185~tplv-k3u1fbpfcp-zoom-1.jpg

      资源 & 数据准备
    由于预训练数据集体积比较大,采用下载的方式不是很方便。借助于 DLC 提供的 OSS 路径的挂载功能,可以很方便的直接使用存储在 OSS 上的大规模预训练数据集。
    9988f920ff0a4242bba5e60f618b78e4~tplv-k3u1fbpfcp-zoom-1.jpg
    任务资源配置建议使用单机八卡 A100 来训练 1.3B 以上的 GPT-MoE 模型。
    0357ee37e4fe42fdb6c37dc4d5602da3~tplv-k3u1fbpfcp-zoom-1.jpg
      任务创建 任务创建完成后,进入任务监控页面观察任务执行状态,如下所示:
    8ce3106305a14523b661bcbf9e153922~tplv-k3u1fbpfcp-zoom-1.jpg
    点击日志查看运行状态,如下所示:
    8fb0fd5550c54a9a9b7e3be713308678~tplv-k3u1fbpfcp-zoom-1.jpg

      基于 PAI DSW 的 GPT-MoE 微调诗歌生成
    使用 DLC 完成 GPT-MoE 的基础预训练后,还需要对模型进行微调才能在下游任务生成领域比如诗歌,小说,文等领域获得比较好的生成效果。接下来我们通过 PAI-DSW 产品来演示如何执行 GPT-MoE 的下游任务微调。我们以 0.35B+MoE64 的 GPT 大模型为例,尝试对诗歌生成任务进行微调来获得比较好的生成效果。
      环境准备 首先创建 DSW 任务,资源类型选择单机八卡 V100-32G,如下所示:
    a63b482051244456a853dedafc11359e~tplv-k3u1fbpfcp-zoom-1.jpg
    由于预训练 checkpoint 体积比较大,采用下载的方式不是很方便。借助于 DSW 提供的 OSS 路径的挂载功能,可以很方便的直接使用存储在 OSS 上的预训练模型来进行下游任务微调,配置方法如下图所示。
    18e48b6b3c944eb9b51bc69e24206509~tplv-k3u1fbpfcp-zoom-1.jpg
    接着配置镜像,采用和 DLC 中同样的镜像地址:http://pai-image-manage-registry.cn-shanghai.cr.aliyuncs.com/pai/pai-rf-image-poc-moe:0.2
    1c6a59b619bf4db299c81c5e5ca7fe3d~tplv-k3u1fbpfcp-zoom-1.jpg
    创建好后,点击打开进入到 DSW 交互式开发环境
    a336c33482e7448ca25f3ca33a3aadbc~tplv-k3u1fbpfcp-zoom-1.jpg
      数据准备 首先,您需要下载用于本示例的训练和测试集,并创建保存模型的文件夹,命令如下:
    !wget https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/text_generation_datasets/poetry/train.tsv
  • !wget https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/text_generation_datasets/poetry/dev.tsv
  • --2023-01-05 06:45:39--  https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/text_generation_datasets/poetry/train.tsv
  • Resolving atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com (atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com)... 47.101.88.27
  • Connecting to atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com (atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com)|47.101.88.27|:443... connected.
  • HTTP request sent, awaiting response... 200 OK
  • Length: 43411824 (41M) [text/tab-separated-values]
  • Saving to: ‘train.tsv’
  • train.tsv           100%[===================>]  41.40M  33.2MB/s    in 1.2s   
  • 2023-01-05 06:45:40 (33.2 MB/s) - ‘train.tsv’ saved [43411824/43411824]
  • --2023-01-05 06:45:41--  https://atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com/release/tutorials/text_generation_datasets/poetry/dev.tsv
  • Resolving atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com (atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com)... 47.101.88.27
  • Connecting to atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com (atp-modelzoo-sh.oss-cn-shanghai.aliyuncs.com)|47.101.88.27|:443... connected.
  • HTTP request sent, awaiting response... 200 OK
  • Length: 208167 (203K) [text/tab-separated-values]
  • Saving to: ‘dev.tsv’
  • dev.tsv             100%[===================>] 203.29K  --.-KB/s    in 0.1s   
  • 2023-01-05 06:45:41 (1.69 MB/s) - ‘dev.tsv’ saved [208167/208167]
  • 复制代码
    数据下载完成后,可以通过以下代码查看第一条数据。在训练集验证集中,每一行为一条诗歌数据。
    print('Training data sample:')
  • ! head -n 1 train.tsv
  • print('Development set data sample:')
  • ! head -n 1 dev.tsv
  • Training data sample:
  • 半生长以客为家,罢直初来瀚海槎。始信人间行不尽,天涯更复有天涯。
  • Development set data sample:
  • 云髻高梳鬓不分,扫除虚室事元君。新糊白纸屏风上,尽画蓬莱五色云。
  • 复制代码
      初始化 在 EasyNLP 专属镜像环境下,我们首先引入模型运行需要的各种库,并做一些初始化。在本教程中,我们使用 gpt-moe-0.35B+MoE64 作为预训练模型底座。
    from functools import partial
  • import torch
  • from megatron import get_args
  • from megatron.model import ModelType
  • from megatron.utils import (average_losses_across_data_parallel_group,
  • get_ltor_masks_and_position_ids)
  • from rapidformer.application.zeroshot_nlu.zeroshot_gpt_finetuner import \
  • GPTFinetuner
  • from rapidformer.dataset.gpt_dataset import GPTDataset
  • from rapidformer.engine.engine import RapidformerEngine
  • from rapidformer.engine.initialize import get_tokenizer
  • from rapidformer.model.transformer.gpt_model import GPTModel
  • 复制代码
      模型训练 & 评估
    finetuner = MegatronGPTMoEFinetuner(engine=engine)
  • finetuner.train()
  • 复制代码
      一步执行 值得一提的是,上述所有训练 / 评估,都已经被集成到 EasyNLP/examples/rapidformer/gpt_moe/finetune_megatron_gpt.py 中,可采用直接执行脚本文件 EasyNLP/examples/rapidformer/gpt_moe/run_finetune_text_generation_gpt.sh 的方式,一步执行上述所有训练 / 评估。根据脚本 run_finetune_text_generation_gpt.sh,需要设置的具体参数如下:
    TASK_NAME=$1                    #任务名称,这里是poetry
  • TRAIN_DATASET_PATH=$2           #训练集路径
  • VALID_DATASET_PATH=$3           #验证集路径
  • PRETRAIN_CHECKPOINT_PATH=$4     #预训练模型路径
  • MODEL_SIZE=$5                   #预训练模型大小
  • MOE=$6                          #专家数量
  • RT=$7                           #路由类型
  • BATCH_SIZE=$8                   #batch size
  • EPOCH=$9                        #训练轮次
  • TP=${10}                        #模型并行度
  • AC=${11}                        #激活检查点类型
  • ZERO=${12}                      #降显存类型
  • SEQ_LEN=${13}                   #序列长度
  • sh run_finetune_text_generation_gpt.sh
  • poetry
  • /mnt/workspace/train.tsv
  • /mnt/workspace/train.tsv
  • /workspace/checkpoints/wudao-megatron-gpt-moe-64-0.35B-lr-3e-4-bs-4-gbs-256-tp-1-ac-sel-zero-none
  • 0.35B
  • 64
  • 0
  • 16
  • 2
  • 1
  • sel
  • none
  • 128
  • 复制代码
      分析 Tensorboard 分析 Tensorboard,对比不同实验参数设置,比如我们选择调试训练轮次分别是 2 和 5,观察收敛曲线的变化,如下所示:
    c801e787022442849c8801d4e3988a39~tplv-k3u1fbpfcp-zoom-1.jpg
    66dc050ec0434be9908571fc67ac1239~tplv-k3u1fbpfcp-zoom-1.jpg
    从上图可以看出,训练轮次越大,验证集 loss 越低,收敛效果越好。于是我们选择训练 5 个 epoch 后的 ckpt 来做诗歌生成的预测

      模型预测
    文本生成效果预测已经被集成到 EasyNLP/examples/rapidformer/gpt_moe/generate_text_gpt.py 中,可采用直接执行脚本文件 EasyNLP/examples/rapidformer/gpt_moe/run_text_generation_gpt.sh 的方式,一步执行诗歌生成和预测。首先按照如何格式准备预测用的数据集。
    [
  •     {
  •         "id": 0,
  •         "txt": "大漠孤烟直"
  •     },
  •     {
  •         "id": 1,
  •         "txt": "江上归帆天际开"
  •     }
  • ]
  • 复制代码
    然后根据脚本 run_finetune_text_generation_gpt.sh 里面的参数设置,运行命令:sh run_text_generation_gpt.sh
    CHECKPOINT_PATH=$1           #微调后的模型路径
  • MODEL_SIZE=$2                #模型大小
  • MOE=$3                       #专家数量
  • SEQ_LEN=$4                   #序列长度
  • TOP_K=$5                     #topk
  • INPUT_SEQ_LEN=$6             #输入最大长度
  • OUTPUT_SEQ_LEN=$7            #输出最大长度
  • INPUT_FILE=$8                #输入文件路径
  • OUTPUT_FILE=$9               #输出文件路径
  • sh run_text_generation_gpt.sh
  • /workspace/checkpoints/finetune-poetry-ckpts
  • 0.35B
  • 64
  • 128
  • 5
  • 20
  • 128
  • input_poetry
  • output_poetry
  • 复制代码
    生成结果如下:
    {
  •         "id": 0,
  •         "prompt": "大漠孤烟直",
  •         "output_poetry": "大漠孤烟直,雄哉太山岑。万古长松树,青青如碧玉。"
  • }
  • {
  •         "id": 1,
  •         "prompt": "江上归帆天际开",
  •         "output_poetry": "江上归帆天际开,一帆秋色望中来。何当一洗三千丈,万里风风尽下来。"
  • }
  • 复制代码
    基于 PAI EAS 的在线推理部署
    使用 DSW 完成 GPT-MoE 在下游任务上的微调后,就可以在线部署下游文本生成任务的服务了。接下来我们通过 PAI-EAS 产品来演示如何执行 GPT-MoE 的下游任务服务的在线部署。
      开发基于 FasterTransformer 的 Processor 首先使用 Faster Transformer Converter 将微调后的诗歌模型进行格式转换
    cd ~/RapidformerPro/examples/fastertransformer
  • sh run_convert.sh
  • model_type=$1             #模型类型:dense or moe
  • tokenizer=$2              #分词器类型:gpt2bpe or jiebabpe
  • infer_gpu_num=$3          #推理用的卡数
  • INPUT_DIR=$4              #微调后的模型路径名
  • SAVED_DIR=$5              #转换后的模型路径名
  • 复制代码
    然后基于 EAS 提供的开发参考 https://help.aliyun.com/document_detail/130248.html,开发文本生成 processor。核心 process 方法参考如下
        def process(self, data):
  •         """ process the request data
  •         """
  •         data_str = data.decode('utf-8')
  •         data_json = json.loads(data_str)
  •         data = self.pre_proccess(data)
  •         contexts = [data_json['inputs'][0]]
  •         user_parameters = data_json['parameters']
  •         max_length = int(user_parameters['max_length'])
  •         seed = 42
  •         top_k = int(user_parameters['top_k'])
  •         self.top_k = top_k
  •         self.output_len = max_length
  •         start_ids = [
  •             torch.IntTensor(
  •                 self.tokenzer.tokenize(
  •                     c.replace('\n', '\n').replace('"', '"')))
  •             for c in contexts
  •         ]
  •         start_lengths = [len(ids) for ids in start_ids]
  •         start_ids = pad_sequence(start_ids,
  •                                  batch_first=True,
  •                                  padding_value=self.end_id)
  •         start_lengths = torch.IntTensor(start_lengths)
  •         torch.manual_seed(seed)
  •         random_seed_tensor = torch.zeros([1], dtype=torch.int64)
  •         with torch.no_grad():
  •             tokens_batch = self.gpt(
  •                 start_ids, start_lengths, self.output_len, self.beam_width,
  •                 self.top_k *
  •                 torch.ones(size=[self.max_batch_size], dtype=torch.int32),
  •                 self.top_p *
  •                 torch.ones(size=[self.max_batch_size], dtype=torch.float32),
  •                 self.beam_search_diversity_rate *
  •                 torch.ones(size=[self.max_batch_size], dtype=torch.float32),
  •                 self.temperature *
  •                 torch.ones(size=[self.max_batch_size], dtype=torch.float32),
  •                 self.len_penalty *
  •                 torch.ones(size=[self.max_batch_size], dtype=torch.float32),
  •                 self.repetition_penalty *
  •                 torch.ones(size=[self.max_batch_size], dtype=torch.float32),
  •                 random_seed_tensor, self.return_output_length,
  •                 self.return_cum_log_probs)
  •             if self.return_cum_log_probs > 0:
  •                 tokens_batch, _, cum_log_probs = tokens_batch
  •                 print('[INFO] Log probs of sentences:', cum_log_probs)
  •             outputs = []
  •             batch_size = min(len(contexts), self.max_batch_size)
  •             outputs_token = np.ones([batch_size, self.output_len], dtype=int)
  •             tokens_batch = tokens_batch.cpu().numpy()
  •             for i, (context, tokens) in enumerate(zip(contexts, tokens_batch)):
  •                 for beam_id in range(self.beam_width):
  •                     token = tokens[beam_id][:start_lengths[i] +
  •                                             self.output_len]
  •                     token = token[~np.isin(token, torch.tensor([7]))]
  •                     output = self.tokenzer.detokenize(token)
  •                     outputs.append(output)
  •                     print(f'[INFO] batch {i}, beam'
  •                           f' {beam_id}:'
  •                           f' \n[Context]\n{context}\n\n[Output]\n{output}\n')
  •                     output_token = tokens[beam_id][
  •                         start_lengths[i]:start_lengths[i] + self.output_len]
  •                     outputs_token[i] = output_token
  •             outputs = [o.replace('\n', '\n') for o in outputs]
  •         result_dict = {'text': outputs[0]}
  •         return get_result_str(result_dict=result_dict)
  • 复制代码
    搭建在线服务
    0007cb75b2304aa9847930a091643709~tplv-k3u1fbpfcp-zoom-1.jpg
    a6e58e275723420aa39ad199142b9a11~tplv-k3u1fbpfcp-zoom-1.jpg

      基于 ModelScope 的在线文本生成演示
    我们已经搭建了诗歌,广告文案,作文三个文本生成服务,具体的在线体验地址是:https://www.modelscope.cn/organization/PAI
    b2da086381a748eaa477ec95114a9f6a~tplv-k3u1fbpfcp-zoom-1.jpg
    我们可以修改 modelscope 页面上的 README.md 信息来设计应用样式
    tasks:
  • - text-generation
  • widgets:
  • - examples:
  • - name: 1
  • title: 诗歌生成
  • inputs:
  • - name: text
  • data: 大漠孤烟直
  • parameters:
  • - name: max_length
  • type: int
  • value: 128
  • - name: top_k
  • type: int
  • value: 5
  • 复制代码
    在 modelscope 上呈现出来的效果如下所示:
    11f505dc592d4ab4aace8d57e732c4c1~tplv-k3u1fbpfcp-zoom-1.jpg
      参考文献
    [1] . Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer
  • [2]. GShard: Scaling Giant Models with Conditional Computation and Automatic Sharding
  • [3]. Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity
  • [4]. BASE Layers: Simplifying Training of Large, Sparse Models
  • [5]. Hash Layers For Large Sparse Models
  • [6]. TAMING SPARSELY ACTIVATED TRANSFORMER WITH STOCHASTIC EXPERTS
  • [7]. GLaM: Efficient Scaling of Language Models with Mixture-of-Experts
  • [8]. Unified Scaling Laws for Routed Language Models
  • [9]. Designing Effective Sparse Expert Models
  • [10]. Large Margin Deep Networks for Classification
  • 复制代码