Heim >Technologie-Peripheriegeräte >KI >Ein umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch

Ein umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch

William Shakespeare
William ShakespeareOriginal
2025-03-10 09:30:13260Durchsuche

Ziel dieses Tutorials ist es, ein umfassendes Verständnis dafür zu vermitteln, wie ein Transformatormodell mit Pytorch konstruiert werden kann. Der Transformator ist eines der mächtigsten Modelle im modernen maschinellen Lernen. Sie haben das Feld revolutioniert, insbesondere bei Aufgaben der natürlichen Sprachverarbeitung (NLP) wie Sprachübersetzung und Textbefugnis. LAND-Kurzzeitspeicher (LSTM) -Netzwerke wurden in diesen Aufgaben durch Transformatoren ersetzt

Das in diesem Leitfaden verwendete Tool zum Aufbau des Transformators ist Pytorch, eine beliebte Open-Source-Bibliothek für maschinelles Lernen, die für die Einfachheit, Vielseitigkeit und Effizienz bekannt ist. Mit einem dynamischen Berechnungsdiagramm und umfangreichen Bibliotheken ist Pytorch für Forscher und Entwickler im Bereich des maschinellen Lernens und der künstlichen Intelligenz zu einer Anlaufstelle geworden.

Für diejenigen, die mit Pytorch nicht vertraut sind, wird ein Besuch in DataCamps Kurs eingeführt. Einführung in das Deep Learning with Pytorch wird für eine solide Erdung empfohlen.

Hintergrund und Theorie

Zuerst in die Aufmerksamkeit des Papiers ist alles, was Sie von Vaswani et al. Brauchen, Transformatoren sind seitdem aufgrund ihres einzigartigen Designs und ihrer Effektivität zu einem Eckpfeiler vieler NLP -Aufgaben geworden.

im Herzen von Transformatoren steht der Aufmerksamkeitsmechanismus, insbesondere das Konzept der Selbstbekämpfung, mit dem das Modell verschiedene Teile der Eingabedaten wiegen und priorisieren kann. Dieser Mechanismus ermöglicht es Transformatoren, Langstreckenabhängigkeiten in Daten zu verwalten. Grundsätzlich ist es ein Gewichtungsschema, mit dem ein Modell bei der Erzeugung eines Ausgangs auf verschiedene Teile des Eingangs konzentriert wird.

Mit diesem Mechanismus kann das Modell unterschiedliche Wörter oder Merkmale in der Eingabebereich berücksichtigen und jedem ein 'Gewicht' zuweisen, das seine Bedeutung für die Erzeugung einer bestimmten Ausgabe bedeutet.

Zum Beispiel kann das Modell in einer Satzübersetzungsaufgabe bei der Übersetzung eines bestimmten Wortes den Wörtern, die grammatikalisch oder semantisch mit dem Zielwort zusammenhängen, höhere Aufmerksamkeitsgewichte zuweist. Dieser Prozess ermöglicht es dem Transformator, Abhängigkeiten zwischen Wörtern oder Merkmalen zu erfassen, unabhängig von seinem Abstand voneinander in der Sequenz.

Die Auswirkung der Transformatoren auf dem Gebiet von NLP kann nicht überbewertet werden. Sie haben traditionelle Modelle in vielen Aufgaben übertroffen und überlegene Fähigkeiten zum Verständnis und Generieren von menschlicher Sprache auf nuanciertere Weise gezeigt.

Für ein tieferes Verständnis von NLP ist DataCamps Einführung in die natürliche Sprachverarbeitung im Python -Kurs eine empfohlene Ressource.

Einrichten von Pytorch

Bevor Sie in den Aufbau eines Transformators eintauchen, ist es wichtig, die Arbeitsumgebung korrekt einzurichten. In erster Linie muss Pytorch installiert werden. Pytorch (aktuelle stabile Version - 2.0.1) kann einfach über PIP- oder Conda -Paketmanager installiert werden.

Verwenden Sie für PIP den Befehl:

Verwenden Sie für Conda den Befehl:
pip3 install torch torchvision torchaudio
pip3 install torch torchvision torchaudio

Für die Verwendung von Pytorch mit einer CPU besuchen Sie bitte die Pytorch -Dokumentation.

Zusätzlich ist es vorteilhaft, ein grundlegendes Verständnis für tiefe Lernkonzepte zu haben, da diese für das Verständnis des Betriebs von Transformatoren von grundlegender Bedeutung sind. Für diejenigen, die eine Auffrischung benötigen, ist der DataCamp -Kurs Deep Learning in Python eine wertvolle Ressource, die Schlüsselkonzepte im Deep Learning abdeckt.

Erstellen des Transformatormodells mit Pytorch

Um das Transformatormodell zu erstellen Die folgenden Schritte sind erforderlich:

  1. Importieren der Bibliotheken und Module
  2. Definieren der grundlegenden Bausteine-Aufmerksamkeit mit mehreren Kopf, positionelle Feed-Forward-Netzwerke, Positionscodierung
  3. Erstellen des Encoderblocks
  4. Erstellen des Decoderblocks
  5. Kombinieren Sie die Encoder- und Decoder -Ebenen, um das vollständige Transformator -Netzwerk zu erstellen.

1. Importieren der erforderlichen Bibliotheken und Module

Wir beginnen mit dem Importieren der Pytorch -Bibliothek für Kernfunktionalität, des neuronalen Netzwerkmoduls zum Erstellen neuronaler Netzwerke, des Optimierungsmoduls für Trainingsnetzwerke und der Datenversorgungsfunktionen für die Bearbeitung von Daten. Darüber hinaus importieren wir das Standard -Python -Mathon -Modul für mathematische Operationen und das Kopiermodul zum Erstellen von Kopien komplexer Objekte.

