NLP系列之句子向量、语义匹配(三):BERT_avg/BERT_whitening/SBERT/SimCSE—实验代码
共 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
前言
上篇主要讨论了四种方法的原理,本篇通过中文数据集对四种方法的表现进行对比。
项目实验代码地址:
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的打分,所以评测指标采用斯皮尔曼等级相关系数,指标介绍可以看这篇博文
在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.39 | 48.34 |
BERT-avg(First-last avg.) | 40.35 | 38.20 |
Bert-Whitening
把STS-B训练集输入BERT,用第一层和最后一层的输出求平均得到句子的embeddings,然后计算得到u和变换矩阵W保存下来。
预测时先得到句子的embedding,再用保存好的u和W做变换,还实验了降维为512和256的版本,效果如下:
STS-B(dev) | STS-B(test) | |
---|---|---|
BERT-whitening | 74.70 | 66.98 |
BERT-whitening(512) | 74.97 | 67.04 |
BERT-whitening(256) | 74.18 | 67.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.97 | 68.78 |
SBERT(STS-B) | 80.39 | 74.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.12 | 60.57 |
SmiCSE(supervised) | 75.42 | 73.61 |
总结
这里还是从实际可能遇到的场景出发,假如现在要做一个相似度检索的场景,
场景1:没有任务相关的labeled数据,只能用unlabeled数据做无监督训练,或者从其它相似的labeled数据集上进行监督训练。例如目前有SNLI这个已标注好的数据集,目标场景是STS-B数据集。
STS-B(dev) | STS-B(test) | |
---|---|---|
BERT-avg(CLS-token) | 54.39 | 48.34 |
BERT-avg(First-last avg.) | 40.35 | 38.20 |
BERT-whitening | 74.70 | 66.98 |
BERT-whitening(512) | 74.97 | 67.04 |
BERT-whitening(256) | 74.18 | 67.21 |
SBERT(SNLI) | 72.97 | 68.78 |
SmiCSE(unsupervised) | 63.12 | 60.57 |
SmiCSE(supervised) | 75.42 | 73.61 |
场景2:有任务相关的labeled数据集,那当然是用任务相关的数据进行监督训练好,或者先在相关数据集上做监督训练,再在任务相关的数据集上继续做监督训练。
STS-B(dev) | STS-B(test) | |
---|---|---|
SBERT(STS-B) | 80.39 | 74.21 |
总的来说,SmiCSE(supervised)和SBERT(STS-B) 效果是较好的。不过做具体的业务时,还需要多根据业务的数据特点,选择最优的方法,并根据实验科学地选择最佳的超参。
参考资料:
zhengyanzhao1997/NLP-model
autoliuweijie/BERT-whitening-pytorch
中文任务还是SOTA吗?我们给SimCSE补充了一些实验 - 科学空间|Scientific Spaces