投稿问答最小化  关闭

万维书刊APP下载

课程总结 | Outlier Suppression:突破Transformer语言模型低比特量化瓶颈

2022/11/7 13:53:27  阅读:562 发布者:

以下文章来源于商汤学术 ,作者商汤学术

— 导读 —

以下为本次公开课的课程总结~

Part 1 | 语言模型压缩概述

Part 2 | 论文背景介绍

Part 3 | 异常值分析

Part 4 | 异常值抑制框架

Part 5 | 实验结果

Part 6 | MQBench NLP demo

Part 1 语言模型压缩概述

近年来,随着模型日益增大,在精度变好的同时,也给落地设备上的部署带来了许多挑战,其中一个就是如何设计有效的transformer语言模型。

今年出现了非常多的高效语言模型工作,包括:

网络结构设计:更加稀疏的attention结构,一些线性的attention的结构,高效的网络结构搜索...

剪枝:比如对attention头的冗余程度进行一系列分析

除上述两种工作外,还有本次课程探讨的重点内容——量化,即是用更少的比特(如8比特或4比特或更低),表达网络中的权重和激活值。其中也有一些比较经典的工作:

I-BERT:对transformer架构中的一些非线性算子进行一些多项式的近似,帮助在落地设备上获得更好的加速比

BinaryBERT:将蒸馏和量化进行结合,探索二值化神经网络的极限

Q-BERT:研究BERT中混合比特的情况,并进行一些海森特征值的分析

Part 2 论文背景介绍

去年有一篇关于PEG的工作注意到transformer语言模型有一个很重要的量化挑战:这类模型有一些范围非常大的激活值,即有很多很大的异常值。这会给模型带来非常明显的精度下降,例如在8比特的量化中,一些基础模型BERT-base就能达到高达12%的效果下降,但这在其他领域和类型的基础模型(例如CVResNe50)上非常少见。

为了更好地应对这个挑战,上述工作提出了一个更加细粒度的量化方案,但本文作者发现对于此方案,它的异常值在网络中依然存在,并且会增加计算复杂度。

Part 3 异常值分析

为了解决这个问题,首先需要更好地理解这些异常值,因此对异常值进行了一些深入分析。

本文作者发现,这个异常值其实主要出现在LayerNorm normGLUE激活函数的输出上。它有两个比较特别的特点:

在一些特定的embedding维度,几乎所有的token都会贡献异常值,例如下图展示了BERT-base的一个例子:在308维上有一个条带现象。这说明几乎所有token在这些维度上都会贡献一些异常值

在这些维度上,不同token之间提供的异常值程度又有一些区别:其中有一些token,例如SEP、句号、CLS还有像有ofthe,它其实会提供一些相比于其他token更大的异常值

本文作者对异常值的诱因进行了分析,发现有一个很关键的诱因是LayerNorm中的scaling parameterLayerNorm在每次前向传播时,对每个token计算均值和方差,进行一次normalization,再乘和加一些参数(例如乘以γ、加上β)来进行一些放缩和平移的变化。

LayerNorm的输出中,当发现出现比较严重的异常值时,其中一个非常自然的行为就是观察该LayerNorm的结构,绘制它的参数,看看它的分布和LayerNorm的输出分布之间有无联系。

通过下图发现,它的scaling parameter放缩参数γ和LayerNorm的输出,在同样的维度都表现出异常值。这说明,作为一个乘数scaling parameter,它其实能够放大输出中的异常值,并且作为一个共享参数,它可以对所有Token都能产生在embedding dimensions上的异常值放大作用。这也就解释了为什么在BERT中,或在其他transformer语言模型中,它的异常值往往集中在特定的维度。

另一个诱因,本文作者猜测它是由于pre-training阶段的一个不均匀的token frequency导致。这其实也就说明了为什么有一些Token可能会表现出一个更加异常的异常值现象。由于调整pre-training阶段的成本比较高,后面考虑用裁剪来解决这部分的异常值。

现在回到LayerNorm中的scaling parameter这个诱因,本文作者想把scaling parameterLayerNorm中提取出来,得到一个non scaling LayerNorm。对比Non-scaling LayerNorm和原本的LayerNorm的输出,发现这些异常值在308维度上被极大地削弱。这也就说明将scaling parameterLayerNorm中提取出来,得到的Non-Scaling LayerNorm能带来一个量化更加友好的分布。这个发现启发了本文作者从诱因角度去削弱异常值。

接着,本文作者对异常值的裁剪影响进行了探究。以这个GLUE激活函数为例,从下图可见,当裁剪一个很大的范围(例如从100裁剪到10),它的精度可能一直保持不变,但如果继续裁剪,它的精度会出现一个骤降。这说明在精度上,这些异常值的重要性其实有很大区别。

