文本分类任务在用bert做特征提取的时候,往往采用【CLS】标识对应的向量作为句向量。但除了这种方法,其实还有多种其他方法:
-
cls:在输入中加入特殊词 [CLS],由于该词无语义,故该词的向量表示应只包含其上下文的语义信息。
-
last-layer-average(last-avg):将最后一层所有词的向量表示求平均。
-
first-last-layer-average(first-last-avg):将第一层和最后一层所有词的向量表示求平均。
今天要说的就是first-last-layer-avg为什么比cls更适合作为句向量,以及多种框架的实现方式。
从抽象与具体的角度来说:
Transformer 模型中的不同层通常捕获不同类型的信息。底层通常编码更常见、通用和基础广泛的信息,而靠近输出的顶层编码则更近似于本地化和特定于手头任务的信息。
也就是说,底层的编码信息更具体,顶层的信息更抽象;底层的更原始和基础,顶层的更符合当前任务。
从语义层面来说:
第一层Transformer得到的embedding向量包含更多的词向量信息,最后一层Transformer之后的embedding向量包含更多语句向量信息,将两者累加之后可以最大程度上保留词和语句的向量信息。
tensorflow实现
在论文On the Sentence Embeddings from Pre-trained Language Models中提到了last2avg,本来含义是最后两层输出的平均向量,但它的代码实际上是“第一层+最后一层”输出的平均向量。
苏剑林大神的bert4keras
苏剑林的bert4keras中,首先提取出bert的每一层输出,得到encoder_layers,然后取出其中的第一层和最后一层,然后通过Average来做取均值操作。
Pytorch实现
这是我自己写的pytorch实现,有啥问题欢迎指正。
效果
数据:27000条训练数据,3000条测试,文本分类模型
提取CLS作为句向量(上两图)
提取first-last-layer-avg作为特征(上两图)
对比一下,提升效果还是比较明显的。