[PYTHON] Ich habe die Ausgabespezifikationen von Bidirectional LSTM von PyTorch überprüft

Einführung

Beim Deklarieren eines LSTM beim Umgang mit bidirektionalem LSTM in PyTorch, wie in der LSTM-Referenz (https://pytorch.org/docs/stable/nn.html?highlight=lstm#torch.nn.LSTM) Es ist in Ordnung, nur "bidirektional = wahr" für anzugeben, und es ist sehr einfach zu handhaben (Keras ist in Ordnung, nur um das LSTM mit Bidrectional zu umgeben). Wenn ich mir die Referenz anschaue, denke ich nicht, dass die Ausgabe von LSTM Bidirectional viel erwähnt wird. Selbst wenn ich es gegoogelt habe, konnte ich die Ausgabespezifikationen von Bidirectional LSTM in PyTorch nicht verstehen, daher werde ich es hier zusammenfassen.

Referenz

  1. Bidirectional recurrent neural networks
  2. Understanding Bidirectional RNN in PyTorch

Spezifikationsbestätigung

Wie Sie aus den Referenzen 1 und 2 sehen können, können Sie sehen, dass die bidirektionalen RNN und LSTM sehr einfach sind, da sich die RNN und LSTM in der vorderen und hinteren Richtung überlappen.

Ich werde es vorerst tatsächlich benutzen.

import torch
import torch.nn as nn

#5 eingebettete Dimensionen für jede Serie
#Die Größe der verborgenen Schicht der LSTM-Schicht beträgt 6
# batch_first=True für das Eingabeformat(batch_size, vocab_size, embedding_dim)Ich mache
# bidrectional=Deklarieren Sie bidirektionales LSTM mit True
bilstm = nn.LSTM(5, 6, batch_first=True, bidirectional=True)

#Chargengröße 1
#Die Länge der Serie beträgt 4
#Die Anzahl der eingebetteten Dimensionen jeder Serie beträgt 5
#Erzeugen Sie einen Tensor wie
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]]])

#Wie ein normales LSTM verfügt es über zwei Ausgänge, sodass beide empfangen werden.
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>))

Wie bei normalem LSTM gibt es zwei Ausgänge, "out" und "hc", und "hc" gibt "hc = (h, c)" im Tapple-Format zurück, wie bei normalem LSTM. Ich denke, es gibt zwei Unterschiede zur Ausgabe von normalem LSTM.

Das Folgende ist eine kurze Erklärung dessen, was diese bedeuten.

(C wird weggelassen. Ich habe die Einbettungsschicht geschrieben, aber die Einbettungsschicht wird nicht von LSTM erstellt.)

image.png

image.png

Wie Sie aus der obigen Abbildung sehen können, verbindet jedes Element von "out" jeden verborgenen Ebenenvektor in Vorwärts- und Rückwärtsrichtung. (Die Abmessungen jedes Elements sind also doppelt so groß wie üblich.) Außerdem gibt "h" in "hc = (h, c)" den letzten verborgenen Schichtvektor in Vorwärts- bzw. Rückwärtsrichtung zurück.

Mit anderen Worten

Wird sein. Sie können es aus der Quellcode-Ausgabe des obigen Beispiels lesen, was bedeutet, dass.

print(out[:,-1][:,:6]) #Die erste Hälfte des letzten Elements von out
print(hc[0][0])        #Wert der letzten verborgenen Schicht von Forward-LSTM
#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:]) #Die hintere Hälfte des ersten Elements von out
print(hc[0][1])       #Der Wert der letzten ausgeblendeten Ebene des Rückwärts-LSTM
#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>)

Sobald Sie die Ausgabespezifikationen kennen, können Sie nach Belieben kochen. Bei der Erstellung eines Many-to-One-Modells wie der Satzklassifizierung in bidirektionales LSTM scheint es verschiedene Methoden zu geben, z. B. das Kombinieren des zweiten Rückgabewerts von LSTM, das Mitteln und das Aufnehmen des Elementprodukts. Im Fall von Keras scheint es (standardmäßig) auf der Keras-Seite kombiniert zu werden, aber im Fall von PyTorch müssen diese Prozesse anscheinend selbst implementiert werden. Wenn ich beispielsweise Satzklassifizierung nach LSTM als bidirektionales LSTM poste, sieht es wie folgt aus.

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)
        #Versteckt, weil es eine Kombination der letzten verborgenen Ebenenvektoren in Vorwärts- und Rückwärtsrichtung empfängt_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]->Letzter versteckter Schichtvektor des Vorwärts-LSTM
        # bilstm_out[0][1]->Rückwärts LSTM letzter versteckter Schichtvektor
        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

abschließend

――Es mag eine Geschichte sein, die in der Welt leicht zu verstehen scheint, aber selbst für einen Moment, wenn Sie sich wie Sie mit Bidirektionalem LSTM mit PyTorch beschäftigen? Ich hoffe, dieser Artikel hilft denen, die denken, dass es Zeit ist, ihn nachzuschlagen. Übrigens wird GRU zu bidirektionaler GRU mit "bidirektional = wahr" wie LSTM. Ich denke, dass es kein Problem mit dem Ausgabeformat gibt, wenn die obigen LSTM-Spezifikationen bekannt sind.

Ende

Recommended Posts

Ich habe die Ausgabespezifikationen von Bidirectional LSTM von PyTorch überprüft
Ich habe den Inhalt des Docker-Volumes überprüft
Ich habe die Liste der Tastenkombinationen von Jupyter überprüft
Ich habe die Sitzungsaufbewahrungsdauer von Django überprüft
Ich habe die Verarbeitungsgeschwindigkeit der numpy eindimensionalisierung überprüft
Ich habe mir die Versionen von Blender und Python angesehen
Ich habe das Standardbetriebssystem und die Shell der Docker-Maschine überprüft
Filtern Sie die Ausgabe von tracemalloc
Keras Ich möchte die Ausgabe einer beliebigen Ebene erhalten !!
Ich habe den Mechanismus der Flaschenanmeldung untersucht!
Ich möchte den Anfang des nächsten Monats mit Python ausgeben
Ich habe den Nutzungsstatus des Parkplatzes anhand von Satellitenbildern überprüft.
Ich habe das Bild der Science University auf Twitter mit Word2Vec überprüft.
Ich habe den Betrag der Schenkungssteuer überprüft
Ich habe die Anzahl der bundesweit geschlossenen und eröffneten Geschäfte von Corona überprüft
Ich möchte kühl auf die Konsole ausgeben
Ich habe den asynchronen Server von Django 3.0 ausprobiert
Ich kannte die Grundlagen von Python nicht
Die Python-Projektvorlage, an die ich denke.
Dekodierung von Keras 'LSTM model.predict
Geben Sie die Anzahl der CPU-Kerne in Python aus
Ich habe die Pivot-Table-Funktion von Pandas ausprobiert
Ich habe in der Bibliothek nach der Verwendung der Gracenote-API gesucht
Ich habe versucht, die Wetterkarte einer Clusteranalyse zu unterziehen
Ich habe die Implementierung von range gelesen (Objects / rangeobject.c)
Einstellung zur Ausgabe des Protokolls zur Ausführung von cron
Ich habe das tiefste Problem von Hiroshi Yuki gelöst.
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Lesen Sie die Ausgabe von subprocess.Popen in Echtzeit
Probieren Sie Progate Free Edition [Python I]
Ich habe einige der neuen Funktionen von Python 3.8 touched angesprochen
Ausgabe in Form eines Python-Arrays
Ich habe die Varianten von UKR gelesen und implementiert
Ich möchte das Erscheinungsbild von zabbix anpassen
Ich habe den im Qiita Adventskalender 2016 gelöschten Kalender überprüft
Ich habe versucht, den Bildfilter von OpenCV zu verwenden
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
[SLAYER] Ich habe versucht, die Stahlseele zu bestätigen, indem ich die Texte von Slash Metal [Word Cloud] visualisiert habe.