对于这个异常值不那么重要的区域,它虽然覆盖范围很广,但只由非常少量的Token来提供,例如只有3%token。故这个范围,它可能是由SEP、句号之类的token进行贡献。这一点也与之前提到的“不同Token之间提供的异常值有很大区别”相吻合。

受上述实验启发,如果能找到一个更好的裁剪范围,对量化无疑有非常大的帮助。

Part 4 异常值抑制框架

针对前面两个发现,本文作者提出了一个异常值的抑制框架。它包含两个组件,第一个组件是Gamma Migration,伽马迁移。目前已知Non-scaling LayerNorm的输出使量化更加友好,并且这个γ对outlier起到放大作用,所以将γ从原本的LayerNorm中抽取出来,迁移到后面的一些结构中,这样可以得到一个量化更加友好的模型。在这个量化更加友好的模型上,考虑对剩下的异常值做一些裁剪。作者提出一个token-wise clipping的方法,它可以找到一个合适的裁剪范围,并且能够非常高效地完成搜索的过程。

本文作者进一步探讨该框架中的每个组件如何运行。对于Gamma Migration,提出了一个全精度模型(即浮点模型)的迁移等价性。

LayerNorm后面接着残差连接为例,展示这种等价变换。首先,将γ从LayerNorm中提取出来,这个位置它就变成了一个Non-scaling LayerNorm。然后,将γ推到后面的两个分支中,在shortcut的分支中重新构建一个γ参数。对于另一个分支,使用下一层的权重吸收γ参数,如下图公式所示。而且γ作为一个共享参数,对于所有token,这个公式它都成立,所以可以很自然地将γ吸收进weight中。

紧接着,是完成伽马迁移后的一个量化方式。在LayerNorm后面的输出中添加量化节点,这个位置更好量化。同时,这种迁移方案不会引入额外的计算负担,相当于将γ的计算从原本的LayerNorm推迟到shortcut的分支上。此外,本文作者也在论文中进行了理论分析和实际实验,以此表明这样的做法对下一层weight的量化几乎没有影响。

在得到更加友好的量化模型后,本文作者实施了第二个方法——Token wise clipping,进一步追求一个更好的异常值的裁剪效果。

根据前面的发现,异常值它的重要性差别极大。在考虑什么样的裁剪范围适合现有的比较低的比特时,一些局部的优化方法(例如OMSE),可能不是很适用。所以,本文作者提出需要考虑网络最终的一个影响,即需要搜索一个裁剪范围,在这种裁剪范围下量化,计算出来的结果和原本浮点的结果更加接近。

为了高效地完成上述过程,本文作者设计了一个coarse-to-fine的范式。这是因为,对于这个不重要的区域,它覆盖了一个很大的范围,如果根据直方图一个值一个值地枚举,搜索过程非常低效。同时,希望高效地跳过一些不重要的阶段,将更多精力放在更加关键的区域上。考虑到这个不重要的区域对应的token数量非常少,先用coarse-grained stage,以token-wise的方式搜索,这样就能快速跳过这个区域。具体地说,提取token的最大值或者最小值作为它的一个代表,对代表元素进行搜索,这样能大大减小搜索空间。

根据找到的一个还不错的初步解,进行一些细粒度的调整,比如通过学习获得一个更好的最终效果。这样可以以非常高效的方法找到一个最终效果很好的裁剪范围。

Part 5 实验结果

研究者经常会把量化分成两大类:

离线量化:一般使用很少的数据量、非常比较短的时间,完成校准获得量化后的模型

在线量化:使用更多更完整的数据量及整体的end to end训练模型,对GPU要求较高

本文提出的框架对这两类训练的流程都非常适用。

对于离线量化,该框架可以直接应用:在BERT RobertBART模型上进行应用,在分类任务、问答任务和摘要生成任务上都验证了框架的有效性。

对于在线量化,需分成两步:第一步是校准阶段,第二步是训练阶段。该方法可以取代它的校准阶段,并且能够和任意的训练方法进行配合使用。在具体实践中,使用了非常强的基准训练算法LSQ+。这种复合使用,验证了通过获得一个更好的校准阶段的解(即初始化结果),就可以对transformer语言模型的量化带来极大帮助。

5.1 离线量化算法的结果

• 消融实验

伽马迁移作为一个模型结构上的变化(即插即用),它可以和任何寻找裁剪范围的算法相结合,对MinMaxToken-Wise Clipping等多种方法均有精度提升。而Token-Wise Clipping也大幅超越了baseline,在QNLIMRPC上都有超过10个点的提升。

• 对比不同的寻找裁剪范围方法

token-wise clippingcoarse phase的效果和其他常见方法进行比较,例如OMSE(对裁减范围进行局部优化的算法)、Step size learning(直接学习clipping Range的算法)、Percentile(寻找clipping Range的算法,但在这种场景下比较低效),可以发现,哪怕是粗范式阶段,本文的方法得到的结果就已经大幅超越了其他方法。在算法运行效率上,该方法也达到了一个最快效果,大概两分钟就可以在bert base找到一个初步解。