Diese Tools legen die Grundlage für die Definition der Architektur des Modells, das Verwalten von Daten und die Festlegung des Schulungsprozesses.

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

2. Definieren der grundlegenden Bausteine: Multi-Head-Aufmerksamkeit, positionelle Feed-Forward-Netzwerke, Positionscodierung

Multi-Head-Aufmerksamkeit

Der Multi-Head-Aufmerksamkeitsmechanismus berechnet die Aufmerksamkeit zwischen jedem Positionspaar in einer Sequenz. Es besteht aus mehreren „Aufmerksamkeitsköpfen“, die verschiedene Aspekte der Eingabesequenz erfassen.

, um mehr über die Aufmerksamkeit mit mehreren Köpfen zu erfahren, lesen Sie diesen Abschnitt "Aufmerksamkeitsmechanismen" des LLMS-Konzeptenverlaufs (Langwary Models).

Ein umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch

Abbildung 1. Multi-Head-Aufmerksamkeit (Quelle: Bild erstellt vom Autor)

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Klassendefinition und Initialisierung:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        # Ensure that the model dimension (d_model) is divisible by the number of heads
        assert d_model % num_heads == 0, "d_model must be divisible by num_heads"
        
        # Initialize dimensions
        self.d_model = d_model # Model's dimension
        self.num_heads = num_heads # Number of attention heads
        self.d_k = d_model // num_heads # Dimension of each head's key, query, and value
        
        # Linear layers for transforming inputs
        self.W_q = nn.Linear(d_model, d_model) # Query transformation
        self.W_k = nn.Linear(d_model, d_model) # Key transformation
        self.W_v = nn.Linear(d_model, d_model) # Value transformation
        self.W_o = nn.Linear(d_model, d_model) # Output transformation
        
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        # Calculate attention scores
        attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # Apply mask if provided (useful for preventing attention to certain parts like padding)
        if mask is not None:
            attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
        
        # Softmax is applied to obtain attention probabilities
        attn_probs = torch.softmax(attn_scores, dim=-1)
        
        # Multiply by values to obtain the final output
        output = torch.matmul(attn_probs, V)
        return output
        
    def split_heads(self, x):
        # Reshape the input to have num_heads for multi-head attention
        batch_size, seq_length, d_model = x.size()
        return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
        
    def combine_heads(self, x):
        # Combine the multiple heads back to original shape
        batch_size, _, seq_length, d_k = x.size()
        return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
        
    def forward(self, Q, K, V, mask=None):
        # Apply linear transformations and split heads
        Q = self.split_heads(self.W_q(Q))
        K = self.split_heads(self.W_k(K))
        V = self.split_heads(self.W_v(V))
        
        # Perform scaled dot-product attention
        attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # Combine heads and apply output transformation
        output = self.W_o(self.combine_heads(attn_output))
        return output

Die Klasse ist als Unterklasse von Pytorchs nn.module definiert.

  1. d_model: Dimensionalität der Eingabe.
  2. num_heads: Die Anzahl der Aufmerksamkeit führt zur Aufteilung der Eingabe in.

Die Initialisierung prüft, ob d_model durch num_heads teilbar ist und dann die Transformationsgewichte für Abfrage, Schlüssel, Wert und Ausgabe definiert.

skalierte Aufmerksamkeit der DOT-Produkte:

pip3 install torch torchvision torchaudio
  1. Berechnung der Aufmerksamkeitswerte: attn_scores = fackel.matmul (q, k.transpsis (-2, -1)) / math.sqrt (self.d_k). Hier werden die Aufmerksamkeitswerte berechnet, indem das Punktprodukt von Abfragen (q) und Schlüssel (k) und dann durch die Quadratwurzel der Schlüsseldimension (D_K) skaliert wird.
  2. Maske anwenden: Wenn eine Maske bereitgestellt wird, wird sie in die Aufmerksamkeitswerte angewendet, um bestimmte Werte auszubilden.
  3. Berechnung der Aufmerksamkeitsgewichte: Die Aufmerksamkeitswerte werden durch eine Softmax -Funktion geleitet, um sie in Wahrscheinlichkeiten umzuwandeln, die auf 1.
  4. summieren
  5. Berechnung der Ausgabe: Die endgültige Ausgabe der Aufmerksamkeit wird berechnet, indem die Aufmerksamkeitsgewichte mit den Werten (v) multipliziert werden.

Spaltungsköpfe:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

Diese Methode formuliert die Eingabe X in die Form (batch_size, num_heads, seq_length, d_k). Es ermöglicht das Modell, mehrere Aufmerksamkeitsköpfe gleichzeitig zu verarbeiten und eine parallele Berechnung zu ermöglichen.

Kombinieren Köpfe:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Nachdem diese Methode getrennt auf jeden Kopf aufmerksam gemacht wurde, kombiniert sie die Ergebnisse in einen einzelnen Formsor der Form (batch_size, seq_length, d_model). Dies bereitet das Ergebnis für die weitere Verarbeitung vor.

