语义文本相似性(STS)

2023-01-12 12:47 1290 阅读 ID:683
磐创AI
磐创AI

介绍

自然语言处理(NLP)在信息提取、自然语言理解和自然语言生成方面有着巨大的现实应用。比较自然语言文本之间的相似性对于许多信息提取应用程序至关重要,例如Google搜索、Spotify的Podcast搜索、Home Depot的产品搜索等。

语义文本相似性(STS)问题试图比较两个文本,并确定它们在意义上是否相似。这是一个众所周知的难题,因为自然语言的细微差别,两篇文本可能相似,尽管没有一个共同的单词!

虽然这一挑战已经存在了很长时间,但NLP的最新进展为解决这一问题开辟了许多算法。

有些方法将两个文本作为输入,并直接对两个文本的相似程度进行评分。其他一些技术只将每个文本转换为一个称为嵌入的数字向量,然后我们可以通过数学计算向量之间的距离来进行比较。回想一下,

“嵌入”向量是自然语言文本的数字表示,以便我们的计算机能够理解文本的上下文和含义。

本文将介绍几种在不同场景中解决STS问题的技术。我的目标是尽可能多地使用预训练过的模型,这样可以提供开箱即用的出色结果。在文章的末尾,我提供了一个流程图,帮助你确定解决自定义问题的最佳方法。具体来说,在本文中,我们将讨论以下内容。单击链接跳转到该部分:

  1. 设置环境并下载一些数据
  2. 使用经典非上下文算法测量文本相似性
  3. 用现代上下文算法测量文本相似性
  4. 结果与结论

我们将在本文中使用Huggingface数据集上提供的stsb_multi_mt数据集。数据集包含成对的句子和一个表示每对句子相似性的正实数标签,范围从0(最不相似)到5(最相似)。

作者已根据Commons Attribution-Share Alike 4.0 International License授权该数据集。

设置环境并下载一些数据

我们首先需要安装所有必要的库来测试各种嵌入策略。我们将使用mini-forge中的conda来管理此项目的虚拟环境。

设置环境并安装必要的库

由于我们将在这篇文章中介绍几种不同的算法,我们需要安装各种库才能使它们全部工作。

不幸的是,WMD算法所必需的pyemd库在安装pip时不起作用,因此我们需要在这个项目中使用conda。

# Create the necessary directories 
mkdir -p semantic_similarity/notebooks semantic_similarity/data/nlp

# Create and activate a conda environment
conda create -n semantic_similarity python=3.8
conda activate semantic_similarity

# Pip install the necessary libraries
pip install -U jupyterlab pandas datasets matplotlib plotly scikit-learn tqdm ipywidgets 
pip install -U numpy spacy textdistance fasttext gensim 
pip install -U tensorflow tensorflow_hub sentence-transformers openai
conda install pyemd

# Download the Spacy Model
python -m spacy download en_core_web_sm

加载STSB数据集

我们将使用Huggingface的数据集库将STSB数据集快速加载到pandas数据帧中。STSB数据集由一个列表和一个测试表组成。我们将这两个表拆分为各自的数据帧stsb_train和stsb_test。

# Imports
from datasets import load_dataset
import pandas as pd
import numpy as np
from tqdm import tqdm
tqdm.pandas()

# Load the English STSB dataset
stsb_dataset = load_dataset('stsb_multi_mt', 'en')
stsb_train = pd.DataFrame(stsb_dataset['train'])
stsb_test = pd.DataFrame(stsb_dataset['test'])

# Check loaded data
print(stsb_train.shape, stsb_test.shape)
stsb_test.head()

创建一些辅助函数

让我们为将在本文中重复执行的操作创建两个辅助函数。

第一个函数是通过词形还原、小写和删除数字和停用词来预处理文本。

第二个函数接受两列文本嵌入,并返回两列之间的行余弦相似性。

