【NLP实战】XLNet只存在于论文?已经替你封装好了!

  • 2020 年 2 月 20 日
  • 筆記

以下文章来源于AI实战派 ,作者AI实战派

相信前段时间大家都被各种XLNet的解读、解析轰炸了吧。好容易熬过了学会了,到网上一搜,诶!官方没有公布中文预训练模型,其他大佬都还没动静,散了散了,追ALBERT的热点去了。

在 ymcui大佬 的中文XLNet 和 CyberZHG大佬的keras_xlnet发布,再经过两个月左右让心急手快的大佬们当第一批吃螃蟹的人,提了bug和各种疑惑并被大佬们修复与解答后,现在无疑是我等平民上车XLNet的好时机。

而目前,笔者已经封装好Keras的XLNet待大家使用了,目的就为了让大家调用XLNet如同word2vec等Embedding一样轻松方便。

本文介绍一下封装的过程及使用的大佬们的工作,以及封装后的使用方法,XLNet理论什么的相信大家也看腻了,只会在有必要的时候提一嘴。

本文分为两部分:封装篇操作篇,不关注如何封装只想看如何使用的可以直接跳到操作篇。代码在我的github:https://github.com/zedom1/XLNet_embbeding

封装篇

XLNet模型

首先自然是一切的核心:XLNet模型参数啦,鉴于官方没有发布中文版(也不能怪人家,他也没有义务一定要做),目前市面上开源的中文XLNet只有两家,做的最好的是ymcui大佬的Chinese-PreTrained-XLNethttps://github.com/ymcui/Chinese-PreTrained-XLNet

他在8月18日放出了24层的中文mid版模型,并于9月5日放出12层版本的中文base模型,不仅如此,还是tensorflow、pytorch版本双全,谷歌下载讯飞云下载兼备,不由感叹大佬考虑周全。

中文模型就从这里下载啦,至于是12层的base版还是24层的mid版,除了个人喜好、任务难度之外,还要看看你显卡够不够level了,他们在微调mid时使用的是64G HBM的谷歌Cloud TPU v2,而笔者使用显存16G的Tesla V100微调24层的mid模型时轻轻松松爆显存,微调12层的base版本较为轻松。

因此建议显存小于16G的读者就不要凑mid版的热闹了,12层的base也不错,而显存若大于16G则可以一战。

Keras调用XLNet

有了XLNet模型,接下来就是调用啦。当然你也可以直接从上面的中文XLNet中魔改大佬的tensorflow运行脚本来完成自己的任务,不过既然都点进来的,想必是跟我一样的懒人,希望最好能一键运行、一键优化(automl了解一下?)的。

学过没学过tensorflow的应该都知道keras封装了tensorflow,比tensorflow本身好用得多(那不然怎么叫封装),从最近比较火的Tensorflow2.0大幅向keras靠拢可见一斑。

那keras要想调用XLNet首先得先有大佬在keras上把XLNet模型搭好,才能灌参数进去,想必各位跟我一样也不太想碰这个硬骨头吧,那就感谢CyberZHG大佬的keras_xlnet吧:https://github.com/CyberZHG/keras-XLNet,除了keras_xlnet外,大佬还封装了keras-bert,笔者之前做bert微调就是用的这位大佬的keras-bert。

这位大佬给我们搭好了XLNet,到这里我们就可以用keras跑XLNet模型了,然而这还达不到我们想要的,我们需要的是将XLNet作为embedding调用,在后面接我们自己的模型,而XLNet是有自己的语言模型预测任务的,因此和BERT一样,我们要取其中一层或某几层的输出作为输入句子的编码,鉴于hanxiao大佬的xlnet-as-service没动静,那就只好自己动手丰衣足食吧。

XLNet Embedding

然后就到了笔者出场的时候啦,到这里还剩下的就是根据需要取XLNet的层,用spiece编码文本,将文本编码输入和XLNet的模型输入对齐,网络demo搭建了。

让我从零开始自己干?算了算了,毕竟在巨人的肩膀上才能看得又高又远,经过搜寻找到了yongzhuo大佬Keras-TextClassification:https://github.com/yongzhuo/Keras-TextClassification, 参考了下大佬的实现,不过在XLNet部分训练版本输入没有对齐,取层输出时有错误,花了笔者几天的时间debug,这部分网上也没有什么资料可供参考,只得一边看错误提示一边翻keras_xlnet的源码与demo,可算废了挺多功夫。

在取层方面,首先将keras版的xlnet输出一下,明确哪些层可以取(点击放大看超长长长长图):

从图中可以看到base版总共129层,其中前9层大部分是输入+embedding(4个输入和4个embedding+1个乱入的transformer),最后一层softmax是XLNet的语言模型预测任务,中间则是每十个层算一个transformer的模块(第一个模块框内9层+Input模块的transformer)。

每个模块就取layer normalization后的输出,总共12个,再加上可能有些人喜欢原味,再提供一个position embedding后的输出,那么可选的输出模块就是【0,12】啦。

取完还不算完,如果一次取多层,那就要考虑一下融合方式了,笔者挑选了常用的融合方式:add、concat、max、average,具体选哪个通过配置文件改就可以了。

然后是文本的编码,参考了keras_xlnet中demo的写法,需要考虑到单输入和双输入的差异。对于单输入,在前面填充PAD标签,最后加一个CLS标签,然后在segment id中将最后的CLS标为1。

而对于双输入有些许复杂,在两个输入之间和之后加SEP标签,然后再填充和加CLS,而segment id就可选了,可以直接默认全零+最后的CLS为1(keras_xlnet的demo):

也可以填充、第一个输入、第二个输入、CLS各自使用各自的id(keras_xlnet的demo):

具体用哪种方案就看实验结果了。

然后附上一个简单的小实验,从清华的中文文本分类数据集 THUCNews(http://thuctc.thunlp.org/) 中抽取18w数据,按9:1切分为训练语料和验证语料,另取1w作为测试语料。

类似的实验在Chinese-Text-Classification-Pytorch(https://github.com/649453932/Chinese-Text-Classification-Pytorch)中有做。

模型参数基本默认,选择XLNet可训练,取倒数第二层,embedding出来后加一个fasttext。其中训练过程:

只训练了一个epoch就足够了,验证集准确率93.7%,测试集上也差不多:

这是没有经过调参的实验结果,相信细致调参加修改模型结构会得到更好的分数。

操作篇

接下来就是怎么使用啦,分为正常人版和究极急性子懒人版,在正常人版里介绍一下你可能需要修改的函数以及修改方式。对于究极急性子懒人,唯一的目的就是尽快让代码跑!起!来!所以教你如何以最少的操作让代码跑起来。

首先,不论是哪个版本,首先得到ymcui大佬的Chinese-PreTrained-XLNethttps://github.com/ymcui/Chinese-PreTrained-XLNet 把模型下好。

然后到我的github:https://github.com/zedom1/XLNet_embbeding,下载代码,按照requirements配置好环境,装好keras_bert、keras_xlnet包以及依赖。

正常人版

文件不多,跟xlnet相关的py文件就两个,其中xlnet_embedding封装了模型读取和取层等操作,一般情况是不需要管的,然后打开demo.py。

首先介绍下整个demo的运行过程:

因为xlnet自带字典,因此需要加载并使用它的tokenizer,当然这是下载下来的模型文件自带的,为了美观起见笔者将xlnet相关的都统一放在xlnet_embedding下了。先单独读取tokenizer,提前将文本编码好,要训练时再加载XLNet模型。

然后是demo里面的函数和类全局一览:

里面可以修改的函数上面都加了注释了,前面三个可以不用理,f1_callback就是调用sklearn的report实现了keras下的f1计算,每轮训练结束后调用这个回调函数就会对验证集计算report。

encode_data就是将文本按xlnet的需要进行编码啦,也可以不用管,init为初始化,加载XLNet的词典。

下面就是个性化的部分了。

get_config中修改模型及XLNet各种配置,如batch_size等等。

process_data下分为训练、测试和预测,基本上就是常规的文本读取,有需要可以在这里面加些预处理的措施。

create_model里面就是构建XLNet、灌预训练好的参数以及搭建后面的网络啦:

里面的embedding就是XLNet啦,把它当作一个普通的embedding模块就行了,后面可以加个fast text之类的。

在train函数下改改优化器类型和loss就差不多啦。

究极急性子懒人版

懒人们疯狂下滑终于等到这一版啦,如果你的任务是短文本分类的话可以开始偷笑了,如果还已经将label转成数字那就可以大笑了。

下载完模型和代码,安装完依赖之后,把训练数据按 文本 t 标签 的txt格式放好在data目录下,命名为train.txt:

然后打开demo.py,找到get_config函数,如果分类数目不是10,必须修改label项,其他可以不改,看心情。

然后拉到最下面:

只要训练的话就把test和predict注释了,如果需要的话就按上面训练文本的准备方式放好test和predict的txt文件,predict.txt文件里不需要标签。

最后,python demo.py。冲冲冲!

The End