Cara menghitung kemiripan kalimat menggunakan model word2vec dari gensim dengan python

125

Menurut Gensim Word2Vec , saya dapat menggunakan model word2vec dalam paket gensim untuk menghitung kesamaan antara 2 kata.

misalnya

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

Namun, model word2vec gagal memprediksi kemiripan kalimat. Saya menemukan model LSI dengan kemiripan kalimat dalam gensim, tetapi, tampaknya tidak dapat digabungkan dengan model word2vec. Panjang korpus setiap kalimat yang saya miliki tidak terlalu panjang (lebih pendek dari 10 kata). Jadi, adakah cara sederhana untuk mencapai tujuan tersebut?

zhfkt
sumber
4
Ada tutorial ACL yang membahas masalah ini (antara lain): youtube.com/watch?v=_ASOqXiWBVo&feature=youtu.be
Emiel
7
Anda sekarang dapat menggunakan doc2vec gensim dan mendapatkan kesamaan kalimat dari modul yang sama
kampta
@ampta. Hai, apakah Anda akan menyarankan postingan yang menunjukkan penerapannya?
Ian_De_Oliveira

Jawaban:

86

Ini sebenarnya adalah masalah yang cukup menantang yang Anda tanyakan. Menghitung kesamaan kalimat membutuhkan membangun model gramatikal kalimat, memahami struktur yang setara (misalnya "dia berjalan ke toko kemarin" dan "kemarin, dia berjalan ke toko"), menemukan kesamaan tidak hanya dalam kata ganti dan kata kerja tetapi juga dalam kata benda yang tepat, menemukan kejadian / hubungan statistik dalam banyak contoh tekstual nyata, dll.

Hal paling sederhana yang dapat Anda coba - meskipun saya tidak tahu seberapa baik kinerjanya dan pasti tidak akan memberikan hasil yang optimal - adalah dengan terlebih dahulu menghapus semua kata "stop" (kata seperti "the", "sebuah ", dll. yang tidak memberi banyak arti pada kalimat) lalu jalankan word2vec pada kata-kata di kedua kalimat, jumlahkan vektor di satu kalimat, jumlahkan vektor di kalimat lain, lalu temukan perbedaan antara jumlahnya. Dengan menjumlahkannya alih-alih melakukan perbedaan bijak, Anda setidaknya tidak akan tunduk pada urutan kata. Meskipun demikian, ini akan gagal dalam banyak hal dan bukan merupakan solusi yang baik dengan cara apa pun (meskipun solusi yang baik untuk masalah ini hampir selalu melibatkan sejumlah NLP, pembelajaran mesin, dan kepintaran lainnya).

Jadi, jawaban singkatnya adalah, tidak, tidak ada cara mudah untuk melakukan ini (setidaknya tidak melakukannya dengan baik).

Michael Aaron Safyan
sumber
4
Saya pikir Anda benar. Metode yang paling sederhana adalah dengan mengumpulkan semua vektor kata dalam satu kalimat dan mencari perbedaan antara jumlah tersebut. Ngomong-ngomong, apakah metode sederhana ini akan dipengaruhi oleh jumlah kata? Karena semakin banyak kata dalam satu kalimat, semakin banyak histogram yang akan dijumlahkan.
zhfkt
2
@zhfkt, kemungkinan besar, ya. Jadi, Anda mungkin perlu membaginya dengan jumlah kata atau semacamnya untuk mencoba memfaktorkannya. Bagaimanapun, heuristik seperti ini akan sangat cacat.
Michael Aaron Safyan
75

Karena Anda menggunakan gensim, Anda mungkin harus menggunakan implementasi doc2vec itu. doc2vec adalah perpanjangan dari word2vec ke tingkat frase-, kalimat-, dan dokumen. Ini ekstensi yang cukup sederhana, dijelaskan di sini

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

Gensim bagus karena intuitif, cepat, dan fleksibel. Yang hebat adalah Anda dapat mengambil embeddings kata yang telah dilatih sebelumnya dari halaman resmi word2vec dan lapisan syn0 model Doc2Vec gensim terbuka sehingga Anda dapat menyemai kata embeddings dengan vektor berkualitas tinggi ini!

GoogleNews-vektor-negative300.bin.gz (seperti yang ditautkan di Google Code )

Saya pikir gensim jelas merupakan alat termudah (dan sejauh ini bagi saya, yang terbaik) untuk menyematkan kalimat dalam ruang vektor.

Terdapat teknik kalimat-ke-vektor selain yang diusulkan dalam makalah Le & Mikolov di atas. Socher dan Manning dari Stanford jelas merupakan dua peneliti paling terkenal yang bekerja di bidang ini. Karya mereka didasarkan pada prinsip komposisi - semantik kalimat berasal dari:

1. semantics of the words

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

Mereka telah mengusulkan beberapa model seperti itu (menjadi semakin kompleks) untuk bagaimana menggunakan komposisionalitas untuk membangun representasi tingkat kalimat.

2011 - autoencoder rekursif terbuka (sangat relatif sederhana. Mulai di sini jika tertarik)