Vorwärtsmethode:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        # Ensure that the model dimension (d_model) is divisible by the number of heads
        assert d_model % num_heads == 0, "d_model must be divisible by num_heads"
        
        # Initialize dimensions
        self.d_model = d_model # Model's dimension
        self.num_heads = num_heads # Number of attention heads
        self.d_k = d_model // num_heads # Dimension of each head's key, query, and value
        
        # Linear layers for transforming inputs
        self.W_q = nn.Linear(d_model, d_model) # Query transformation
        self.W_k = nn.Linear(d_model, d_model) # Key transformation
        self.W_v = nn.Linear(d_model, d_model) # Value transformation
        self.W_o = nn.Linear(d_model, d_model) # Output transformation
        
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        # Calculate attention scores
        attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # Apply mask if provided (useful for preventing attention to certain parts like padding)
        if mask is not None:
            attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
        
        # Softmax is applied to obtain attention probabilities
        attn_probs = torch.softmax(attn_scores, dim=-1)
        
        # Multiply by values to obtain the final output
        output = torch.matmul(attn_probs, V)
        return output
        
    def split_heads(self, x):
        # Reshape the input to have num_heads for multi-head attention
        batch_size, seq_length, d_model = x.size()
        return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
        
    def combine_heads(self, x):
        # Combine the multiple heads back to original shape
        batch_size, _, seq_length, d_k = x.size()
        return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
        
    def forward(self, Q, K, V, mask=None):
        # Apply linear transformations and split heads
        Q = self.split_heads(self.W_q(Q))
        K = self.split_heads(self.W_k(K))
        V = self.split_heads(self.W_v(V))
        
        # Perform scaled dot-product attention
        attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # Combine heads and apply output transformation
        output = self.W_o(self.combine_heads(attn_output))
        return output

In der Vorwärtsmethode kommt die tatsächliche Berechnung auf:

  1. Lineare Transformationen anwenden: Die Abfragen (q), Schlüssel (k) und Werte (v) werden zuerst unter Verwendung der in der Initialisierung definierten Gewichte durch lineare Transformationen geleitet.
  2. geteilte Köpfe: Die transformierte Q, k, v werden unter Verwendung der Methode Split_heads in mehrere Köpfe aufgeteilt.
  3. Aufmerksamkeit der skalierten DOT-Produkte anwenden: Die Methode scaled_dot_product_attention wird auf die geteilten Köpfe aufgerufen.
  4. Kombinationsköpfe: Die Ergebnisse von jedem Kopf werden mit der Methode combine_heads wieder in einen einzelnen Tensor kombiniert.
  5. Ausgangstransformation anwenden: Schließlich wird der kombinierte Tensor durch eine lineare Ausgangstransformation geleitet.

Zusammenfassend lässt sich die MultiheadAdtention-Klasse den Multi-Head-Aufmerksamkeitsmechanismus zusammenschließen, der üblicherweise in Transformatormodellen verwendet wird. Es kümmert sich um die Aufteilung der Eingabe in mehrere Aufmerksamkeitsköpfe, die Aufmerksamkeit auf jeden Kopf und die Kombination der Ergebnisse. Auf diese Weise kann das Modell verschiedene Beziehungen in den Eingabedaten auf verschiedenen Skalen aufnehmen und die ausdrucksstarke Fähigkeit des Modells verbessern.

positionelle Feed-Forward-Netzwerke

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):

Klassendefinition:

def scaled_dot_product_attention(self, Q, K, V, mask=None):

Die Klasse ist eine Unterklasse von Pytorchs nn.module, was bedeutet, dass sie alle Funktionen erben wird, die für die Arbeit mit neuronalen Netzwerkschichten erforderlich sind.

Initialisierung:

pip3 install torch torchvision torchaudio
  1. d_model: Dimensionalität des Eingangs und Ausgangs des Modells.
  2. d_ff: Dimensionalität der inneren Schicht im Feed-Forward-Netzwerk.
  3. self.fc1 und self.fc2: zwei vollständig verbundene (lineare) Ebenen mit Eingangs- und Ausgangsdimensionen, wie durch D_Model und D_ff.
  4. definiert
  5. self.relu: Relu (behobene lineare Einheit) Aktivierungsfunktion, die die Nichtlinearität zwischen den beiden linearen Schichten einführt.

Vorwärtsmethode:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia
  1. x: Die Eingabe in das Feed-Forward-Netzwerk.
  2. self.fc1 (x): Der Eingang wird zuerst durch die erste lineare Schicht (fc1) geleitet.
  3. self.relu (...): Die Ausgabe von FC1 wird dann durch eine Relu -Aktivierungsfunktion geleitet. Relu ersetzt alle negativen Werte durch Nullen und führt die Nichtlinearität in das Modell ein.
  4. self.fc2 (...): Der aktivierte Ausgang wird dann durch die zweite lineare Schicht (FC2) geleitet, wodurch die endgültige Ausgabe erzeugt wird.

Zusammenfassend definiert die Position der Position in der Position im neuronalen Netzwerk, das aus zwei linearen Schichten mit einer Relu-Aktivierungsfunktion dazwischen besteht. Im Kontext von Transformatormodellen wird dieses Feed-Forward-Netzwerk getrennt und identisch auf jede Position angewendet. Es hilft bei der Transformation der Merkmale, die die Aufmerksamkeitsmechanismen innerhalb des Transformators gelernt haben, und wirkt als zusätzlicher Verarbeitungsschritt für die Aufmerksamkeitsausgänge.

Positionscodierung

