Как рассчитать сходство предложений с помощью модели gensim word2vec с python

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

например

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

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

11 ответов

Решение

Это на самом деле довольно сложная проблема, которую вы задаете. Вычисление сходства предложений требует построения грамматической модели предложения, понимания эквивалентных структур (например, "он ходил в магазин вчера" и "вчера он ходил в магазин"), поиска сходства не только в местоимениях и глаголах, но и в имена собственные, поиск статистических совпадений / отношений во множестве реальных текстовых примеров и т. д.

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

Таким образом, краткий ответ: нет, нет простого способа сделать это (по крайней мере, не делать это хорошо).

Поскольку вы используете gensim, вам, вероятно, следует использовать его реализацию doc2vec. doc2vec - это расширение word2vec на уровне фраз, предложений и документов. Это довольно простое расширение, описанное здесь

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

Gensim хорош, потому что он интуитивно понятен, быстр и гибок. Что замечательно, так это то, что вы можете получить предварительно подготовленные вложения слов с официальной страницы word2vec, а слой syn0 модели Doc2Vec компании gensim представлен так, что вы можете заполнять вложения слов этими высококачественными векторами!

GoogleNews-векторы-negative300.bin.gz

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

Существуют и другие методы предложения векторов, чем те, которые были предложены в статье Ле и Миколова выше. Сохер и Мэннинг из Стэнфорда, безусловно, являются двумя самыми известными исследователями, работающими в этой области. Их работа основана на принципе композиционно - семантика предложения происходит от:

1. semantics of the words

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

Они предложили несколько таких моделей (становящихся все более и более сложными) о том, как использовать композицию для построения представлений на уровне предложений.

2011 - развертывание рекурсивного автоэнкодера (очень просто. Начните здесь, если интересно)

2012 - матрично-векторная нейронная сеть

2013(?) - нейронная тензорная сеть

2015 - Дерево ЛСТМ

все его работы доступны на socher.org. Некоторые из этих моделей доступны, но я бы по-прежнему рекомендовал gensim's doc2vec. Во-первых, УРАЭ 2011 года не особенно сильна. Кроме того, он предварительно подготовлен с весами, подходящими для перефразирования новостных данных. Код, который он предоставляет, не позволяет вам переучивать сеть. Вы также не можете поменять местами разные слова, так что вы застряли с вложениями pre-word2vec 2011 года из Turian. Эти векторы, конечно, не находятся на уровне word2vec или GloVe.

Еще не работал с Tree LSTM, но это выглядит очень многообещающе!

tl; dr Да, используйте gensim's doc2vec. Но другие методы существуют!

Если вы используете 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

Вы можете использовать алгоритм расстояния Word Mover. Вот простое описание ОМУ.

#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

Как только вы вычислите сумму двух наборов векторов слов, вы должны взять косинус между векторами, а не разность. Косинус можно вычислить, взяв нормализованное скалярное произведение двух векторов. Таким образом, количество слов не является фактором.

Я хотел бы обновить существующее решение, чтобы помочь людям, которые собираются вычислять семантическое сходство предложений.

Шаг 1:

Загрузите подходящую модель, используя gensim, рассчитайте векторы слов для слов в предложении и сохраните их в виде списка слов.

Шаг 2: Вычисление вектора предложения

Вычисление семантического сходства между предложениями было трудным до этого, но недавно была предложена статья под названием " ПРОСТОЙ, НО УДЕРЖИВАЕМЫЙ БАЗА ДЛЯ ВЛОЖЕНИЙ ОТНОШЕНИЙ", который предлагает простой подход путем вычисления средневзвешенного значения векторов слов в предложении, а затем удаляет проекции средних векторов на их первый главный компонент. Здесь вес слова w равен /(a ​​+ p(w)) с параметром, а p (w) (оценочная) частота слова, называемая гладкой обратной частотой Этот метод работает значительно лучше.

Простой код для вычисления вектора предложения с использованием SIF(сглаженная обратная частота), предложенный в статье, был приведен здесь.

Шаг 3: используя sklearn cosine_s Similarity, загрузите два вектора для предложений и вычислите сходство.

Это самый простой и эффективный метод для вычисления подобия предложения.

В документации есть функция, которая берет список слов и сравнивает их сходства.

s1 = 'This room is dirty'
s3 = 'dirty and disgusting room'

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

Я использую следующий метод, и он работает хорошо. Сначала вам нужно запустить POSTagger, а затем отфильтровать предложение, чтобы избавиться от стоп-слов (определителей, союзов,...). Я рекомендую TextBlob APTagger. Затем вы строите word2vec, беря среднее значение каждого слова вектора в предложении. Метод n_sogeneity в Gemsim word2vec делает именно это, позволяя передавать два набора слов для сравнения.

Существуют расширения Word2Vec, предназначенные для решения проблемы сравнения более длинных фрагментов текста, таких как фразы или предложения. Одним из них является параграф 2vec или doc2vec.

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

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

Gensim реализует модель под названием Doc2Vec для встраивания абзацев.

Существуют различные учебные пособия, представленные как записные книжки IPython:

Другой метод будет опираться на Word2Vec и Word Mover's Distance (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 sentence', wv)
print(sim)

Наконец, если вы можете запустить Tensorflow, вы можете попробовать: https://tfhub.dev/google/universal-sentence-encoder/2

Если вы не используете 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

Я попробовал методы, предоставленные предыдущими ответами. Это работает, но главный недостаток заключается в том, что чем длиннее предложения, тем больше будет сходство (для вычисления сходства я использую косинус-оценку двух средних вложений любых двух предложений), поскольку чем больше слов, тем больше позитивных семантических эффектов будут добавлены к предложению.

Я подумал, что должен передумать и использовать вместо этого вложение предложения, как описано в этой статье и в этом.

Исследовательская группа Facebook выпустила новое решение под названием InferSent. Результаты и код опубликованы на Github, проверьте их репозиторий. Это довольно круто. Я планирую использовать это. https://github.com/facebookresearch/InferSent

их статья https://arxiv.org/abs/1705.02364 Аннотация: Многие современные системы НЛП используют в качестве базовых функций встраивание слов, ранее обучавшихся неконтролируемым образом в больших корпусах. Однако попытки получить вложения для больших кусков текста, таких как предложения, не были столь успешными. Несколько попыток изучения неконтролируемых представлений предложений не достигли достаточной производительности, чтобы быть широко принятыми. В этой статье мы показываем, как универсальные представления предложений, обученные с использованием контролируемых данных наборов данных естественного языка Стэнфорда, могут последовательно превосходить неконтролируемые методы, такие как векторы SkipThought, в широком спектре задач переноса. Подобно тому, как компьютерное зрение использует ImageNet для получения функций, которые затем могут быть перенесены на другие задачи, наша работа, как правило, указывает на пригодность логического вывода для передачи обучения другим задачам НЛП. Наш кодировщик общедоступен.

Вы можете просто сложить векторы слов одного предложения вместе. Затем посчитайте косинусное сходство вектора двух предложений как сходство двух предложений. Думаю, это самый простой способ.

Другие вопросы по тегам