from sklearn.metrics.pairwise import cosine_similarity
import spacy
nlp = spacy.load("en_core_web_sm")

def text_processing(sentence):
    """
    Lemmatize, lowercase, remove numbers and stop words

    Args:
      sentence: The sentence we want to process.

    Returns:
      A list of processed words
    """
    sentence = [token.lemma_.lower()
                for token in nlp(sentence) 
                if token.is_alpha and not token.is_stop]

    return sentence


def cos_sim(sentence1_emb, sentence2_emb):
    """
    Cosine similarity between two columns of sentence embeddings

    Args:
      sentence1_emb: sentence1 embedding column
      sentence2_emb: sentence2 embedding column

    Returns:
      The row-wise cosine similarity between the two columns.
      For instance is sentence1_emb=[a,b,c] and sentence2_emb=[x,y,z]
      Then the result is [cosine_similarity(a,x), cosine_similarity(b,y), cosine_similarity(c,z)]
    """
    cos_sim = cosine_similarity(sentence1_emb, sentence2_emb)
    return np.diag(cos_sim)

现在我们有了环境和数据,让我们开始讨论算法吧!

使用经典非上下文算法测量文本相似性

本节将讨论一些使用经典非上下文方法测量文本之间相似性的技术。

在这些算法中,我们只使用实际单词进行相似性计算,而不考虑每个单词出现的上下文。正如人们所料,这些技术通常比更现代的上下文方法性能更差。

Jaccard相似性

比较两篇文章最简单的方法是计算它们共同的独特单词的数量。然而,如果我们只计算唯一常用词的数量,那么较长的文档将有更多的常用词。为了克服对较长文档的偏见,在Jaccard相似性中,我们将共同独特单词的数量标准化为两个文本中共同独特单词总数。

Jaccard相似度是Python中可以使用textdistance库计算的几个距离之一。请注意,在运行Jaccard相似性之前,要对文本进行预处理,以删除非索引词、小写字母,并对其进行赋值,以确保在计算中只使用信息性单词。

import textdistance

def jaccard_sim(row):
    # Text Processing
    sentence1 = text_processing(row['sentence1'])
    sentence2 = text_processing(row['sentence2'])

    # Jaccard similarity
    return textdistance.jaccard.normalized_similarity(sentence1, sentence2)


# Jaccard Similarity
stsb_test['Jaccard_score'] = stsb_test.progress_apply(jaccard_sim, axis=1)

在上面的代码中,我们只使用unigram来计算Jaccard相似性。然而,该技术也可以很容易地扩展到任何N-gram。使用N-gram代替单词(1-gram)的Jaccard相似性称为w-shingling。

尽管Jaccard相似性和w-shinling是测量文本相似性的简单方法,但它们在实践中表现得相当不错,如本文末尾的结果部分所示!

词袋(BoW)

词袋是从文本中提取特征并将其转换为数字嵌入向量的经典方法的集合。然后通过计算它们之间的余弦相似性来比较这些嵌入向量。有两种流行的使用词袋的方法:计数向量器和TFIDF向量器。

计数向量器

该算法将整个文本语料库中的每个唯一单词映射到一个唯一的向量索引。每个文档的向量值是每个特定单词在该文本中出现的次数。

因此,向量可以由整数值组成,包括0,这表示单词没有出现在文本中。虽然Count Vectorizer易于理解和实现,但它的主要缺点是无论单词的实际重要性如何,它都将所有单词同等重要。

TFIDF向量器

为了克服计数向量器的缺点,我们可以使用TFIDF向量器。该算法还将整个文本语料库中的每个唯一单词映射到一个唯一的向量索引。但是,每个文档的向量值不是简单的计数,而是两个值的乘积:词频(TF)和逆文档频率(IDF)。

  1. 词频(TF):每个单词的TF是该单词在该文档中出现的次数,与计数向量器中的值相同。这是一个衡量单词对文档重要性的指标。
  2. 逆文档频率(IDF):它衡量这个词在整个语料库中的罕见程度。

