NLP模型压缩方法综述

2020年10月16日 By pyjamaroom.com

字幕组双语原文:NLP 模型压缩方法综述

近年来,基于Transformer的语言模型在神经机器翻译,自然语言推理,and 其他一揽子自然语言理解任务中取得了实质性进展。 采用不同语言建模损失进行自监督的预训练,意味着模型可以通过大规模语料来提高许多下游任务的性能。 然而,海量参数和长计算轨迹意味着BERT及其变体在生产部署中困难重重。 值得庆幸的是,在过去2年里,我们看到了各种各样的技术的发展,它们缓解了这些苦痛并加速了模型的预测。具体来说,本文将重点介绍下面这套模型预训练后可以打的组合拳,这能降低模型预测的计算成本:

方案健全了药品招采平台准入机制,对医保目录药品、国家基本药物、1类新药等药品进行查漏补缺,全部纳入平台在线交易范围,更好满足临床和群众的用药需求;同时建立公开公平的市场化竞价机制,鼓励同品种不同厂家的药品之间开展竞争,形成更加优惠的价格;提升招采平台服务功能,扩大省药品招采平台服务对象,鼓励民营医疗机构和零售药店自愿在省药品招采平台采购,提高民营医疗机构和零售药店的议价能力,降低其采购成本。

在J.S. McCarley和Rishav Chakravarti以及Avirup Sil的”Structured Pruning of a BERT-based Question Answering Model”中,作者探索了一种更通用的模型剪枝方法。 作者没有只关注注意力头,还对每一层的输入以及每个BERT层的前馈层的激活进行了门控。他们探索了几种机制来选出要剪枝的网络元素——包括Michel等人提出的方法——最终确定了一种L0正则化项,它可以用在精调期间,提高模型的稀疏性。为了使这个L0正则化项可微,他们采用了类似于变分自编码器中的重参数化技巧。

这图要是做成T-shirt的话我必穿来游街。

虽然所有这些方法本身都很意思(结构化层丢弃在实际应用中表现出巨大的前景),但我对那些可以在部署应用并仍然提升性能的方法更感兴趣。这类方法通常基于”模型中只有一部分是解决具体任务所必需的”这一事实。

据了解,浙江省推行药品集中采购制度已有10余年,基本能满足临床和群众的用药需求。但传统的药品采购和医保支付制度存在一定的缺陷:一方面,由于历史原因和药品特殊性,浙江省药械采购平台一直存在医保药品中标在线交易品种不齐全、产品价格竞争不充分的问题;另一方面,由于民营医疗机构和零售药店未纳入集中招采范围内,一定程度存在部分非中标药品价格虚高问题,增加了参保群众和医保基金的负担。

数值精度缩减可能是加速模型预测的最通用方法。在过去的几年里,GPU硬件对16位浮点数运算的支持不佳,这意味着降低权重和激活函数的计算精度往往效果适得其反,但带有Tensor Core的NVIDIA Volta和Turing 架构的引入意味着现代GPU现在已经具备了高效的16位浮点数运算能力。

在Squad 2.0上剪枝模型的注意力头和前馈激活的鲁棒性。

这种隐式行为的一个好处是,我们不再需要选择如何用目标模型损失来加权各种知识蒸馏损失——因为它通常需要一个超参数α,使得模型损失的形式为L=αLKD+(1-α)LCEL=αLKD+(1-α)LCE。 与TinyBERT不同的是,它没有二次预训练这一步——模型压缩与下游精调是同时进行的。 最后,渐进式模块替换方法也适用于模型架构不同的情况——它在设计中就没有利用Transformer的任何具体特征。

列表中的最后一篇文章有两个与众不同之处:一是采用了比较新颖的模型压缩方法,二是文章里有这么张图:

NVIDIA已经发布了一套与浮点精度缩减相关的通用基准——在实践中,这种方法可以实现高达3倍的加速。

忒修斯BERT是对 “忒修斯之船 “悖论的延展,这个悖论探讨的是一艘船在经过不断的细小维修和升级后,是否还是那一艘船。 忒修斯BERT将这种渐进式替换的思想应用在了模型压缩上。

我觉得渐进式模块替换方法十分诱人的部分原因是,它打开了用实验方法提高其他模型吞吐量的大门, 而以前模型通常需要从零开始重新训练。 对于独立研究员和小公司来说,从头开始重新训练Transformer模型的成本通常是难以承受的,所以哪些提出了更高效模型的好点子但没发布预训练模型的论文就很难复现。

较不精确的数值表示法能够从两个方面加速计算:

除了浮点缩减和量化,操作合并也为更高效的预测提供了一个实用而通用的选择。合并的基本原理是将一些网络层执行的操作结合起来,以更高效少次地访问设备内存。 通过将多种操作合并到一个核(kernel)中,可以大幅提高访问内存的速度。

忒修斯BERT的GLUE跑分结果

上图中,将跳连的求和操作与层标准化的缩放和偏置合并.  

他们实验发现, 用稀疏性惩罚来微调比”Are 16 Heads Really Better than 1 “中提出的重要性估计方法更胜一筹,并且他们发现可以多去掉近50%的前馈激活,而对短问题回答任务(他们视之为基准任务)的性能影响可以忽略不计。

相异模型架构的知识蒸馏

浙江省医疗保障局相关负责人强调,这次改革总目标是扩大医保目录药品的采购覆盖面,并不是调整医保药品目录,有利于在更大范围内保障医保用药的需求。在改革推进过程中,过去一些民营医疗机构和零售药店销售的个别厂家生产的药品,因企业自身原因尚未全部进入平台在线交易,但不同厂家生产的同种药品,包括进口原研药和国产仿制药品都有供应,临床和群众医保用药是有保证的。对还未纳入平台的其他药企生产的药品,药品采购平台将始终保持开放,符合政策要求的药品都可以继续申请纳入集中采购。

数值精度缩减: 通过减少浮点数精度和量化来加快速度 操作合并: 在计算图中合并所选节点 剪枝: 识别并删除网络中的非必要部分 知识蒸馏: 训练高效的小规模学生模型,以模仿表达力更强、开销更大的老师模型 模块替换: 通过替换来降低模型的复杂性或深度

在实践中,作者发现20 – 40%的头可以剪枝,它们对精度的影响可以忽略不计。

浮点类型存储三种的数值信息——符号、指数和分数。 传统的32位浮点数表示法用8位表示指数,用23位来表示尾数。 而传统的16位浮点数表示法(即NVIDIA硬件使用的格式)将32位表示法中的指数和尾数位差不多减少了一半。TPU则用了一种名为 bfloat16 的表示方法,它将部分比特位从尾数移至指数,以部分精度为代价换取了更大的数值表示能力。

据介绍,在这次扩容中,坚持所有药品价格不高于全国最低价,鼓励价格有明显优势产品优先进入,同时统一医保药品支付标准。

为进一步加速模型,作者的还推荐使用下一个技术——”知识蒸馏”

原生半精度指令 更紧凑的表示使得批尺寸(batch size)更大

“Are Sixteen Heads Really Better than One?”, 一文中,Paul Michel、Peter Levy和Graham Neubig迭代地从BERT中减少头的数量. 他们使用基于梯度检测的方法(梯度是在下游任务上估计出来的)来估计每个头的重要性,并以头剪枝百分比作为性能的函数来评估模型对头剪枝的鲁棒性。

网络层合并与计算图优化

图片由NVIDIA开发者博客提供

在前文提到的论文中,教师模型和学生基本架构是相似的,教师模型的权重通常用来初始化学生模型的权重。然而,即使在教师模型和学生模型架构差异巨大的情况下,也可以应用知识蒸馏损失。在 “Training Compact Models for Low Resource Entity Tagging using Pre-trained Language Models”一文中, 英特尔AI实验室的Peter Izsak、Shira Guskin和Moshe Wasserblat将一个在命名实体识别任务上训练的BERT教师模型(约330M个参数)蒸馏成了一个明显更紧凑高效的CNN-LSTM学生模型(约3M个参数)。 这样的学生模型以最少的精度损失在CPU硬件上的提速高达2个数量级。

论文作者用线性学习率进行了实验,他发现随着时间的推移,线性增加模块的替换率比恒定的替换率效果要好。

知识蒸馏有助于恢复剪枝过程中丢失的信息。 

我很想看看忒修斯BERT提出的渐进式模块替换, 是否能够很好地替换

通过门控在精调过程中剪枝

