Che cos'è la codifica posizionale?

Che cos'è la codifica posizionale?

La codifica posizionale è una tecnica che inietta informazioni sulla posizione delle parole in una sequenza alle architetture trasformative.

L'ordine delle parole gioca un ruolo fondamentale nella comprensione del significato semantico di una frase. Ad esempio, "Allen porta a spasso il cane" e "il cane porta a spasso Allen" hanno significati completamente diversi nonostante abbiano le stesse parole o token. Quando implementiamo applicazioni di elaborazione del linguaggio naturale (NPL) utilizzando il deep learning e le reti neurali, dobbiamo creare un meccanismo mediante il quale le macchine possano conservare l'ordine delle parole in una frase per produrre un output logico.  

Tradizionalmente, modelli come le reti neurali ricorrenti (RNN) o le memorie a breve-lungo termine (LSTM) hanno un meccanismo integrato che gestisce l'ordine delle parole. Le RNN e le LSTM elaborano gli input in ordine, un token alla volta, memorizzando tutte le posizioni delle parole in una sequenza. In altre parole, il vettore n-dimensionale, detto anche “vettore di input”, viene elaborato uno dopo l’altro, imparando intrinsecamente gli ordini. Al contrario, altre architetture che utilizzano al meglio le reti neurali convoluzionali (CNN) o i trasformatori (Vaswani et al. 2017) non mantengono l'ordine delle parole ed elaborano i token in parallelo. Pertanto, abbiamo bisogno di implementare un meccanismo in grado di rappresentare esplicitamente l'ordine delle parole in una sequenza, una tecnica nota come codifica posizionale. La codifica posizionale consente al trasformatore di conservare le informazioni sull'ordine delle parole, consentendo la parallelizzazione e l'addestramento efficiente del modello. Spesso è possibile trovare implementazioni della codifica posizionale su GitHub.  

Le ultime tendenze in materia di AI, proposte da esperti

Ricevi insight selezionati sulle notizie più importanti e interessanti sull'AI. Iscriviti alla nostra newsletter settimanale Think. Leggi l'Informativa sulla privacy IBM.

Grazie per aver effettuato l'iscrizione!

L'abbonamento sarà fornito in lingua inglese. Troverai un link per annullare l'iscrizione in tutte le newsletter. Puoi gestire i tuoi abbonamenti o annullarli qui. Per ulteriori informazioni, consulta l'Informativa sulla privacy IBM.

Perché la codifica posizionale è importante?

L'ordine delle parole in una frase o in una sequenza determina il significato intrinseco della frase nelle lingue naturali. Inoltre, per il machine learning, la codifica dell'ordine delle parole ci fornisce un "dizionario" su dove dovrebbe essere ogni parola. Queste informazioni vengono conservate e possono essere generalizzate durante l'addestramento dei modelli di trasformatori, consentendo la parallelizzazione e superando RNN e LSTM per la loro efficienza di addestramento.  

Rivediamo l'esempio:

  • "Allen porta a spasso il cane"
  • "il cane porta a spasso Allen"

Queste due frasi con gli stessi tre token hanno significati completamente diversi a seconda dell'ordine delle parole. I trasformatori, che si basano sull'autoattenzione e sul meccanismo di attenzione multi-testa, non hanno una rappresentazione intrinseca degli ordini delle parole e tratterebbero la singola parola in una sequenza in modo identico se non fornissimo informazioni posizionali esplicite. Vogliamo che il modello capisca chi porta a spasso e chi viene portato a spasso, il che dipende interamente dalle posizioni.  

Raggiungiamo questo obiettivo elaborando innanzitutto ogni parola come un vettore che ne rappresenta il significato: ad esempio, "cane" verrà codificato in un array ad alta dimensionalità che ne codifica il concetto. In termini tecnici, ogni parola o sottoparola viene mappata su un embedding dell'input di lunghezza variabile. Tuttavia, da solo, il vettore del significato non ci dice dove appare il cane nella frase. La codifica posizionale aggiunge un secondo vettore, che codifica l'indice di posizione, ad esempio "prima parola" o "seconda parola" e così via. I due vettori vengono quindi aggiunti per rappresentare cos'è la parola e dove si trova la parola. Questo vettore risultante viene spesso definito vettore di codifica posizionale.   

Esistono diversi modi per creare la codifica posizionale. In questo articolo, esploriamo l'esempio più noto di utilizzo di una funzione sinusoidale introdotta dagli autori in Attention is all you need1 per creare una codifica posizionale.  

Mixture of Experts | 28 agosto, episodio 70

Decoding AI: Weekly News Roundup

Unisciti al nostro gruppo di livello mondiale di ingegneri, ricercatori, leader di prodotto e molti altri mentre si fanno strada nell'enorme quantità di informazioni sull'AI per darti le ultime notizie e gli ultimi insight sull'argomento.

Codifica posizionale nei trasformatori

Nell'articolo originale introdotto da Vaswani et al. 2017, l'idea chiave è quella di generare una codifica fissa e deterministica per ogni posizione in una sequenza utilizzando una funzione sinusoidale, in particolare le funzioni seno sin(x) e coseno cos(x) .  

Cosa sono le funzioni sinusoidali?

Le funzioni sinusoidali sono un concetto matematico fondamentale che produce un modello uniforme di lunghezza d'onda. In particolare, le funzioni coseno e seno sono utilizzate dagli autori nelle funzioni del trasformatore originale per aiutare la codifica posizionale.

Se tracciamo sin(x) e  cos(x) , vedremo una curva che sale e scende tra -1 e 1 in uno schema periodico ripetuto.

Alcune proprietà del seno che lo rendono potente per la codifica posizionale: 

  • È periodico: si ripete regolarmente a intervalli, il che è utile per rappresentare schemi ripetuti.

  • È fluido e continuo: piccole variazioni nell'input comportano piccole variazioni nell'output, il che ci dà un modo per rappresentare le posizioni in uno spazio differenziabile.

  • Variando la frequenza delle lunghezze d'onda tra le dimensioni, possiamo creare una ricca rappresentazione multiscala della posizione. 

Tracciamo le onde seno e coseno per visualizzare come appaiono:

import numpy as np 
import matplotlib.pyplot as plt 

# Create an array of 100 x values evenly spaced from 0 to 2π (approx 6.28)
x = np.linspace(0, 2 * np.pi, 100) 

# Compute the sine and cosine of each x value 
sin_values = np.sin(x) 

# Create the plot 
plt.figure(figsize=(5, 2)) 
plt.plot(x, sin_values, label='sin(x)', color='blue') 

# Customize the plot 
plt.title('Sine Function') 
plt.xlabel('x') 
plt.ylabel('Function value') 
plt.axhline(0, color='black', linewidth=0.5) # horizontal line at y=0 
plt.axvline(0, color='black', linewidth=0.5) # vertical line at x=0 
#plt.grid(True, linestyle='--', alpha=0.5) 
plt.legend() 
plt.tight_layout() 

# Show the plot 
plt.show() 

La funzione seno

Grafico della funzione seno, una curva ripetuta con un intervallo positivo e negativo.

E ora diamo un'occhiata a come possiamo tracciare la funzione coseno:

#apply the cosine function to the same array, x
cosine = np.cos(x) 

plt.figure(figsize = (5,2)) 
plt.plot(x, cosine, label = 'cos(x)', color = 'blue') 
plt.title('The Cosine Function') 
plt.xlabel('x') 
plt.ylabel('Function value') 
plt.axhline(0, color='black', linewidth=0.5) # horizontal line at y=0 
plt.axvline(0, color='black', linewidth=0.5) # vertical line at x=0 
#plt.grid(True, linestyle='--', alpha=0.5) 
plt.legend() 
plt.tight_layout() 
Un grafico della funzione coseno, che illustra la sua natura periodica e le sue caratteristiche chiave.

Le formule di codifica della posizione sinusoidale, definite dagli autori dell'articolo originale sui trasformatori (Vaswani et al. 2017), sono mostrate come segue:

Per posizioni pari:

 PEpos,2i=sin(pos100002i/dmodel) 

Per posizioni dispari:

 PEpos,2i+1=cos(pos100002i/dmodel) 

  •  k : la posizione della parola nella frase (ad esempio, 0 per la prima parola, 1 per la seconda e così via).

  •  i : l'indice di dimensione del vettore di embedding. è associato all'indice di colonna. 2i indicherà una posizione pari e 2i+1 indicherà una posizione dispari.

  •  dmodel : la dimensionalità predefinita degli embedding dei token (ad esempio, 512)

  •  n : valore scaler definito dall'utente (ad esempio, 10000)

  •  PE : funzione di posizione per mappare la posizione k nella sequenza di input per ottenere la mappatura posizionale

     

 

Utilizzando questa formula, ogni parola, in corrispondenza della posizione k, avrà un valore di embedding basato sulla posizione della parola. Prendiamo l'esempio che abbiamo utilizzato, "Allen porta a spasso il cane", e possiamo calcolare l'embedding per ogni parola:

-  k1 = "Allen"

-  k2 = "porta a spasso"

-  k3 ="cane"

Scriviamo una semplice funzione Python per calcolare il valore di  PE(k) :

import numpy as np 

import matplotlib.pyplot as plt 

  

# create the positional encoding function using the formula above 

def getPositionEncoding(seq_len, d, n=10000): 

    # instantiate an array of 0s as a starting point 

    P = np.zeros((seq_len, d)) 

    # iterate through the positions of each word  

    for k in range(seq_len): 

        #calculate the positional encoding for even and odd position of each word 

        for i in np.arange(int(d/2)): 

            denominator = np.power(n, 2*i/d) 

            P[k, 2*i] = np.sin(k/denominator) 

            P[k, 2*i+1] = np.cos(k/denominator) 
    return P 

Una volta che abbiamo chiamato la funzione e inserito il valore corrispondente nel nostro esempio, dove la lunghezza della sequenza è 3, con una dimensione semplificata di  d=4 , e  n=10000 

P = getPositionEncoding(seq_len=3, d=4, n=10000) 

print(P) 

Otteniamo la seguente matrice di codifica (nota anche come tensore):

[[ 0,                      1,                      0,                       1,        ]

 [ 0,84147098  0,54030231  0,09983342  0,99500417]

 [ 0,90929743 -0,41614684  0,19866933  0,98006658]]

Per rappresentare più concretamente questo risultato, otteniamo

Posizione della parolaDim 0
sin(pos ÷ 10000^(0 ÷ 4))
Dim 1
cos(pos ÷ 10000^(0 ÷ 4))
Dim 2
sin(pos ÷ 10000^(2 ÷ 4))
Dim 3
cos(pos ÷ 10000^(2 ÷ 4))
“Allen” k = 00,00000,00000,00001,0000
«porta a spasso» k = 10,8414710,5403020,0100000,999950
«cane» k = 20,909297-0,4161470,0200000,999800

Qui possiamo vedere il valore concreto di ogni parola e il corrispondente valore di embedding posizionale. Tuttavia, non possiamo usare questi embedding direttamente per interpretare l'ordine delle parole. Il valore calcolato qui viene utilizzato per inserire informazioni sulla posizione in un vettore di input del trasformatore. Poiché l'input di sin(x)  e  cos(x) sono diversi, ogni posizione  k  risponderà a una diversa funzione sinusoidale. La posizione corrispondente delle diverse funzioni sinusoidali ci fornisce informazioni sulla posizione assoluta e relativa della parola in "Allen porta a spasso il cane". In altre parole, queste informazioni possono essere utilizzate dal modello in modo tale che possa imparare ad associare questi schemi all'ordine, alla spaziatura e alla struttura.  

Ora implementiamo una funzione Python per visualizzare la matrice posizionale

import numpy as np 

import matplotlib.pyplot as plt 

  

def get_position_encoding(seq_len, d_model, n=10000): 

    P = np.zeros((seq_len, d_model)) 

    for pos in range(seq_len): 

        for i in range(d_model): 

            angle = pos / np.power(n, (2 * (i // 2)) / d_model) 

            P[pos, i] = np.sin(angle) if i % 2 == 0 else np.cos(angle) 

    return P 

  

# Parameters 

seq_len = 100   # Number of tokens 

d_model = 512   # Embedding dimensions 

  

# Generate positional encoding 

P = get_position_encoding(seq_len, d_model) 

  

# Plot 

plt.figure(figsize=(10, 6)) 

cax = plt.matshow(P, cmap='viridis', aspect='auto') 

plt.title("Sinusoidal Positional Encoding Heatmap") 

plt.xlabel("Embedding Dimension") 

plt.ylabel("Token Position") 

plt.colorbar(cax) 

plt.tight_layout() 

plt.show() 
Mappa termica sinusoidale

Considerazioni finali

Come possiamo vedere con le diverse frequenze basate sui valori di x, ogni posizione corrispondente dalla parola di input k differirà su una scala di  [-1.1] —l'intervallo della funzione  sin(x) . Da lì il nostro modello di trasformatore basato su encoder e decoder apprenderà e conserverà la diversa codifica di posizione di ogni parola, consentendo al modello di conservare le informazioni per l'addestramento. Il vettore di posizione codificato rimane statico durante l'addestramento, consentendo il calcolo parallelo.

Soluzioni correlate
IBM watsonx.ai

Addestra, convalida, adatta e implementa le funzionalità di AI generativa, foundation model e machine learning con IBM watsonx.ai, uno studio aziendale di nuova generazione per builder AI. Crea applicazioni AI in tempi ridotti e con una minima quantità di dati.

Scopri watsonx.ai
Soluzioni di intelligenza artificiale

Metti l'AI al servizio della tua azienda grazie all'esperienza leader di settore e alla gamma di soluzioni di IBM nel campo dell'AI.

Esplora le soluzioni AI
Consulenza e servizi sull'AI

Reinventa i flussi di lavoro e le operazioni critiche aggiungendo l'AI per massimizzare le esperienze, il processo decisionale in tempo reale e il valore di business.

Esplora i servizi AI
Fai il passo successivo

Ottieni l'accesso completo a funzionalità che coprono l'intero ciclo di vita dello sviluppo dell'AI. Crea soluzioni AI all'avanguardia con interfacce intuitive, workflow e accesso alle API e agli SDK standard di settore.

Esplora watsonx.ai Prenota una demo live
Note a piè di pagina

1. "Attention Is All You Need", Ashish Vaswani et al., Atti della 31a conferenza internazionale sui sistemi di elaborazione delle informazioni neurali, arXiv:1706.03762v7, revisionato il 2 agosto 2023.

2. “Long Short-Term Memories”, Sepp Hochreiter and Jürgen Schmidhuber. 1997. Long Short-Term Memory. Neural Comput. 9, 8 (15 novembre 1997), 1735–1780., 

3. “Foundations of Recurrent Neural Networks (RNNs) and Long Short-Term Memories” Alex Sherstinsky et al., Elsevier “Physica D: Nonlinear Phenomena” journal, Volume 404, marzo 2020: numero speciale su machine learning e sistemi dinamici