最后,每个文档中每个单词的TFIDF值是单个TF和IDF分数的乘积。

这里的直觉是,在整个语料库中相对罕见的一个文档中的频繁单词是该文档的关键单词,并且具有较高的TFIDF分数。TFIDF的大多数实现都将值规范化为文档长度,以便较长的文档不会主导计算。

使用sklearn库在代码中实现TFIDF很简单,它以稍微复杂的方式计算IDF,实现标准化并防止除0。TFIDF是本文中唯一一个我们需要训练以学习语料库中所有独特单词及其相关IDF值的模型。

from sklearn.feature_extraction.text import TfidfVectorizer
model = TfidfVectorizer(lowercase=True, stop_words='english')

# Train the model
X_train = pd.concat([stsb_train['sentence1'], stsb_train['sentence2']]).unique()
model.fit(X_train)

# Generate Embeddings on Test
sentence1_emb = model.transform(stsb_test['sentence1'])
sentence2_emb = model.transform(stsb_test['sentence2'])

# Cosine Similarity
stsb_test['TFIDF_cosine_score'] = cos_sim(sentence1_emb, sentence2_emb)

虽然词袋方法直观,为我们提供了文本的向量表示,但它们在现实世界中的表现差异很大。在STSB任务中,TFIDF没有Jaccard相似性好,如结果部分所示。

词袋方法的其他潜在缺陷包括

  1. 如果文档数量很大,那么这种方法生成的向量将具有非常高的维度,因为语料库中会有许多独特的单词。
  2. 这些向量非常稀疏,因为大多数单词不会出现在大多数文档中。

以下测量文本相似性的方法通过使用预训练的词嵌入克服了这些限制。

单词移动距离(WMD)

Jaccard Similarity和TFIDF假设相似文本有许多相同的单词。但是,情况并非总是如此。

我们可以解决这个问题的一种方法是使用预训练的词嵌入。

document1: “Obama speaks to the media in Illinois” 
document2: “The president greets the press in Chicago”

词嵌入是将单词编码为数字向量的模型,这样相似的单词在向量空间中具有彼此相邻的向量。

有几种生成词嵌入的方法,最突出的是Word2Vec、GloVe和FastText。

由于我们需要比较包含多个单词的文本之间的相似性,从单个词嵌入到单个句子嵌入的最简单方法是计算该文本中所有词嵌入的元素平均值。然而,有一种更好的方法可以直接从词嵌入中计算文本之间的相似性,称为单词移动距离(WMD)。

WMD是一个文档中的词嵌入“移动”到我们正在比较的文档的词嵌入所需的最小距离。由于每个文档包含多个单词,WMD计算需要计算每个单词到其他单词的距离。它还根据每个单词的词频来进行衡量。

幸运的是,gensim库使用快速WMD算法高效地实现了这种复杂的计算。我们只需一行代码就可以轻松使用它!

尽管我们可以在WMD中使用任何词嵌入模型,但我决定使用在维基百科上预训练过的FastText模型,这主要是因为FastTexts使用子单词信息,并且不会遇到Word2Vec或GloVe可能遇到的词汇表外问题。

请注意,要对文本进行预处理,以删除非索引词、小写字母,并将它们进行逻辑化,以确保WMD计算仅使用信息性单词。

最后,由于WMD是一个距离度量,而我们正在寻找一个相似度量,因此我们将WMD值乘以-1(负WMD),以便更相似的文本具有更大的数值。

import gensim.downloader as api

# Load the pre-trained model
model = api.load('fasttext-wiki-news-subwords-300')

def word_movers_distance(row):
    # Text Processing
    sentence1 = text_processing(row['sentence1'])
    sentence2 = text_processing(row['sentence2'])

    # Negative Word Movers Distance
    return -model.wmdistance(sentence1, sentence2)


