PyTorch LSTMCell – Forme di Input, Stato Nascosto, Stato della Cella e Output

PyTorch LSTMCell - Input, Hidden State, Cell State, and Output Shapes

In Pytorch, per utilizzare un LSTMCell (con nn.LSTMCell), è necessario capire come dovrebbero essere strutturati i tensori che rappresentano la serie temporale di input, il vettore di stato nascosto e il vettore di stato della cella. In questo articolo, supponiamo che tu stia lavorando con una serie temporale multivariata. Ogni serie temporale multivariata nel dataset contiene più serie temporali univariate.

In questo articolo, utilizziamo la seguente terminologia:

batch = numero di serie temporali multivariate in un singolo batch del dataset

input_features = numero di serie temporali univariate in una serie temporale multivariata

time_steps = numero di passaggi temporali in ogni serie temporale multivariata

Il batch di serie temporali multivariate da cui viene fornito in input al LSTMCell deve essere un tensore di forma (time_steps, batch, input_features)

L’immagine seguente fornisce una comprensione di questa forma per l’input:

L’input a un LSTMCell viene fornito in un modo specifico. Fondamentalmente, l’intera serie temporale multivariata non viene fornita come input come serie temporale. Il vettore x_t, che è il vettore in un determinato passaggio temporale nella MTS, viene fornito in input al LSTMCell. Per elaborare il vettore di un singolo passaggio temporale, il LSTMCell ha bisogno di un singolo vettore di stato nascosto come parte dell’input e un singolo vettore di stato della cella come parte dell’input. Questi sono rappresentati rispettivamente come h_0 e c_0, . L’output del LSTMCell sarà lo stato nascosto e lo stato della cella che verranno utilizzati durante l’elaborazione del vettore di input al successivo istante di tempo x_t+1. Questi stati nascosti e della cella sono rappresentati rispettivamente come h_1 e c_1. Il LSTMCell viene chiamato in un loop, passando h_1 e c_1 come h_0 e c_0 per i successivi passaggi temporali. Questo concetto è illustrato nel seguente frammento di codice.

Mentre si inizializza un oggetto LSTMCell, vanno forniti gli argomenti input_features e hidden_size.

Qui,

input_features = numero di serie temporali univariate in una serie temporale multivariata (stesso valore di input_features menzionato in precedenza)

hidden_size = numero di dimensioni nel vettore di stato nascosto. Questa stessa dimensione dovrebbe essere utilizzata anche per il numero di dimensioni nel vettore di stato della cella.

I valori iniziali dello stato nascosto e dello stato della cella nel LSTMCell dovrebbero essere creati con forma (batch, hidden_size). Qui, il batch dovrebbe corrispondere al batch nella serie temporale multivariata di input. Ciò significa che, per ogni MTS nel batch di input, c’è uno stato_nascosto e uno stato_della_cella corrispondenti.

La serie temporale dello stato nascosto iniziale e dello stato della cella iniziale dovrebbe essere fornita in input per una propagazione in avanti attraverso il LSTMCell.

La propagazione in avanti del vettore di un passaggio temporale specifico della MTS iniziale, dello stato nascosto iniziale e dello stato della cella iniziale attraverso l’oggetto LSTMCell dovrebbe essere nel formato:

LSTMCell(x_t, (h_0, c_0))

L’immagine seguente fornisce una comprensione di questa forma per lo stato nascosto e lo stato della cella:

Ecco un esempio di codice. Una spiegazione del codice segue.

import torch
import torch.nn as nn
lstm_0 = nn.LSTMCell(10, 20) # (input_features, hidden_size)
inp = torch.randn(7, 3, 10) # (time_steps, batch, input_features) -> serie temporale di input
hx = torch.randn(3, 20) # (batch, hidden_size) -> valore iniziale dello stato nascosto
cx = torch.randn(3, 20) # (batch, hidden_size) -> valore iniziale dello stato della cella
for i in range(inp.size()[0]):
     hx, cx = lstm_0(inp[i], (hx, cx)) # propagazione in avanti dell'input tramite LSTMCell
     output.append(hx)
output = torch.stack(output, dim=0)

Chiamare nn.LSTMCell() chiamerà il metodo magico __init__() e creerà un oggetto LSTMCell. Nel codice sopra questo oggetto è referenziato come lstm_0.

Nelle RNN in generale (LSTM è un tipo di RNN), ogni time_step della serie temporale di input dovrebbe essere passato alla RNN uno alla volta in ordine sequenziale per essere elaborato dalla RNN.

Per elaborare serie temporali multivariate in un batch utilizzando un LSTMCell, ogni time_step in tutte le MTS nel batch dovrebbe essere passato attraverso l’LSTMCell in sequenza.

Ciò viene ottenuto dal ciclo for. Il ciclo itera su ogni time_step della MTS (la prima dimensione di inp.size() è il numero di time_steps) e passa il vettore del time_step in ogni MTS nel batch parallelamente nell’LSTMCell. Una singola chiamata all’LSTMCell elabora solo il vettore del time_step in MTS.

L’output della chiamata lstm_0(inp[i], (hx, cx)) all’interno del ciclo for è la creazione del prossimo hidden_state e cell state per ogni time_step. L’hidden_state di output (hx) e lo cell_state (cx) vengono calcolati in modo ricorsivo in base all’hx e al cx precedenti.

Output: (h_1, c_1)

Questo output viene calcolato per ogni serie temporale in tutto il batch. La forma dell’output è (batch, hidden_size).

La seguente immagine fornisce una comprensione della forma dell’hidden state e del cell state che vengono prodotti in output:

Questi hx calcolati che vengono creati per ogni time step in ogni MTS nel batch di input vengono aggiunti al tensore di output, che a sua volta viene impilato lungo l’asse 0. Pertanto, l’output ha le dimensioni (time_steps, batch, hidden_size).

Per l’esempio di codice sopra, questo è l’output:

tensor([[[ 0.0087,  0.0365, -0.1233, -0.2641,  0.2908, -0.5075,  0.2587,           0.1057, -0.2079, -0.2327,  0.1390,  0.1023, -0.1186,  0.3302,           0.1139,  0.1591, -0.0264, -0.0499,  0.0153,  0.3881],         [ 0.3585, -0.4133, -0.0259,  0.2490, -0.0936, -0.2756, -0.1941,          -0.0967,  0.1501, -0.0334, -0.1904, -0.3945, -0.1036, -0.2091,           0.0545,  0.1937, -0.2338,  0.0382,  0.2344,  0.1169],         [-0.2532,  0.0745, -0.0329,  0.0971, -0.1057, -0.0383,  0.1328,           0.1263, -0.1422,  0.0351,  0.3957, -0.4115, -0.2951, -0.5560,           0.1941,  0.0100,  0.3028, -0.1803,  0.0028,  0.3210]],        [[ 0.1105, -0.1295, -0.0636, -0.2510,  0.1923, -0.2457,  0.2401,           0.1379, -0.1373, -0.2451,  0.0387,  0.1004, -0.0580,  0.3430,          -0.0149,  0.1827, -0.0229, -0.2061,  0.1718,  0.3146],         [ 0.2741, -0.2413, -0.1310,  0.1206,  0.0379, -0.1738, -0.0568,           0.0417,  0.0756,  0.1020,  0.0262, -0.3280, -0.0352, -0.1713,           0.1065,  0.0458, -0.3404, -0.0795,  0.0586,  0.0026],         [-0.0112,  0.0883, -0.1755, -0.0438,  0.0193,  0.0151,  0.1010,           0.1614, -0.0524,  0.0970,  0.2092, -0.3518, -0.0715, -0.3941,           0.1422,  0.1164,  0.2946, -0.1919,  0.1493,  0.1203]]],       grad_fn=<StackBackward0>)

Per ogni passo temporale nell’input (time_steps nell’input = 2) viene creato un array (vengono creati 2 array). Ciascuno di questi array contiene array per ciascuna MTS nel batch (batch_size = 3). Per ogni passo temporale nell’MTS, otteniamo un vettore di stato nascosto di dimensione hidden_size (qui hidden_size = 20). Quindi, per ogni passo temporale, il valore MTS è un vettore. Questo vettore in un passo temporale viene mappato in un vettore hidden_state a 20 dimensioni.

La seguente immagine fornisce una comprensione di questa forma per il batch di serie temporali multivariate di output:

Se stampi hx nel codice sopra per un passo temporale (per una iterazione nel ciclo), il seguente è l’output:

tensor([[ 0.1034, -0.0192, -0.0581, -0.0772, -0.1578, -0.1450,  0.0377, -0.0013,         -0.2641, -0.1821,  0.0431, -0.2262,  0.3025,  0.0952,  0.4113, -0.2968,         -0.4377,  0.0794,  0.3683, -0.0021],        [ 0.0309,  0.3957,  0.2143,  0.1020,  0.0640, -0.0628,  0.4390,  0.1818,          0.0373,  0.2497, -0.1768, -0.2038, -0.1249, -0.2995,  0.0786, -0.0522,         -0.0080, -0.3095, -0.0815,  0.2874],        [-0.2458,  0.1622,  0.2564, -0.3136,  0.0631,  0.0643,  0.4036,  0.3293,         -0.1806, -0.0251, -0.4505, -0.1437, -0.1718, -0.0479, -0.1116, -0.1065,         -0.3289,  0.1137,  0.1160,  0.1227]], grad_fn=<MulBackward0>)

Ha un array corrispondente a un passo temporale. All’interno di questo passo temporale, ci sono 3 array, corrispondenti a 3 MTS nel batch. Ciascuno di questi array corrispondente a una MTS ha un vettore nascosto a 20 dimensioni. Quindi, l’output in un passo temporale è (batch, hidden_size).

Questa dimensione di output può essere compresa utilizzando la seguente immagine:

Gli argomenti di inizializzazione di nn.LSTMCell sono:

input_size

hidden_size

bias

device

dtype

Non ha num_layers. Poiché si tratta di una singola cella, non può avere più layer LSTM.