这应该是业界第一个全面支持Transformer、GPT等多种模型高速推理的开源引擎。2017年,谷歌提出了Transformer[1]模型,并基于它诞生了很多优秀的预训练语言模型和机器翻译模型,如BERT[2]、GPT系列[13]等,不断刷新许多自然语言处理模型。任务的能力水平。与此同时,这些模型的参数数量也呈现出近乎指数级的增长(如下图所示)。例如最近引发热议的GPT-3[3],其参数数量达到1750亿个,再次刷新了参数数量的记录。如此庞大的参数量也给模型推理部署带来了挑战。以机器翻译为例,目前WMT[4]竞赛中的SOTA模型已经达到了50多层。在主流的深度学习框架下,翻译一句话需要几秒钟的时间。这带来了两个问题:一是翻译时间过长,影响了产品的用户体验;二是单卡QPS(每秒查询率)太低,导致服务成本高。因此,今天我就给大家介绍一个速度非常快、性能非常好、支持很多特性的时序推理引擎——LightSeq。深度优化了基于Transformer的序列特征提取器(Encoder)和自回归序列解码器(Decoder)。早在2019年12月就已经开源,并应用于包括火山翻译在内的众多业务和场景。.据了解,这应该是业界第一个全面支持Transformer、GPT等多种模型高速推理的开源引擎。LightSeq可应用于机器翻译、自动问答、智能写作、对话回复生成等诸多文本生成场景,大大提升在线模型推理速度,提升用户体验,为企业降低运营服务成本.与目前其他开源序列推理引擎相比,LightSeq具有以下优势:1.高性能LightSeq推理速度非常快。例如,在翻译任务上,LightSeq可以实现比Tensorflow快14倍的速度。同时,它领先于其他开源序列推理引擎,例如,它可以比FasterTransformer快1.4倍。2.支持多种模型功能LightSeq支持BERT、GPT、Transformer、VAE等多种模型,支持beamsearch、diversebeamsearch[5]、sampling等多种解码方式。下表详细列出了FasterTransformer[7]、TurboTransformers[6]和LightSeq在文本生成场景下的功能差异:3.简单易用,无缝对接Tensorflow、PyTorch等深度学习框架LightSeq定义了模型协议支持灵活导入各种深度学习框架训练的模型。同时包含开箱即用的端到端模型服务,即无需编写一行代码即可部署高速模型推理,还灵活支持多级复用。如何使用用LightSeq部署在线服务比较简单。LightSeq支持TritonInferenceServer[8],这是一个由Nvidia开源的GPU推理服务器,包括许多有用的服务中间件。LightSeq支持服务器的自定义推理引擎API。因此,只要将训练好的模型导出到LightSeq定义的模型协议[9]中,即可一键启动端到端的高效模型服务,无需编写代码。可以轻松支持更改模型配置(例如层数和嵌入大小)。具体过程如下:首先,准备模型库。下面是目录结构示例,其中transformer.pb是根据模型协议导出的模型权重,libtransformer.so是LightSeq的编译产物。-model_zoo/-model_repo/-config.pbtxt-transformer.pb-1/-libtransformer.so然后你可以启动TritonInferenceServer[8]并设置模型服务。trtserver--model-store=${model_zoo}性能测试在NVIDIATeslaP4和NVIDIATeslaT4显卡上,笔者测试了LightSeq的性能,选择了深度学习框架Tensorflowv1.13和FasterTransformerv2,支持更丰富的解码场景.1实现以供比较。TurboTransformers的解码方式比较简单(只支持BeamSearch,不支持文本生成常用的采样解码),还不能满足实际应用需求,所以不做对比。机器翻译性能在机器翻译场景中,作者使用beamsearch解码测试了Transformer基础模型(6层编码器,6层解码器,隐藏层维度512)的性能。实验结果如下:可以发现在smallbatch场景下,FasterTransformer和LightSeq相比Tensorflow都实现了10倍左右的加速。随着batch的增加,由于矩阵乘法运算的比例越来越大,两者对Tensorflow的加速比都呈现下降趋势。LightSeq衰减相对平稳,尤其是在大批量场景下,最多可以比FasterTransformer快1.4倍。这也为以后的一些推理优化工作提供了指导:在小批量场景下,只要做好非计算密集型的算子融合,可以获得很高的加速收益;而在大批量场景下,需要持续优化计算密集型算子。算子,比如矩阵乘法等最后,在WMT14标准的法英翻译任务上,作者测试了Transformer大模型的性能。LightSeq在TeslaP4显卡上每句话的平均翻译延迟为167毫秒,在TeslaT4上减少到82毫秒。相比之下,TensorFlow延迟为1071ms,LightSeq分别实现了6.41和13.06倍的加速。此外,笔者尝试了其他多种机型配置,都获得了比较一致的加速效率。例如,在更深的模型结构上(编码器加深到16层),LightSeq获得的加速比分别为6.97和13.85倍。文本生成性能上述机器翻译通常采用BeamSearch方式进行解码,但在文本生成场景中,往往需要采样(Sampling)来提高生成结果的多样性。下图是Transformer基础模型使用top-k/top-p采样的性能测试对比:可以发现,在需要采样解码的任务中,LightSeq在大多数配置上都领先于FasterTransformer,最多额外增加了1.4倍加速度。此外,与TensorFlow实现相比,LightSeq在GPT、VAE等生成模型上也取得了5倍以上的加速效果。服务压力测试在云服务上,笔者在实际应用中测试了GPT场景下模型服务从Tensorflow切换到LightSeq的延迟变化(服务显卡使用NVIDIATeslaP4)。可以观察到pct99的延迟降低了3~5倍,峰值从360毫秒左右下降到80毫秒左右。详细结果如下图所示:更多对比实验结果可以查看LightSeq性能评估报告[10]到达。技术原理以Transformer为例,机器翻译/文本生成模型的推理过程包括两部分:序列编码模块特征计算和自回归解码算法。特征计算部分以self-attention机制和特征变换(矩阵乘法,计算量大)为中心,伴随着大量的IO密集型操作,如Elementwise(如Reshape)和Reduce(如LayerNormalization);解码算法部分包括wordTableSoftmax、beamscreening、cacherefresh等过程计算起来很简单,引入了更复杂的动态形状。这给模型推理带来诸多挑战:1.IO密集型计算的细粒度核函数调用带来大量冗余内存读写,成为特征计算的性能瓶颈。2.复杂的动态形状给计算图的优化带来挑战,导致模型推理时大量动态申请显存,耗时较长。3.解码和生成字符的每一步逻辑复杂,难以并行计算以发挥硬件优势。LightSeq取得了如此好的推理加速效果,针对这些挑战做了哪些针对性的优化呢?根据笔者的分析,其核心技术包括这几项:多个计算操作的融合以减少IO开销,显存的多路复用避免动态申请,以及解码算法的分层重写以提高推理速度。以下部分详细介绍了每个部分中的优化挑战和LightSeq的解决方案。Operatormulti-operationfusion近年来,由于其高效的特征提取能力,Transformerencoder/decoder结构被广泛应用于各种NLP任务,例如海量无标签文本的预训练。大多数深度学习框架(如Tensorflow、Pytorch等)通常会调用基础计算库中的核函数(kernelfunction)来实现encoder/decoder的计算过程。这些内核函数往往是细粒度的,通常一个组件需要调用多个内核函数来实现。以LayerNormalization为例,Tensorflow是这样实现的:mean=tf.reduce_mean(x,axis=[-1],keepdims=True)variance=tf.reduce_mean(tf.square(x-mean),axis=[-1],keepdims=True)result=(x-mean)*tf.rsqrt(variance+epsilon)*scale+bias可以查到,甚至基于编译优化技术(自动融合广播(Broadcast)操作和Byelement(Elementwise)操作),它仍然需要调用3次核函数(2次reduce_mean,1次计算最终结果)和2次显存读写中间结果(mean和variance)。基于CUDA,我们可以自定义一个专门用于层归??一化的核函数,将中间结果两次写入寄存器。这样就实现了一次内核函数调用,同时没有显存读写的中间结果,大大节省了计算成本。有兴趣的同学可以在文末的参考链接中进一步查看具体实现[11]。基于这一思想,LightSeq利用CUDA矩阵运算库cuBLAS[12]提供的矩阵乘法和自定义核函数实现了Transformer。具体结构如下图所示:蓝色部分为自定义核函数,黄色部分为矩阵乘法。可以发现,矩阵乘法之间的所有运算都是用自定义的内核函数实现的,从而大大减少了内核函数调用和显存读写,最终提高了运算速度。动态显存复用为了避免在计算过程中释放显存申请,节省显存使用量,LightSeq首先为模型中的所有动态形状定义最大值(如最大序列长度),并将所有动态转换形状为静态。然后在服务启动时,为计算过程中的每一个中间计算结果,根据最大值分配显存,为中间结果共享显存,没有依赖关系。这样,对于每个请求,模型在推理时不需要申请显存,这样:不同请求的同一个Tensor复用了显存;同一请求的不同张量根据形状和依赖性重用显存。通过这种内存复用策略,LightSeq可以在一块T4显卡上同时部署多达8个Transformer大模型(batch_size=8,最大序列长度=8,beam_size=4,vocab_size=30,000)。如此一来,在低频或错峰等场景下,显卡的利用率得到大幅提升。HierarchicalDecodingComputation在自回归序列生成场景中,最复杂和耗时的部分是解码。LightSeq目前支持beamsearch、diversitybeamsearch、top-k/top-psampling等多种解码方式,与Transformer、GPT结合使用可以实现数倍的加速比。这里我们以应用最广泛的beamsearch为例,介绍LightSeq对解码过程的优化。我们先来看看传统的一步解码计算在深度学习框架中是如何进行的:#1.计算以每个token结尾的序列的log概率log_token_prob=tf.nn.log_softmax(logit)#[batch_size,beam_size,vocab_size]log_seq_prob+=log_token_prob#[batch_size,beam_size,vocab_size]log_seq_prob=tf.reshape(log_seq_prob,[-1,beam_size*vocab_size])#2.对于每个序列(batch元素),找到topktokentopk_log_probs,topk_indices=tf。nn.top_k(log_seq_prob,k=K)#3.根据beamid,刷新decoder中selfattention模块中的key和value的缓存refresh_cache(cache,topk_indices)可以找到,以便选择token以概率top-k,必须对[batch_size,beam_size,vocab_size]大小的logit矩阵进行softmax计算和显存读写,然后进行batch_size次排序。通常vocab_size在几万,所以计算量非常大,这只是一步解码的计算消耗。因此在实践中也可以发现,解码模块在自回归序列生成任务中的累积延迟非常高(超过30%)。LightSeq的创新点是结合GPU的计算特性,借鉴搜索和推荐中常用的粗选和精排序的两阶段策略,将解码计算改写成层次化的方法,设计了logit粗选核函数,成功避免了softmax的计算和对几十万个元素的排序。粗选核函数遍历logit矩阵两次:?在第一遍中,对于每个beam,将其logit值随机分成k组,取每组的最大值,然后取一个最小值对于k个最大值,作为一个近似的top-k值(必须小于或等于真实的top-k值),记为R-top-k。在遍历过程中,可以同时计算出beam中logit的log_sum_exp值。?第二次遍历,对每个beam,找出所有大于等于R-top-k的logit值,将(logit-log_sum_exp+batch_id*offset,beam_id*vocab_size+vocab_id)写入候选队列,其中offset是logit下界。在第一次遍历中,logit值通常服从正态分布,因此计算出的R-top-k值与真实的top-k值非常接近。同时,由于这一步只涉及寄存器的读写,算法复杂度低,可以快速执行(十几个指令周期)。实际观察发现,在top-4的设置下,根据R-top-k,从几万个token中粗略选出十几个候选,效率很高。第二次遍历,根据R-top-k粗选候选,同时logit值偏移batch_id,多线程并发写入显存中的候选队列。粗选完成后,在候选队列中进行一次排序,得到整个batch中每个序列准确的top-k值,然后更新缓存,快速完成一步解码过程。下面是在k=2,词汇量=8的情况下的具体例子(列代表字符输出,行代表每个位置的候选)。可以看出,原本需要排序的元素有16个,采用分层解码后,最后只需要排序5个元素,大大降低了排序的复杂度。计算延迟可视化分析为了验证上述优化技术的实际效果,作者使用GPUprofile工具对LightSeq的一个推理过程进行了延迟分析。下图是各计算模块在32位浮点数和16位浮点数精度下的延迟比:可以发现,在两种计算精度下:1.经过优化后,计算延迟cuBLAS的矩阵乘法比例分别为82%和88%,成为推理加速新的主要瓶颈。作为对比,我们测试了Tensorflow模型,矩阵乘法计算延迟仅占25%。这表明LightSeq的束搜索优化已将延迟降低到非常低的水平。2、缓存刷新分别占10%和6%,占比也比较高,但很难继续优化。以后可以尝试减少缓存量(比如减少解码器层数,降低缓存精度等)来继续降低延迟。3.其他操作一共占了8%和6%,包括LayerNormalization,beamsearch,中间结果的显存读写。可视化结果表明LightSeq已经优化到了极致,大大提高了推理速度。传送门:GitHub项目地址:https://github.com/bytedance/lightseq
