Come calcolare la somiglianza della frase usando il modello word2vec di gensim con python


125

Secondo Gensim Word2Vec , posso usare il modello word2vec nel pacchetto gensim per calcolare la somiglianza tra 2 parole.

per esempio

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

Tuttavia, il modello word2vec non riesce a prevedere la somiglianza della frase. Ho scoperto il modello LSI con somiglianza di frasi in gensim, ma, che non sembra che possa essere combinato con il modello word2vec. La lunghezza del corpus di ogni frase che ho non è molto lunga (inferiore a 10 parole). Quindi, ci sono modi semplici per raggiungere l'obiettivo?


4
C'è un tutorial ACL che discute di questo problema (tra le altre cose): youtube.com/watch?v=_ASOqXiWBVo&feature=youtu.be
Emiel

7
Ora puoi usare doc2vec di gensim e ottenere la somiglianza della frase dallo stesso modulo
kampta

@kampta. Salve, suggeriresti qualche post che mostri l'implementazione?
Ian_De_Oliveira

Risposte:


86

Questo è in realtà un problema piuttosto impegnativo che stai chiedendo. Il calcolo della somiglianza della frase richiede la costruzione di un modello grammaticale della frase, la comprensione di strutture equivalenti (ad es. "Ieri è andato al negozio" e "ieri, è andato al negozio"), trovando somiglianze non solo nei pronomi e nei verbi, ma anche nel nomi propri, trovare coincidenze / relazioni statistiche in molti esempi testuali reali, ecc.

La cosa più semplice che potresti provare - anche se non so quanto bene questo funzionerebbe e certamente non ti darebbe i risultati ottimali - sarebbe rimuovere prima tutte le parole "stop" (parole come "il", "un ", ecc. che non aggiungono molto significato alla frase) e quindi eseguire word2vec sulle parole in entrambe le frasi, riassumere i vettori in una frase, riassumere i vettori nell'altra frase e poi trovare la differenza tra le somme. Riassumendoli invece di fare una differenza in termini di parole, almeno non sarai soggetto all'ordine delle parole. Detto questo, questo fallirà in molti modi e non è affatto una buona soluzione (sebbene le buone soluzioni a questo problema implichino quasi sempre una certa quantità di PNL, apprendimento automatico e altre abilità).

Quindi, la risposta breve è no, non c'è un modo semplice per farlo (almeno non farlo bene).


4
Penso che tu abbia ragione. Il metodo più semplice consiste nell'accumulare tutti i vettori di parole in una frase e trovare la differenza tra le somme. A proposito, questo metodo semplice sarà effettuato dal conteggio delle parole? Perché più parole in una frase, più istogramma verrà riassunto.
zhfkt

2
@zhfkt, molto probabilmente, sì. Quindi potresti dover dividere per il numero di parole o qualcosa del genere per cercare di escluderlo. In ogni caso, qualsiasi euristica come questa sarà gravemente difettosa.
Michael Aaron Safyan


75

Dato che stai usando gensim, dovresti probabilmente usare la sua implementazione doc2vec. doc2vec è un'estensione di word2vec a livello di frase, frase e documento. È un'estensione piuttosto semplice, descritta qui

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

Gensim è carino perché è intuitivo, veloce e flessibile. La cosa fantastica è che puoi prendere gli incorporamenti di parole pre-addestrati dalla pagina ufficiale di word2vec e il livello syn0 del modello Doc2Vec di gensim è esposto in modo da poter seminare gli incorporamenti di parole con questi vettori di alta qualità!

GoogleNews-vectors-negative300.bin.gz (come collegato in Google Code )

Penso che gensim sia sicuramente lo strumento più semplice (e finora per me, il migliore) per incorporare una frase in uno spazio vettoriale.

Esistono altre tecniche da frase a vettore rispetto a quella proposta nel documento di Le & Mikolov sopra. Socher e Manning di Stanford sono sicuramente due dei più famosi ricercatori che lavorano in questo settore. Il loro lavoro si è basato sul principio della composizione - la semantica della frase proviene da:

1. semantics of the words

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

Hanno proposto alcuni di questi modelli (diventando sempre più complessi) su come utilizzare la composizionalità per costruire rappresentazioni a livello di frase.

2011 - spiegamento del codificatore automatico ricorsivo (molto relativamente semplice. Inizia qui se interessati)

2012 - rete neurale matrice-vettore

2013 - rete tensoriale neurale

2015 - Albero LSTM

i suoi documenti sono tutti disponibili su socher.org. Alcuni di questi modelli sono disponibili, ma consiglierei comunque doc2vec di gensim. Per prima cosa, l'URAE 2011 non è particolarmente potente. Inoltre, viene pre-addestrato con pesi adatti per parafrasare i dati di notizie. Il codice che fornisce non consente di riaddestrare la rete. Inoltre, non puoi scambiare diversi vettori di parole, quindi sei bloccato con gli incorporamenti pre-word2vec del 2011 di Turian. Questi vettori non sono certamente al livello di word2vec o GloVe.

Non ho ancora lavorato con Tree LSTM, ma sembra molto promettente!

tl; dr Sì, usa doc2vec di gensim. Ma esistono altri metodi!


Hai maggiori informazioni su come inizializzare il modello doc2vec con valori word2vec pre-addestrati?
Simon H

42

Se stai usando word2vec, devi calcolare il vettore medio per tutte le parole in ogni frase / documento e usare la somiglianza del coseno tra i vettori:

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

Calcola la somiglianza:

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
Potresti fornire ulteriori spiegazioni su index2word_set e model.index2word? Grazie.
theteddyboy

3
Si noti che il calcolo del "vettore medio" è una scelta tanto arbitraria quanto non calcolarlo affatto.
gented

2
Sono stupito perché questa non è la risposta migliore, funziona abbastanza bene e non ha problemi di sequenza quale metodo di media ha.
Asim

Questa è la risposta che stavo cercando. Ha risolto il mio problema. Grazie per la soluzione
iRunner

25

puoi usare l'algoritmo Distance di Word Mover. ecco una semplice descrizione delle armi di distruzione di massa .

#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: se riscontri un errore sull'importazione della libreria pyemd , puoi installarla utilizzando il seguente comando:

pip install pyemd

2
Ho usato WMD prima e funziona abbastanza bene, tuttavia si strozzerebbe su un corpus di grandi dimensioni. Prova SoftCosineSimilarity. Trovato anche in gensim ( twitter.com/gensim_py/status/963382840934195200 )
krinker

1
Tuttavia, WMD non è molto veloce quando si desidera interrogare un corpus.
Amartya

18

Dopo aver calcolato la somma dei due insiemi di vettori di parole, dovresti prendere il coseno tra i vettori, non il diff. Il coseno può essere calcolato prendendo il prodotto scalare dei due vettori normalizzati. Pertanto, il conteggio delle parole non è un fattore.


1
puoi fornire un po 'di pseudocodice su come farlo (non sto usando gensim / python)
dcsan

13

C'è una funzione dalla documentazione che prende un elenco di parole e confronta le loro somiglianze.

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

Vorrei aggiornare la soluzione esistente per aiutare le persone che calcoleranno la somiglianza semantica delle frasi.

Passo 1:

Carica il modello adatto usando gensim e calcola i vettori di parole per le parole nella frase e memorizzali come un elenco di parole

Passaggio 2: calcolo del vettore della frase

Il calcolo della somiglianza semantica tra le frasi era difficile prima, ma recentemente un articolo intitolato " UNA LINEA DI BASE SEMPLICE MA DURA DA BATTERE PER INCASTRO DI SENTENZE stato proposto " che suggerisce un approccio semplice calcolando la media ponderata dei vettori di parole nella frase e quindi rimuovere le proiezioni dei vettori medi sulla loro prima componente principale. Qui il peso di una parola w è a / (a ​​+ p (w)) con a essendo un parametro ep (w) la frequenza (stimata) della parola chiamata frequenza inversa liscia .questo metodo ha prestazioni significativamente migliori.

Qui è stato fornito un semplice codice per calcolare il vettore della frase utilizzando SIF (smooth inverse frequency), il metodo proposto nell'articolo

Passaggio 3: utilizzando sklearn cosine_similarity carica due vettori per le frasi e calcola la somiglianza.

Questo è il metodo più semplice ed efficiente per calcolare la somiglianza della frase.


2
carta molto bella. nota: il collegamento all'implementazione SIF richiede la scrittura del metodo get_word_frequency () che può essere facilmente realizzato utilizzando Counter () di Python e restituendo un dict con chiavi: parole uniche w, valori: # w / # total doc len
Quetzalcoatl

