Guida passo-passo a Word2Vec con Gensim

Guida a Word2Vec con Gensim

Introduzione

Qualche mese fa, quando ho iniziato a lavorare in Office People, mi sono interessato ai Modelli di Linguaggio, in particolare a Word2Vec. Essendo un utente Python nativo, mi sono naturalmente concentrato sull’implementazione di Word2Vec di Gensim e ho cercato articoli e tutorial online. Ho applicato direttamente e duplicato frammenti di codice da diverse fonti, come farebbe qualsiasi buon data scientist. Sono andato sempre più in profondità nel tentativo di capire cosa non andava nel mio metodo, leggendo conversazioni su Stackoverflow, i gruppi di discussione di Gensim e la documentazione della libreria.

Tuttavia, ho sempre pensato che mancasse uno degli aspetti più importanti nella creazione di un modello Word2Vec. Durante i miei esperimenti, ho scoperto che la lemmatizzazione delle frasi o la ricerca di frasi/bigrammi in esse aveva un impatto significativo sui risultati e sulle prestazioni dei miei modelli. Anche se l’impatto della pre-elaborazione varia a seconda del dataset e dell’applicazione, ho deciso di includere i passaggi di preparazione dei dati in questo articolo e di utilizzare la fantastica libreria spaCy insieme ad essa.

Alcuni di questi problemi mi infastidiscono, quindi ho deciso di scrivere il mio articolo. Non prometto che sia perfetto o il modo migliore per implementare Word2Vec, ma solo che è migliore di molte altre risorse disponibili.

Obiettivi di Apprendimento

  • Comprendere le word embeddings e il loro ruolo nella cattura delle relazioni semantiche.
  • Implementare modelli Word2Vec utilizzando librerie popolari come Gensim o TensorFlow.
  • Misurare la similarità delle parole e calcolare le distanze utilizzando le word embeddings di Word2Vec.
  • Esplorare analogie tra parole e relazioni semantiche catturate da Word2Vec.
  • Applicare Word2Vec in vari compiti di elaborazione del linguaggio naturale come l’analisi del sentiment e la traduzione automatica.
  • Apprendere tecniche per affinare i modelli Word2Vec per compiti o domini specifici.
  • Gestire parole fuori vocabolario utilizzando informazioni subword o embeddings pre-addestrati.
  • Comprendere le limitazioni e i compromessi di Word2Vec, come la disambiguazione del senso delle parole e la semantica a livello di frase.
  • Approfondire argomenti avanzati come gli embeddings subword e l’ottimizzazione del modello con Word2Vec.

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

Breve Descrizione di Word2Vec

Un team di ricercatori di Google ha introdotto Word2Vec in due articoli tra settembre e ottobre 2013. I ricercatori hanno anche pubblicato la loro implementazione in linguaggio C insieme agli articoli. Gensim ha completato l’implementazione in Python poco dopo il primo articolo.

Il presupposto alla base di Word2Vec è che due parole con contesti simili abbiano significati simili e, di conseguenza, una rappresentazione vettoriale simile nel modello. Ad esempio, “cane”, “cucciolo” e “cucciolo” sono frequentemente usati in contesti simili, con parole circostanti simili come “buono”, “soffice” o “carino”, e quindi hanno una rappresentazione vettoriale simile secondo Word2Vec.

Basandosi su questo presupposto, Word2Vec può essere utilizzato per scoprire le relazioni tra le parole in un dataset, calcolare la loro similarità o utilizzare la rappresentazione vettoriale di queste parole come input per altre applicazioni come la classificazione del testo o il clustering.

Implementazione di Word2vec

L’idea alla base di Word2Vec è piuttosto semplice. Si fa l’assunzione che il significato di una parola possa essere dedotto dall’ambiente in cui si trova. Questo è analogo al detto “Dimmi con chi vai e ti dirò chi sei”. Ecco un’implementazione di Word2Vec.

Configurazione dell’Ambiente

python==3.6.3

Librerie utilizzate:

  • xlrd==1.1.0:
  • spaCy==2.0.12:
  • gensim==3.4.0:
  • scikit-learn==0.19.1:
  • seaborn==0.8:
import re  # Per la pre-elaborazione
import pandas as pd  # Per la gestione dei dati
from time import time  # Per misurare le operazioni
from collections import defaultdict  # Per la frequenza delle parole

import spacy  # Per la pre-elaborazione

