NLP系列之句子向量、语义匹配(三):BERT_avg/BERT_whitening/SBERT/SimCSE—实验代码

DayNightStudy

共 3329字,需浏览 7分钟

 ·

2021-09-11 20:15


 作者简介




作者:ZHOU-JC (广州云迪科技有限公司 NLP算法工程师)

原文:https://zhuanlan.zhihu.com/p/387271169

转载者:杨夕

面筋地址:https://github.com/km1994/NLP-Interview-Notes

个人笔记:https://github.com/km1994/nlp_paper_study


前言

上篇主要讨论了四种方法的原理,本篇通过中文数据集对四种方法的表现进行对比。

项目实验代码地址:

https://github.com/zhoujx4/NLP-Series-sentence-embeddingsgithub.com/zhoujx4/NLP-Series-sentence-embeddings

Base BERT用的是哈工大科大讯飞联合实验室发布的6层RoBERTa。

用于验证的是STS-B数据集(中文版本)的验证集和测试集,监督训练SBERT和SmiCSE用的是SNLI数据集(中文版本)。

数据集来源于github.com/pluto-junzen, 是从原英文数据集SNLI和STS-B通过翻译加部分人工修正的方法得到的,感谢开源数据集的朋友。

下方为数据示例

  • SNLI数据集是三元组的方式,每个样本为(原句,与原句有蕴含关系的句子,与原句矛盾的句子)

STS-B数据集,句子的相似度分为0~5共六个等级

评测指标:斯皮尔曼等级相关系数Spearman's rank correlation coefficient

把句子对分别输入模型编码得到embedding对后,计算embedding对的余弦距离。

由于STS-B数据集是把句子对进行0~5的打分,所以评测指标采用斯皮尔曼等级相关系数,指标介绍可以看这篇博文

斯皮尔曼等级相关系数Spearman's rank correlation coefficient16 赞同 · 1 评论文章

在python中只需要调用scipy库则可计算,

BERT-avg

BERT-avg实现了

  • 使用CLS-token最后一层的输出作为embedding(没有用BERT做NSP任务得到的CLS-pooling层)

  • 使用第一层和最后一层的输出求平均作为embedding


STS-B(dev)STS-B(test)
BERT-avg(CLS-token)54.3948.34
BERT-avg(First-last avg.)40.3538.20

Bert-Whitening

把STS-B训练集输入BERT,用第一层和最后一层的输出求平均得到句子的embeddings,然后计算得到u和变换矩阵W保存下来。

预测时先得到句子的embedding,再用保存好的u和W做变换,还实验了降维为512和256的版本,效果如下:


STS-B(dev)STS-B(test)
BERT-whitening74.7066.98
BERT-whitening(512)74.9767.04
BERT-whitening(256)74.1867.21

BERT-Whitening论文里提到降维到原来的1/3效果是最好的。因为特征值小的方向,噪声成份多(通常有用信息的方差大,噪声方差小),因此降维不仅能起到节约存储空间、提高计算效率的好处,还能降噪。但实验发现,768、512、256维的效果都差不多,在差不多的情况下,当然是取维度小的。

SBERT

训练用到SentenceTransformers库,提供了模型、数据集、损失函数、评价器,训练,预测等接口。库十分丰富,其中损失函数就有如下这么多种,远远不止SBERT论文里提到的SoftmaxLoss、MSELoss、TripletLoss。

损失函数的选择需要根据自己手头训练集的特性。但无论采用哪种,预测的时候只用到BERT的输出得到句子的embeddings,求它们的余弦距离作为相似度。

  • SBERT(SNLI) :用SNLI训练集进行监督训练SBERT,因为SNLI是三元组(anchor, positive, negative)的形式,所以这里损失函数为TripleLoss

  • SBERT(STS-B):用STS-B训练集进行监督训练SBERT,因为把STS-B标签的0·5映射为相似度0, 0.2, 0.4, 0.6, 0.8, 1。损失函数采用与评价指标一样的CosineSimilarLoss

学习率都用库默认的默认参数,SBERT(SNLI) 训练2个epoch,SBERT(STS-B)训练8个epoch,验证集都使用STS-B(dev),评价指标就为Spearman's rank correlation coefficient,库提供了很好的封装,保存在验证集上分数最好的模型,然后对测试集进行计算。


STS-B(dev)STS-B(test)
SBERT(SNLI)72.9768.78
SBERT(STS-B)80.3974.21

SmiCSE

比较两种方法

  • SmiCSE(unsupervised):用STS-B训练集无监督训练,训练细节为attention层和hidden层的dropout都设为0.3,batch_size=128,epoch=8,学习率=4e-5,每20个step在STS-B(dev)上计算Spearman's rank correlation coefficient,保存最佳的模型,用最佳模型在STS-B(test)计算分数

  • SmiCSE(supervised):用SNLI训练集监督训练,训练细节为batch_size=64,epoch=2,学习率=4e-5,每200个step在STS-B(dev)上计算Spearman's rank correlation coefficient,保存最佳的模型,设置了早停策略,用最佳模型在STS-B(test)计算分数


STS-B(dev)STS-B(test)
SmiCSE(unsupervised)63.1260.57
SmiCSE(supervised)75.4273.61

总结

这里还是从实际可能遇到的场景出发,假如现在要做一个相似度检索的场景,

  • 场景1:没有任务相关的labeled数据,只能用unlabeled数据做无监督训练,或者从其它相似的labeled数据集上进行监督训练。例如目前有SNLI这个已标注好的数据集,目标场景是STS-B数据集。


STS-B(dev)STS-B(test)
BERT-avg(CLS-token)54.3948.34
BERT-avg(First-last avg.)40.3538.20
BERT-whitening74.7066.98
BERT-whitening(512)74.9767.04
BERT-whitening(256)74.1867.21
SBERT(SNLI)72.9768.78
SmiCSE(unsupervised)63.1260.57
SmiCSE(supervised)75.4273.61
  • 场景2:有任务相关的labeled数据集,那当然是用任务相关的数据进行监督训练好,或者先在相关数据集上做监督训练,再在任务相关的数据集上继续做监督训练。


STS-B(dev)STS-B(test)
SBERT(STS-B)80.3974.21

总的来说,SmiCSE(supervised)和SBERT(STS-B) 效果是较好的。不过做具体的业务时,还需要多根据业务的数据特点,选择最优的方法,并根据实验科学地选择最佳的超参。

参考资料:

  1. zhengyanzhao1997/NLP-model

  2. autoliuweijie/BERT-whitening-pytorch

  3. 中文任务还是SOTA吗?我们给SimCSE补充了一些实验 - 科学空间|Scientific Spaces

浏览 123
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报