# Word2vec

Word2vec è un insieme di modelli che sono utilizzati per produrre word embedding, il cui pacchetto fu originariamente creato in C da Tomas Mikolov, poi implementato anche in Python e Java. Word2vec è una semplice rete neurale artificiale a due strati progettata per elaborare il linguaggio naturale, l'algoritmo richiede in ingresso un corpus e restituisce un insieme di vettori che rappresentano la distribuzione semantica delle parole nel testo. Per ogni parola contenuta nel corpus, in modo univoco, viene costruito un vettore in modo da rappresentarla come un punto nello spazio multidimensionale creato. In questo spazio le parole saranno più vicine se riconosciute come semanticamente più simili. Per capire come Word2vec possa produrre word embedding è necessario comprendere le architetture CBOW e Skip-Gram.

## CBOW e Skip-Gram

Word2vec può produrre word embedding utilizzando uno tra i seguenti due modelli di architettura: continuous bag-of-words (CBOW) e Skip-Gram.
Per addestrare i modelli è necessario disporre di un corpus di documenti testuali quanto più ampio possibile. Da questo corpus sarà possibile estrarre un vocabolario di parole distinte (token).
Ogni token distinto è quindi rappresentato con una codifica One-hot encoding.
Questo approccio presenta però alcuni limiti poiché la dimensione del vettore $V$ dipende dalla dimensione del vocabolario che potrebbe essere anche molto ampia. Questo enorme utilizzo di dati potrebbe manifestarsi nella curse of dimensionality. Inoltre, se venissero aggiunti/rimossi token dal word embedding, il modello dovrebbe essere riaddestrato da zero. L'ultimo grosso limite di questo approccio è dovuto al fatto che non viene risolto il problema della polisemia dei termini (meaning conflation deficiency).
Nell'esempio di corpus sopra riportato sono presenti 13 token distinti, perciò la lunghezza del vettore $V$ è necessariamente 13.
I due modelli esplorano il contesto dei token investigando gli altri token che sono prossimi a quest'ultimo. Qui si evidenzia la principale differenza tra le architetture CBOW e Skip-Gram.
Se la prima architettura mira a predire il token corrente (output) a partire da una finestra di parole di contesto (input); la seconda ha lo scopo di predire le parole di contesto (output) a partire dal token corrente (input).
Il parametro $C$ definisce la dimensione della finestra di contesto: sono incluse nel contesto i $C$ token immediatamente precedenti/successivi al token corrente.
Finestra di contesto con C=2 per il testo "Nel mezzo del cammin di nostra vita" :
| token corrente | finestra di contesto |
| nel | (nel,mezzo) (nel,del) |
| mezzo | (nel, mezzo) (mezzo,del) (mezzo,cammin) |
| cammin | (mezzo, cammin)(del,cammin)(cammin,di)(cammin,nostra) |
| di | (del,di)(cammin,di)(di,nostra)(di,vita) |
| nostra | (cammin,nostra)(di,nostra)(nostra,vita) |
| vita | (di,vita)(nostra,vita) |
Entrambi i modelli sono implementati tramite una rete neurale artificiale costituita da tre strati: uno strato d'ingresso (input layer), uno strato nascosto (hidden layer) e uno strato d'uscita (output layer).
L'input varia a seconda del modello di architettura utilizzato così come varia il tipo di output predetto. Infatti, a seconda dell'architettura il token corrente e la finestra di contesto saranno l'input o l'output del modello.
A seguito del training del modello tramite backpropagation, la matrice dei pesi $W$ conterrà le rappresentazioni delle word embedding dei $V$ token del vocabolario dove N è la dimensione del word embedding. In altre parole, la riga $[w_{(i,1)},w_{(i,2)},...,w_{(i,N-1)},w_{(i,N)}]$ della matrice $W$ conterrà la rappresentazione word embedding del token $V_{i}$.
La funzione softmax viene applicata nell'ultimo layer della rete neurale.

### CBOW

L'architettura CBOW ha lo scopo di predire il token corrente (output, es. nel) a partire da una finestra di parole di contesto (input, es. mezzo e del). L'input consiste quindi nella rappresentazione One-hot encoding di $C*2$ token di contesto. La matrice $W$ è la stessa descritta nell'architettura generale, ma, in questo caso, l'hidden layer è la media dei vettori $W_{i}$ corrispondenti alle parole di contesto in ingresso.
Facendo ciò l'hidden layer perde l'informazione della posizione nel testo dei token che fanno parte della finestra di contesto così come avviene nella rappresentazione bag of words.

### Skip-Gram

L'architettura Skip-Gram ha lo scopo di predire le parole di contesto (output, es. nel, del e cammin) a partire dal token corrente (input, es. mezzo). L'output è rappresentato da un vettore $Vx1$ ottenuto dalla media della rappresentazione One-hot encoding di ogni token di contesto. L'input consiste invece nella rappresentazione One-hot encoding del token corrente. L'hidden layer corrisponde quindi alla rappresentazione word embedding del token corrente.
Il modello genererà un vettore di output per ogni token di contesto. Di conseguenza saranno presenti altrettanti vettori di errore di dimensione $Vx1$. Al fine di avviare la back propagation i $C*2$ vettori di errore vengono sommati tra di loro per ottenere un solo vettore $Vx1$. I pesi dell'hidden layer verranno quindi aggiornati in base a questo vettore di errore cumulativo.
Anche nell'architettura skip-gram non viene quindi tenuto conto della posizione nel testo dei token di contesto .

## Parametri word2vec
### Shell, C

Il pacchetto originale di Word2vec permette di lanciare da shell l'algoritmo scritto in C. Il file demo-word.sh infatti riporta questo comando:
Dove $BIN_DIR/word2vec è il percorso delle cartelle per arrivare al file word2vec nella cartella bin; $TEXT_DATA va sostituito invece con il corpus formato testo con cui si vuole fare l'addestramento e $VECTOR_DATA sarà il nome del file che l'algoritmo andrà a creare.
Successivamente possiamo vedere dei parametri modificabili:
* size per definire la dimensione dei vettori da creare.
* window per decidere la massima distanza tra la parola corrente e quella predetta all'interno di una frase.
* threads per decidere quanti thread del processore usare per addestrare il modello.
* binary determina in che codifica sarà salvato il file (se il parametro è inizializzato a 1 il file creato sarà binario, altrimenti sarà leggibile dall'uomo, cioè in formato testo).

### Gensim, Python

Vi sono vari parametri che si possono modificare per personalizzare il processamento dell'algoritmo, alcuni sono scritti di seguito:
* sentence=var, è il primo parametro da inserire per inizializzare il modello a partire da una variabile var iterabile e sotto forma di lista di parole (stringhe unicode) che verranno usate per l'addestramento.
* size=n, permette di decidere la dimensione dei vettori che l'algoritmo andrà a creare.
* window=n, permette di decidere la massima distanza tra la parola corrente e quella predetta all'interno di una frase.
* min_count=n, permette di ignorare le parole con una frequenza minima minori di n.
* workers=n, permette di decidere quanti thread del processore usare per addestrare il modello.
* seed=n, per il generatore di numeri casuali.
Il tutorial di gensim inizializza i parametri (n) in questo modo:

### DL4J, Java

I parametri spiegati sulla documentazione di DL4J sono:
* batchSize è la quantità di parole da elaborare contemporaneamente.
* minWordFrequency è la frequenza minima che devono avere le parole per essere prese in considerazione dall'algoritmo.
* layerSize è il numero di dimensioni che vogliamo dare ai vettori che l'algoritmo andrà a creare.
La documentazione di DL4J inizializza i parametri in questo modo: