Як обчислити подібність речень за допомогою моделі word2vec gensim з python


125

Згідно з Gensim Word2Vec , я можу використовувати модель word2vec в пакеті gensim, щоб обчислити схожість між двома словами.

напр

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

Однак модель word2vec не спрогнозує подібність речень. Я знаходжу модель LSI з подібністю речень у gensim, але, мабуть, це не може поєднуватися з моделлю word2vec. Довжина корпусу кожного речення, яке у мене є, не дуже довге (коротше 10 слів). Отже, чи є прості способи досягнення мети?


4
Є підручник ACL, який обговорює це питання (серед іншого): youtube.com/watch?v=_ASOqXiWBVo&feature=youtu.be
Еміель,

7
Тепер ви можете використовувати doc2vec gensim і отримувати подібність вироків з того ж модуля
kampta

@kampta. Привіт, ви б запропонували будь-яку посаду, яка показує реалізацію?
Ian_De_Oliveira

Відповіді:


86

Це насправді досить складна проблема, яку ви ставите. Обчислювальна подібність речень вимагає побудови граматичної моделі речення, розуміння рівнозначних структур (наприклад, "він вчора ходив до магазину" та "вчора, він ходив до магазину"), знаходячи схожість не лише в займенниках і дієсловах, але і в власні іменники, знаходження статистичних співзв’язків / зв’язків у безлічі реальних текстових прикладів тощо.

Найпростіша річ, яку ви могли б спробувати - хоча я не знаю, наскільки це було б добре, і це, безумовно, не дало б оптимальних результатів - було б спочатку видалити всі слова "стоп" (слова типу "the", "an "і т. д., які не додають великого значення реченню), а потім запустіть word2vec над словами в обох реченнях, підсумуйте вектори в одному реченні, підсумуйте вектори в іншому реченні, а потім знайдіть різницю між суми. Підсумовуючи їх, замість того, щоб робити різницю в слово, ви, принаймні, не будете підпорядковані впорядкуванню слів. Однак, це може зазнати невдачі в багатьох напрямках і не є хорошим рішенням будь-якими способами (хоча хороші рішення цієї проблеми майже завжди передбачають деяку кількість НЛП, машинне навчання та іншу кмітливість).

Отже, коротка відповідь - ні, немає простого способу зробити це (принаймні, не зробити це добре).


4
Я думаю, ти маєш рацію. Найпростіший метод - зібрати всі вектори слів в одному реченні і знайти різницю між сумами. До речі, чи буде цей простий метод впливати на кількість слів? Тому що чим більше слів в одному реченні, тим більше буде підсумована гістограма.
zhfkt

2
@zhfkt, швидше за все, так. Тож вам може знадобитися розділити на кількість слів або кілька таких, щоб спробувати це визначити. У будь-якому випадку будь-який евристичний подібний буде сильно хибним.
Майкл Аарон Сафян


75

Оскільки ви використовуєте gensim, ви, ймовірно, повинні використовувати його doc2vec. doc2vec - це розширення word2vec на рівні фрази, речення та документа. Це досить просте розширення, описане тут

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

Gensim приємний тим, що він інтуїтивний, швидкий і гнучкий. Що чудово, це те, що ви можете перехопити вкладені слова, що перевіряються, на офіційній сторінці word2vec, а шар syn0 gensim Doc2Vec піддається впливу, щоб ви могли наносити слово вбудовування за допомогою цих високоякісних векторів!

GoogleNews-vectors-negative300.bin.gz (як пов’язано в коді Google )

Я думаю, що gensim, безумовно, найпростіший (і поки що для мене найкращий) інструмент для вбудовування речення у векторний простір.

Існують інші методи речення у векторному реченні, ніж ті, що запропоновані в статті Le & Mikolov вище. Сочер і Меннінг зі Стенфорда, безумовно, два найвідоміші дослідники, що працюють в цій галузі. Їх робота базується на композиційному принципі - семантика речення походить від:

1. semantics of the words

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

Вони запропонували кілька таких моделей (стають все складнішими) щодо використання композиційності для побудови уявлень на рівні речень.

2011 - розгортання рекурсивного автокодера (дуже порівняно простий. Почніть тут, якщо зацікавлено)

2012 рік - матрично-векторна нейронна мережа

2013 рік - нейронна тензорна мережа

2015 - Дерево LSTM

всі його документи доступні на socher.org. Деякі з цих моделей доступні, але я все-таки рекомендую gensim's doc2vec. Для одного URAE 2011 року не особливо потужний. Крім того, він перевіряється з вагами, що підходять для перефразовування даних новин-у. Код, який він надає, не дозволяє перенавчати мережу. Ви також не можете поміняти місцями в різних векторах слів, тому ви застрягли з вбудованими попереднім словом2vec 2011 року від Turian. Ці вектори, звичайно, не знаходяться на рівні word2vec або GloVe.

Ще не працювали з Деревом LSTM, але це здається дуже перспективним!