# Negative Word Movers Distance
stsb_test['NegWMD_score'] = stsb_test.progress_apply(word_movers_distance, axis=1)

在STSB数据集上,负WMD分数的表现仅略优于Jaccard相似性,因为该数据集中的大多数句子都有许多相似的单词。NegWMD在文本间通用词较少的数据集上的性能要比Jaccard好得多。

WMD的一个局限性是,WMD中使用的词嵌入是非上下文的,其中每个单词都得到相同的嵌入向量,而与它出现的句子的其他上下文无关。本文后面的算法也可以利用上下文来克服这个问题。

用现代上下文算法测量文本相似性

本节将讨论几种衡量语义文本相似性的技术,考虑到不同单词出现的上下文。这些方法通常比非上下文方法更准确。

通用句子编码器(USE)

在USE中,谷歌的研究人员首先对基于Transformer的多任务目标模型进行了预训练,然后将其用于迁移学习。

为了计算文本相似度,我们首先使用预训练的use模型计算句子中每个单词的上下文词嵌入。然后,我们通过执行所有单词向量的元素级求和并除以句子长度的平方根来规范化句子长度,从而计算句子嵌入。

一旦我们为每个句子都嵌入了USE,我们就可以使用本文开头定义的helper函数计算余弦相似性。研究人员已经公开了Tensorflow预训练好的模型,我们将直接使用该模型。

import tensorflow as tf
import tensorflow_hub as hub

# Load the pre-trained model
gpus = tf.config.list_physical_devices('GPU')
for gpu in gpus:
    # Control GPU memory usage
    tf.config.experimental.set_memory_growth(gpu, True)

module_url = 'https://tfhub.dev/google/universal-sentence-encoder/4'
model = hub.load(module_url)

# Generate Embeddings
sentence1_emb = model(stsb_test['sentence1']).numpy()
sentence2_emb = model(stsb_test['sentence2']).numpy()

# Cosine Similarity
stsb_test['USE_cosine_score'] = cos_sim(sentence1_emb, sentence2_emb)

与NegWMD度量相比,USE在STSB数据集上实现了显著的跳跃。它显示了在迁移学习环境中使用Transformer生成的上下文句子嵌入的潜力。随后,研究人员开发了更先进的方法,使用度量学习对基于Transformer的模型进行预训练,以获得更好的性能!

交叉编码器

2018年,BERT模型问世,打破了多项基准,开创了NLP的新纪元。随着时间的推移,研究人员继续改进原始的BERT模型,产生了一些显著的变体,如本文中讨论的RoBERTa、DistilBERT、ALBERT等。

BERT的力量来源于其名为屏蔽语言建模”(Masked Language Modeling,MLM)的自我监督预训练任务,在该任务中,我们随机隐藏一些单词,并训练模型预测缺失单词前后的单词。通过对大量文本的训练,BERT可以学习语言中各个单词之间的语义关系。

通过向BERT模型的输出中添加分类头,我们可以将BERT用作交叉编码器。交叉编码器模型将一对文本文档作为输入,并直接输出两个文档相似的概率。

通过在标记的STS数据集上微调预训练的BERT模型,我们可以在STS任务上取得最先进的结果!

我们将使用sentence_transformers库有效地使用在SNLI和STS数据集上训练的各种开源交叉编码器模型。

from sentence_transformers import CrossEncoder

# Load the pre-trained model
model = CrossEncoder('cross-encoder/stsb-roberta-base')

sentence_pairs = []
for sentence1, sentence2 in zip(stsb_test['sentence1'], stsb_test['sentence2']):
    sentence_pairs.append([sentence1, sentence2])

stsb_test['SBERT CrossEncoder_score'] = model.predict(sentence_pairs, show_progress_bar=True)

交叉编码器不输出任何嵌入向量,因此无法扩展到数千个文档之外。但总的来说,BERT交叉编码器在大多数句子相似性任务中提供了最佳性能。在我们的STSB数据集中,BERT交叉编码器提供了最好的分数!