glue benchmark8个分类任务上的实验结果

对于8比特BERT模型,虽然以前的方法大部分表现也还可以,但本文的方法在这种cola比较难以进行量化的模型上,仍提升了接近5%

本文作者尝试了一个更具有挑战的实验,将权重和激活值均量化为6比特,可以看到该方法在BERT上已经可以达到完全接近全精度模型的效果。

本文还同PEG方法进行了比较。需要注意的是,对PG量化可能会带来额外的计算开销,并且可能无法在实际部署中使用,但本文的框架可以在硬件上享受一个无损的加速,并且在6比特上大幅超越PEG

此外,本文的方法在RoBERTaBART上,相比已有的方法也具有明显优势:在RoBERTa上,6比特的准确率提高了接近10%;在BART上,6比特的准确率提高了接近12%

总体来说,本文的框架在6比特语言模型上的量化,已经达到了当前SOTA的水平。

• 生成任务的结果

下表为摘要生成任务,通过在XSUMCNN dailyMail的两个数据集上进行测试,以验证该方法具有更广泛的有效性:在8比特上,其可以带来接近全精度模型的性能;在6比特上,可以带来约4%的提升。

5.2 在线量化算法的结果

ablation study

本文的方法是与LSQ+复合使用。通过提供更好的初始化参数,该方法不仅可以达到一个更好的初步结果,并且能够让在线量化的训练收敛得更加容易和快速。

glue benchmark

下表为其在BERT上的结果,展示了和LSQ+方法的公平比较;其他模型的结果可以在论文中查阅。在一个比较困难的实验设置下,例如4比特量化,该方法取得了接近全精度模型的性能,比LSQ+高了约10个点;而在一些更低的比特,例如2比特(2-2-4)这种设定下,本文的方法相比于它可以涨到14个点。同时,该方法可以和知识蒸馏这种常见的手段配合使用,以此达到更好的性能。

论文代码已经开源,即将加入到一个多平台量化工具MQBench中,欢迎关注。

Codes: https://github.com/wimh966/outlier_suppression

Join in: MQBench  (http://mqbench.tech/)

Part 6 MQBench NLP demo

6.1 MQBench量化框架

MQBench是能够帮助硬件⼚商识别有⽤的量化算法、帮助研究员保证硬件可部署、帮助量化模型规模化⽣产的一种工具。

MQBench的主要特点:

支持多种硬件平台后端量化:GPUVitisDSPNNIETVMOpenVIVOTengine

支持CVNLP任务

一键量化部署

支持了多种PTQQATSOTA算法

MQBench目前⽀持很多SOTA的量化算法,⽀持⼤规模的模型落地,同时⽀持很多硬件平台,⽐如说GPUVitisDSPOpenVINO这些。商汤模型工具链团队也扩展了不同的算法和任务,欢迎尝试。

项目链接:

https://github.com/ModelTC/MQBench

项目文档:

https://mqbench.readthedocs.io/en/latest/index.html

6.2 NLP模型量化模式简介

对于⼀个NLP模型,MQBench按照以下⽅式量化。

Weight量化:

Embedding.weight: Token/Position/Segment QuantEmed

Linear / Gemm.weight:  Q/K/V/Proj/FC1/FC2 Gemm/Bias

Activation量化:需要量化的activation如下图⽩⾊框所示,具体的位置已经标注在下表。

MQBenchNLP模型上能⾃动完成量化节点的插⼊,简化了模型量化的流程。由MQBench导出BERT-Large量化后的模型,推理速度也有⼤幅提升。

6.3 MQBench分类任务实例

得益于HuggingFace中实现的tracerMQBench能够轻松⽀持各项NLP任务。

以分类任务为例,需要模型定义、Trace模型、量化参数的校准,最后导出可部署的模型。

具体地说,⾸先需要定义⼀个模型,然后对模型forward函数中的参数设定默认值,为trace做准备。接着,使⽤MQBench中提供的prepare接口,指定concrete_argscustom_tracer完成模型的trace和量化节点的插⼊。

下⼀步,需要使⽤少量数据对量化节点中的参数进行校准。最后,使⽤MQBenchconvert_deploy接⼝完成ONNX模型的导出:可以使⽤模型内置的参数,如指定输⼊输出名和动态坐标等。

下表是⼀个使⽤MQBench导出的Bert模型在GLUE benchmark上的结果,在8比特上几乎没有掉点。在实际生产中,MQBench可以帮助模型快速落地。

转自:arXiv每日学术速递”微信公众号

如有侵权,请联系本站删除!


  • 万维QQ投稿交流群    招募志愿者

    版权所有 Copyright@2009-2015豫ICP证合字09037080号

     纯自助论文投稿平台    E-mail:eshukan@163.com