tl; dr Так, використовуйте gensim's doc2vec. Але інші методи існують!


Чи є у вас більше інформації про те, як ініціалізувати модель 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
Зауважте, що обчислення "середнього вектора" є настільки ж довільним вибором, як і зовсім не обчислення.
позолочено

2
Я здивований, чому це не найкраща відповідь, вона працює досить добре і не має проблеми з послідовністю, яку має метод усереднення.
Асим

Цю відповідь я шукав. Розв’язав мою проблему. Дякую за рішення
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, і він працює добре, проте він задихнувся на великому корпусі. Спробуйте SoftCosineS подібності. Також знайдено у gensim ( twitter.com/gensim_py/status/963382840934195200 )
krinker

1
Однак ЗМД не дуже швидкий, коли потрібно запитувати корпус.
Амартія

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: Обчислення вектора речень

Розрахунок смислової подібності між реченнями був важким раніше, але нещодавно було запропоновано документ під назвою " ПРОСТИЙ, АБО БЕЗПЕЧНИЙ ОСНОВ ДЛЯ ПОСЛУГАННЯ СТОРІН ", який пропонує простий підхід, обчислюючи середнє зважене значення векторів слів у реченні, а потім видалити проекції середніх векторів на їх першу головну складову. Звідси вага слова w - a / (a ​​+ p (w)), що є параметром, а p (w) (оціночною) частотою слова називається гладкою зворотною частотою .це метод, який працює значно краще.

Простий код для обчислення вектора вироку з допомогою SIF (плавного зворотного частоти) методу , запропонованого в роботі була дано тут

Крок 3: використовуючи sklearn cosine_s Sličity, завантажте два вектори для речень і обчисліть схожість.

Це найпростіший та ефективний метод обчислення подібності речень.


2
дуже приємний папір. Примітка: посилання на реалізацію SIF вимагає написання методу get_word_frequency (), який можна легко здійснити за допомогою лічильника Python () та повернення дикту з ключами: унікальні слова w, значення: # w / # загальний doc len
Quetzalcoatl

8

Я використовую наступний метод, і він працює добре. Спочатку потрібно запустити POSTagger, а потім відфільтрувати своє речення, щоб позбутися від стоп-слів (визначників, сполучників, ...). Я рекомендую TextBlob APTagger . Потім ви будуєте word2vec, беручи середнє значення кожного слова в реченні. Метод n_slike у Gemsim word2vec робить саме це, дозволяючи передати два набори слів для порівняння.


Яка різниця між взяттям середнього вектора та додаванням їх для створення вектору речення?
Καrτhικ

1
Різниця полягає в тому, що розмір вектора фіксується для всіх речень
lechatpito

Немає різниці, якщо ви використовуєте схожість косинусів. @lechatpito Нічого спільного з розміром вектора. Вектори підсумовані, а не зв'язані.
Вок

6

Існують розширення Word2Vec, призначені вирішити проблему порівняння довших фрагментів тексту, як-от фрази чи речення. Один з них - абзац2vec або doc2vec.

"Розподілені представлення вироків і документів" http://cs.stanford.edu/~quocle/paragraph_vector.pdf

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


2
Варто коротко згадати, як працює представлений алгоритм. Ви в основному додаєте унікальний "маркер" до кожного висловлювання і обчислюєте вектори word2vec. Наприкінці ви отримаєте вектори слів для кожного свого слова в корпусі (за умови, що ви запитаєте всі слова, також унікальні). Кожен унікальний "маркер" у висловленні буде представляти це висловлювання. Існує певна суперечка щодо результатів, представлених у статті, але це вже інша історія.
Владислав Довгалеч

5

Gensim реалізує модель під назвою Doc2Vec для вбудовування абзацу .

Існують різні підручники, представлені як зошити IPython:

Інший метод покладається на відстань Word2Vec та Word Mover's (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 і код публікуються на Github, перевірте їх репо. Це досить приголомшливо. Я планую його використовувати. https://github.com/facebookresearch/InferSent

їхній документ https://arxiv.org/abs/1705.02364 Анотація: Багато сучасних систем НЛП покладаються на вбудовування слів, які раніше були без нагляду на великих корпораціях, як основні характеристики. Намагання отримати вкладиші для великих фрагментів тексту, наприклад, речення, не були такими успішними. Кілька спроб навчитись неуспішним уявленням речень не досягли достатньо задовільних результатів, щоб бути широко прийнятими. У цій роботі ми демонструємо, як універсальні представлення речень, навчені за допомогою контрольованих даних наборів даних природного мовлення Стенфорда, можуть стабільно перевершувати непідконтрольні методи, такі як вектори SkipThought, у широкому діапазоні завдань передачі. Так само, як комп’ютерне бачення використовує ImageNet для отримання функцій, які потім можуть бути передані іншим завданням, наша робота, як правило, вказує на придатність природничого мовлення для перенесення навчання іншим завданням НЛП. Наш кодер є загальнодоступним.


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.