度量学习

度量学习是生成嵌入的最有前途的方法之一,特别是对于相似性搜索应用程序。在最基本的层面上,在度量学习中,

  1. 我们使用BERT等神经网络将文本转换为嵌入。
  2. 我们构造这些嵌入,以便语义相似的文本彼此靠近,而不相似的文本则相隔更远。

训练度量学习模型需要在数据处理方式和模型训练方式方面进行创新,如我在前一篇文章中详细描述的。

在用这种方法训练模型之后,我们可以通过数学计算两个文本向量之间的余弦相似性来发现它们之间的相似性。

SBERT双编码器

Sentence Transformers(也称为SBERT)是当前最先进的NLP句子嵌入。它使用BERT及其变体作为基本模型,并使用一种称为对比学习的度量学习进行预训练。

在对比学习中,对比损失函数比较两个嵌入是相似的(0)还是不同的(1)。

SBERT的核心思想如下。

  1. 使用标记的SNLI数据集或STS数据集作为训练数据。这些数据集包含数千对标注为相似或不相似的句子。
  2. 对于训练数据集中的每个文本,使用任何预训练的BERT模型作为编码器,计算该文本的上下文词嵌入。
  3. 计算所有标记嵌入的元素平均值,以获得整个文本的单个固定维句子嵌入。此操作称为平均池。
  4. 使用具有对比损失的暹罗网络体系结构训练模型。该模型的目标是将相似文本的嵌入移近,使它们之间的距离接近0。相反,该模型的目的是将不同文本的嵌入移动得更远,使它们彼此之间的距离更大。
  5. 完成模型训练后,我们可以通过计算这两个文本嵌入之间的余弦相似性来比较任意两个文本。

SBERT模型每次只接受一个文本作为输入,并输出一个固定维嵌入向量作为输出。然后,我们可以通过计算这两个文档嵌入之间的余弦相似性来比较任何两个文档。

虽然在STSB数据集上,双编码器Sentence Transformers的性能略低于交叉编码器,但通过将 Bi-Encoder 与Milvus等矢量搜索数据库相结合,在扩展到数十亿甚至数万亿个文档时,Bi-Encoder 表现出色!

我们将使用sentence_transformers库来有效地使用在SNLI和STS数据集上训练的各种开源SBERT Bi编码器模型。

from sentence_transformers import SentenceTransformer

# Load the pre-trained model
model = SentenceTransformer('stsb-mpnet-base-v2')

# Generate Embeddings
sentence1_emb = model.encode(stsb_test['sentence1'], show_progress_bar=True)
sentence2_emb = model.encode(stsb_test['sentence2'], show_progress_bar=True)

# Cosine Similarity
stsb_test['SBERT BiEncoder_cosine_score'] = cos_sim(sentence1_emb, sentence2_emb)

尽管STSB数据集的性能很好,但遗憾的是,Sentence Transformers是完全受监督的模型,需要大量标记的句子对语料库来训练。

因此,在新领域中采用Sentence Transformers是一个收集大量高质量标记数据的耗时且昂贵的过程。

幸运的是,在半监督和自我监督学习方面的一些前沿研究显示出了可喜的结果!

SimCSE

在我上一篇关于计算机视觉嵌入的文章中,我介绍了SimCLR,一种使用对比度损失学习图像嵌入的自我监督算法。在本文中,让我们讨论SimCSE,SimCLR的NLP等价物。

SimCSE代表句子嵌入的简单对比学习。如果标签数据可用,我们可以将其训练为受监督的模型,或者以完全无监督的方式!