2012 - jaringan saraf matriks-vektor

2013 - jaringan tensor saraf

2015 - Pohon LSTM

makalahnya semua tersedia di socher.org. Beberapa model ini tersedia, tetapi saya tetap merekomendasikan doc2vec gensim. Pertama, URAE 2011 tidak terlalu kuat. Selain itu, ia dilengkapi dengan bobot yang sesuai untuk parafrase data news-y. Kode yang dia berikan tidak memungkinkan Anda melatih ulang jaringan. Anda juga tidak dapat menukar vektor kata yang berbeda, jadi Anda terjebak dengan embeddings pra-word2vec 2011 dari Turian. Vektor-vektor ini tentu saja tidak berada pada level word2vec atau GloVe.

Belum bekerja dengan Tree LSTM, tapi sepertinya sangat menjanjikan!

tl; dr Ya, gunakan doc2vec gensim. Tetapi metode lain memang ada!

Willie
sumber
Apakah Anda memiliki informasi lebih lanjut tentang cara menginisialisasi model doc2vec dengan nilai word2vec yang telah dilatih sebelumnya?
Simon H
42

Jika Anda menggunakan word2vec, Anda perlu menghitung vektor rata-rata untuk semua kata di setiap kalimat / dokumen dan menggunakan kesamaan kosinus antar vektor:

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

Hitung kesamaan:

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
tbmihailov
sumber
4
Bisakah Anda memberikan penjelasan lebih lanjut tentang index2word_set dan model.index2word? Terima kasih.
theteddyboy
3
Perhatikan bahwa menghitung "vektor rata-rata" adalah pilihan yang sewenang-wenang daripada tidak menghitungnya sama sekali.
Tuan
2
Saya heran mengapa ini bukan jawaban teratas, ini berfungsi dengan baik dan tidak memiliki masalah urutan yang dimiliki metode rata-rata.
Asim
Ini adalah jawaban yang saya cari. Memecahkan masalah saya. Terima kasih atas solusinya
iRunner
25

Anda dapat menggunakan algoritma Jarak Penggerak Kata. berikut adalah penjelasan mudah tentang 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)

NB: jika Anda menghadapi kesalahan tentang impor pustaka pyemd , Anda dapat menginstalnya menggunakan perintah berikut:

pip install pyemd
Ehsan
sumber
2
Saya menggunakan WMD sebelumnya dan bekerja dengan sangat baik, namun akan tersedak pada korpus besar. Coba SoftCosineSimilarity. Juga ditemukan di gensim ( twitter.com/gensim_py/status/963382840934195200 )
krinker
1
Namun, WMD tidak terlalu cepat ketika Anda ingin meminta korpus.
Amartya
18

Setelah Anda menghitung jumlah dari dua kumpulan vektor kata, Anda harus mengambil kosinus di antara vektor, bukan selisihnya. Kosinus dapat dihitung dengan mengambil produk titik dari dua vektor yang dinormalisasi. Jadi, jumlah kata bukanlah faktor.

Rani Nelken
sumber
1
dapatkah Anda memberikan sedikit pseudocode tentang cara melakukan ini (saya tidak menggunakan gensim / python)
dcsan
13

Ada fungsi dari dokumentasi yang mengambil daftar kata dan membandingkan kesamaannya.

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

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

Saya ingin memperbarui solusi yang ada untuk membantu orang-orang yang akan menghitung kesamaan semantik kalimat.

Langkah 1:

Muat model yang sesuai menggunakan gensim dan hitung vektor kata untuk kata dalam kalimat dan simpan sebagai daftar kata

Langkah 2: Menghitung vektor kalimat

Perhitungan kemiripan semantik antara kalimat sulit sebelumnya tetapi baru-baru ini sebuah makalah bernama " A SIMPLE BUT TOUGH-TO-BEAT BASELINE FOR SENTENCE EMBEDDINGS " diusulkan yang menyarankan pendekatan sederhana dengan menghitung rata-rata tertimbang vektor kata dalam kalimat dan kemudian menghapus proyeksi vektor rata-rata pada komponen utama pertamanya. Di sini bobot kata w adalah a / (a ​​+ p (w)) dengan a menjadi parameter dan p (w) frekuensi kata (perkiraan) disebut frekuensi invers halus .metode ini berkinerja jauh lebih baik.

Kode sederhana untuk menghitung vektor kalimat menggunakan SIF (smooth inverse frequency) metode yang diusulkan di makalah telah diberikan di sini

Langkah 3: menggunakan sklearn cosine_similarity memuat dua vektor untuk kalimat dan menghitung kesamaan.

Ini adalah metode paling sederhana dan efisien untuk menghitung kesamaan kalimat.

Poorna Prudhvi
sumber
2
kertas yang sangat bagus. catatan: tautan ke implementasi SIF membutuhkan penulisan metode get_word_frequency () yang dapat dengan mudah dicapai dengan menggunakan Python's Counter () dan mengembalikan sebuah dict dengan kunci: kata-kata unik w, nilai: # w / # total doc len
Quetzalcoatl
8

