SimCSE初步使用且和Bert的简单对比

SimCSE初步使用且和Bert的简单对比

在很多 NLP 任务中都会用到句子向量,例如文本检索、文本粗排、语义匹配等任务。现在有不少基于 Bert 的方式获取句子向量,例如 Bert-flow 和 Bert-whitening 等,这些方法会对预训练 Bert 的输出进行变换从而得到更好的句子向量。本文介绍 SimCSE,SimCSE 通过对比学习的方法训练模型,取得 SOTA 的效果。

模型下载

huggingface这个网站真的是太棒了。提供了封装好后的SimCSE。其实SimCSE也是在Bert基础上进行了修改。所以使用方式和Bert没有什么区别。

可以去这个网址下载https://huggingface.co/princeton-nlp/sup-simcse-bert-base-uncased模型文件。我是预先下载到本地了。

简单使用

import torch
from scipy.spatial.distance import cosine
from transformers import AutoModel, AutoTokenizer

model_path_simcse = "../pretrained_models/sup-simcse-bert-base-uncased"
model_path_bert = "../pretrained_models/bert-base-uncased"
# 从本地加载simcse模型
tokenizer_simcse = AutoTokenizer.from_pretrained(model_path_simcse)
model_simcse = AutoModel.from_pretrained(model_path_simcse)
# 从本地加载bert模型
tokenizer_bert = AutoTokenizer.from_pretrained(model_path_bert)
model_bert = AutoModel.from_pretrained(model_path_bert)

# Tokenize input texts
texts = [
    "Deep Learning",
    "Hello",
    "World"
]

inputs_simcse = tokenizer_simcse(texts, padding=True, truncation=True, return_tensors="pt")
inputs_bert = tokenizer_bert(texts, padding=True, truncation=True, return_tensors="pt")

with torch.no_grad():
    embeddings_simcse = model_simcse(**inputs_simcse, output_hidden_states=True, return_dict=True).pooler_output
    embeddings_bert = model_bert(**inputs_bert, output_hidden_states=True, return_dict=True).pooler_output

# 计算余弦相似度
cosine_sim_0_1_simcse = 1 - cosine(embeddings_simcse[0], embeddings_simcse[1])
cosine_sim_0_2_simcse = 1 - cosine(embeddings_simcse[0], embeddings_simcse[2])
print("使用SimCSE")
print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[1], cosine_sim_0_1_simcse))
print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[2], cosine_sim_0_2_simcse))

cosine_sim_0_1_bert = 1 - cosine(embeddings_bert[0], embeddings_bert[1])
cosine_sim_0_2_bert = 1 - cosine(embeddings_bert[0], embeddings_bert[2])
print("使用原生Bert")
print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[1], cosine_sim_0_1_bert))
print("Cosine similarity between \"%s\" and \"%s\" is: %.3f" % (texts[0], texts[2], cosine_sim_0_2_bert))

结果展示

使用SimCSE
Cosine similarity between "Deep Learning" and "Hello" is: 0.209
Cosine similarity between "Deep Learning" and "World" is: 0.432
使用原生Bert
Cosine similarity between "Deep Learning" and "Hello" is: 0.919
Cosine similarity between "Deep Learning" and "World" is: 0.818

小结

引用知乎文章https://zhuanlan.zhihu.com/p/430580960的解释.Bert存在两个问题

  1. Bert encode出来的向量表达具有各向异性
    • 什么叫各向异性?举个例子,一些电阻原件,正接是良导体,反接是绝缘体或者电阻很大,沿不同方向差异很大。在bert出来的向量中表现为,用不同的方式去衡量它,他表现出不同的语义,差别很大,也就是不能完整的衡量出bert向量中全部语义信息
  2. 分布不均匀,低频词分布稀疏,高频词分布紧密。
    • 也就是高频词会集中在头部,离原点近,低频词会集中在尾部,离远点远高频词与低频词分布在不同的区域,那高频词与低频词之间的相识度也就没法计算了。这也反映出来的就是明显的低频词没有得到一个很好的训练。同时,高频词频次高,也会主宰句子表达。

从实验中我们也可以看出来Bert做文本表达任务很明显效果不好。Deep LearningHello 的余弦相似度竟然高达0.919。而SimCSE很明显比Bert的表达更好一点。

补充

值得注意的是,单词级相似度比较不适用于BERT embeddings,因为这些嵌入是上下文相关的,这意味着单词vector会根据它出现在的句子而变化。这就允许了像一词多义这样的奇妙的东西,例如,你的表示编码了river “bank”,而不是金融机构“bank”,但却使得直接的词与词之间的相似性比较变得不那么有价值。但是,对于句子嵌入相似性比较仍然是有效的,这样就可以对一个句子查询其他句子的数据集,从而找到最相似的句子。根据使用的相似度度量,得到的相似度值将比相似度输出的相对排序提供的信息更少,因为许多相似度度量对向量空间(例如,等权重维度)做了假设,而这些假设不适用于768维向量空间。

你可能感兴趣的:(深度学习,深度学习,bert,分类)