8

Sto usando il seguente metodo e funziona bene. Devi prima eseguire un POSTagger e quindi filtrare la frase per eliminare le parole chiave (determinanti, congiunzioni, ...). Raccomando TextBlob APTagger . Quindi costruisci un word2vec prendendo la media di ogni vettore di parola nella frase. Il metodo n_similarity in Gemsim word2vec fa esattamente questo consentendo di passare due serie di parole da confrontare.


Qual è la differenza tra prendere la media dei vettori e aggiungerli per creare un vettore di frase?
Καrτhικ

1
La differenza è che la dimensione del vettore è fissa per tutte le frasi
lechatpito

Non c'è differenza finché usi la somiglianza del coseno. @lechatpito Niente a che fare con la dimensione del vettore. I vettori sono sommati, non concatenati.
Wok

6

Esistono estensioni di Word2Vec destinate a risolvere il problema del confronto di parti di testo più lunghe come frasi o frasi. Uno di questi è paragraph2vec o doc2vec.

"Rappresentazioni distribuite di frasi e documenti" http://cs.stanford.edu/~quocle/paragraph_vector.pdf

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


2
Vale la pena menzionare brevemente come funziona l'algoritmo presentato. Fondamentalmente aggiungi un "segno" univoco a ogni espressione e calcoli i vettori word2vec. Alla fine otterrai i vettori di parole per ciascuna delle tue parole nel corpus (a condizione che tu chieda tutte le parole, anche quelle uniche). Ogni "segno" univoco nell'enunciato rappresenterà quell'enunciato. C'è qualche controversia sui risultati presentati nel documento, ma questa è un'altra storia.
Vladislavs Dovgalecs

5

Gensim implementa un modello chiamato Doc2Vec per l' incorporamento dei paragrafi .

Esistono diversi tutorial presentati come notebook IPython:

Un altro metodo si baserebbe su Word2Vec e Word Mover's Distance (WMD) , come mostrato in questo tutorial:

Una soluzione alternativa sarebbe affidarsi a vettori medi:

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)

Infine, se riesci a eseguire Tensorflow, puoi provare: https://tfhub.dev/google/universal-sentence-encoder/2


4

Ho provato i metodi forniti dalle risposte precedenti. Funziona, ma lo svantaggio principale è che più lunghe sono le frasi maggiore sarà la somiglianza (per calcolare la somiglianza uso il punteggio del coseno dei due incorporamenti medi di due frasi qualsiasi) poiché più sono le parole più effetti semantici positivi verrà aggiunto alla frase.

Ho pensato che avrei dovuto cambiare idea e usare invece l'incorporamento della frase come studiato in questo articolo e in questo .


3

Il gruppo di ricerca di Facebook ha rilasciato una nuova soluzione chiamata InferSent Results e il codice viene pubblicato su Github, controlla il loro repo. È davvero fantastico. Ho intenzione di usarlo. https://github.com/facebookresearch/InferSent

il loro articolo https://arxiv.org/abs/1705.02364 Riassunto: molti sistemi PNL moderni si basano su word embedding, precedentemente addestrati in modo non supervisionato su grandi corpora, come funzionalità di base. Tuttavia, gli sforzi per ottenere incorporamenti per porzioni di testo più grandi, come le frasi, non hanno avuto altrettanto successo. Diversi tentativi di apprendere rappresentazioni di frasi senza supervisione non hanno raggiunto prestazioni sufficientemente soddisfacenti per essere ampiamente adottate. In questo articolo, mostriamo come le rappresentazioni di frasi universali addestrate utilizzando i dati supervisionati dei set di dati di Stanford Natural Language Inference possono superare costantemente metodi non supervisionati come i vettori SkipThought su un'ampia gamma di attività di trasferimento. Proprio come il modo in cui la visione artificiale utilizza ImageNet per ottenere funzionalità, che possono quindi essere trasferite ad altre attività, il nostro lavoro tende a indicare l'idoneità dell'inferenza del linguaggio naturale per trasferire l'apprendimento ad altri compiti di PNL. Il nostro codificatore è disponibile pubblicamente.


3

Se non si utilizza Word2Vec, abbiamo un altro modello per trovarlo utilizzando BERT per l'incorporamento. Di seguito sono riportati i link di riferimento 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))

Altro collegamento da seguire https://github.com/hanxiao/bert-as-service

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.