需要帮助创建一个合适的模型来预测两个句子之间的语义相似性

Need help in creating an appropriate model to predict semantic similarity between two sentences

我是 ML 领域的新手,正在尝试创建一个模型来预测两个句子之间的语义相似性。 我正在使用以下方法:

1.Using gensim 包中的 word2vec 模型将问题中出现的每个单词向量化

2.Calculate 每个 sentence/document

中所有单词的平均向量
import numpy as np
from scipy import spatial

index2word_set = set(model.wv.index2word)

def avg_feature_vector(sentence, model, num_features, index2word_set):
    words = sentence.split()
    feature_vec = np.zeros((num_features, ), dtype='float32')
    n_words = 0
    for word in words:
        if word in index2word_set:
            n_words += 1
            feature_vec = np.add(feature_vec, model[word])
    if (n_words > 0):
        feature_vec = np.divide(feature_vec, n_words)
    return feature_vec

3.Next计算这两个平均向量之间的余弦相似度

s1_afv = avg_feature_vector('this is a sentence', model=model, 
num_features=300, index2word_set=index2word_set)
s2_afv = avg_feature_vector('this is also sentence', model=model, 
num_features=300, index2word_set=index2word_set)
sim = 1 - spatial.distance.cosine(s1_afv, s2_afv)
print(sim)

参考Whosebug问题: How to calculate the sentence similarity using word2vec model of gensim with python

以下挑战需要帮助:

因为我想创建一个模型来预测两个句子之间的语义相似性,所以我不太确定:

1.Which 模型最适合这个问题

2.Next更重要的是如何训练那个模型?

我是否应该创建一个矩阵,其中每一行将包含两个句子: sen1 和 sen2,我会将它们矢量化并计算余弦相似度(按照上述方法)

然后对于训练数据:

X_Train:sen1 和 sen2 的平均向量及其余弦相似度值

y_Train(预测):一组二进制值(如果余弦相似度 > 0.7 则为 1 或类似值,否则为 0)

我很困惑我的方法是否正确以及如何以工作代码库的形式放置正确的方法。

互联网和在线资料是我学习 ML 的唯一老师;因此请求您的指导,以帮助消除我在理解上的差距,并帮助为我的问题提出一个好的工作模型。

您的总体做法是合理的。句子中单词向量的平均值通常可以用作句子的粗略摘要向量。 (还有许多其他可能做得更好的技术,但这是一个很好的简单开始。)

您可以使用其他人的预训练词向量,但如果您的域中有大量良好的文本训练集,这些词向量可能会更好。您应该寻找有关如何使用 gensim 训练您自己的词向量的教程。例如,它包含一个演示 Jupyter notebook word2vec.ipynb,在其 docs/notebooks 目录中,您也可以在线查看:

https://github.com/RaRe-Technologies/gensim/blob/develop/docs/notebooks/word2vec.ipynb

您当前的 avg_feature_vector() 功能存在一些问题。特别是:

  • 如果你传入model,它已经包含了固定的index2word列表,以及一个已经确定的维数——所以不需要多余地传递那些

  • 您正在遍历模型中的所有单词,而不仅仅是您句子中的单词,因此不只是根据您的句子进行计算

  • 有更好、更 pythonic 的方法来执行您正在尝试的各种数组数学运算——包括在 numpy 库中一个简单的 mean() 函数,它可以让您省心adding/dividing 创造平均值

您可能想解决这些问题,作为练习,但您也可以在词向量上使用实用方法 model。特别是,查看 n_similarity() - 它专门采用两组词,自动对每组进行平均,然后报告相似度值(接近 1.0 表示更相似,接近 -1.0 表示最不相似)两组之间。参见:

https://radimrehurek.com/gensim/models/keyedvectors.html#gensim.models.keyedvectors.Word2VecKeyedVectors.n_similarity

因此,如果您在 sent1sent2 中有两个句子(作为字符串),并且在 kv_model,你可以通过以下方式得到句子的相似度:

kv_model.n_similarity(sent1.split(), sent2.split())

(如果模型不知道任何单词标记,您可能仍然会出错。)

您是否真的为不同的句子创建平均向量并将它们存储在一些 list/dict/dataframe/etc 中,或者只是记住某处的成对相似性,这将取决于您接下来要做什么。

并且,在您掌握了处理这种简单的文本相似性度量的基础知识之后,您可以研究其他技术。例如,另一种使用词向量比较两个文本的方法——但不是通过简单平均——称为 "Word Mover's Distance"。 (虽然计算起来要慢一点。)

为了比较,另一种将文本折叠成单个向量的技术在 gensim 中可用,如 Doc2Vec – 它的工作原理与 Word2Vec 非常相似,但也会创建向量-per-longer-text,而不只是 vectors-per-individual-word。

首先感谢你提出这个问题,我也在研究同样的问题,首先这不是一个简单的问题,因为它涉及语言的细微差别以及如何让机器理解人类语言。

自从提出这个问题到现在,ML/AI 世界发生了很多变化,所以我认为更新这个答案可能会对某些人有所帮助。

你的方法的问题是获取一个句子中所有单词的平均值并将其取平均值以获得你的句子的派生向量,考虑到当时的工具它可能没问题但你应该做一些事情更复杂,例如来自 gensim 的 Doc2Vec

对于今天的时间,我觉得存在更复杂、更有效的词嵌入而不是句子嵌入,您可以使用。

HuggingFace 的 this github 回购中精心策划了其中的少数列表。

还有一个很棒的讨论,我想向阅读本文的人指出:

https://github.com/huggingface/transformers/issues/876

人们经常尝试使用 ElasticSearch BM25 + Embeddings 的组合,但实际准确率仍然较低。

我仍在寻找可以帮助我对域数据进行语义搜索的语义搜索技术。

最后是 Transfer Learning,您可以在其中使用预训练模型并在其上添加域数据以微调该模型。

你可以看看这个例子: https://github.com/UKPLab/sentence-transformers/blob/master/examples/application_semantic_search.py

但是这样我们也无法考虑 ontology 以及单词重叠应该出现的各种场景。