SimCSE的核心思想如下。

  1. 给定一个文本文档,使用任何预训练的BERT模型作为编码器计算该文本的嵌入,并获取[CLS]的嵌入。
  2. 通过在原始嵌入上应用两个不同的“删除”遮罩,创建同一文本嵌入的两个噪波版本。由相同输入文本生成的这两个噪声嵌入被视为“正”对,模型预计它们的余弦距离为0。SimCSE论文中的实验发现,对于STSB数据集来说,0.1的删除率是最佳的。
  3. 我们将批次中所有其他文本的嵌入视为“负值”。该模型预计“负数”与上一步的目标文本嵌入的余弦距离为1。然后,损失函数更新编码器模型的参数,使嵌入更接近我们的期望。
  4. 监督SimCSE还有一个额外的步骤,我们使用自然语言推理(NLI)标记的数据集从标记为“隐含”的文本中获取“正”对,从标记为”矛盾“的文本中获得“负”对

下图从概念上解释了整个过程。

SimCSE模型是使用SimCSE方法训练的双编码器Sentence Transformers模型。因此,我们可以直接重用Bi-EncoderSentence Transformers模型中的所有代码,但将预训练的模型更改为SimCSE模型。

########## Supervised ##########
# Load the pre-trained model
model = SentenceTransformer('princeton-nlp/sup-simcse-roberta-large')

# Generate Embeddings
sentence1_emb = model.encode(stsb_test['sentence1'], show_progress_bar=True)
sentence2_emb = model.encode(stsb_test['sentence2'], show_progress_bar=True)

# Cosine Similarity
stsb_test['SimCSE Supervised_cosine_score'] = cos_sim(sentence1_emb, sentence2_emb)


########## Un-Supervised ##########
# Load the pre-trained model
model = SentenceTransformer('princeton-nlp/unsup-simcse-roberta-large')

# Generate Embeddings
sentence1_emb = model.encode(stsb_test['sentence1'], show_progress_bar=True)
sentence2_emb = model.encode(stsb_test['sentence2'], show_progress_bar=True)

# Cosine Similarity
stsb_test['SimCSE Unsupervised_cosine_score'] = cos_sim(sentence1_emb, sentence2_emb)

从STSB数据集的结果来看,与受监督的SimCSE和其他受监督的Sentence Transformers模型相比,未受监督的SimCSE模型的性能显著下降,但在没有足够的标记数据或收集成本高昂的领域中,无监督SimCSE将是一种可行的方法。

OpenAI

所有基于BERT的模型(如Sentence Transformers和SimCSE)的一个重要限制是,它们只能对长达512个单词的文本进行编码。这一限制是因为BERT系列模型号有512个单词输入限制。

此外,由于BERT的子单词分词器可能会将每个单词拆分为多个标记,因此可以使用这些技术转换为嵌入的文本需要少于512个单词。如果需要比较较长文档之间的相似性,可能会出现问题。

非BERT模型不面临这一限制,但其性能比基于BERT的模型差,因此,如果有更好的替代方案,我们宁愿避免使用它们。

生成最先进的嵌入的最后一种方法是使用付费托管服务,如OpenAI的嵌入端点。它支持最多2048个单词的文本,因此它非常适合于长度超过BERT 512个单词限制的较长文本文档。然而,OpenAI端点价格昂贵,尺寸较大(12288个尺寸,而基于BERT的模型为768个尺寸),与同类最佳的免费开源Sentence Transformers模型相比,性能有所下降。

为了让你知道它的成本有多高,我花了大约20美元在这个小型STSB数据集上生成OpenAI-Davinci嵌入,即使在确保每个唯一文本只生成一次嵌入之后!

即使对于一个大型组织来说,将这个嵌入扩展到一个巨大的语料库也太昂贵了。收集标记数据并在内部训练你的模型可能会更便宜。

因此,我认为这项技术在现实世界中的用途有限,但我仍将其包含在本文中以供完成。

import openai
import os
import pickle
openai.api_key = 'update_your_openai_API_key_here'

if os.path.exists('../data/nlp/davinci_emb.pkl'):
    print('Loading Davinci Embeddings')
    with open('../data/nlp/davinci_emb.pkl', 'rb') as f:
        davinci_emb = pickle.load(f)