import logging  # Configurazione dei log per monitorare gensim
logging.basicConfig(format="%(levelname)s - %(asctime)s: %(message)s", 
                    datefmt= '%H:%M:%S', level=logging.INFO)

Dataset

Questo dataset contiene informazioni sui personaggi, le location, i dettagli degli episodi e le righe di script di oltre 600 episodi dei Simpsons risalenti al 1989. È disponibile su Kaggle. (~25MB)

Preprocessing

Nel preprocessing, manterremo solo due colonne del dataset: raw_character_text e spoken_words.

  • raw_character_text: il personaggio che parla (utile per tenere traccia delle fasi di preprocessing).
  • spoken_words: il testo grezzo della riga di dialogo

Poiché vogliamo fare il nostro proprio preprocessing, non manteniamo normalized_text.

df = pd.read_csv('../input/simpsons_dataset.csv')
df.shape

df.head()

I valori mancanti provengono da una sezione dello script in cui succede qualcosa ma non c’è dialogo. “Springfield Elementary School: EXT. ELEMENTARY – SCHOOL PLAYGROUND – AFTERNOON” è un esempio.

df.isnull().sum()

Cleaning

Per ogni riga di dialogo, stiamo lemmatizzando e rimuovendo le stopwords e i caratteri non alfabetici.

nlp = spacy.load('en', disable=['ner', 'parser']) 

def cleaning(doc):
    # Lemmatizza e rimuove le stopwords
    # doc deve essere un oggetto Doc di spacy
    txt = [token.lemma_ for token in doc if not token.is_stop]



    if len(txt) > 2:
        return ' '.join(txt)

Rimuove i caratteri non alfabetici:

brief_cleaning = (re.sub("[^A-Za-z']+", ' ', str(row)).lower() for row in df['spoken_words'])

Utilizzando l’attributo spaCy.pipe() per accelerare il processo di pulizia:

t = time()

txt = [cleaning(doc) for doc in nlp.pipe(brief_cleaning, batch_size=5000,
                   n_threads=-1)]

print('Tempo impiegato per pulire tutto: {} minuti'.format(round((time() - t) / 60, 2)))

Per rimuovere i valori mancanti e i duplicati, inserisci i risultati in un DataFrame:

df_clean = pd.DataFrame({'clean': txt})
df_clean = df_clean.dropna().drop_duplicates()
df_clean.shape

Bigrammi

I bigrammi sono un concetto utilizzato nell’elaborazione del linguaggio naturale e nell’analisi del testo. Si riferiscono a coppie consecutive di parole o caratteri che compaiono in una sequenza di testo. Analizzando i bigrammi, possiamo ottenere informazioni sulle relazioni tra le parole o i caratteri in un determinato testo.

Prendiamo ad esempio la frase: “Amo il gelato”. Per identificare i bigrammi in questa frase, guardiamo le coppie di parole consecutive:

“Amo il”

“il gelato”

Ogni coppia rappresenta un bigramma. I bigrammi possono essere utili in vari compiti di elaborazione del linguaggio. Ad esempio, nella modellazione del linguaggio, possiamo utilizzare i bigrammi per prevedere la prossima parola in una frase in base alla parola precedente.

I bigrammi possono essere estesi a sequenze più grandi chiamate trigrammi (terne consecutive) o n-grammi (sequenze consecutive di n parole o caratteri). La scelta di n dipende dall’analisi o dal compito specifico in questione.

Il pacchetto Gensim Phrases viene utilizzato per rilevare automaticamente frasi comuni (bigrammi) da un elenco di frasi. https://radimrehurek.com/gensim/models/phrases.html

Lo facciamo principalmente per catturare parole come “mr_burns” e “bart_simpson”!

from gensim.models.phrases import Phrases, Phraser
sent = [row.split() for row in df_clean['clean']]

Le seguenti frasi vengono generate dall’elenco di frasi:

phrases = Phrases(sent, min_count=30, progress_per=10000)

Lo scopo di Phraser() è ridurre il consumo di memoria di Phrases() eliminando lo stato del modello che non è strettamente necessario per il compito di rilevamento dei bigrammi:

bigram = Phraser(phrases)

Trasforma il corpus in base ai bigrammi rilevati:

sentences = bigram[sent]

Parole più frequenti

Principalmente un controllo di coerenza sull’efficacia della lemmatizzazione, della rimozione delle stopword e dell’aggiunta di bigrammi.

word_freq = defaultdict(int)
for sent in sentences:
    for i in sent:
        word_freq[i] += 1
len(word_freq)

sorted(word_freq, key=word_freq.get, reverse=True)[:10]

Separare l’addestramento del modello in 3 passaggi

Per chiarezza e monitoraggio, preferisco dividere l’addestramento in tre passaggi distinti.

  • Word2Vec():
    • In questo primo passaggio, imposto i parametri del modello uno per uno.
    • Intenzionalmente lascio il modello non inizializzato non fornendo il parametro “sentences”.
  • build_vocab():
    • Inizializza il modello costruendo il vocabolario da una sequenza di frasi.
    • Puoi monitorare il progresso e, più importantemente, l’effetto di min_count e sample sul corpus di parole utilizzando i loggings. Ho scoperto che questi due parametri, in particolare sample, hanno un impatto significativo sulle prestazioni del modello. La visualizzazione di entrambi consente una gestione più accurata e semplice del loro influsso.
  • .train():
    • Infine, il modello viene addestrato.
    • I loggings in questa pagina sono principalmente utili.
import multiprocessing

from gensim.models import Word2Vec

cores = multiprocessing.cpu_count() # Conta il numero di core in un computer


w2v_model = Word2Vec(min_count=20,
                     window=2,
                     size=300,
                     sample=6e-5, 
                     alpha=0.03, 
                     min_alpha=0.0007, 
                     negative=20,
                     workers=cores-1)

Implementazione di Gensim di word2vec: https://radimrehurek.com/gensim/models/word2vec.html

Costruzione della tabella del vocabolario

Word2Vec ci richiede di creare la tabella del vocabolario (elaborando tutte le parole, filtrando le parole uniche e eseguendo alcune semplici conteggi su di esse):

t = time()

w2v_model.build_vocab(sentences, progress_per=10000)

print('Tempo per costruire il vocabolario: {} minuti'.format(round((time() - t) / 60, 2)))

La tabella del vocabolario è cruciale per codificare le parole come indici e cercare le loro corrispondenti word embeddings durante l’addestramento o l’inferenza. Essa forma la base per l’addestramento dei modelli Word2Vec e consente una rappresentazione efficiente delle parole nello spazio vettoriale continuo.

Addestramento del Modello

L’addestramento di un modello Word2Vec implica l’inserimento di un corpus di dati testuali nell’algoritmo e l’ottimizzazione dei parametri del modello per apprendere word embeddings. I parametri di addestramento per Word2Vec includono vari iperparametri e impostazioni che influenzano il processo di addestramento e la qualità dei word embeddings risultanti. Ecco alcuni parametri di addestramento comunemente utilizzati per Word2Vec:

  • total_examples = int – Il numero di frasi;
  • epochs = int – Il numero di iterazioni (epoche) sul corpus – [10, 20, 30]
t = time()

w2v_model.train(sentences, total_examples=w2v_model.corpus_count, epochs=30, report_delay=1)

print('Tempo per addestrare il modello: {} minuti'.format(round((time() - t) / 60, 2)))

Stiamo chiamando init_sims() per rendere il modello molto più efficiente in termini di memoria poiché non abbiamo intenzione di addestrarlo ulteriormente:

w2v_model.init_sims(replace=True)

Questi parametri controllano aspetti come la dimensione della finestra di contesto, il compromesso tra parole frequenti e rare, il tasso di apprendimento, l’algoritmo di addestramento e il numero di campioni negativi per il campionamento negativo. La regolazione di questi parametri può influire sulla qualità, l’efficienza e i requisiti di memoria del processo di addestramento di Word2Vec.

Esplorazione del Modello

Una volta addestrato un modello Word2Vec, è possibile esplorarlo per ottenere informazioni sui word embeddings appresi ed estrarre informazioni utili. Ecco alcuni modi per esplorare il modello Word2Vec:

Più simile a

In Word2Vec, è possibile trovare le parole più simili a una data parola in base ai word embeddings appresi. La similarità viene tipicamente calcolata utilizzando la similarità coseno. Ecco un esempio di ricerca delle parole più simili a una parola target utilizzando Word2Vec:

Vediamo cosa otteniamo per il personaggio principale dello spettacolo:

similar_words = w2v_model.wv.most_similar(positive=["homer"])
for word, similarity in similar_words:
    print(f"{word}: {similarity}")

Per essere chiari, quando guardiamo le parole più simili a “homer”, non otteniamo necessariamente i suoi membri della famiglia, tratti di personalità o anche le sue citazioni più memorabili.

Confronta ciò che restituisce il bigramma “homer_simpson”:

w2v_model.wv.most_similar(positive=["homer_simpson"])

E Marge ora?

w2v_model.wv.most_similar(positive=["marge"])

Verifichiamo ora Bart:

w2v_model.wv.most_similar(positive=["bart"])

Sembra che abbia senso!

Similarità

Ecco un esempio di calcolo della similarità coseno tra due parole utilizzando Word2Vec:

Esempio: Calcolo della similarità coseno tra due parole.

w2v_model.wv.similarity("moe_'s", 'tavern')

Chi potrebbe dimenticare la taverna di Moe? Non Barney.

w2v_model.wv.similarity('maggie', 'baby')

Maggie è sicuramente il bebè più famoso dei Simpson!

w2v_model.wv.similarity('bart', 'nelson')

Bart e Nelson, anche se amici, non sono così vicini, ha senso!

Odd-One-Out

Qui chiediamo al nostro modello di darci la parola che non appartiene alla lista!

Tra Jimbo, Milhouse e Kearney, chi non è un bullo?

w2v_model.wv.doesnt_match(['jimbo', 'milhouse', 'kearney'])

Cosa succede se confrontiamo l’amicizia tra Nelson, Bart e Milhouse?

w2v_model.wv.doesnt_match(["nelson", "bart", "milhouse"])

Sembra che Nelson sia l’eccezione qui!

Ultimo ma non meno importante, qual è la relazione tra Homer e le sue cognate?

w2v_model.wv.doesnt_match(['homer', 'patty', 'selma'])

Accidenti, loro davvero non ti vogliono bene, Homer!

Differenza Analoga

Quale parola è a donna come Homer è a Marge?

w2v_model.wv.most_similar(positive=["woman", "homer"], negative=["marge"], topn=3)

“man” viene al primo posto, sembra giusto!

Quale parola è a donna come Bart è a uomo?

w2v_model.wv.most_similar(positive=["woman", "bart"], negative=["man"], topn=3)

Lisa è la sorella di Bart, suo corrispondente maschile!

Conclusioni

In conclusione, Word2Vec è un algoritmo ampiamente utilizzato nel campo dell’elaborazione del linguaggio naturale (NLP) che apprende l’incorporamento delle parole rappresentandole come vettori densi in uno spazio vettoriale continuo. Cattura le relazioni semantiche e sintattiche tra le parole in base ai loro schemi di co-occorrenza in un ampio corpus di testo.

Word2Vec funziona utilizzando il modello Continuous Bag-of-Words (CBOW) o il modello Skip-gram, che sono architetture di reti neurali. Le word embeddings, generate da Word2Vec, sono rappresentazioni vettoriali dense delle parole che codificano informazioni semantiche e sintattiche. Consentono operazioni matematiche come il calcolo della similarità tra parole e possono essere utilizzate come feature in varie attività di elaborazione del linguaggio naturale.

Punti chiave

  • Word2Vec apprende le word embeddings, rappresentazioni vettoriali dense delle parole.
  • Analizza i pattern di co-occorrenza in un corpus di testo per catturare le relazioni semantiche.
  • L’algoritmo utilizza una rete neurale con il modello CBOW o il modello Skip-gram.
  • Le word embeddings consentono il calcolo della similarità tra parole.
  • Possiamo usarle come feature in varie attività di elaborazione del linguaggio naturale.
  • Word2Vec richiede un grande corpus di addestramento per ottenere delle word embeddings accurate.
  • Non cattura la disambiguazione del senso delle parole.
  • Word2Vec non considera l’ordine delle parole.
  • Parole fuori vocabolario possono rappresentare delle sfide.
  • Nonostante le limitazioni, Word2Vec ha significative applicazioni nell’elaborazione del linguaggio naturale.

Anche se Word2Vec è un algoritmo potente, presenta alcune limitazioni. Richiede una grande quantità di dati di addestramento per apprendere delle word embeddings precise. Tratta ogni parola come un’entità atomica e non cattura la disambiguazione del senso delle parole. Le parole fuori vocabolario possono rappresentare una sfida, poiché non hanno delle word embeddings preesistenti.

Word2Vec ha contribuito in modo significativo ai progressi nell’elaborazione del linguaggio naturale e continua ad essere uno strumento prezioso per attività come il recupero delle informazioni, l’analisi dei sentimenti, la traduzione automatica e altro ancora.

Domande frequenti

I media mostrati in questo articolo non sono di proprietà di Analytics Vidhya e vengono utilizzati a discrezione dell’autore.