Python ile gensim'in word2vec modeli kullanılarak cümle benzerliği nasıl hesaplanır


125

Gensim Word2Vec'e göre 2 kelime arasındaki benzerliği hesaplamak için gensim paketindeki word2vec modelini kullanabilirim.

Örneğin

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

Bununla birlikte, word2vec modeli cümle benzerliğini tahmin edemez. LSI modelini gensim'de cümle benzerliği ile buldum, ancak bu word2vec modeliyle birleştirilemeyecek gibi görünüyor. Sahip olduğum her cümlenin külliyatının uzunluğu çok uzun değil (10 kelimeden kısa). Peki, hedefe ulaşmanın basit yolları var mı?


4
Bu sorunu tartışan bir ACL öğreticisi var (diğer şeylerin yanı sıra): youtube.com/watch?v=_ASOqXiWBVo&feature=youtu.be
Emiel

7
Artık gensim'in doc2vec'ini kullanabilir ve aynı modülden cümle benzerliği elde edebilirsiniz
kampta

@kampta. Merhaba, uygulamayı gösteren herhangi bir gönderi önerir misiniz?
Ian_De_Oliveira

Yanıtlar:


86

Bu aslında sorduğunuz oldukça zor bir problem. Cümle benzerliğini hesaplamak, cümlenin gramer modelini oluşturmayı, eşdeğer yapıları anlamayı (örneğin "dün mağazaya gitti" ve "dün mağazaya yürüdü"), sadece zamirlerde ve fiillerde değil, aynı zamanda uygun isimler, birçok gerçek metin örneğinde istatistiksel birlikte oluşumları / ilişkileri bulma, vb.