Saya menggunakan metode berikut dan berfungsi dengan baik. Pertama-tama Anda perlu menjalankan POSTagger dan kemudian memfilter kalimat Anda untuk menghilangkan kata-kata penghenti (determinan, konjungsi, ...). Saya merekomendasikan TextBlob APTagger . Kemudian Anda membangun word2vec dengan mengambil mean dari setiap vektor kata dalam kalimat. The Metode n_similarity di Gemsim word2vec tidak tepat dengan memungkinkan untuk lulus dua set kata-kata untuk membandingkan.

lechatpito
sumber
Apa perbedaan antara mengambil mean vektor vs. menambahkannya untuk membuat vektor kalimat?
Καrτhικ
1
Perbedaannya adalah bahwa ukuran vektor ditetapkan untuk semua kalimat
lechatpito
Tidak ada perbedaan selama Anda menggunakan cosine similarity. @lechatpito Tidak ada hubungannya dengan ukuran vektor. Vektor-vektor tersebut dijumlahkan, tidak digabung.
Wajan
6

Ada ekstensi Word2Vec yang dimaksudkan untuk memecahkan masalah membandingkan bagian teks yang lebih panjang seperti frasa atau kalimat. Salah satunya adalah paragraph2vec atau doc2vec.

"Representasi Terdistribusi dari Kalimat dan Dokumen" http://cs.stanford.edu/~quocle/paragraph_vector.pdf

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

Max
sumber
2
Perlu disebutkan secara singkat bagaimana algoritma yang disajikan bekerja. Anda pada dasarnya menambahkan "token" unik ke setiap ucapan dan menghitung vektor word2vec. Pada akhirnya Anda akan mendapatkan vektor kata untuk setiap kata Anda dalam korpus (asalkan Anda meminta semua kata, juga kata yang unik). Setiap "token" unik dalam ucapan akan mewakili ucapan itu. Ada beberapa kontroversi tentang hasil yang disajikan di koran tetapi itu adalah cerita lain.
Vladislavs Dovgalecs
5

Gensim mengimplementasikan model yang disebut Doc2Vec untuk penyematan paragraf .

Ada berbagai tutorial yang disajikan sebagai notebook IPython:

Metode lain akan bergantung pada Word2Vec dan Word Mover's Distance (WMD) , seperti yang ditunjukkan dalam tutorial ini:

Solusi alternatif akan mengandalkan vektor rata-rata:

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)

Terakhir, jika Anda dapat menjalankan Tensorflow, Anda dapat mencoba: https://tfhub.dev/google/universal-sentence-encoder/2

Wajan
sumber
4

Saya telah mencoba metode yang diberikan oleh jawaban sebelumnya. Ini berfungsi, tetapi kelemahan utamanya adalah semakin panjang kalimatnya semakin besar kesamaannya (untuk menghitung kesamaan saya menggunakan skor cosinus dari dua embeddings rata-rata dari dua kalimat apa pun) karena semakin banyak kata semakin banyak efek semantik positif akan ditambahkan ke kalimat.

Saya pikir saya harus berubah pikiran dan menggunakan kalimat embedding seperti yang dipelajari dalam makalah ini dan ini .

Lerner Zhang
sumber
3

Grup Riset Facebook merilis solusi baru yang disebut Hasil InferSent dan kode diterbitkan di Github, periksa repo mereka. Ini sangat mengagumkan. Saya berencana untuk menggunakannya. https://github.com/facebookresearch/InferSent

makalah mereka https://arxiv.org/abs/1705.02364 Abstrak: Banyak sistem NLP modern yang mengandalkan embeddings kata, yang sebelumnya dilatih dengan cara tanpa pengawasan pada korpora besar, sebagai fitur dasar. Upaya untuk mendapatkan embeddings untuk potongan teks yang lebih besar, seperti kalimat, tidak begitu berhasil. Beberapa upaya untuk mempelajari representasi kalimat tanpa pengawasan belum mencapai kinerja yang cukup memuaskan untuk diadopsi secara luas. Dalam makalah ini, kami menunjukkan bagaimana representasi kalimat universal yang dilatih menggunakan data yang diawasi dari set data Inferensi Bahasa Alami Stanford dapat secara konsisten mengungguli metode tanpa pengawasan seperti vektor SkipThought pada berbagai tugas transfer. Mirip seperti bagaimana computer vision menggunakan ImageNet untuk mendapatkan fitur, yang kemudian dapat ditransfer ke tugas lain, pekerjaan kami cenderung menunjukkan kesesuaian inferensi bahasa alami untuk pembelajaran transfer ke tugas NLP lainnya. Pembuat enkode kami tersedia untuk umum.

Ayman Salama
sumber
3

Jika tidak menggunakan Word2Vec, kami memiliki model lain untuk menemukannya menggunakan BERT untuk penyematan. Di bawah ini adalah tautan referensi 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))

Tautan lain untuk mengikuti https://github.com/hanxiao/bert-as-service

kamran kausar
sumber