วิธีคำนวณความเหมือนของประโยคโดยใช้ word2vec model ของ gensim กับ python


125

ตามGensim Word2Vecฉันสามารถใช้โมเดล word2vec ในแพ็คเกจ gensim เพื่อคำนวณความคล้ายคลึงกันระหว่าง 2 คำ

เช่น

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

อย่างไรก็ตามโมเดล word2vec ไม่สามารถทำนายความคล้ายคลึงของประโยคได้ ฉันพบว่าโมเดล LSI ที่มีความคล้ายคลึงกันของประโยคใน gensim แต่ดูเหมือนจะไม่สามารถใช้ร่วมกับโมเดล word2vec ได้ ความยาวของคลังข้อมูลของแต่ละประโยคที่ฉันมีไม่ยาวมาก (สั้นกว่า 10 คำ) มีวิธีง่ายๆในการบรรลุเป้าหมายหรือไม่?


4
มีบทช่วยสอน ACL ที่พูดถึงปัญหานี้ (เหนือสิ่งอื่นใด): youtube.com/watch?v=_ASOqXiWBVo&feature=youtu.be
Emiel

7
ตอนนี้คุณสามารถใช้ doc2vec ของ gensim และรับความคล้ายคลึงกันของประโยคจากโมดูลเดียวกันได้แล้ว
kampta

@kampta. สวัสดีคุณช่วยแนะนำโพสต์ที่แสดงการใช้งานได้หรือไม่?
Ian_De_Oliveira

คำตอบ:


86

นี่เป็นปัญหาที่ค่อนข้างท้าทายที่คุณกำลังถาม การคำนวณความเหมือนของประโยคต้องใช้การสร้างแบบจำลองทางไวยากรณ์ของประโยคการทำความเข้าใจโครงสร้างที่เทียบเท่ากัน (เช่น "เขาเดินไปที่ร้านเมื่อวาน" และ "เมื่อวานนี้เขาเดินไปที่ร้าน") การค้นหาความคล้ายคลึงกันไม่เพียง แต่ในสรรพนามและคำกริยาเท่านั้น แต่ยังรวมถึง คำนามที่เหมาะสมการค้นหาเหตุการณ์ร่วม / ความสัมพันธ์ทางสถิติในตัวอย่างข้อความจริง ฯลฯ

สิ่งที่ง่ายที่สุดที่คุณสามารถลองได้ - แม้ว่าฉันจะไม่รู้ว่ามันจะทำงานได้ดีเพียงใดและแน่นอนว่ามันจะไม่ให้ผลลัพธ์ที่ดีที่สุด - ก่อนอื่นก็คือการลบคำ "หยุด" ทั้งหมดออก (คำเช่น "the", "และ "ฯลฯ ที่ไม่ได้เพิ่มความหมายให้กับประโยคมากนัก) จากนั้นเรียกใช้ word2vec บนคำในทั้งสองประโยคสรุปเวกเตอร์ในประโยคเดียวรวมเวกเตอร์ในประโยคอื่นแล้วหาความแตกต่างระหว่าง ผลรวม โดยการสรุปแทนการสร้างความแตกต่างอย่างชาญฉลาดอย่างน้อยคุณจะไม่ต้องอยู่ภายใต้ลำดับคำ ดังที่กล่าวมานี้จะล้มเหลวในหลาย ๆ วิธีและไม่ใช่วิธีแก้ปัญหาที่ดีด้วยวิธีการใด ๆ (แม้ว่าวิธีแก้ปัญหาที่ดีสำหรับปัญหานี้มักจะเกี่ยวข้องกับ NLP จำนวนหนึ่งการเรียนรู้ของเครื่องและความฉลาดอื่น ๆ )

ดังนั้นคำตอบสั้น ๆ คือไม่ไม่มีวิธีง่ายๆในการทำสิ่งนี้ (อย่างน้อยก็ไม่ต้องทำดี)


4
ฉันคิดว่าคุณถูก. วิธีที่ง่ายที่สุดคือการสะสมเวกเตอร์ของคำทั้งหมดในประโยคเดียวและค้นหาความแตกต่างระหว่างผลรวมอย่างไรก็ตามวิธีง่ายๆนี้จะได้รับผลจากการนับจำนวนคำหรือไม่? เนื่องจากยิ่งมีคำในหนึ่งประโยคมากก็จะยิ่งมีการสรุปฮิสโตแกรมมากขึ้น
zhfkt

