Python으로 Gensim의 word2vec 모델을 사용하여 문장 유사성을 계산하는 방법


125

Gensim Word2Vec 에 따르면 gensim 패키지의 word2vec 모델을 사용하여 두 단어 사이의 유사성을 계산할 수 있습니다.

예 :

trained_model.similarity('woman', 'man') 
0.73723527

그러나 word2vec 모델은 문장 유사성을 예측하지 못합니다. gensim에서 문장 유사성을 가진 LSI 모델을 찾았지만 word2vec 모델과 결합 할 수없는 것 같습니다. 내가 가지고있는 각 문장의 말뭉치 길이는 그리 길지 않습니다 (10 단어 미만). 그렇다면 목표를 달성하는 간단한 방법이 있습니까?


4
이 문제에 대해 설명하는 ACL 자습서가 있습니다 (특히) : youtube.com/watch?v=_ASOqXiWBVo&feature=youtu.be
Emiel

7
이제 gensim의 doc2vec를 사용하고 동일한 모듈에서 문장 유사성을 얻을 수 있습니다
kampta

@kampta. 안녕하세요 구현을 보여주는 게시물을 제안 하시겠습니까?
Ian_De_Oliveira

답변:


86

이것은 실제로 당신이 묻는 꽤 어려운 문제입니다. 문장 유사성을 계산하려면 문장의 문법적 모델을 구축하고 동등한 구조를 이해해야합니다 (예 : "그는 어제 가게에 걸어 갔다"및 "어제 가게에 걸어갔습니다"). 대명사와 동사뿐 아니라 고유 명사, 많은 실제 텍스트 예제에서 통계적 동시 발생 / 관계 찾기 등

시도해 볼 수있는 가장 간단한 방법은-이것이 얼마나 잘 수행 될지 그리고 확실히 최적의 결과를 제공하지는 못하지만-먼저 모든 "중지"단어 ( "the", "an "등)을 입력하고 두 문장의 단어에 대해 word2vec를 실행하고 한 문장의 벡터를 합산하고 다른 문장의 벡터를 합산 한 다음 차이점을 찾습니다. 합계. 단어 별 차이 대신 요약하면 적어도 단어 순서에 영향을받지 않을 것입니다. 즉, 이것은 많은 방법으로 실패 할 것이며 어떤 방법으로도 좋은 해결책이 아닙니다 (이 문제에 대한 좋은 해결책은 거의 항상 NLP, 기계 학습 및 기타 영리함을 포함합니다).

따라서 간단히 대답 할 수는 없습니다.이 작업을 수행하는 쉬운 방법은 없습니다 (적어도 제대로 수행하지 않음).


4
그 쪽이 맞는 거 같아요. 가장 간단한 방법은 모든 단어 벡터를 한 문장에 모아서 합계의 차이를 찾는 것인데,이 간단한 방법이 단어 수에 영향을받을까요? 한 문장에 단어가 많을수록 더 많은 히스토그램이 요약됩니다.
zhfkt

2
@zhfkt, 아마도 그렇습니다. 따라서 그것을 고려하기 위해 단어의 수 또는 일부로 나누어야 할 수도 있습니다. 어느 쪽이든 이와 같은 휴리스틱은 심각한 결함이 있습니다.
Michael Aaron Safyan 2014 년


75

gensim을 사용하고 있으므로 아마도 doc2vec 구현을 사용해야합니다. doc2vec는 word2vec를 구문, 문장 및 문서 수준으로 확장 한 것입니다. 여기에 설명 된 매우 간단한 확장입니다.

http://cs.stanford.edu/~quocle/paragraph_vector.pdf

Gensim은 직관적이고 빠르며 유연하기 때문에 훌륭합니다. 멋진 점은 공식 word2vec 페이지에서 사전 훈련 된 단어 임베딩을 가져올 수 있고 gensim의 Doc2Vec 모델의 syn0 레이어가 노출되어 이러한 고품질 벡터로 단어 임베딩을 시드 할 수 있다는 것입니다!

GoogleNews-vectors-negative300.bin.gz ( Google 코드에 링크 됨 )

저는 gensim이 벡터 공간에 문장을 삽입하는 가장 쉬운 도구라고 생각합니다.

위의 Le & Mikolov의 논문에서 제안 된 것과 다른 문장-벡터 기법이 있습니다. Stanford의 Socher와 Manning은 확실히이 분야에서 일하는 가장 유명한 연구자입니다. 그들의 작업은 구성 원칙에 기반을두고 있습니다. 문장의 의미는 다음과 같습니다.