Positionscodierung wird verwendet, um die Positionsinformationen jedes Tokens in die Eingabesequenz zu injizieren. Es verwendet Sinus- und Cosinusfunktionen verschiedener Frequenzen, um die Positionscodierung zu erzeugen.

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Klassendefinition:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        # Ensure that the model dimension (d_model) is divisible by the number of heads
        assert d_model % num_heads == 0, "d_model must be divisible by num_heads"
        
        # Initialize dimensions
        self.d_model = d_model # Model's dimension
        self.num_heads = num_heads # Number of attention heads
        self.d_k = d_model // num_heads # Dimension of each head's key, query, and value
        
        # Linear layers for transforming inputs
        self.W_q = nn.Linear(d_model, d_model) # Query transformation
        self.W_k = nn.Linear(d_model, d_model) # Key transformation
        self.W_v = nn.Linear(d_model, d_model) # Value transformation
        self.W_o = nn.Linear(d_model, d_model) # Output transformation
        
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        # Calculate attention scores
        attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # Apply mask if provided (useful for preventing attention to certain parts like padding)
        if mask is not None:
            attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
        
        # Softmax is applied to obtain attention probabilities
        attn_probs = torch.softmax(attn_scores, dim=-1)
        
        # Multiply by values to obtain the final output
        output = torch.matmul(attn_probs, V)
        return output
        
    def split_heads(self, x):
        # Reshape the input to have num_heads for multi-head attention
        batch_size, seq_length, d_model = x.size()
        return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
        
    def combine_heads(self, x):
        # Combine the multiple heads back to original shape
        batch_size, _, seq_length, d_k = x.size()
        return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
        
    def forward(self, Q, K, V, mask=None):
        # Apply linear transformations and split heads
        Q = self.split_heads(self.W_q(Q))
        K = self.split_heads(self.W_k(K))
        V = self.split_heads(self.W_v(V))
        
        # Perform scaled dot-product attention
        attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # Combine heads and apply output transformation
        output = self.W_o(self.combine_heads(attn_output))
        return output

Die Klasse wird als Unterklasse von Pytorchs nn.module definiert, sodass sie als Standard -Pytorch -Schicht verwendet werden kann.

Initialisierung:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
  1. d_model: Die Dimension der Eingabe des Modells.
  2. max_seq_length: Die maximale Länge der Sequenz, für die Positioncodierungen vorbereitet sind.
  3. pe: Ein mit Nullen gefüllter Tensor, der mit Positionscodierungen gefüllt wird.
  4. Position: Ein Tensor, der die Positionsindizes für jede Position in der Sequenz enthält.
  5. div_term: Ein Begriff, der zur Skalierung der Positionsindizes auf eine bestimmte Weise verwendet wird.
  6. Die Sinusfunktion wird auf die gerade Indizes und die Cosinusfunktion auf die ungeraden Indizes von PE angewendet.
  7. Schließlich ist PE als Puffer registriert, was bedeutet, dass es Teil des Status des Moduls ist, aber nicht als trainierbarer Parameter angesehen wird.

Vorwärtsmethode:

def scaled_dot_product_attention(self, Q, K, V, mask=None):

Die Vorwärtsmethode fügt einfach die Positionscodierungen zum Eingang x.

hinzu

Es verwendet die ersten X.Size (1) Elemente von PE, um sicherzustellen, dass die Positionskodierungen der tatsächlichen Sequenzlänge von x.

Zusammenfassung

Die Position der PositionalenCodierung fügt Informationen über die Position der Token in der Sequenz hinzu. Da dem Transformatormodell keine inhärente Kenntnis der Reihenfolge der Tokens (aufgrund seines Selbstbekämpfungsmechanismus) ist, hilft diese Klasse dem Modell, die Position von Token in der Sequenz zu berücksichtigen. Die verwendeten sinusförmigen Funktionen werden ausgewählt, damit das Modell leicht zu relativen Positionen gelernt wird, da es für jede Position in der Sequenz eine einzigartige und glatte Codierung erzeugt.

3. Erstellen der Encoderblöcke

Ein umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch

Abbildung 2. Der Encoder -Teil des Transformator -Netzwerks (Quelle: Bild aus dem Originalpapier)

pip3 install torch torchvision torchaudio

Klassendefinition:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

Die Klasse ist als Unterklasse von Pytorchs nn.module definiert, was bedeutet, dass sie als Baustein für neuronale Netze in Pytorch verwendet werden kann.

Initialisierung:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Parameter:

  1. d_model: Die Dimensionalität der Eingabe.
  2. num_heads: Die Anzahl der Aufmerksamkeitsköpfe in der Aufmerksamkeit mit mehreren Köpfen.
  3. d_ff: Die Dimensionalität der inneren Schicht im Positions-Feed-Forward-Netzwerk.
  4. Dropout: Die für die Regularisierung verwendete Abbrecherrate.

Komponenten:

    self.elf_attn: Multi-Head-Aufmerksamkeitsmechanismus.
  1. self.feed_forward: Positions- und futtermittel neuronales Netzwerk.
  2. self.norm1 und self.norm2: Schichtnormalisierung, angewendet, um den Eingang der Schicht zu glätten.
  3. self.dropout: Dropout -Schicht, zur Verhinderung von Überanpassungen, indem einige Aktivierungen während des Trainings zufällig auf Null gesetzt werden.

Vorwärtsmethode:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        # Ensure that the model dimension (d_model) is divisible by the number of heads
        assert d_model % num_heads == 0, "d_model must be divisible by num_heads"
        
        # Initialize dimensions
        self.d_model = d_model # Model's dimension
        self.num_heads = num_heads # Number of attention heads
        self.d_k = d_model // num_heads # Dimension of each head's key, query, and value
        
        # Linear layers for transforming inputs
        self.W_q = nn.Linear(d_model, d_model) # Query transformation
        self.W_k = nn.Linear(d_model, d_model) # Key transformation
        self.W_v = nn.Linear(d_model, d_model) # Value transformation
        self.W_o = nn.Linear(d_model, d_model) # Output transformation
        
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        # Calculate attention scores
        attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # Apply mask if provided (useful for preventing attention to certain parts like padding)
        if mask is not None:
            attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
        
        # Softmax is applied to obtain attention probabilities
        attn_probs = torch.softmax(attn_scores, dim=-1)
        
        # Multiply by values to obtain the final output
        output = torch.matmul(attn_probs, V)
        return output
        
    def split_heads(self, x):
        # Reshape the input to have num_heads for multi-head attention
        batch_size, seq_length, d_model = x.size()
        return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
        
    def combine_heads(self, x):
        # Combine the multiple heads back to original shape
        batch_size, _, seq_length, d_k = x.size()
        return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
        
    def forward(self, Q, K, V, mask=None):
        # Apply linear transformations and split heads
        Q = self.split_heads(self.W_q(Q))
        K = self.split_heads(self.W_k(K))
        V = self.split_heads(self.W_v(V))
        
        # Perform scaled dot-product attention
        attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # Combine heads and apply output transformation
        output = self.W_o(self.combine_heads(attn_output))
        return output

