[PYTHON] Negative / positive Beurteilung von Sätzen und Visualisierung von Gründen durch Transformer

1. Zuallererst

Ich lese ** "Developmental Deep Learning mit PyTorch" **. Dieses Mal habe ich in Kapitel 7 Transformer studiert, daher möchte ich meine eigene Zusammenfassung ausgeben.

2. Was ist Transformator?

Im Jahr 2017 wurde ein epochales Papier ** "Attention All You Need" ** im Bereich der Verarbeitung natürlicher Sprache veröffentlicht. Das vorgeschlagene Modell war ** Transformer **, das SoTA allein mit ** Attention ** erreichte, ohne eines der zuvor gängigen RNNs für Übersetzungsaufgaben zu verwenden.

Seitdem haben Modelle, die auf diesem Transformer basieren, wie ** BERT, XLNet und ALBERT **, das Gebiet der Verarbeitung natürlicher Sprache dominiert, und es wurde Transformer für die Verarbeitung natürlicher Sprache genannt.

スクリーンショット 2020-07-28 10.04.07.png

Hier ist ein Modelldiagramm des Transformators, der die Übersetzungsaufgabe ausführt. Wenn Sie beispielsweise die japanisch-englische Übersetzung berücksichtigen, lernt der ** Encoder ** auf der linken Seite die Aufmerksamkeit jedes Wortes im japanischen Satz, und der ** Decoder ** auf der rechten Seite lernt die Aufmerksamkeit jedes Wortes im englischen Satz, während er sich auf diese Informationen bezieht. ist. Lassen Sie mich nun fünf Funktionen erläutern.

1) Psitional Encoding Das größte Ziel von Transformer ist es, die GPU zu verwenden und die Verarbeitungsgeschwindigkeit erheblich zu erhöhen, indem alle Wörter ** parallel ** für jeden Satz verarbeitet werden, anstatt die Wörter einzeln wie RNN zu verarbeiten. .. Daher fügt ** Positionscodierung ** jedem Wort Wortordnungsinformationen hinzu, um zu verhindern, dass die Wortreihenfolgeinformationen aufgrund der Parallelverarbeitung verloren gehen.

2) Scaled dot-product Attention Dies ist das Herz von Transformer, daher werde ich es etwas genauer erklären. Für die Aufmerksamkeitsberechnung ** Abfrage ** (Wortvektor, für den die Aufmerksamkeit berechnet wird), ** Schlüssel ** (Sammlung von Wortvektoren, die für die Relevanzberechnung verwendet werden), ** Wert ** (Vektor für die Berechnung der gewichteten Summe) 3) erscheint.

スクリーンショット 2020-07-28 13.55.03.png Ich werde erklären, wie man die Aufmerksamkeit von "I" berechnet, wenn der Satz aus 5 Wörtern besteht: "I", "Ha", "Cat", "De" und "Aru".

Da der Relevanzgrad durch das innere Produkt der Vektoren berechnet werden kann, wird das innere Produkt des "I" -Vektors ** Query ** und der transponierten Matrix ** $ Key ^ T $ ** der fünf Wortvektoren genommen. Wenn Sie dann durch $ {\ sqrt {d_k}} $ dividieren und dann mit Softmax multiplizieren, können Sie das Gewicht (** Aufmerksamkeitsgewicht **) ermitteln, das angibt, welches Wort mit "I" in Beziehung steht und wie viel.

Der Grund für die Division durch $ {\ sqrt {d_k}} $ ist, dass bei einem zu großen Wert in der internen Produktberechnung, wenn Softmax multipliziert wird, die anderen Werte 0 werden können.

Als nächstes dominiert durch ** inneres Produkt ** von ** Aufmerksamkeitsgewicht ** und eine Matrix von fünf Wortvektoren ** Wert ** die Vektorkomponente von Wörtern, die eng mit "I" verwandt sind, dominant * * Kontextvektor kann berechnet werden. Dies ist die Berechnung der Aufmerksamkeit von "I".

