《Comparing Sentence Similarity Methods》Yves Peirsman; May 2, 2018

原文链接:http://nlp.town/blog/sentence-similarity/

这篇文章对比了几种当时最流行的计算句子相似度的方法。这里是代码,代码超赞!

数据集

对比实验使用了两个测试集,一个STS Benchmark数据集,一个SICK data数据集。

方法

Baseline

  • 表示方法:平均词嵌入
  • 度量方法:余弦相似度

改进思路:去停用词;加权,比如tf-idf;

Word Mover's Distance

词移距离,论文:http://proceedings.mlr.press/v37/kusnerb15.pdf

Smooth Inverse Frequency

  • 加权,权重*词向量,权重=a/(a+p(w)),a是一个常数,通常是0.001,p(w)是词在语料集中的频率;
  • 移除第一主成分,比如but、just等;

论文:https://openreview.net/forum?id=SyK00v5xx

from sklearn.decomposition import TruncatedSVD

def remove_first_principal_component(X):
    svd = TruncatedSVD(n_components=1, n_iter=7, random_state=0)
    svd.fit(X)
    pc = svd.components_
    XX = X - X.dot(pc.transpose()) * pc
    return XX


def run_sif_benchmark(sentences1, sentences2, model, freqs={}, use_stoplist=False, a=0.001): 
    total_freq = sum(freqs.values())
    
    embeddings = []
    
    # SIF requires us to first collect all sentence embeddings and then perform 
    # common component analysis.
    for (sent1, sent2) in zip(sentences1, sentences2): 
        
        tokens1 = sent1.tokens_without_stop if use_stoplist else sent1.tokens
        tokens2 = sent2.tokens_without_stop if use_stoplist else sent2.tokens
        
        tokens1 = [token for token in tokens1 if token in model]
        tokens2 = [token for token in tokens2 if token in model]
        
        weights1 = [a/(a+freqs.get(token,0)/total_freq) for token in tokens1]
        weights2 = [a/(a+freqs.get(token,0)/total_freq) for token in tokens2]
        
        embedding1 = np.average([model[token] for token in tokens1], axis=0, weights=weights1)
        embedding2 = np.average([model[token] for token in tokens2], axis=0, weights=weights2)
        
        embeddings.append(embedding1)
        embeddings.append(embedding2)
        
    embeddings = remove_first_principal_component(np.array(embeddings))
    sims = [cosine_similarity(embeddings[idx*2].reshape(1, -1), 
                              embeddings[idx*2+1].reshape(1, -1))[0][0] 
            for idx in range(int(len(embeddings)/2))]

    return sims

预训练

  • Facebook‘s InferSent
  • Google Sentence Encoder
  • 没有使用Transformer模型

结果

Baseline

  • w2v比glove效果好
  • 去停用词和tf-idf加权不稳定

Word Mover's Distance

  • 效果不明显

Smooth Inverse Frequency

  • 比平均词嵌入效果好

Pre-trained encoders

  • 使用Pearson correlation coefficient评估,效果和SIF差不多;
  • 使用Spearman correlation评估,google sentence encoder表现较好;

结论

句子相似度是一个复杂的事物。句子的含义不仅和句子中的词有关,也和词的组合方式有关。语义相似度和句子相似度也有较大的差异,目前句子嵌入方法也只是刚刚从表面起步。

  • 通常w2v比GloVe更好;
  • SIF通常比简单的平均词嵌入效果好;
  • 如果使用预训练方法,Google Sentence Encoder比InferSent效果好;
posted @ 2020-07-09 10:46  ZH奶酪  阅读(133)  评论(0编辑  收藏