Eingabe:

    x: Die Eingabe in die Encoder -Schicht.
  1. Maske: Optionale Maske, um bestimmte Teile des Eingangs zu ignorieren.

Verarbeitungsschritte:

    Selbstbekämpfung: Die Eingabe X wird durch den Multi-Head-Selbstattentierungsmechanismus weitergeleitet.
  1. Hinzufügen und Normalisieren (nach Aufmerksamkeit): Die Aufmerksamkeitsausgabe wird zum ursprünglichen Eingang (Restverbindung) hinzugefügt, gefolgt von Tropfen und Normalisierung unter Verwendung von Norm1.
  2. Feed-Forward-Netzwerk: Die Ausgabe aus dem vorherigen Schritt wird durch das Positions-Feed-Forward-Netzwerk weitergeleitet.
  3. Hinzufügen und Normalisieren (nach dem Vorwärtsspeisen): Ähnlich wie bei Schritt 2 wird der Eingang der Vorspeise zur Eingabe dieser Stufe (Restverbindung) hinzugefügt, gefolgt von Ausfall und Normalisierung unter Verwendung von NORM2.
  4. Ausgabe: Der verarbeitete Tensor wird als Ausgabe der Encoder -Schicht zurückgegeben.

Zusammenfassung:

Die Encoderlayer -Klasse definiert eine einzige Ebene des Transformator -Encoders. Es fasst einen mehrköpfigen Selbstbekämpfungsmechanismus zusammen, gefolgt von positionellem neuronalem Netzwerk mit Restverbindungen mit Restverbindungen, Schichtnormalisierung und Tropfen, die gegebenenfalls angewendet werden. Mit diesen Komponenten können der Encoder zusammen komplexe Beziehungen in den Eingabedaten erfassen und sie in eine nützliche Darstellung für nachgeschaltete Aufgaben umwandeln. In der Regel werden mehrere solcher Encoderschichten gestapelt, um den vollständigen Encoder -Teil eines Transformatormodells zu bilden.

4. Bauen der Decoderblöcke

bauen

Ein umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch

pip3 install torch torchvision torchaudio

Klassendefinition:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

Initialisierung:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Parameter :

  1. d_model: Die Dimensionalität der Eingabe.
  2. num_heads: Die Anzahl der Aufmerksamkeitsköpfe in der Aufmerksamkeit mit mehreren Köpfen.
  3. d_ff: Die Dimensionalität der inneren Schicht im Feed-Forward-Netzwerk.
  4. Dropout: Die Abbrecherrate für die Regularisierung.

Komponenten :

  1. self.elf_attn: Mehrköpfiger Selbstbekämpfungsmechanismus für die Zielsequenz.
  2. self.cross_attn: Multi-Head-Aufmerksamkeitsmechanismus, der sich mit der Ausgabe des Encoders befasst.
  3. self.feed_forward: Positions- und futtermittel neuronales Netzwerk.
  4. self.norm1, self.norm2, self.norm3: Schichtnormalisierungskomponenten.
  5. self.dropout: Dropout -Schicht zur Regularisierung.

Vorwärts Methode :

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        # Ensure that the model dimension (d_model) is divisible by the number of heads
        assert d_model % num_heads == 0, "d_model must be divisible by num_heads"
        
        # Initialize dimensions
        self.d_model = d_model # Model's dimension
        self.num_heads = num_heads # Number of attention heads
        self.d_k = d_model // num_heads # Dimension of each head's key, query, and value
        
        # Linear layers for transforming inputs
        self.W_q = nn.Linear(d_model, d_model) # Query transformation
        self.W_k = nn.Linear(d_model, d_model) # Key transformation
        self.W_v = nn.Linear(d_model, d_model) # Value transformation
        self.W_o = nn.Linear(d_model, d_model) # Output transformation
        
    def scaled_dot_product_attention(self, Q, K, V, mask=None):
        # Calculate attention scores
        attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
        
        # Apply mask if provided (useful for preventing attention to certain parts like padding)
        if mask is not None:
            attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
        
        # Softmax is applied to obtain attention probabilities
        attn_probs = torch.softmax(attn_scores, dim=-1)
        
        # Multiply by values to obtain the final output
        output = torch.matmul(attn_probs, V)
        return output
        
    def split_heads(self, x):
        # Reshape the input to have num_heads for multi-head attention
        batch_size, seq_length, d_model = x.size()
        return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
        
    def combine_heads(self, x):
        # Combine the multiple heads back to original shape
        batch_size, _, seq_length, d_k = x.size()
        return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
        
    def forward(self, Q, K, V, mask=None):
        # Apply linear transformations and split heads
        Q = self.split_heads(self.W_q(Q))
        K = self.split_heads(self.W_k(K))
        V = self.split_heads(self.W_v(V))
        
        # Perform scaled dot-product attention
        attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
        
        # Combine heads and apply output transformation
        output = self.W_o(self.combine_heads(attn_output))
        return output