else:
    print('Querying Davinci Embeddings')
    davinci_emb = {}
    engine='text-similarity-davinci-001'

    unique_sentences = list(set(stsb_test['sentence1'].values.tolist() + stsb_test['sentence2'].values.tolist()))
    for sentence in tqdm(unique_sentences):
        if sentence not in davinci_emb.keys():
            davinci_emb[sentence] = openai.Embedding.create(input = [sentence], 
                                                            engine=engine)['data'][0]['embedding']
    # Save embeddings to file      
    with open('../data/nlp/davinci_emb.pkl', 'wb') as f:
        pickle.dump(davinci_emb, f)

# Generate Embeddings
sentence1_emb = [davinci_emb[sentence] for sentence in stsb_test['sentence1']]
sentence2_emb = [davinci_emb[sentence] for sentence in stsb_test['sentence2']]

# Cosine Similarity
stsb_test['OpenAI Davinci_cosine_score'] = cos_sim(sentence1_emb, sentence2_emb)

结果与结论

最后,让我们比较一下我在本文中介绍的各种文本相似性方法的结果。许多关于语义文本相似性的论文使用Spearman秩相关系数来衡量模型的性能,因为它对本文描述的异常值、非线性关系或非正态分布数据不敏感。

因此,我们将计算每种方法的相似性分数与STSB数据集提供的实际相似性分数标签之间的Spearman秩相关。使用pandas的内置corr方法计算相对简单,如下所示。

score_cols = [col for col in stsb_test.columns if '_score' in col]

# Spearman Rank Correlation
spearman_rank_corr = stsb_test[score_cols].corr(method='spearman').iloc[1:, 0:1]*100
spearman_rank_corr.head(10)

下面的Spearman秩相关分数表明,SBERT交叉编码器的性能最好,紧随其后的是SBERT双编码器。

无监督SimCSE的性能非常有希望,因为它比其他方法(如Jaccard、TFIDF、WMD和USE)要好得多。

最后,OpenAI Davinci显示了良好的性能,但它的成本超过了接受超过512个单词的文本的大部分好处。

我们绘制了各种算法的实际相似性分数和预测相似性之间的相关性。从视觉上看,SBERT和SimCSE的相关性非常强!

from plotly.subplots import make_subplots
import plotly.graph_objects as go

nrows = 4
ncols = 3
plot_array = np.arange(0, nrows*ncols).reshape(nrows, ncols)

subplot_titles = [f'{row.Index.split("_")[0]}: {row.similarity_score:.2f}' for row in spearman_rank_corr.itertuples()]
fig = make_subplots(rows=nrows, cols=ncols, subplot_titles=subplot_titles)

for index, score in enumerate(spearman_rank_corr.index):
    row, col = np.argwhere(plot_array == index)[0]

    fig.add_trace(
        go.Scatter(
            x=stsb_test[score_cols[0]], 
            y=stsb_test[score],
            mode='markers',
        ),
        row=row+1, col=col+1
    )


fig.update_layout(height=700, width=1000, title_text='Spearman Rank Correlation (ρ × 100)', showlegend=False)
fig.show()

我制定了下面的流程图,以帮助你为自己的语义文本相似性任务选择一种方法。我希望它能让你为你的用例选择最好的技术!

要了解如何比较图像之间的相似性,请阅读下面的帖子。

https://towardsdatascience.com/powering-semantic-similarity-search-in-computer-vision-with-state-of-the-art-embeddings-f6c183fff134

请阅读以下文章,了解如何在生产环境中部署文本图像多模式搜索引擎。

https://blog.milvus.io/supercharged-semantic-similarity-search-in-production-f2a3c35c4e00

感谢阅读!

免责声明:作者保留权利,不代表本站立场。如想了解更多和作者有关的信息可以查看页面右侧作者信息卡片。
反馈
to-top--btn