摘要:BERT由于效果好和适用范围广两大优势,因此在NLP领域具备里程碑意义。实际项目中主要使用BERT来作文本分类任务,其实就是给文本打标签。由于原生态BERT预训练模型动辄几百兆甚至上千兆的大小,模型训练速度很是慢,对于BERT模型线上化很是不友好。本篇研究目前比较火的BERT最新派生产品ALBERT来完成BERT线上化服务。ALBERT使用参数减小技术来下降内存消耗从而最终达到提升BERT的训练速度,而且在主要基准测试中均名列前茅,可谓跑的快,还跑的好。但愿对须要将BERT线上化感兴趣的小伙伴有些许帮助。
目录
01 项目背景介绍
02 从BERT到ALBERT
03 万里第一步:先跑通模型
04 多分类任务实践
总结
01 项目背景介绍
原生态BERT预训练模型动辄几百兆甚至上千兆的大小,训练速度很是慢,对于模型线上化很是不友好。为了实现BERT模型线上化问题,其实就是如何又快有好的训练模型,经调研目前超火的BERT最新派生产品ALBERT项目能很好的解决上述问题。
ALBERT是由论文《ALBERT: A Lite BERT For Self-Supervised Learningof Language Representations》提出来的。一般状况下增长预训练模型大小能够提高模型在下游任务中的性能,可是由于“GPU/TPU内存的限制、更长的训练时间以及意想不到的模型退化”等问题,做者提出了ALBERT模型。
论文下载地址:
https://arxiv.org/pdf/1909.11942.pdf
通俗的理解ALBERT就是参数数量更少的轻量级BERT模型。ALBERT是BERT最新派生产品,虽然轻量,可是效果并没打折,在主要基准测试中均名列前茅。
02 从BERT到ALBERT
1. ALBERT出现背景
自从深度学习引爆计算机视觉领域以后,提高模型性能最简单也最有效的一个方法就是增长网络深度。下图中拿图片分类任务举例,能够看出随着网络层数不断增长,模型的效果也会有很大提高:python
一样的状况也出如今BERT上,随着网络变深变宽使得模型的效果获得提高:git
可是网络变深变宽带来一个显著的问题:参数爆炸。这里看下不一样规模参数的BERT模型参数量的变“胖”之路:github
如何作到,让BERT不那么“胖”,可是效果依旧好是目前学术界的研究重点,也是如何将BERT线上化的重点工做之一。这也是ALBERT要作的事情。
2. BERT“胖”在哪里
想让BERT变瘦,先要知道“肉”长在哪里。BERT使用Transformer做为特征抽取器,这是BERT参数的来源。以前广告行业中那些趣事系列4:详解从配角到C位出道的Transformer很深刻的剖析了Transformer,有兴趣的小伙伴能够回头看看。
Transformer的参数来源主要有大块:第一块是token embedding映射模块,参数量占比为20%,第二块是attention层和前向反馈层FFN,参数量占比为80%。微信
3. ALBERT优化策略
策略1、对embedding参数因式分解(Factorized embedding parameterization)
BERT将词的one-hot向量映射到高维空间,参数量是O(VXH),ALBERT则采用因式分解的方式先将词的one-hot向量映射到低维空间(大小为E),而后再映射回一个高维的空间(大小为H),这样使用的参数仅仅是O(VXE+EXH),若是E<<H的时候参数量会减小不少。这里就必定程度上减小了上面说的BERT第一部分参数token embedding的部分。
能够经过因式分解减小参数量的缘由是token embedding是上下文独立的,经过one-hot向量转化成dense向量。而第二部分的attention和FFN做为隐藏层是上下文依赖的,包含更多信息。因此经过一个小于H的E作中介将词的one-hot向量先通过一个低维的embedding矩阵,而后再映射回高维的embedding矩阵是可行的。下图中红色方框显示了因式分解部分:网络
查看token embedding因式分解效果状况:整体来看下降了17%的模型参数,可是模型效果仅仅下降了不到1%。性能
策略2、共享层与层之间的参数(Cross-layer parameter sharing)
经过对Transformer各层参数可视化分析发现各层参数相似,都是在[CLS]token和对角线上分配更多的注意力,因此可使用跨层的参数共享方案。
一般来讲,跨层的参数共享对应Transformer编码器中的结构有两种方案:一种是attention模块的参数共享,另外一种是前馈神经网络层FFN的参数共享。具体的效果以下图所示:学习
当映射到低维空间E=768时,对比不共享参数和共享FFN层的参数能够看出,参数减小了近50%,这也是致使模型效果降低的主要缘由。而共享attention层的参数则对模型效果影响较小。
策略3、构建自学习任务-句子连贯性预测
经过改造NSP(Next Sentence Prediction)任务,加强网络学习句子的连续型来提升预训练任务。
广告行业中那些趣事系列3:NLP中的巨星BERT重点讲解了BERT模型,其中提到BERT是近几年NLP领域杰出成果的集大成者,自己的创新主要是随机屏蔽的语言模型Masked LM和下一句预测Next Sentence Prediction。有兴趣的小伙伴能够倒回去再好好看下。
NSP任务自己是一个二分类任务,目的是预测两句话是不是连续的语句。NSP实际包含两个子任务,分别是主题预测和关系一致性预测。NSP任务选择同一文档中连续的两个句子做为正样本,选择不一样文档的句子做为负样本。由于来自不一样的文档,差别性可能很是大。为了提高模型预测连续型句子的能力,ALBERT提出了新的任务SOP(SenteceOrder Prediction),正样本获取方式和NSP相同,负样本则将正样本的语句顺序颠倒。
SOP和NSP效果展现以下图所示:
测试
从图中能够看出NSP任务没法预测SOP类任务,可是SOP能够预测NSP任务。总体来看,SOP任务的模型效果也优于NSP任务。
策略4、去掉dropout
dropout主要是为了防止过拟合,但实际MLM通常不容易过拟合。去掉dropout还能够较少中间变量从而有效提高模型训练过程当中内存的利用率。
优化
其余策略:网络宽度和深度对模型效果的影响
1. 网络深度是否越深越好
对比ALBERT在不一样深度下的效果能够发现:随着层数加深,不一样NLP任务的模型效果是有必定提高。可是这种状况并非绝对的,有些任务效果反而会降低。
编码
2. 网络宽度是否越宽越好
对比深度为3的ALBERT-large模型下不一样网络宽度的模型效果状况能够发现:模型宽度的影响和深度相似,随着网络宽度增长,不一样NLP任务的模型效果是有必定提高。某些任务也会存在效果降低的状况。
整体来看,ALBERT的实质是使用参数减小技术来下降内存消耗从而最终达到提升BERT的训练速度,主要优化了如下几个方面:
03 万里第一步:先跑通模型
由于实际项目中主要是识别中文,因此主要是使用ALBERT中文版本ALBERT_zh,项目的github地址:https://github.com/brightmart/albert_zh。
记得以前看过一个图片颇有意思,能很好的描述此刻个人心情:
对于我这种“拿来主义者”来讲,再牛逼的模型第一步永远都是先跑通它,至于优化的先放一放。跑通它不只能提高自信心,最实际的做用就是能快速实现项目上线。由于我须要完成文本分类任务,因此经过上面的github地址下载项目后,在集群上跳转到albert_zh目录下,执行sh run_classifier_lcqmc.sh命令便可跑起来。由于项目没有句子分类任务,只有个相似的句子关系判断任务,因此先跑通这个任务,后期再根据这个任务的代码来改就好了。
run_classifier_lcqmc.sh脚本中整体分红两大块,第一块是模型运行的准备工做,第二块就是模型运行。下面是模型的第一块,其中涉及获取数据、预训练模型、设备以及模型相关的参数等等。
第二块就是负责模型运行,主要就是python运行程序的指令以及须要的相关参数配置。
总结下,这里重点讲了如何运行成功ALBERT_zh自己提供的一个句子关系判断任务。这个demo是和咱们实际项目中文本分类任务很类似的任务,下面就是经过改造这个脚本以及执行的代码来完成咱们的实际项目文本分类。
04 多分类任务实践
项目改造的github地址以下:https://github.com/wilsonlsm006/albert_zh。
将原项目fork下来,这里我增长了两个文件run_classifier_multiclass.sh和run_classifier_multiclass.py。这是用来执行文本分类的任务脚本以及代码。改造的原理其实也比较简单,这里大体讲解下。
项目原来提供的句子关系判断任务的数据格式是:id,text_a,text_b,label,任务其实就是来判断两句话到底有没有关系。正样本举例以下:
text_a:成龙大哥代言的一刀传奇好玩么?
text_b:成龙大哥还代言过其余传奇么?
label:1
负样本则多是这样的:
text_a:成龙大哥代言的一刀传奇好玩么?
text_b:成都市内哪一个景点最好玩?
label:0
经过上面两个正负样本的例子你们应该能了解什么是句子关系判断任务,其实就是有监督学习的分类任务。咱们实际项目主要经过BERT来作文本分类,识别一句话属于哪一个标签,对应到上面的任务其实就是只有text_a,label。由于任务类型一致,因此修改代码的策略就是重点分析有text_b的代码的部分。具体脚本和代码修改就是上面说的两个文件,有须要的小伙伴自取。这里须要注意的是原来的数据文件是tsv格式,我这边是csv格式,数据输入有点点不一样,模型其余的都没动。
总结
实际项目中须要将BERT线上化须要使模型又快又好的训练,因此通过调研使用目前BERT最新的派生产品ALBERT。ALBERT经过因式分解和共享层与层之间的参数减小了模型参数量,提高了参数效率;经过SOP替代NOP,加强了网络学习句子的连续性的能力,提高了自监督学习任务的能力;经过去掉dropout能够节省不少临时变量,有效提高模型训练过程当中内存的利用率,提高了模型的效率,减小了训练数据的规模。最后将项目中的句子关系判断任务改形成咱们实际项目中的文本分类任务用于实际业务需求。能够说是有理论,帮助小伙伴们理解ALBERT为啥训练快了,效果还不错。也有实践,若是须要使用ALBERT作文本分类任务,直接用我改造好的脚本和代码跑起来就行。
喜欢本类型文章的小伙伴能够关注个人微信公众号:数据拾光者。有任何干货我会首先发布在微信公众号,还会同步在知乎、头条、简书、csdn等平台。也欢迎小伙伴多交流。若是有问题,能够在微信公众号随时Q我哈。