持续创造,加快成长!这是我参加「日新方案 10 月更文应战」的第16天,点击查看活动详情
本文合计2944字,阅读大概需求花费6分钟
论文简介
论文链接:SimCSE: Simple Contrastive Learning of Sentence Embeddings
假如大家了解比照学习的话就好办了,这篇文章便是将比照学习运用到了自然语言处理范畴。起初对学习先是用在图像范畴的。假如你了解的话就能够继续往下看,假如你不了解的话我主张是先了解一下比照学习。 别的推荐几篇我写的比照学习的文章。
- 诸神黄昏时代的比照学习 – ()
- 军备竞赛时期的比照学习
无监督获取语句向量:
-
运用预练习好的 Bert 直接获得语句向量,可所以 CLS 位的向量,也可所以不同 token 向量的平均值。
-
Bert-flow:On the Sentence Embeddings from Pre-trained Language Models,主要是运用流模型校正 Bert 的向量。
-
Bert-whitening:Whitening Sentence Representations for Better Semantics and Faster Retrieval,用预练习 Bert 获得一切语句的向量,得到语句向量矩阵,然后经过一个线性变换把语句向量矩阵变为一个均值 0,协方差矩阵为单位阵的矩阵。
有监督的办法主要是:
- Sentence-Bert (SBERT):Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks,经过 Bert 的孪生网络获得两个语句的向量,进行有监督学习,SBERT 的结构如下图所示。
对于比照学习来说,最重要是怎么结构正负样本。
在图像中有多种结构比照学习的样本,比SimCLR中说到的:反转、部分裁剪、部分显出、裁剪翻转、调整饱和度、调整色彩、运用各种滤波器比方最大值滤波器,最小值滤波器、锐化滤波器。
在自然语言处理中也有许多的数据增广办法,可是他们对语句的影响都特别大。会严峻下降比照学习的作用。为了处理这个问题SimCSE模型提出了一种经过随机采样dropout mask的操作来结构正样本的办法。模型运用的是BERT,每次出来的Dropout是不同的。随机dropout masks机制存在于模型的fully-connected layers和attention probabilities上,因而相同的输入,经过模型后会得到不同的成果。所以只需求将同一个语句两次喂给模型就能够得到两个不同的表明。运用这种办法产生出来的类似样本对语义完全共同,只是生成的embedding不同罢了,能够认为是数据增强的最小方式。比其他的数据增强办法都要好许多。
什么是dropout
首要咱们要了解什么是dropout。dropout在深度学习中通常被用来防止模型过拟合。dropout最初由Hinton组于2014年提出。能够看一下我之前的文章:模型泛化 | 正则化 | 权重衰退 | dropout
模型为什么会过拟合。由于咱们的数据集相较于咱们的模型来说太小了。而咱们的模型相较于咱们的数据集来说太复杂。因而为了防止模型过拟合,咱们能够运用dropout,让模型在练习的时分忽略一些节点。就像上图中那样。这样模型在练习数据时每次都在练习不同的网络,模型不会太依靠某些部分的特征,所以模型的泛化性更强,下降了过拟合产生的概率。
dropout和其他数据增强办法进行比较
经过dropout masks机制进行数据增强结构正例的办法。
作者在STS-B数据集进步行试验。比较dropout与其他数据增强办法的差异。
裁剪,删去和替换等数据增强办法,作用均不如dropout masks机制,即便删去一个词也会危害功能,详细如下表所示:
dropout正例与原始样本之间选用完全相同的语句,只要在向量表征过程中的dropout mask有所不同。能够视为一种最小方式的数据扩充。
不同的dropout rate
为了验证模型dropout rate对无监督SimCSE的影响,作者在STS-B数据集进步行了融化试验。从上面表格中咱们能够看出当dropout rate设置为0.1的时分,模型在STS-B测验集的作用最好。
上图中Fixed0.1Fixed 0.1表明对于同一个样本运用相同的dropout mask,也便是说编码两次得到的向量是相同的,能够看到这种情况下作用是最差的。
我个人感觉Fixed0.1Fixed 0.1的时分能达到40%以上现已挺好的了。毕竟在我眼里或许会造成模型坍塌。
我还看了一下他人复现这篇论文的文章,复现的人说尝试了0.1 0.2 0.3,作用都差不多,最终仍是挑选了论文中的0.1.不。
比照学习评价目标
alignment 和 uniformity 是比照学习中比较重要的两种特点,可用于衡量比照学习的作用。
- alignment 核算一切正样本对之间的距离,假如 alignment 越小,则正样本的向量越挨近,比照学习作用越好,核算公式如下:
- uniformity 表明一切语句向量分布的均匀程度,越小表明向量分布越均匀,比照学习作用越好,核算公式如下:
其间pdatap_{data}表明数据分布。这两个目标与比照学习的目标是共同的:正例之间学到的特征应该是附近的,而任意向量的语义特征应该尽或许地涣散在超球体上。
至于这个“超球体”我认为是像InstDisc中右侧这个图相同,将每个样本的特征表明映射到空间中。(个人观点,假如了解有错请各位指导。)
无监督
无监督的目标函数是这样的。看一下上边,他图中示例是把三个语句作为输入传给编码器,然后编码器会得到对应语句的embedding。输入两次会得到两次不同的embedding。一个语句和它对应增强的语句是正样本,其余的语句作为负样本。终究运用的损失函数如下:
有监督
运用有监督学习的一个难点,便是要找到适合结构正负样本的数据集。终究作者的挑选如下:
那它的正负利是怎么结构的呢。 以其间的NLI数据集为例,在这个数据会集打进一个前提。便是注释者需求手动编写一个绝对正确的语句及蕴语句。一个或许正确的语句,中立语句。和一个绝对过错的语句对立语句。然后这篇论文就将这个数据集进行扩展,将原来的(语句,包括语句)改变为(语句,包括语句,对立语句)。在这个数据会集正样本是这个语句及其包括包括关系的语句。负样本有两种,是这个语句包括对立关系的语句以及其他的语句。 损失函数如下:
成果
对7个语义文本类似度(STS)使命进行了试验,将无监督和有监督的SimCSE与STS使命中的最先进的语句嵌入办法进行了比较,能够发现,无监督和有监督的SimCSE均获得了sota的作用,详细如下表所示:
由于SimCSE做的是一个语句表征的使命,即获得更好的语句的embedding,试验作用如上图。作者运用根据BERT和根据RoBERTa的SimCSE别离与Baseline进行比较,均获得较好的作用。
下边是SimCSE运用不同版别的BERT及其变体做出的模型,对应的模型能够直接从hugging face上获取.
Model | Avg. STS |
---|---|
princeton-nlp/unsup-simcse-bert-base-uncased | 76.25 |
princeton-nlp/unsup-simcse-bert-large-uncased | 78.41 |
princeton-nlp/unsup-simcse-roberta-base | 76.57 |
princeton-nlp/unsup-simcse-roberta-large | 78.90 |
princeton-nlp/sup-simcse-bert-base-uncased | 81.57 |
princeton-nlp/sup-simcse-bert-large-uncased | 82.21 |
princeton-nlp/sup-simcse-roberta-base | 82.52 |
princeton-nlp/sup-simcse-roberta-large | 83.76 |
代码实践
已然它的作用这么好,怎么方便的在电脑上运用SimCSE呢?
先安装一下:
pip install simcse
用这两行代码加载模型。我上面那个表格里写了不同的版别, SimCSE("在这里填写不同版别")
。
from simcse import SimCSE
model = SimCSE("princeton-nlp/sup-simcse-bert-base-uncased")
已然是用来做sentence embedding的,那先看一下他怎么给语句编码:
embeddings = model.encode("A woman is reading.")
它反应比较慢,你需求等一下它才会出成果。不出意外的话,它应该会给出一个特别长的embedding编码。
我输出一下看一下,他应该是把一个语句编码成768维度的向量。
核算两组语句之间的余弦类似性:
sentences_a = ['A woman is reading.', 'A man is playing a guitar.']
sentences_b = ['He plays guitar.', 'A woman is making a photo.']
similarities = model.similarity(sentences_a, sentences_b)
similarities1 = model.similarity('A woman is reading.', 'A man is playing a guitar.')
similarities2 = model.similarity('He plays guitar.', 'A man is playing a guitar.')
除了核算语句组之间,我还放了核算两个语句的一些类似性。最终作用显现如下:
他还能够为那一组语句构建index,构建之后你再输入一个语句,从其间进行查找。他会找到和哪个语句更为类似。而且输出类似度是多少。
sentences = ['A woman is reading.', 'A man is playing a guitar.']
model.build_index(sentences)
results = model.search("He plays guitar.")
在上一段代码中我现已核算过这两个语句之间的类似度,咱们能够看到跟上一段代码中的成果是相同的。
similarities2 = model.similarity('He plays guitar.', 'A man is playing a guitar.')
的输出成果是0.8934233….. 现在你查询He plays guitar.
它输出最类似的语句为A man is playing a guitar.
类似度为0.8934233…..