1. semantics of the words

2. rules for how these words interact and combine into phrases

그들은 문장 수준의 표현을 구축하기 위해 구성 성을 사용하는 방법에 대해 몇 가지 그러한 모델을 제안했습니다 (갈수록 복잡 해짐).

2011- 재귀 적 오토 인코더 전개 (매우 비교적 간단합니다. 관심이 있으면 여기에서 시작)

2012- 행렬-벡터 신경망

2013- 신경 텐서 네트워크

2015- 트리 LSTM

그의 논문은 모두 socher.org에서 볼 수 있습니다. 이 모델 중 일부를 사용할 수 있지만 여전히 gensim의 doc2vec을 권장합니다. 우선 2011 URAE는 그다지 강력하지 않습니다. 또한 뉴스와 같은 데이터를 패러 프레이징하는 데 적합한 가중치로 사전 학습됩니다. 그가 제공하는 코드로는 네트워크를 재교육 할 수 없습니다. 또한 다른 단어 벡터로 바꿀 수 없으므로 Turian의 2011 년 pre-word2vec 임베딩에 갇혀 있습니다. 이러한 벡터는 확실히 word2vec 또는 GloVe 수준이 아닙니다.

아직 Tree LSTM을 사용하지 않았지만 매우 유망 해 보입니다!

tl; dr 예, gensim의 doc2vec를 사용하십시오. 그러나 다른 방법이 존재합니다!


사전 훈련 된 word2vec 값으로 doc2vec 모델을 초기화하는 방법에 대한 자세한 정보가 있습니까?
Simon H

42

word2vec를 사용하는 경우 모든 문장 / 문서의 모든 단어에 대한 평균 벡터를 계산하고 벡터간에 코사인 유사성을 사용해야합니다.

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

유사성 계산 :

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)

> 0.915479828613

4
index2word_set 및 model.index2word에 대해 더 자세히 설명해 주시겠습니까? 감사합니다.
theteddyboy apr

3
"평균 벡터"를 계산하는 것은 전혀 계산하지 않는 것만 큼 임의적 인 선택입니다.
-08-16

2
왜 이것이 최고의 대답이 아닌지 놀랐습니다. 꽤 잘 작동하며 평균화 방법이 갖는 시퀀스 문제가 없습니다.
Asim

이것이 내가 찾고 있던 대답입니다. 내 문제를 해결했습니다. 솔루션에 감사드립니다
iRunner

25

Word Mover의 거리 알고리즘을 사용할 수 있습니다. 여기 에 WMD에 대한 간단한 설명이 있습니다.

#load word2vec model, here GoogleNews is used
model = gensim.models.KeyedVectors.load_word2vec_format('../GoogleNews-vectors-negative300.bin', binary=True)
#two sample sentences 
s1 = 'the first sentence'
s2 = 'the second text'

#calculate distance between two sentences using WMD algorithm
distance = model.wmdistance(s1, s2)

print ('distance = %.3f' % distance)

추신 : 가져 오기에 대한 오류가 발생하는 경우 pyemd 라이브러리 하면 다음 명령을 사용하여 설치할 수 있습니다.

pip install pyemd

2
이전에 WMD를 사용했는데 조용히 잘 작동하지만 큰 말뭉치에서는 질식 할 것입니다. SoftCosineSimilarity를 ​​사용해보십시오. Gensim에서도 발견됨 ( twitter.com/gensim_py/status/963382840934195200 )
krinker

1
WMD는 매우 빠르지 않지만 말뭉치를 쿼리하려는 경우입니다.
Amartya

18

두 단어 벡터 세트의 합을 계산하면 diff가 아닌 벡터 사이의 코사인을 취해야합니다. 코사인은 정규화 된 두 벡터의 내적을 취하여 계산할 수 있습니다. 따라서 단어 수는 요인이 아닙니다.


1
이 작업을 수행하는 방법에 대해 약간의 의사 코드를 제공 할 수 있습니까 (저는 gensim / python을 사용하지 않습니다)
dcsan

13

문서 에서 단어 목록을 가져와 유사점을 비교 하는 기능이 있습니다 .

s1 = 'This room is dirty'
s2 = 'dirty and disgusting room' #corrected variable name

distance = model.wv.n_similarity(s1.lower().split(), s2.lower().split())

12

문장의 의미 적 유사성을 계산하려는 사람들을 돕기 위해 기존 솔루션을 업데이트하고 싶습니다.

1 단계:

gensim을 사용하여 적합한 모델을로드하고 문장의 단어에 대한 단어 벡터를 계산하여 단어 목록으로 저장

2 단계 : 문장 벡터 계산

문장 사이의 의미 적 유사성 계산은 이전에는 어려웠지만 최근에는 문장 내 단어 벡터의 가중 평균을 계산하고 제거하는 간단한 접근 방식을 제안하는 " A SIMPLE BUT TOUGH-TO-BEAT BASELINE FOR SENTENCE EMBEDDINGS "라는 논문 이 제안되었습니다. 첫 번째 주성분에 대한 평균 벡터의 투영 여기에서 단어 w의 가중치는 매개 변수가되는 a / (a ​​+ p (w))이고 p (w)는 부드러운 역 주파수라고하는 (추정 된) 단어 빈도입니다. .이 방법이 훨씬 더 잘 수행됩니다.

논문에서 제안한 방법 인 SIF (smooth inverse frequency)를 이용하여 문장 벡터를 계산하는 간단한 코드가 여기에 있습니다.

3 단계 : sklearn cosine_similarity를 ​​사용하여 문장에 대해 두 개의 벡터를로드하고 유사성을 계산합니다.

이것은 문장 유사성을 계산하는 가장 간단하고 효율적인 방법입니다.


2
아주 좋은 종이. 참고 : SIF 구현에 대한 링크는 Python의 Counter ()를 사용하고 키로 dict를 반환하여 쉽게 수행 할 수있는 get_word_frequency () 메서드를 작성해야합니다. 고유 단어 w, 값 : # w / # total doc len
Quetzalcoatl

8

다음 방법을 사용하고 있으며 잘 작동합니다. 먼저 POSTagger를 실행 한 다음 불용어 (행정사, 접속사, ...)를 제거하기 위해 문장을 필터링해야합니다. TextBlob APTagger를 권장 합니다. 그런 다음 문장의 각 단어 벡터의 평균을 취하여 word2vec을 만듭니다. Gemsim word2vecn_similarity 메소드는 비교할 두 단어 세트를 전달할 수 있도록 허용함으로써 정확히 수행합니다.


벡터의 평균을 취하는 것과 문장 벡터를 만들기 위해 벡터를 추가하는 것의 차이점은 무엇입니까?
Καrτhικ

1
차이는 벡터의 크기가 모든 문장에 대한 고정되어 있다는 것입니다
lechatpito

코사인 유사성을 사용하는 한 차이가 없습니다. @lechatpito 벡터 크기와 관련이 없습니다. 벡터는 연결되지 않고 합산됩니다.
Wok

6

구나 문장과 같은 긴 텍스트를 비교하는 문제를 해결하기위한 Word2Vec의 확장이 있습니다. 그중 하나는 paragraph2vec 또는 doc2vec입니다.

"문장 및 문서의 분산 표현" http://cs.stanford.edu/~quocle/paragraph_vector.pdf

http://rare-technologies.com/doc2vec-tutorial/


2
제시된 알고리즘이 어떻게 작동하는지 간단히 언급 할 가치가 있습니다. 기본적으로 모든 발화에 고유 한 "토큰"을 추가하고 word2vec 벡터를 계산합니다. 마지막에 말뭉치의 각 단어에 대한 단어 벡터를 얻습니다 (모든 단어와 고유 한 단어를 요청하는 경우). 발화의 각 고유 한 "토큰"은 해당 발화를 나타냅니다. 논문에 제시된 결과에 대한 논란이 있지만 그것은 또 다른 이야기입니다.
Vladislavs Dovgalecs

5

Gensim단락 삽입을 위해 Doc2Vec 이라는 모델을 구현합니다 .

IPython 노트북으로 제공되는 다양한 튜토리얼이 있습니다.

또 다른 방법은 Word2Vec에 의존 하고 이 튜토리얼에 표시된대로 WMD (Word Mover 's Distance) .

대체 솔루션은 평균 벡터에 의존하는 것입니다.

from gensim.models import KeyedVectors
from gensim.utils import simple_preprocess    

def tidy_sentence(sentence, vocabulary):
    return [word for word in simple_preprocess(sentence) if word in vocabulary]    

def compute_sentence_similarity(sentence_1, sentence_2, model_wv):
    vocabulary = set(model_wv.index2word)    
    tokens_1 = tidy_sentence(sentence_1, vocabulary)    
    tokens_2 = tidy_sentence(sentence_2, vocabulary)    
    return model_wv.n_similarity(tokens_1, tokens_2)

wv = KeyedVectors.load('model.wv', mmap='r')
sim = compute_sentence_similarity('this is a sentence', 'this is also a sentence', wv)
print(sim)

마지막으로 Tensorflow를 실행할 수 있다면 https://tfhub.dev/google/universal-sentence-encoder/2를 시도해 볼 수 있습니다.


4

이전 답변에서 제공 한 방법을 시도했습니다. 작동하지만 그 주요 단점은 단어가 많을수록 더 긍정적 인 의미 효과가 있기 때문에 문장이 길수록 유사성이 더 커진다는 것입니다 (유사성을 계산하기 위해 두 문장의 두 평균 임베딩의 코사인 점수를 사용합니다). 문장에 추가됩니다.

나는 내 마음을 변경하고 내장 대신 같은 연구 문장을 사용해야하는 생각 이 종이 .


3

Facebook Research 그룹은 InferSent Results라는 새로운 솔루션을 출시하고 코드가 Github에 게시되어 저장소를 확인합니다. 꽤 굉장합니다. 나는 그것을 사용할 계획입니다. https://github.com/facebookresearch/InferSent

그들의 종이 https://arxiv.org/abs/1705.02364 요약 : 많은 현대 NLP 시스템은 이전에 대규모 말뭉치에 대해 감독되지 않은 방식으로 훈련 된 단어 임베딩을 기본 기능으로 사용합니다. 그러나 문장과 같은 더 큰 텍스트 청크에 대한 임베딩을 얻으려는 노력은 그다지 성공적이지 못했습니다. 감독되지 않은 문장 표현을 학습하려는 여러 시도는 널리 채택되기에 충분한 성능에 도달하지 못했습니다. 이 백서에서는 Stanford Natural Language Inference 데이터 세트의지도 데이터를 사용하여 훈련 된 범용 문장 표현이 다양한 전송 작업에서 SkipThought 벡터와 같은 비지도 방법을 지속적으로 능가하는 방법을 보여줍니다. 컴퓨터 비전이 ImageNet을 사용하여 기능을 얻은 다음 다른 작업으로 전송할 수있는 것과 매우 유사합니다. 우리의 연구는 다른 NLP 작업에 대한 전이 학습에 대한 자연어 추론의 적합성을 나타내는 경향이 있습니다. 인코더는 공개적으로 사용할 수 있습니다.


3

Word2Vec을 사용하지 않는 경우 포함을 위해 BERT를 사용하여 찾을 수있는 다른 모델이 있습니다. 아래는 참조 링크입니다. https://github.com/UKPLab/sentence-transformers

pip install -U sentence-transformers

from sentence_transformers import SentenceTransformer
import scipy.spatial

embedder = SentenceTransformer('bert-base-nli-mean-tokens')

# Corpus with example sentences
corpus = ['A man is eating a food.',
          'A man is eating a piece of bread.',
          'The girl is carrying a baby.',
          'A man is riding a horse.',
          'A woman is playing violin.',
          'Two men pushed carts through the woods.',
          'A man is riding a white horse on an enclosed ground.',
          'A monkey is playing drums.',
          'A cheetah is running behind its prey.'
          ]
corpus_embeddings = embedder.encode(corpus)

# Query sentences:
queries = ['A man is eating pasta.', 'Someone in a gorilla costume is playing a set of drums.', 'A cheetah chases prey on across a field.']
query_embeddings = embedder.encode(queries)

# Find the closest 5 sentences of the corpus for each query sentence based on cosine similarity
closest_n = 5
for query, query_embedding in zip(queries, query_embeddings):
    distances = scipy.spatial.distance.cdist([query_embedding], corpus_embeddings, "cosine")[0]

    results = zip(range(len(distances)), distances)
    results = sorted(results, key=lambda x: x[1])

    print("\n\n======================\n\n")
    print("Query:", query)
    print("\nTop 5 most similar sentences in corpus:")

    for idx, distance in results[0:closest_n]:
        print(corpus[idx].strip(), "(Score: %.4f)" % (1-distance))

팔로우 할 기타 링크 https://github.com/hanxiao/bert-as-service

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.