Übrigens kann Trindformer eine parallele Berechnung durchführen und alle Abfragen gleichzeitig berechnen スクリーンショット 2020-07-28 18.41.37.png

Auf diese Weise wird die Aufmerksamkeitsberechnung aller Abfragen auf einmal abgeschlossen. Diese Berechnung wird durch die folgende Formel im Papier ausgedrückt.

Attention(Q, K, V)=softmax(\frac{QK^T}{\sqrt{d_k}})V

3) Multi-Head Attention

スクリーンショット 2020-07-28 18.30.55.png

Eingabe in das skalierte Punktprodukt Achtung ** Abfrage, Schlüssel, Wert ** hat eine Struktur, in der die Ausgabe der vorherigen Stufe über jede vollständig verbundene Schicht eingeht. Mit anderen Worten wird die Ausgabe der vorherigen Stufe mit den Gewichten $ W_q, W_k bzw. W_v $ multipliziert. Zu diesem Zeitpunkt haben Sie nicht nur eine große Abfrage, einen Schlüssel, einen Wert (als Kopf bezeichnet), sondern mehrere kleine Abfrage-, Schlüssel- und Wertköpfe, und jeder Kopf hat einen latenten Ausdruck $ W_q, W_k, ** Multi-Head Attention ** zeigt, dass die Leistung verbessert wird, indem W_v $ berechnet und am Ende eins gemacht wird.

4) Musked Multi-Head Attention スクリーンショット 2020-07-29 09.37.30.png

Die Aufmerksamkeit auf der Decoderseite wird ebenfalls parallel berechnet, aber wenn bei der Berechnung der Aufmerksamkeit von "I", wenn "am", "a", "cat" im Berechnungsziel enthalten sind, wird das vorherzusagende Wort eingemacht. Maskieren Sie also das vorherige Wort im Schlüssel, um es unsichtbar zu machen. Multi-Head Attention mit dieser Funktion wird als ** Musked Multi-Head Attention ** bezeichnet.

5) Position-wise Feed-Forward Networks Dies ist eine Einheit, die die Merkmalsmenge der Ausgabe von der Aufmerksamkeitsebene mit zwei vollständig verbundenen Ebenen konvertiert. Die Eingabe ist (Anzahl der Wörter, Anzahl der eingebetteten Dimensionen von Wörtern), und das Produkt aus dieser und den Gewichten der beiden vollständig verbundenen Schichten ist die Ausgabe (Anzahl der Wörter, Anzahl der eingebetteten Dimensionen der Wörter). Wir haben es ** positionell ** genannt, weil es so aussieht, als gäbe es für jedes Wort ein unabhängiges neuronales Netzwerk.

3. Dieses Mal zu implementierendes Modell

Dieses Mal werden wir ein Modell implementieren, das die Klassifizierungsaufgabe lösen kann, indem wir die Aufmerksamkeit jedes Wortes des Satzes ** lernen, indem wir nur den Encoder auf der linken Seite des Transformer-Übersetzungsmodells verwenden. Bei der Priorisierung der Klarheit handelt es sich außerdem um Einzelkopfaufmerksamkeit, nicht um Mehrkopfaufmerksamkeit. スクリーンショット 2020-07-27 16.53.25.png

Der verwendete Datensatz ist ** IMDb ** (Internet Movie Dataset), der zusammenfasst, ob der Inhalt einer Filmkritik (auf Englisch) positiv oder negativ ist.

Indem Sie das Modell trainieren, bestimmen Sie bei der Eingabe einer Rezension eines Films **, ob die Rezension positiv oder negativ ist **, und geben Sie anhand der gegenseitigen Aufmerksamkeit der Rezensionswörter ** deutlich das Wort an, auf dem die Entscheidung basiert * * Lass mich das machen.

Dann möchte ich in der Reihenfolge von der Eingabe implementieren.

4. Modellcode

class Embedder(nn.Module):
    '''Konvertiert das durch id angegebene Wort in einen Vektor'''

    def __init__(self, text_embedding_vectors):
        super(Embedder, self).__init__()

        self.embeddings = nn.Embedding.from_pretrained(
            embeddings=text_embedding_vectors, freeze=True)
        # freeze=True wird nicht aktualisiert und ändert sich nicht in der Rückübertragung

    def forward(self, x):
        x_vec = self.embeddings(x)

        return x_vec

Dies ist der Teil, der die Wort-ID mithilfe der nn.Embedding-Einheit von Pytorch in einen eingebetteten Vektor konvertiert.

class PositionalEncoder(nn.Module):
    '''Fügen Sie Vektorinformationen hinzu, die die Position des eingegebenen Wortes angeben'''

    def __init__(self, d_model=300, max_seq_len=256):
        super().__init__()

        self.d_model = d_model  #Anzahl der Dimensionen des Wortvektors

        #Erstellen Sie eine Wertetabelle als pe, die eindeutig durch die Reihenfolge der Wörter (pos) und die Position der Dimension des eingebetteten Vektors (i) bestimmt wird.
        pe = torch.zeros(max_seq_len, d_model)

        #An GPU senden, wenn GPU verfügbar ist
        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        pe = pe.to(device)

        for pos in range(max_seq_len):
            for i in range(0, d_model, 2):
                pe[pos, i] = math.sin(pos / (10000 ** ((2 * i)/d_model)))
                pe[pos, i + 1] = math.cos(pos / (10000 ** ((2 * i)/d_model)))

        #Fügen Sie die Mini-Batch-Dimension am Anfang der Tabelle pe hinzu
        self.pe = pe.unsqueeze(0)

        #Vermeiden Sie die Berechnung des Gradienten
        self.pe.requires_grad = False

    def forward(self, x):

        #Fügen Sie Eingabe x und Positive Codierung hinzu
        #x ist kleiner als pe, also mach es größer
        ret = math.sqrt(self.d_model)*x + self.pe
        return ret

Dies ist der Teil des Positionsgebers.

class Attention(nn.Module):
    '''Transformator ist wirklich eine Mehrkopfaufmerksamkeit,
Klarheit wird Priorität eingeräumt und mit einer einzigen Aufmerksamkeit umgesetzt'''

    def __init__(self, d_model=300):
        super().__init__()

        #SAGAN verwendete 1dConv, aber diesmal wird die Feature-Menge in die vollständig verbundene Ebene konvertiert.
        self.q_linear = nn.Linear(d_model, d_model)
        self.v_linear = nn.Linear(d_model, d_model)
        self.k_linear = nn.Linear(d_model, d_model)

        #Vollständig verbundene Schicht für die Ausgabe
        self.out = nn.Linear(d_model, d_model)

        #Variable zur Anpassung der Aufmerksamkeitsgröße
        self.d_k = d_model

    def forward(self, q, k, v, mask):
        #Konvertieren Sie Features in vollständig verbundene Ebenen
        k = self.k_linear(k)
        q = self.q_linear(q)
        v = self.v_linear(v)

        #Berechnen Sie den Wert von Attention
        #Wenn Sie jeden Wert hinzufügen, ist er zu groß, also root(d_k)Teilen und anpassen
        weights = torch.matmul(q, k.transpose(1, 2)) / math.sqrt(self.d_k)

        #Berechnen Sie hier die Maske
        mask = mask.unsqueeze(1)
        weights = weights.masked_fill(mask == 0, -1e9)

        #Mit Softmax standardisieren
        normlized_weights = F.softmax(weights, dim=-1)

        #Aufmerksamkeit mit Wert multiplizieren
        output = torch.matmul(normlized_weights, v)

        #Konvertieren Sie Features in vollständig verbundene Ebenen
        output = self.out(output)

        return output, normlized_weights