2
@zhfkt น่าจะใช่ ดังนั้นคุณอาจต้องหารด้วยจำนวนคำหรือบางคำเพื่อพยายามแยกตัวประกอบ ไม่ว่าจะด้วยวิธีใดฮิวริสติกเช่นนี้จะมีข้อบกพร่องอย่างรุนแรง
Michael Aaron Safyan


75

เนื่องจากคุณใช้ gensim คุณจึงควรใช้ doc2vec doc2vec เป็นส่วนขยายของ word2vec ไปยังระดับวลีประโยคและระดับเอกสาร มันเป็นส่วนขยายที่ค่อนข้างเรียบง่ายอธิบายไว้ที่นี่

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

Gensim นั้นดีเพราะใช้งานง่ายรวดเร็วและยืดหยุ่น สิ่งที่ยอดเยี่ยมคือคุณสามารถใช้การฝังคำที่ผ่านการฝึกอบรมมาแล้วจากหน้า word2vec อย่างเป็นทางการและชั้น syn0 ของโมเดล Doc2Vec ของ gensim จะถูกเปิดเผยเพื่อให้คุณสามารถเริ่มต้นการฝังคำด้วยเวกเตอร์คุณภาพสูงเหล่านี้ได้!

GoogleNews-vectors-negative300.bin.gz (ตามที่เชื่อมโยงในGoogle Code )

ฉันคิดว่า gensim เป็นเครื่องมือที่ง่ายที่สุด (และสำหรับฉันแล้วนั่นคือเครื่องมือที่ดีที่สุด) สำหรับการฝังประโยคในปริภูมิเวกเตอร์

มีเทคนิคประโยคต่อเวกเตอร์อื่น ๆ นอกเหนือจากที่เสนอไว้ในกระดาษของ Le & Mikolov ด้านบน Socher และ Manning จาก Stanford เป็นนักวิจัยที่มีชื่อเสียงที่สุดสองคนที่ทำงานในด้านนี้ งานของพวกเขาตั้งอยู่บนหลักการขององค์ประกอบ - ความหมายของประโยคมาจาก:

1. semantics of the words

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

พวกเขาได้เสนอแบบจำลองดังกล่าวสองสามแบบ (ซับซ้อนมากขึ้นเรื่อย ๆ ) สำหรับวิธีใช้การเรียบเรียงเพื่อสร้างการแสดงระดับประโยค

2011 - การคลี่ตัวเข้ารหัสอัตโนมัติแบบเรียกซ้ำ (ค่อนข้างง่ายมากเริ่มที่นี่หากสนใจ)

2012 - เครือข่ายประสาทเทียมเมทริกซ์เวกเตอร์

2013 - เครือข่ายเทนเซอร์ประสาท

2015 - Tree LSTM

เอกสารของเขามีอยู่ที่ socher.org บางรุ่นมีวางจำหน่าย แต่ฉันยังคงแนะนำ doc2vec ของ gensim ประการแรก URAE ปี 2011 ไม่ได้ทรงพลังเป็นพิเศษ นอกจากนี้ยังมาพร้อมกับน้ำหนักที่เหมาะสมสำหรับการถอดความข้อมูลข่าวสาร -y รหัสที่เขาระบุไม่อนุญาตให้คุณฝึกอบรมเครือข่ายอีกครั้ง คุณไม่สามารถสลับเวกเตอร์คำต่างๆได้ดังนั้นคุณจึงติดอยู่กับการฝังตัวก่อน word2vec จาก Turian ในปี 2011 เวกเตอร์เหล่านี้ไม่ได้อยู่ในระดับของ word2vec หรือ GloVe อย่างแน่นอน

ยังไม่ได้ทำงานกับ Tree LSTM แต่ดูเหมือนว่าจะมีแนวโน้มมาก!

tl; dr ใช่ใช้ doc2vec ของ gensim แต่วิธีอื่นมีอยู่จริง!


คุณมีข้อมูลเพิ่มเติมเกี่ยวกับวิธีการเริ่มต้นโมเดล doc2vec ด้วยค่า word2vec ที่ได้รับการฝึกฝนมาก่อนหรือไม่
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

3
สังเกตว่าการคำนวณ "เวกเตอร์เฉลี่ย" เป็นตัวเลือกที่ไม่ได้กำหนดไว้มากพอ ๆ กับการไม่คำนวณเลย
60

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)

Ps: หากคุณพบข้อผิดพลาดเกี่ยวกับการนำเข้าไลบรารีpyemdคุณสามารถติดตั้งได้โดยใช้คำสั่งต่อไปนี้:

pip install pyemd