Eingabe :

  1. x: Die Eingabe in die Decoderschicht.
  2. ENC_OUTPUT: Die Ausgabe aus dem entsprechenden Encoder (verwendet im Querverfolgungsschritt).
  3. src_mask: Quellmaske, um bestimmte Teile der Ausgabe des Encoders zu ignorieren.
  4. TGT_Mask: Zielmaske, um bestimmte Teile der Eingabe des Decoders zu ignorieren.

Verarbeitungsschritte:

  1. Selbstbeziehung in der Zielsequenz: Die Eingabe X wird durch einen Selbstbekämpfungsmechanismus verarbeitet.
  2. hinzufügen und normalisieren (nach Selbstbekämpfung): Die Ausgabe der Selbstbekämpfung wird dem ursprünglichen X hinzugefügt, gefolgt von Ausfall und Normalisierung unter Verwendung von Norm1.
  3. Querverantwortung mit Encoderausgabe: Der normalisierte Ausgang aus dem vorherigen Schritt wird durch einen Kreuzbewegungsmechanismus verarbeitet, der sich mit der Ausgabe des Encoders ausgibt.
  4. hinzufügen und normalisieren (nach Kreuzeinhaltung): Die Ausgabe aus der Kreuzung wird zur Eingabe dieser Stufe hinzugefügt, gefolgt von Tropfen und Normalisierung unter Verwendung von NORM2.
  5. Feed-Forward-Netzwerk: Die Ausgabe aus dem vorherigen Schritt wird durch das Feed-Forward-Netzwerk weitergeleitet.
  6. Hinzufügen und Normalisieren (nach dem Vorlauf): Der Eingang der Vorspeise wird zur Eingabe dieser Stufe hinzugefügt, gefolgt von Tropfen und Normalisierung unter Verwendung von NORM3.
  7. Ausgabe: Der verarbeitete Tensor wird als Ausgabe der Decoderschicht zurückgegeben.

Zusammenfassung:

Die Decoderlayer -Klasse definiert eine einzelne Schicht des Decoders des Transformators. Es besteht aus einem Multi-Head-Selbstbekämpfungsmechanismus, einem Multi-Head-Querbewegungsmechanismus (der sich mit der Ausgabe des Encoders befasst), einem positionellen neuronalen Netzwerk und den entsprechenden verbleibenden Verbindungen, der Normalisierung der Schicht und der Ausfallschichten. Diese Kombination ermöglicht es dem Decoder, aussagekräftige Ausgänge basierend auf den Darstellungen des Encoders zu generieren, wobei sowohl die Zielsequenz als auch die Quellsequenz berücksichtigt werden. Wie beim Encoder sind mehrere Decoderschichten normalerweise gestapelt, um den vollständigen Decoder -Teil eines Transformatormodells zu bilden.

Als nächstes werden die Encoder- und Decoderblöcke zusammengebracht, um das umfassende Transformatormodell zu konstruieren.

5. Kombinieren Sie die Encoder- und Decoder -Ebenen, um das vollständige Transformator -Netzwerk

zu erstellen

Ein umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch

Abbildung 4. Das Transformator -Netzwerk (Quelle: Bild aus dem Originalpapier)

pip3 install torch torchvision torchaudio

Klassendefinition:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

Initialisierung:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Der Konstruktor nimmt die folgenden Parameter an:

  1. src_vocab_size: Quellvokabulargröße.
  2. TGT_VOCAB_SIZE: Zielvokabulargröße.
  3. d_model: Die Dimensionalität der Einbettungen des Modells.
  4. num_heads: Anzahl der Aufmerksamkeitsköpfe im Multi-Head-Aufmerksamkeitsmechanismus.
  5. num_layers: Anzahl der Ebenen sowohl für den Encoder als auch für den Decoder.
  6. d_ff: Dimensionalität der inneren Schicht im Feed-Forward-Netzwerk.
  7. max_seq_length: Maximale Sequenzlänge für die Positioncodierung.
  8. Dropout: Ausfallrate für die Regularisierung.

und es definiert die folgenden Komponenten:

  1. self.encoder_embedding: Schicht für die Quellsequenz einbetten.
  2. self.decoder_embedding: Schicht für die Zielsequenz einbetten.
  3. self.positional_encoding: Positionscodierkomponente.
  4. self.encoder_layers: eine Liste von Encoder -Ebenen.
  5. self.decoder_layers: eine Liste von Decoderebenen.
  6. self.fc: endgültiges vollständig verbundenes (lineares) Layer -Mapping zur Zielvokabulargröße.
  7. self.dropout: Dropout -Schicht.

Maskenmethode erzeugen:

pip3 install torch torchvision torchaudio

Diese Methode wird verwendet, um Masken für die Quell- und Zielsequenzen zu erstellen, um sicherzustellen, dass Polstertoken ignoriert werden und dass zukünftige Token während des Trainings für die Zielsequenz nicht sichtbar sind.

Vorwärtsmethode:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

Diese Methode definiert den Vorwärtspass für den Transformator, nimmt Quell- und Zielsequenzen und erzeugt die Ausgangsvorhersagen.

  1. Eingangseinbettung und Positionscodierung: Die Quell- und Zielsequenzen werden zuerst unter Verwendung ihrer jeweiligen Einbettungsschichten eingebettet und dann zu ihren Positionscodierungen hinzugefügt.
  2. Encoder -Ebenen: Die Quellsequenz wird durch die Encoder -Ebenen geleitet, wobei die endgültige Encoder -Ausgabe die verarbeitete Quellsequenz darstellt.
  3. Decoderschichten: Die Zielsequenz und die Ausgabe des Encoders werden durch die Decoderschichten geleitet, was zur Ausgabe des Decoders führt.
  4. endgültige lineare Schicht: Der Ausgang des Decoders wird der Zielvokabulargröße unter Verwendung einer vollständig verbundenen (linearen) Schicht
  5. abgebildet.