Dies ist der Aufmerksamkeitsteil. Bei der Maskenberechnung sollte der Teil, in dem die Textdaten kurz sind und eingefügt wird, 0 sein, wenn er mit softmax multipliziert wird, damit der entsprechende Teil durch minus unendlich (-1e9) ersetzt wird.

class FeedForward(nn.Module):
    def __init__(self, d_model, d_ff=1024, dropout=0.1):
        '''Es ist eine Einheit, die einfach die Merkmalsmenge aus der Aufmerksamkeitsebene mit zwei vollständig verbundenen Ebenen konvertiert.'''
        super().__init__()

        self.linear_1 = nn.Linear(d_model, d_ff)
        self.dropout = nn.Dropout(dropout)
        self.linear_2 = nn.Linear(d_ff, d_model)

    def forward(self, x):
        x = self.linear_1(x)
        x = self.dropout(F.relu(x))
        x = self.linear_2(x)
        return x

Dies ist der Feed Forward-Teil. Es ist eine einfache zweischichtige, vollständig verbundene Schicht.

class TransformerBlock(nn.Module):
    def __init__(self, d_model, dropout=0.1):
        super().__init__()

        #Ebenennormalisierungsebene
        # https://pytorch.org/docs/stable/nn.html?highlight=layernorm
        self.norm_1 = nn.LayerNorm(d_model)
        self.norm_2 = nn.LayerNorm(d_model)

        #Aufmerksamkeitsschicht
        self.attn = Attention(d_model)

        #Zwei vollständig verbundene Schichten nach Aufmerksamkeit
        self.ff = FeedForward(d_model)

        # Dropout
        self.dropout_1 = nn.Dropout(dropout)
        self.dropout_2 = nn.Dropout(dropout)

    def forward(self, x, mask):
        #Normalisierung und Aufmerksamkeit
        x_normlized = self.norm_1(x)
        output, normlized_weights = self.attn(
            x_normlized, x_normlized, x_normlized, mask)

        x2 = x + self.dropout_1(output)

        #Normalisierung und vollständig verbundene Schicht
        x_normlized2 = self.norm_2(x2)
        output = x2 + self.dropout_2(self.ff(x_normlized2))

        return output, normlized_weights

Dies ist der Teil, der einen Transformatorblock durch Kombinieren von Attention und Feed Foward erstellt. Beide werden mit ** Layer Normalization ** und ** Dropout ** sowie ** Resid Binding ** ähnlich wie bei ResNet multipliziert.

class ClassificationHead(nn.Module):
    '''Transformer_Verwenden Sie Blockausgabe und klassifizieren Sie schließlich'''

    def __init__(self, d_model=300, output_dim=2):
        super().__init__()

        #Vollständig verbundene Schicht
        self.linear = nn.Linear(d_model, output_dim)  # output_dim ist zwei positive und negative

        #Verarbeitung der Gewichtsinitialisierung
        nn.init.normal_(self.linear.weight, std=0.02)
        nn.init.normal_(self.linear.bias, 0)

    def forward(self, x):
        x0 = x[:, 0, :]  #Extrahieren Sie die Merkmalsmenge (300 Dimensionen) des ersten Wortes jedes Satzes jeder Mini-Charge
        out = self.linear(x0)

        return out

Schließlich ist es der Teil, der ein negatives / positives Urteil abgibt. Durch Klassifizieren unter Verwendung der Merkmale des ersten Wortes jedes Satzes und Zurückpropagieren des Lernverlusts werden die Merkmale des ersten Wortes natürlich zu den Merkmalen, die das Negative / Positive des Satzes beurteilen.

class TransformerClassification(nn.Module):
    '''Mit Transformator klassifizieren'''

    def __init__(self, text_embedding_vectors, d_model=300, max_seq_len=256, output_dim=2):
        super().__init__()

        #Modellbau
        self.net1 = Embedder(text_embedding_vectors)
        self.net2 = PositionalEncoder(d_model=d_model, max_seq_len=max_seq_len)
        self.net3_1 = TransformerBlock(d_model=d_model)
        self.net3_2 = TransformerBlock(d_model=d_model)
        self.net4 = ClassificationHead(output_dim=output_dim, d_model=d_model)

    def forward(self, x, mask):
        x1 = self.net1(x)  #Wörter in Vektoren
        x2 = self.net2(x1)  #Positionsinformationen hinzufügen
        x3_1, normlized_weights_1 = self.net3_1(
            x2, mask)  # Self-Konvertieren Sie Features mit Aufmerksamkeit
        x3_2, normlized_weights_2 = self.net3_2(
            x3_1, mask)  # Self-Konvertieren Sie Features mit Aufmerksamkeit
        x4 = self.net4(x3_2)  #Klassifizierung 0 unter Verwendung des 0. Wortes der endgültigen Ausgabe-Ausgabe 1 Skalar
        return x4, normlized_weights_1, normlized_weights_2

Dies ist der Teil, der schließlich das gesamte Modell unter Verwendung der bisher definierten Klassen erstellt.

5. Ganzer Code und Ausführung

Der gesamte Code wurde in Google Colab erstellt und auf Github veröffentlicht. Wenn Sie ihn also selbst ausprobieren möchten, klicken Sie auf diesen ** "Link" **. Sie können es verschieben, indem Sie auf transformer_en_run.ipynb) und oben auf dem angezeigten Blatt auf die Schaltfläche "Colab on Web" klicken.

Wenn du rennst

スクリーンショット 2020-07-29 10.46.38.png

Auf diese Weise werden das Beurteilungsergebnis und seine Grundlage angezeigt.

6. Versuchen Sie es mit einem japanischen Datensatz.

Beim Surfen auf verschiedenen Websites gab es ein Beispiel für das Extrahieren von Sätzen aus dem Wertpapierbericht eines japanischen börsennotierten Unternehmens namens ** chABSA-Dataset **, das ein negatives / positives Urteil fällte und die Urteilsbasis anzeigte. Deshalb habe ich es auch in Google Colab zusammengefasst. Sah. Wenn Sie es selbst ausprobieren möchten, klicken Sie auf diesen ** "Link" ** und er befindet sich oben auf dem angezeigten Blatt. Sie können es verschieben, indem Sie auf die Schaltfläche "Colab on Web" klicken.

(Referenz) ・ Lernen während des Machens! Deep Learning von PyTorchIch habe eine Negativ / Positiv-Analyse-App mit Deep Learning (Python) erstellt [Teil 1]Artikelkommentar Achtung ist alles, was Sie brauchen (Transformer)

Recommended Posts

Negative / positive Beurteilung von Sätzen und Visualisierung von Gründen durch Transformer
Negative / positive Beurteilung von Sätzen durch BERT und Visualisierung von Gründen
Analyse von Finanzdaten durch Pandas und deren Visualisierung (1)
Visualisierung von Daten anhand einer erklärenden Variablen und einer objektiven Variablen
Visualisierung von Daten nach Präfektur
Visualisierung der von numpy erstellten Matrix
Beurteilung, ob durch Listeneinschlussnotation
Negative / Positive Analyse 1 Anwendung der Textanalyse
Aggregation und Visualisierung akkumulierter Zahlen
[Python] Ich habe das Tagebuch eines Mannes im ersten Jahr des Arbeitslebens analysiert und das Arbeitsleben positiv / negativ beurteilt.
Korrelationsvisualisierung der Merkmalsmenge und der Zielvariablen
Erstellung eines negativen / positiven Klassifikators mit BERT
Bestimmen Sie anhand des Bildes des Shiba-Hundes anhand des Bildes des Shiba-Hundes, ob es sich um ein Kind handelt