2
ฉันเคยใช้ WMD มาก่อนและทำงานได้เงียบดี แต่มันจะทำให้หายใจไม่ออกในคลังข้อมูลขนาดใหญ่ ลองใช้ SoftCosineSimilarity พบได้ใน gensim ( twitter.com/gensim_py/status/963382840934195200 )
krinker

1
WMD ไม่เร็วมาก แต่เมื่อคุณต้องการสอบถามคลังข้อมูล
Amartya

18

เมื่อคุณคำนวณผลรวมของเวกเตอร์คำทั้งสองชุดแล้วคุณควรหาโคไซน์ระหว่างเวกเตอร์ไม่ใช่ค่าความต่าง โคไซน์สามารถคำนวณได้โดยนำผลคูณดอทของเวกเตอร์สองตัวมาทำให้เป็นมาตรฐาน ดังนั้นการนับจำนวนคำจึงไม่ใช่ปัจจัย


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 (ความถี่ผกผันเรียบ) วิธีการที่เสนอในกระดาษได้รับที่นี่

ขั้นตอนที่ 3: การใช้ sklearn cosine_similarity โหลดเวกเตอร์สองตัวสำหรับประโยคและคำนวณความคล้ายคลึงกัน

นี่เป็นวิธีที่ง่ายและมีประสิทธิภาพที่สุดในการคำนวณความเหมือนของประโยค


2
กระดาษสวยมาก หมายเหตุ: ลิงก์ไปยังการใช้งาน SIF จำเป็นต้องเขียนเมธอด get_word_frequency () ซึ่งสามารถทำได้อย่างง่ายดายโดยใช้ Python's Counter () และส่งคืนคำสั่งด้วยคีย์: คำที่ไม่ซ้ำ w, ค่า: # w / # total doc len
Quetzalcoatl

8

ฉันใช้วิธีต่อไปนี้และได้ผลดี ก่อนอื่นคุณต้องเรียกใช้ POSTagger จากนั้นกรองประโยคของคุณเพื่อกำจัดคำหยุด (ดีเทอร์มิแนนต์สันธาน ... ) ผมขอแนะนำให้TextBlob APTagger จากนั้นคุณสร้าง word2vec โดยหาค่าเฉลี่ยของเวกเตอร์คำแต่ละคำในประโยค วิธี n_similarity ใน Gemsim word2vecไม่ตรงกับที่โดยการอนุญาตที่จะผ่านทั้งสองชุดของคำเพื่อเปรียบเทียบ


อะไรคือความแตกต่างระหว่างการหาค่าเฉลี่ยของเวกเตอร์เทียบกับการเพิ่มเพื่อสร้างเวกเตอร์ประโยค
Κα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และWord Mover (WMD)ดังที่แสดงในบทช่วยสอนนี้:

อีกทางเลือกหนึ่งคือการใช้เวกเตอร์เฉลี่ย:

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 เปิดตัวโซลูชันใหม่ที่เรียกว่า InferSent Results และมีการเผยแพร่โค้ดบน Github ตรวจสอบ repo ของพวกเขา มันน่ากลัวมาก ฉันกำลังวางแผนที่จะใช้มัน https://github.com/facebookresearch/InferSent

กระดาษของพวกเขา https://arxiv.org/abs/1705.02364 บทคัดย่อ: ระบบ NLP สมัยใหม่จำนวนมากใช้การฝังคำซึ่งก่อนหน้านี้ได้รับการฝึกฝนในลักษณะที่ไม่ได้รับการดูแลในองค์กรขนาดใหญ่เป็นคุณสมบัติพื้นฐาน ความพยายามในการได้รับการฝังสำหรับข้อความจำนวนมากเช่นประโยคยังไม่ประสบความสำเร็จ ความพยายามหลายครั้งในการเรียนรู้การใช้แทนประโยคโดยไม่ได้รับการดูแลยังไม่ได้ประสิทธิภาพที่น่าพอใจเพียงพอที่จะนำไปใช้อย่างกว้างขวาง ในบทความนี้เราจะแสดงให้เห็นว่าการเป็นตัวแทนประโยคสากลที่ได้รับการฝึกฝนโดยใช้ข้อมูลภายใต้การดูแลของชุดข้อมูลการอนุมานภาษาธรรมชาติของสแตนฟอร์ดสามารถทำงานได้ดีกว่าวิธีการที่ไม่ได้รับการดูแลเช่นเวกเตอร์ SkipThought ในงานการถ่ายโอนที่หลากหลาย เช่นเดียวกับวิธีที่ Computer Vision ใช้ 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.