知识蒸馏是由Geoffrey Hinton, Oriol Vinyals, 和Jeff Dean在2015年的工作”Distilling the Knowledge in a Neural Network”中提出的, 知识蒸馏是指到将一个网络(”教师”)中包含的知识通过特定的修正损失迁移到另一个网络中去(”学生”)。  首先想象一下,我们有一大堆无标记的样本。如果我们信赖教师模型的预测,但其模型太过庞大或计算成本太高而无法在实际环境中使用,那我们就用教师模型来分类无标记的样本,并将这些分类信号作为监督信号馈给学生模型。 然而如果不将对应类别的最大似然作为最终目标,而是在所有可能的类别上产生一个概率分布,那么学生模型就可以获得信息更丰富的监督信号。直觉上,学生模型所犯的某些错误比其他错误更合理——把勺子的图认成哈士奇明显就走远了,但把哈士奇误分为一只阿拉斯加就比较想得通了。所以损失函数应该反映出错误的严重程度。通过惩罚教师预测和学生预测之间的差异(鼓励对数匹配),学生可以从教师网络也觉得可能的类别中学习有用信息。作者认为,在原任务上用仅3%的训练数据就可以几乎实现教师网络的性能。

浙江省医疗保障局相关负责人表示,推出这项改革,就是通过整合药品招采和医保支付两项职能,健全竞价机制,补齐制度短板。

后辈模块是低配的先辈模块——下图这种情况里,单个Transformer的层替换掉了一个双层Transformer组成的块  。 与知识蒸馏不同的是,模块替换中没有使用损失来鼓励后辈模块模仿先辈模块。 实际上,是通过后辈和先辈模块的互换使用来鼓励后辈学习模仿先辈的行为。

为了测试其方法的鲁棒性,作者在GLUE跑分的时候在BERT-base上用了”忒修斯压缩”,这轻松超越了几种基于知识蒸馏方法的性能,在将原始模型压缩到50%大小的情况下,仅仅落后BERT-base不到1个百分点。

将32位浮点值量化为8位整型值也是可能的,但应用起来颇为微妙。 特别是,为了确保8位整型值的计算尽可能地接近32位浮点值的计算,训练后必须要增加一个校准步骤.如果你知道一个网络的激活值可能在什么样的区间内,你可以把这个区间划分成256个离散的块,并将每个块分配给一个整数。 只要你记得了缩放因子和区间范围,就可以用整数近似值进行矩阵乘法,并在输出的时候结果恢复为浮点值.

Transformer网络大部分的都可以简单地转换为16位浮点权重和激活,而不会产生精度问题。 而网络剩下的一小部分——特别是softmax操作这部分——必须坚持使用32位浮点数。 这是因为大量小数值(对数计算产生的)的和可能会累积出很大误差。因为同时使用了float16和float32,这种方法通常被称为”混合精度”.

有证据表明,大量参数可能是样本利用率高的关键,而且在同样时长内把大型语言模型训练到某个困惑度也可能比训练一个等效的紧凑模型更有高效,因此,高效地将这些习得的知识迁移到紧凑的学生模型上的方法拥有光明的未来。

下面的资料介绍了如何使用NVIDIA的TensorRT将8位整型值量化应用到自己的模型中:

软件优化还可以让我们重组一些矩阵乘法,以更好地利用并行性。 特别是,这可以将自注意力层的查询、键和值投影合并到一次矩阵乘法中去。

在前面讨论的”Structured Pruning of a BERT-based Question Answering Model” 中作者利用知识蒸馏方法,将未剪枝的教师模型中的知识迁移到剪枝后的学生模型上。 在中立问题数据集(Natural Questions)上,教师模型在长回答和短回答上的F1值分别为70.3和58.8。剪枝50%左右的注意力头和前馈激活后,F1分别下降为67.8和55.5 ——平均下降了约2.5。 如果在微调过程中用蒸馏损失来代替交叉熵损失,F1则可以恢复1.5到2个点,F1分别达到了69.3和58.4。

不幸的是,关于这种图优化所带来的速度提升幅度的细节很少,但我的乐观估计是,这种改进是渐进但不可忽视的——它会在吞吐量上提升10%。

为获得性能提升而进行剪枝对结构化的稀疏性有所要求。 简单地将奇异权重归零并不能有效产生性能提升,因为我们没有实际的方法来利用这种稀疏性。 所以我们必须剪掉网络中更大的部分,才能产生实际的性能提升。

忒修斯BERT的替换率的比较实验

简单来说,你可以选择一个缩放比例和偏移量,使得一组校准输入上的全部浮点数激活都不会被映射到8位整型值表示范围(-128,127)的端点值上。 然而,在这样做的过程中,为了适应极端的值我们牺牲了一些精度。 相反,像TensorRT这样的框架会选择规模和偏移值,来最小化32位浮点版本和8位整型版本的模型激活输出之间的KL散度,这使得我们原则上可以权衡好范围和精度。 由于KL散度就是不同编码下的信息损失量,所以它完美符合计算需求.

有样东西和两个完全不一样。图源维基百科,遵循CC BY-SA 3.0协议发布。