Lors de la déclaration d'un LSTM lors de l'utilisation de LSTM bidirectionnel dans PyTorch, comme dans la référence LSTM (https://pytorch.org/docs/stable/nn.html?highlight=lstm#torch.nn.LSTM) C'est OK juste de spécifier bidirectional = True
pour, et c'est très facile à gérer (Keras est OK juste pour entourer LSTM avec Bidrectional).
Cependant, en regardant la référence, je ne pense pas qu'il y ait beaucoup de mention de la sortie de la fabrication du LSTM bidirectionnel.
Même si je l'ai recherché sur Google, je ne pouvais pas comprendre les spécifications de sortie de Bidirectional LSTM dans PyTorch, je vais donc le résumer ici.
Comme vous pouvez le voir à partir des références 1 et 2, vous pouvez voir que les RNN et LSTM bidirectionnels sont très simples parce que les RNN et LSTM dans les directions avant et arrière se chevauchent.
Je vais en fait l'utiliser pour le moment.
import torch
import torch.nn as nn
#5 dimensions intégrées pour chaque série
#La taille de la couche cachée de la couche LSTM est de 6
# batch_first=Vrai pour le format d'entrée(batch_size, vocab_size, embedding_dim)Je fais
# bidrectional=Déclarez le LSTM bidirectionnel avec True
bilstm = nn.LSTM(5, 6, batch_first=True, bidirectional=True)
#Taille du lot 1
#La longueur de la série est de 4
#Le nombre de dimensions intégrées de chaque série est de 5
#Générer un tenseur comme
a = torch.rand(1, 4, 5)
print(a)
#tensor([[[0.1360, 0.4574, 0.4842, 0.6409, 0.1980],
# [0.0364, 0.4133, 0.0836, 0.2871, 0.3542],
# [0.7796, 0.7209, 0.1754, 0.0147, 0.6572],
# [0.1504, 0.1003, 0.6787, 0.1602, 0.6571]]])
#Comme un LSTM normal, il a deux sorties, donc il reçoit les deux.
out, hc = bilstm(a)
print(out)
#tensor([[[-0.0611, 0.0054, -0.0828, 0.0416, -0.0570, -0.1117, 0.0902, -0.0747, -0.0215, -0.1434, -0.2318, 0.0783],
# [-0.1194, -0.0127, -0.2058, 0.1152, -0.1627, -0.2206, 0.0747, -0.0210, 0.0307, -0.0708, -0.2458, 0.1627],
# [-0.0163, -0.0568, -0.0266, 0.0878, -0.1461, -0.1745, 0.1097, 0.0230, 0.0353, -0.0739, -0.2186, 0.0818],
# [-0.1145, -0.0460, -0.0732, 0.0950, -0.1765, -0.2599, 0.0063, 0.0143, 0.0124, 0.0089, -0.1188, 0.0996]]],
# grad_fn=<TransposeBackward0>)
print(hc)
#(tensor([[[-0.1145, -0.0460, -0.0732, 0.0950, -0.1765, -0.2599]],
# [[ 0.0902, -0.0747, -0.0215, -0.1434, -0.2318, 0.0783]]],
# grad_fn=<StackBackward>),
#tensor([[[-0.2424, -0.1340, -0.1559, 0.3499, -0.3792, -0.5514]],
# [[ 0.1876, -0.1413, -0.0384, -0.2345, -0.4982, 0.1573]]],
# grad_fn=<StackBackward>))
Comme avec le LSTM normal, il y a deux sorties, ʻout et
hc, et
hc renvoie
hc = (h, c) ʻen format tapple comme avec le LSTM normal. Je pense qu'il y a deux différences par rapport à la sortie du LSTM normal.
―― La dimension de chaque élément de ʻout` n'est pas la taille de la dimension de la couche cachée de LSTM (6 cette fois), mais le double de la taille (12 cette fois).
Ce qui suit est une brève explication de ce que cela signifie.
(«C» est omis. J'ai écrit la couche Embedding, mais la couche Embedding n'est pas effectuée par LSTM.)
Comme vous pouvez le voir sur la figure ci-dessus, chaque élément de ʻoutconnecte chaque vecteur de couche caché dans les directions avant et arrière. (Ainsi, les dimensions de chaque élément sont deux fois plus grandes que d'habitude.) De plus,
h in
hc = (h, c)` renvoie le dernier vecteur de calque caché dans les directions avant et arrière respectivement.
En d'autres termes
--La première moitié du dernier élément de ʻoutcorrespond à
h [0]quand
hc = (h, c)`
correspond à
h [1]quand
hc = (h, c)`Sera. Vous pouvez le lire à partir de la sortie du code source de l'exemple ci-dessus, ce qui signifie que.
print(out[:,-1][:,:6]) #La première moitié du dernier élément de out
print(hc[0][0]) #Valeur de la dernière couche cachée du LSTM avant
#tensor([[-0.1145, -0.0460, -0.0732, 0.0950, -0.1765, -0.2599]], grad_fn=<SliceBackward>)
#tensor([[-0.1145, -0.0460, -0.0732, 0.0950, -0.1765, -0.2599]], grad_fn=<SelectBackward>)
print(out[:,0][:,6:]) #La moitié arrière du premier élément de out
print(hc[0][1]) #La valeur de la dernière couche cachée du LSTM arrière
#tensor([[ 0.0902, -0.0747, -0.0215, -0.1434, -0.2318, 0.0783]], grad_fn=<SliceBackward>)
#tensor([[ 0.0902, -0.0747, -0.0215, -0.1434, -0.2318, 0.0783]], grad_fn=<SelectBackward>)
Une fois que vous connaissez les spécifications de sortie, vous pouvez cuisiner comme vous le souhaitez, Lors de la création d'un modèle plusieurs à un tel que la classification de phrases dans le LSTM bidirectionnel, il semble y avoir diverses méthodes telles que la combinaison de la deuxième valeur de retour de LSTM, la moyenne et la prise du produit d'élément. Dans le cas de Keras, il semble qu'il sera combiné côté Keras (par défaut), mais dans le cas de PyTorch, il semble que ces processus doivent être implémentés par vous-même. Par exemple, si je publie Classification des phrases par LSTM en tant que LSTM bidirectionnel, cela ressemblera à ce qui suit.
class LSTMClassifier(nn.Module):
def __init__(self, embedding_dim, hidden_dim, vocab_size, tagset_size, batch_size=100):
super(LSTMClassifier, self).__init__()
self.batch_size = batch_size
self.hidden_dim = hidden_dim
self.word_embeddings = nn.Embedding(vocab_size, embedding_dim, padding_idx=0)
self.bilstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True, bidirectional=True)
#Caché car il reçoit une combinaison des derniers vecteurs de calque cachés dans les directions avant et arrière_Double dim
self.hidden2tag = nn.Linear(hidden_dim * 2, tagset_size)
self.softmax = nn.LogSoftmax()
def forward(self, sentence):
embeds = self.word_embeddings(sentence)
_, bilstm_hc = self.bilstm(embeds)
# bilstm_out[0][0]->Dernier vecteur de couche caché du LSTM avant
# bilstm_out[0][1]->Dernier vecteur de couche caché LSTM arrière
bilstm_out = torch.cat([bilstm_hc[0][0], bilstm_hc[0][1]], dim=1)
tag_space = self.hidden2tag(bilstm_out)
tag_scores = self.softmax(tag_space.squeeze())
return tag_scores
――C'est peut-être une histoire qui semble facile à comprendre dans le monde, mais même pour un moment lorsque vous traitez avec le LSTM bidirectionnel avec PyTorch comme vous? J'espère que cet article aidera ceux qui pensent qu'il est temps de le rechercher.
Au fait, GRU devient GRU bidirectionnel avec bidirectional = True
comme LSTM. Je pense qu'il n'y a pas de problème avec le format de sortie si les spécifications LSTM ci-dessus sont connues.
fin
Recommended Posts