es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo utilizar LSTM en PyTorch?

He estado intentando agregar LSTM a mi modelo PyTorch, pero el problema que tengo es que solicita entrada 3D y no puedo entender qué estoy haciendo mal. He hecho algo así:

“`import torch.nn as nn
torch.manual_seed(random_state)

from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence

class Net(nn.Module):
def init(self, vocab_size= len(vocab), embed_dim= 32, num_class= 3):
super().init()

<pre><code> self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=True)

self.lstm = nn.LSTM(input_size=embed_dim, hidden_size=embed_dim, num_layers=5)

self.lin = nn.Sequential(
nn.Linear(in_features=embed_dim, out_features=embed_dim),
nn.Linear(in_features=embed_dim, out_features=embed_dim),
nn.Linear(in_features=embed_dim, out_features=16),
nn.Linear(in_features=16, out_features=16),
nn.Linear(in_features=16, out_features=8),
nn.Linear(in_features=8, out_features=8),
)

self.out = nn.Sequential(
nn.Linear(in_features=8, out_features=num_class),
)

self.init_weights()

def init_weights(self):
initrange = 0.5
self.embedding.weight.data.uniform_(-initrange, initrange)
for i in self.lin:
if isinstance(i, nn.LSTM): continue
i.weight.data.uniform_(-initrange, initrange)
i.bias.data.zero_()

def forward(self, text, offsets):
x = self.embedding(text, offsets)

########## En las dos siguientes líneas no tengo idea de lo que estoy haciendo.
x = x.view(1, x.shape[0], -1)
x = self.lstm(x)[0][0]
########## Si elimina estas dos líneas, el modelo funciona medio decente.

x = self.lin(x)
return self.out(x)
</code></pre>

model = Net()
model.to(device)“`

Entonces, el lugar que me confunde es donde he dejado el comentario. La razón es que tengo un tamaño de lote de 10, el texto en sí y los desplazamientos, que se necesitan para las incrustaciones.

“Text” es un vector “torch.Size([360])” (no siempre 360 ya que la longitud de la oración puede ser diferente), y los desplazamientos son siempre “torch.Size([10])”. La salida del “self.embedding” entonces tiene un tamaño constante de “torch.Size([10, 32])”. ¿De dónde se supone que se tomará la tercera dimensión? He visto los ejemplos de otras personas y parece que lo que hacen es algo similar a lo que hago a continuación, pero mientras esto funciona, el modelo se vuelve absolutamente terrible y solo predice una clase, así que creo que algo está mal aquí. ¿Alguien sabe la forma correcta de hacer esto?

Si desea ver el código completo en acción (incluidos los conjuntos de datos), esto es casi una copia completa de este tutorial en el sitio web de PyTorch.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Cuando se utiliza LSTM en PyTorch, la forma de entrada requerida es (seq_len, batch, input_size), lo que significa que la entrada debe ser un tensor 3D. En su código, ha reformado la salida de la capa de incrustación a un tensor 2D que no es compatible con la forma de entrada requerida por la capa LSTM. Para solucionar esto, puede utilizar la función pack_padded_sequence para convertir su secuencia acolchada en una secuencia empaquetada que se puede utilizar como entrada para la capa LSTM. Aquí está un ejemplo:

    import torch.nn as nn
    torch.manual_seed(random_state)
    
    from torch.nn.utils.rnn import pack_padded_sequence, pad_packed_sequence
    
    class Net(nn.Module):
        def __init__(self, vocab_size= len(vocab), embed_dim= 32, num_class= 3):
            super().__init__()
    
            self.embedding = nn.EmbeddingBag(vocab_size, embed_dim, sparse=True)
    
            self.lstm = nn.LSTM(input_size= embed_dim, hidden_size= embed_dim, num_layers=5)
    
            self.lin = nn.Sequential(
                nn.Linear(in_features= embed_dim, out_features= embed_dim),
                nn.Linear(in_features= embed_dim, out_features= embed_dim),
                nn.Linear(in_features= embed_dim, out_features= 16),
                nn.Linear(in_features= 16, out_features= 16),
                nn.Linear(in_features= 16, out_features= 8),
                nn.Linear(in_features= 8, out_features= 8),
            )
    
            self.out = nn.Sequential(
                nn.Linear(in_features= 8, out_features= num_class),
                # nn.ReLU(inplace=True),
            )
    
            self.init_weights()
    
        def init_weights(self):
            initrange = 0.5
            self.embedding.weight.data.uniform_(-initrange, initrange)
            for i in self.lin:
              if isinstance(i, nn.LSTM): continue
              i.weight.data.uniform_(-initrange, initrange)
              i.bias.data.zero_()
    
        def forward(self, text, offsets):
            x = self.embedding(text, offsets)
    
            # Convertir la secuencia acolchada en una secuencia empaquetada
            x = pack_padded_sequence(x, offsets.cpu(), enforce_sorted=False)
            # Aplicar la capa LSTM
            x, (h_n, c_n) = self.lstm(x)
            # Concatenar el último estado oculto de cada lote
            x = h_n[-1]
    
            x = self.lin(x)
            return self.out(x)
    
    model = Net()
    model.to(device)
    

    En el método forward, primero usamos pack_padded_sequence para convertir la secuencia de entrada acolchada en una secuencia empaquetada. Esta función toma como entrada el tensor a empaquetar, las longitudes de las secuencias sin acolchado en el lote y el argumento de palabra clave enforce_sorted=False para garantizar que las secuencias no se clasifiquen por longitud. La salida de la capa LSTM es una tupla que contiene la secuencia de salida empaquetada y una tupla (h_n, c_n) que contiene el último estado oculto y el estado de la celda para cada elemento en el lote. Dado que solo queremos utilizar el último estado oculto, tomamos el último estado oculto (h_n) y luego concatenamos el estado oculto de cada lote (ya que la capa LSTM procesa lotes en paralelo). Esto nos da un tensor 2D de tamaño (tamaño_del_lote, tamaño_oculto), que se puede pasar a través de las capas lineales para obtener la salida final.

Comments are closed.