Deneyebileceğiniz en basit şey - bunun ne kadar iyi performans göstereceğini bilmesem ve kesinlikle size en iyi sonuçları vermeyecektir - ilk önce tüm "durdurma" sözcüklerini ("the", " Cümleye fazla anlam katmayan ", vb. toplamlar. Kelime bazında bir fark yapmak yerine onları özetleyerek, en azından kelime sırasına tabi olmayacaksınız. Bununla birlikte, bu birçok yönden başarısız olacaktır ve hiçbir şekilde iyi bir çözüm değildir (ancak bu soruna iyi çözümler neredeyse her zaman bir miktar NLP, makine öğrenimi ve diğer zekayı içerir).

Yani, kısa cevap, hayır, bunu yapmanın kolay bir yolu yok (en azından iyi yapmamak).


4
Bence haklısın. En basit yöntem, kelimelerin tüm vektörlerini tek bir cümlede toplamak ve toplamlar arasındaki farkı bulmaktır.Bu basit yöntem, kelime sayımından etkilenecek mi? Çünkü bir cümlede ne kadar çok kelime varsa, o kadar çok histogram toplanacaktır.
zhfkt

2
@zhfkt, büyük olasılıkla evet. Dolayısıyla, bunu çarpanlarına ayırmaya çalışmak için kelimelerin sayısına veya buna benzer bir sayıya bölmeniz gerekebilir. Her iki durumda da, bunun gibi herhangi bir buluşsal yöntem ciddi şekilde kusurlu olacaktır.
Michael Aaron Safyan


75

Gensim kullandığınız için, muhtemelen onun doc2vec uygulamasını kullanmalısınız. doc2vec, word2vec'in deyim, cümle ve belge düzeyine bir uzantısıdır. Burada açıklanan oldukça basit bir uzantıdır

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

Gensim güzeldir çünkü sezgisel, hızlı ve esnektir. Harika olan, önceden eğitilmiş kelime düğünlerini resmi word2vec sayfasından alabilmeniz ve gensim'in Doc2Vec modelinin syn0 katmanının ortaya çıkması, böylece kelime yerleştirmelerini bu yüksek kaliteli vektörlerle tohumlayabilirsiniz!

GoogleNews-Vectors-negative300.bin.gz ( Google Code'da bağlantılı olduğu gibi )

Sanırım gensim, bir vektör uzayına bir cümle yerleştirmek için kesinlikle en kolay (ve benim için en iyi) araç.

Le & Mikolov'un yukarıdaki makalesinde önerilenden başka cümle-vektöre dönüştürme teknikleri vardır. Stanford'dan Socher ve Manning, kesinlikle bu alanda çalışan en ünlü araştırmacılardan ikisi. Çalışmaları kompozisyonel ilkeye dayanmaktadır - cümlenin anlam bilgisi şunlardan gelir:

1. semantics of the words

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

Cümle düzeyinde temsiller oluşturmak için bileşimin nasıl kullanılacağına dair bu tür birkaç model (giderek daha karmaşık hale geliyor) önerdiler.

2011 - ortaya çıkan özyinelemeli otomatik kodlayıcı (nispeten basit. İlgileniyorsanız buradan başlayın)

2012 - matris-vektör sinir ağı

2013 - sinir tensör ağı

2015 - Ağaç LSTM

makalelerinin tümü socher.org adresinde mevcuttur. Bu modellerden bazıları mevcuttur, ancak yine de gensim'in doc2vec'ini öneririm. Birincisi, 2011 URAE özellikle güçlü değil. Buna ek olarak, haber-y verilerinin yeniden ifade edilmesi için uygun ağırlıklarla önceden eğitilmiş olarak gelir. Sağladığı kod, ağı yeniden eğitmenize izin vermiyor. Ayrıca farklı kelime vektörlerini de değiştiremezsiniz, bu nedenle 2011'in Turian'dan kelime2vec öncesi yerleştirmeleriyle sıkışıp kalıyorsunuz. Bu vektörler kesinlikle word2vec veya GloVe düzeyinde değildir.

Henüz Tree LSTM ile çalışmadım ama çok umut verici görünüyor!

tl; dr Evet, gensim'in doc2vec'ini kullanın. Ancak başka yöntemler de var!


Doc2vec modelinin önceden eğitilmiş word2vec değerleriyle nasıl başlatılacağı hakkında daha fazla bilginiz var mı?
Simon H

42

Word2vec kullanıyorsanız, her cümledeki / belgedeki tüm kelimeler için ortalama vektörü hesaplamanız ve vektörler arasında kosinüs benzerliği kullanmanız gerekir:

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

Benzerliği hesaplayın:

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
İndex2word_set ve model.index2word hakkında daha fazla açıklama yapabilir misiniz? Teşekkür ederim.
theteddyboy

3
"Ortalama vektörü" hesaplamanın, hiç hesaplamamak kadar keyfi bir seçim olduğuna dikkat edin.
2017

2
Neden bunun en iyi cevap olmadığına şaşıyorum, oldukça iyi çalışıyor ve ortalama yönteminin sahip olduğu sıra problemi yok.
Asim

Bu aradığım cevap. Sorunum çözüldü. Çözüm için teşekkürler
iRunner

25

Word Mover'ın Mesafe algoritmasını kullanabilirsiniz. İşte KİS hakkında kolay bir açıklama .

#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)

Not: pyemd kitaplığını içe aktarma konusunda bir hatayla karşılaşırsanız , aşağıdaki komutu kullanarak kurabilirsiniz:

pip install pyemd

2
Daha önce kitle imha silahları kullandım ve oldukça iyi çalışıyor, ancak büyük külliyatta boğuluyordu. SoftCosineSimilarity'yi deneyin. Gensim'de de bulundu ( twitter.com/gensim_py/status/963382840934195200 )
krinker

1
Ancak bir külliyat sorgusu yapmak istediğinizde KİS çok hızlı değildir.
Amartya

18

İki kelime vektörü kümesinin toplamını hesapladıktan sonra, farkları değil vektörler arasındaki kosinüsü almalısınız. Kosinüs, normalize edilmiş iki vektörün iç çarpımı alınarak hesaplanabilir. Bu nedenle, kelime sayısı bir faktör değildir.


1
bunun nasıl yapılacağına dair biraz sahte kod sağlayabilir misin (gensim / python kullanmıyorum)
dcsan

13

Dokümantasyondan bir kelime listesi alan ve benzerliklerini karşılaştıran bir işlev vardır .

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

Cümlelerin anlamsal benzerliğini hesaplayacak kişilere yardımcı olmak için mevcut çözümü güncellemek istiyorum.

Aşama 1:

Uygun modeli gensim kullanarak yükleyin ve cümledeki kelimelerin kelime vektörlerini hesaplayın ve bunları bir kelime listesi olarak saklayın

Adım 2: Cümle vektörünü hesaplama

Cümleler arasındaki anlamsal benzerliğin hesaplanması daha önce zordu, ancak son zamanlarda cümledeki kelime vektörlerinin ağırlıklı ortalamasını hesaplayarak basit bir yaklaşım öneren " BASİT AMA GERÇEK BİR TEMEL " adlı bir makale önerildi ve ardından kaldırıldı Ortalama vektörlerin ilk temel bileşenleri üzerindeki izdüşümleri. Burada w kelimesinin ağırlığı a / (a ​​+ p (w)) olup, bir parametre ve p (w) pürüzsüz ters frekans adı verilen (tahmini) kelime frekansıdır. .bu yöntem önemli ölçüde daha iyi performans gösteriyor.

SIF (pürüzsüz ters frekans) kullanarak cümle vektörünü hesaplamak için basit bir kod, makalede önerilen yöntem burada verilmiştir .

Adım 3: sklearn cosine_similarity kullanarak cümleler için iki vektör yükleyin ve benzerliği hesaplayın.

Bu, cümle benzerliğini hesaplamanın en basit ve etkili yöntemidir.


2
çok güzel kağıt. not: SIF uygulamasına bağlantı, Python'un Sayacı () kullanılarak kolayca gerçekleştirilebilen get_word_frequency () yönteminin yazılmasını ve anahtarlarla bir dikte döndürülmesini gerektirir: benzersiz kelimeler w, değerler: # w / # total doc len
Quetzalcoatl

8

Aşağıdaki yöntemi kullanıyorum ve iyi çalışıyor. Önce bir POSTagger çalıştırmanız ve ardından durdurma sözcüklerinden (determinantlar, bağlaçlar, ...) kurtulmak için cümlenizi filtrelemeniz gerekir. Ben tavsiye TextBlob APTagger . Sonra cümledeki her kelime vektörünün ortalamasını alarak bir word2vec oluşturursunuz. Gemsim word2vec içinde n_similarity yöntemi karşılaştırmak için kelimelerin iki set geçmesine izin vererek tam olarak bunu yapıyor.


Vektörlerin ortalamasını almakla bunları bir cümle vektörü oluşturmak için eklemek arasındaki fark nedir?
Καrτhικ

1
Aradaki fark, vektör boyutunun tüm cümleler için sabit olmasıdır
lechatpito

Kosinüs benzerliğini kullandığınız sürece hiçbir fark yoktur. @lechatpito Vektör boyutuyla ilgisi yok. Vektörler toplanır, birleştirilmez.
Wok

6

Kelime öbekleri veya cümleler gibi daha uzun metin parçalarını karşılaştırma sorununu çözmeyi amaçlayan Word2Vec uzantıları vardır. Bunlardan biri, paragraph2vec veya doc2vec'dir.

"Cümle ve Belgelerin Dağıtılmış Temsilleri" http://cs.stanford.edu/~quocle/paragraph_vector.pdf

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


2
Sunulan algoritmanın nasıl çalıştığından kısaca bahsetmeye değer. Temel olarak, her ifadeye benzersiz bir "simge" eklersiniz ve word2vec vektörlerini hesaplarsınız. Sonunda, bütün sözcüklerinizin her biri için sözcük vektörlerini alacaksınız (tüm sözcükleri, aynı zamanda benzersiz sözcükleri de istemeniz koşuluyla). İfadedeki her benzersiz "simge", bu ifadeyi temsil edecektir. Makalede sunulan sonuçlarla ilgili bazı tartışmalar var ama bu başka bir hikaye.
Vladislavs Dovgalecs

5

Gensim , paragraf yerleştirme için Doc2Vec adlı bir model uygular .

IPython not defterleri olarak sunulan farklı öğreticiler vardır:

Bu öğreticide gösterildiği gibi başka bir yöntem, Word2Vec ve Word Mover'ın Mesafesine (WMD) dayanır :

Alternatif bir çözüm, ortalama vektörlere güvenmektir:

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)

Son olarak, Tensorflow'u çalıştırabilirseniz şunu deneyebilirsiniz: https://tfhub.dev/google/universal-sentence-encoder/2


4

Önceki cevapların sağladığı yöntemleri denedim. İşe yarıyor, ancak ana dezavantajı, cümleler ne kadar uzun olursa benzerliğin de o kadar büyük olacağıdır (benzerliği hesaplamak için herhangi iki cümlenin iki ortalama gömmesinin kosinüs skorunu kullanırım), çünkü kelimeler ne kadar çoksa o kadar olumlu anlamsal etkiler cümleye eklenecek.

Fikrimi değiştirmem gerektiğini ve cümle yerine bu makalede ve bu belgede çalışıldığı gibi yerleştirmeyi kullanmam gerektiğini düşündüm .


3

Facebook Araştırma grubu InferSent Results adlı yeni bir çözüm yayınladı ve kod Github'da yayınlandı, repolarını kontrol edin. Oldukça harika. Kullanmayı planlıyorum. https://github.com/facebookresearch/InferSent

onların kağıdı https://arxiv.org/abs/1705.02364 Özet: Pek çok modern NLP sistemi, temel özellikler olarak daha önce denetimsiz bir şekilde büyük cisimlere dayalı olarak eğitilmiş kelime yerleştirmelerine dayanır. Cümleler gibi daha büyük metin parçaları için düğünler elde etme çabaları, ancak o kadar başarılı olmamıştır. Cümlelerin denetimsiz temsillerini öğrenmeye yönelik çeşitli girişimler, geniş çapta benimsenecek kadar tatmin edici performansa ulaşmamıştır. Bu makalede, Stanford Natural Language Inference veri kümelerinin denetimli verileri kullanılarak eğitilen evrensel cümle temsillerinin, çok çeşitli aktarım görevlerinde SkipThought vektörleri gibi denetimsiz yöntemlerden tutarlı bir şekilde daha iyi performans gösterebileceğini gösteriyoruz. Bilgisayar vizyonunun, daha sonra diğer görevlere aktarılabilen özellikler elde etmek için ImageNet'i kullanması gibi, Çalışmamız, öğrenmeyi diğer NLP görevlerine aktarmak için doğal dil çıkarımının uygunluğunu gösterme eğilimindedir. Kodlayıcımız halka açıktır.


3

Word2Vec kullanmıyorsanız, onu gömmek için BERT kullanarak bulmak için başka bir modelimiz var. Aşağıda referans bağlantısı https://github.com/UKPLab/sentence-transformers bulunmaktadır

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))

Takip edilecek Diğer Bağlantı https://github.com/hanxiao/bert-as-service

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.