Ausgabe:

Der endgültige Ausgang ist ein Tensor, der die Vorhersagen des Modells für die Zielsequenz darstellt.

Zusammenfassung:

Die Transformatorklasse vereint die verschiedenen Komponenten eines Transformatormodells, einschließlich der Einbettungen, der Positionscodierung, der Encoderschichten und der Decoderschichten. Es bietet eine bequeme Schnittstelle für Training und Inferenz, wobei die Komplexität der Aufmerksamkeit mit mehreren Kopf, Feed-Forward-Netzwerken und Schichtnormalisierung eingekapselt wird.

Diese Implementierung folgt der Standard-Transformatorarchitektur und ist für Sequenz-zu-Sequenz-Aufgaben wie maschinelle Übersetzung, Textübersicht usw. geeignet. Die Einbeziehung der Maskierung stellt sicher

Diese sequentiellen Schritte ermöglichen das Transformatormodell, Eingangssequenzen effizient zu verarbeiten und entsprechende Ausgabesequenzen zu erzeugen.

Training des Pytorch -Transformatormodells

Beispieldatenvorbereitung

Für veranschaulichende Zwecke wird in diesem Beispiel ein Dummy -Datensatz hergestellt. In einem praktischen Szenario würde jedoch ein umfangreicherer Datensatz eingesetzt, und der Prozess würde die Vorverarbeitung von Text zusammen mit der Erstellung von Vokabeln sowohl für die Quelle als auch für die Zielsprachen beinhalten.

.
pip3 install torch torchvision torchaudio

Hyperparameter:

Diese Werte definieren die Architektur und das Verhalten des Transformatormodells:

  1. src_vocab_size, TGT_VOCAB_SIZE: Vokabulargrößen für Quell- und Zielsequenzen, beide auf 5000 eingestellt.
  2. d_model: Dimensionalität der Einbettungen des Modells, eingestellt auf 512.
  3. num_heads: Anzahl der Aufmerksamkeitsköpfe im Multi-Head-Aufmerksamkeitsmechanismus, eingestellt auf 8.
  4. num_layers: Anzahl der Ebenen sowohl für den Encoder als auch für den Decoder, auf 6 gesetzt.
  5. d_ff: Dimensionalität der inneren Schicht im Feed-Forward-Netzwerk, auf 2048 festgelegt.
  6. max_seq_length: Maximale Sequenzlänge für die Positioncodierung, auf 100 festgelegt.
  7. Dropout: Ausfallrate für die Regularisierung, auf 0,1 eingestellt.

Erstellen einer Transformatorinstanz:

conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c pytorch -c nvidia

Diese Zeile erstellt eine Instanz der Transformatorklasse, in der sie mit den angegebenen Hyperparametern initialisiert wird. Die Instanz wird die Architektur und das Verhalten durch diese Hyperparameter definieren.

Zufallsbeispieldaten generieren:

Die folgenden Zeilen erzeugen zufällige Quellen- und Zielsequenzen:

  1. src_data: zufällige Ganzzahlen zwischen 1 und src_vocab_size, die eine Stapel von Quellsequenzen mit Form darstellen (64, max_seq_length).
  2. TGT_DATA: Zufällige Ganzzahlen zwischen 1 und TGT_vocab_size, die eine Stapel von Zielsequenzen mit Form darstellen (64, max_seq_length).
  3. Diese zufälligen Sequenzen können als Eingaben für das Transformatormodell verwendet werden, wobei eine Stapel von Daten mit 64 Beispielen und Sequenzen von Länge 100 simuliert wird.

Zusammenfassung:

Der Code -Snippet zeigt, wie ein Transformatormodell initialisiert und zufällige Quellen- und Zielsequenzen generiert werden, die in das Modell eingespeist werden können. Die gewählten Hyperparameter bestimmen die spezifische Struktur und Eigenschaften des Transformators. Dieses Setup könnte Teil eines größeren Skripts sein, in dem das Modell bei tatsächlichen Aufgaben der Sequenz-zu-Sequenz geschult und bewertet wird, z. B. maschinelle Übersetzung oder Textübersetzung.

Training des Modells

Als nächstes wird das Modell unter Verwendung der oben genannten Stichprobendaten geschult. In einem realen Szenario würde jedoch ein deutlich größerer Datensatz verwendet, der typischerweise zu Schulungs- und Validierungszwecken in verschiedene Sets aufgeteilt wird.

import torch
import torch.nn as nn
import torch.optim as optim
import torch.utils.data as data
import math
import copy

Verlustfunktion und Optimierer:

    criterion = nn.crossentropyloss (ignore_index = 0): Definiert die Verlustfunktion als Kreuzentropieverlust. Das Argument ignore_index ist auf 0 gesetzt, was bedeutet, dass der Verlust keine Ziele mit einem Index von 0 betrachtet (typischerweise für Polstertoken reserviert).
  1. optimizer = optim.adam (...): Definiert den Optimierer als Adam mit einer Lernrate von 0,0001 und spezifischen Beta -Werten.

Modelltrainingsmodus:

  1. Transformator.Train (): Legt das Transformatormodell in den Trainingsmodus fest und aktiviert Verhaltensweisen wie Tropfen, die nur während des Trainings gelten.

Trainingsschleife:

Der Code -Snippet trainiert das Modell für 100 Epochen mit einer typischen Trainingsschleife:

  1. für Epoche im Bereich (100): Iteriert über 100 Trainings -Epochen.
  2. optimizer.zero_grad (): Löscht die Gradienten aus der vorherigen Iteration.
  3. output = Transformator (SRC_DATA, TGT_DATA [:,: -1]): Über den Transformator übergibt die Quelldaten und die Zieldaten (mit Ausnahme des letzten Tokens in jeder Sequenz). Dies ist bei Sequence-to-Sequenz-Aufgaben üblich, bei denen das Ziel von einem Token verschoben wird.
  4. Verlust = Kriterium (...): Berechnet den Verlust zwischen den Vorhersagen des Modells und den Zieldaten (ohne das erste Token in jeder Sequenz). Der Verlust wird berechnet, indem die Daten in eindimensionale Tensoren umgestaltet und die Querentropieverlustfunktion verwendet werden.
  5. Verlust.Backward (): Berechnet die Gradienten des Verlusts in Bezug auf die Parameter des Modells.
  6. optimizer.step (): Aktualisiert die Parameter des Modells mit den berechneten Gradienten.
  7. print (f "Epoch: {Epoch 1}, Verlust: {LUST.ITEM ()}"): Druckt die aktuelle Epochennummer und den Verlustwert für diese Epoche.

Zusammenfassung:

Dieser Code -Snippet trainiert das Transformatormodell auf zufällig generierten Quell- und Zielsequenzen für 100 Epochen. Es verwendet den Adam Optimizer und die Cross-Entropy-Verlustfunktion. Der Verlust wird für jede Epoche gedruckt, sodass Sie den Trainingsfortschritt überwachen können. In einem realen Szenario ersetzen Sie die zufälligen Quellen- und Zielsequenzen durch tatsächliche Daten Ihrer Aufgabe, wie z. B. maschinelle Übersetzung.

Transformatormodellleistung Evaluation

Nach dem Training des Modells kann seine Leistung auf einem Validierungsdatensatz oder einem Testdatensatz bewertet werden. Das Folgende ist ein Beispiel dafür, wie dies getan werden kann:

pip3 install torch torchvision torchaudio

Bewertungsmodus:

  1. Transformator.eval (): Steckt das Transformatormodell in den Bewertungsmodus. Dies ist wichtig, da es bestimmte Verhaltensweisen wie Tropfen ausschaltet, die nur während des Trainings verwendet werden.

Generieren Sie zufällige Validierungsdaten:

  1. val_src_data: zufällige Ganzzahlen zwischen 1 und src_vocab_size, die eine Stapel von Validierungsquellensequenzen mit Form darstellen (64, max_seq_length).
  2. val_tgt_data: zufällige Ganzzahlen zwischen 1 und TGT_vocab_size, die eine Stapel von Validierungszielsequenzen mit Form darstellen (64, max_seq_length).

Validierungsschleife:

  1. mit Torch.no_grad (): Deaktiviert die Gradientenberechnung, da wir während der Validierung keine Gradienten berechnen müssen. Dies kann den Speicherverbrauch verringern und die Berechnungen beschleunigen.
  2. val_output = Transformator (VAL_SRC_DATA, VAL_TGT_DATA [:,: -1]): Übergibt die Validierungsquellendaten und die Validierungszieldaten (ohne das letzte Token in jeder Sequenz) durch den Transformer.
  3. val_loss = criterion (...): Berechnet den Verlust zwischen den Vorhersagen des Modells und den Validierungszieldaten (ohne das erste Token in jeder Sequenz). Der Verlust wird berechnet, indem die Daten in eindimensionale Tensoren umgestaltet und die zuvor definierte Quer-Entropie-Verlustfunktion verwendet werden.
  4. print (f "Validierungsverlust: {val_loss.item ()}"): Drucken den Validierungsverlustwert.

Zusammenfassung:

Dieser Code -Snippet bewertet das Transformatormodell in einem zufällig generierten Validierungsdatensatz, berechnet den Validierungsverlust und druckt ihn aus. In einem realen Szenario sollten die zufälligen Validierungsdaten durch die tatsächlichen Validierungsdaten aus der Aufgabe, an der Sie arbeiten, ersetzt werden. Der Validierungsverlust kann Ihnen einen Hinweis geben, wie gut Ihr Modell auf unsichtbaren Daten abschneidet, was ein kritisches Maß für die Verallgemeinerungsfähigkeit des Modells ist.

Für weitere Details zu Transformers und Umarmungsgesicht ist unser Tutorial, eine Einführung in die Verwendung von Transformatoren und Umarmungsgesicht, nützlich.

Schlussfolgerung und weitere Ressourcen

Abschließend zeigte dieses Tutorial, wie ein Transformatormodell mit Pytorch konstruiert wird, eines der vielseitigsten Tools für Deep Learning. Mit ihrer Kapazität zur Parallelisierung und der Fähigkeit, langfristige Abhängigkeiten in Daten zu erfassen, haben Transformatoren in verschiedenen Bereichen ein immenses Potenzial, insbesondere NLP

Für diejenigen, die ihr Verständnis für fortgeschrittene tiefe Lernkonzepte und -techniken vertiefen möchten, sollten Sie den Kurs erwägen, das erweiterte Deep Learning mit Keras auf DataCamp zu untersuchen. Sie können auch über den Aufbau eines einfachen neuronalen Netzwerks mit Pytorch in einem separaten Tutorial lesen.

Das obige ist der detaillierte Inhalt vonEin umfassender Leitfaden zum Aufbau eines Transformatormodells mit Pytorch. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn