最近重新梳理了下Transformer和Bert的一些基本原理和概念,再加上之前做过关于ELMo的测试,于是这次就把Bert加进去,相对完整地在文本分类这任务上对不同的预训练词向量以及不同的编码器等做了简单的对比实验,代码如下Bert/ELMo文本分类 ,使用Pytorch框架完成。
基本框架
文本分类 (text classification) 是NLP的基本任务之一,给定一个包含一堆词的句子,然后判断其类别。 文本分类主要包含三部分:
word embedding 比如使用经典的word2vec, glove或者近几年很火的ELMo和Bert等将word转换为词向量。
Encoder 对word Embedding的输入进行下一步的特征提取,比如常用的CNN,RNN还有近年来很火的Transformer架构,都是能够抽取词的更high-level的语义特征。
池化,将多个词特征进行池化得到一个句向量,进行最后的分类。比较常用的比如max-pooling,average-pooling,或者利用Attention机制计算每个词的不同权重,进行加权求和,得到句向量。
本次实验集中在前两部分,测试在不同的词向量与不同的Encoder的文本分类的效果。
实验设置
本次实验中选择了三类词向量,如下:
- GloVe: 使用Glove.6B.300d的词向量。
- ELMo: 使用AllenNLP提供的预训练的Medium的上下文词向量,LSTM的隐层与输出层维度为2048/256。
- Bert:使用Transformers提供的Bert-base-uncased的词向量,结构为12层的transformer,输出层维度为512。
使用四类Encoder的方法,如下:
- Mean:不适用Encoder,直接对所有的词向量取平均作为句向量。
- CNN:使用卷积神经网络抽取特征。
- RNN:使用GRU网络抽取特征。
- Transformer:结合Position Embedding+Transformer Encoder来抽取特征, 使用Pytorch提供的
nn.Transformer
实现,其中num_head=1
,num_layer=1
。此外实验中发现sin/cos
的位置向量效果很差,使用learning Embedding 而不是sin/cos
由于本实验不考虑池化,因此统一使用mean
将所有词的特征取平均作为句向量。
其余参数均保持一致,可以在config.py
里面查看,比如所有输出层都为64。需要注意的是,本次实验并没有刻意去调超参数,只有所有对比模型保持一致的原则。
代码中模块分工比较明确,可以很方便制定或者修改参数,细节可以参考上述的github链接。
对
bert
与ELMo
的内部参数,目前实验中均保持freeze
, 后续会尝试进行fine-tuning测试。(目前算力不太足)
接着是数据集,本次实验采用2分类的情感分类数据,总计约10k条数据。评价指标使用准确率(Accuracy)。
结果对比
先直接上结果,其中second为每个epoch的training+evaluate的时间:
Embedding | Encoder | Acc | Second |
---|---|---|---|
Bert | MEAN | 0.8031 | 17.98s |
Bert | CNN | 0.8397 | 18.35s |
Bert | RNN | 0.8444 | 18.93s |
Bert | Transformer | 0.8472 | 20.95s |
ELMo | Mean | 0.7572 | 25.05s |
ELMo | CNN | 0.8172 | 25.53s |
ELMo | RNN | 0.8219 | 27.18s |
ELMo | Transformer | 0.8051 | 26.209 |
GloVe | Mean | 0.8003 | 0.60s |
GloVe | CNN | 0.8031 | 0.76s |
GloVe | RNN | 0.8219 | 1.45s |
GloVe | Transformer | 0.8153 | 1.71s |
分析:
- 性能
- Bert实现了最好的性能:Bert+Transformer实现了0.8472的准确率。 此外,在所有的Encoder中Bert均取得了最高的准确率。总体来看Bert > ELM0 ≈ GloVe。
- 比较惊讶的ELMo在文本分类效果并未有所提升,与GloVe不相上下,甚至在Mean和Transformer中效果还不如GloVe, 可能原因是ELMo需要对内部参数进行微调, 后续探究深入原因
TODO
。 - Encoder的比较上,在文本分类中 RNN≈Transformer > CNN > Mean。其中实验中Transformer不如RNN稳定。
- 效率
- 很直观: ELMo < Bert < GloVe. 其中ELMo和Bert都是Contextual的词向量,相比GloVe,速度肯定要慢非常多,这还是在ELMo和Bert并没有开启内部参数fine-tuning的情况下。
- Transformer < RNN < CNN 。CNN最快这个容易理解,不过Transformer比RNN还要慢一些,有点意外,不过总体效率比较接近。
总结
从这个很简单的文本分类任务中,可以看到Bert的确效果很好,领先其他的词向量模型,此外从实验中我们还发现Bert收敛速度也很快,基本前面几个Epoch就差不多了,很稳定。 Bert在NLP领域是一个划时代的产物,需要及时跟进。前面用了几年的word2vec/glove + cnn/rnn的结构,我们也准备一步一步转向Transformer+Bert的阵营。
TODO
- 考虑不同池化层的影响,加入不同的
pooling method
- 更新Bert以及ELMo的参数