RoFormer: Verbesserter Transformator Mit Einbettung Der Drehposition

RoFormer: Verbesserter Transformator Mit Einbettung Der Drehposition

Transformer-basierte Modelle sind bekannt für ihre Fähigkeit, komplexe Texte zu analysieren und zu interpretieren. Sie sind darauf angewiesen, die Reihenfolge und den Kontext von Wörtern zu verstehen – Aufgaben, bei denen herkömmliche Methoden der Positionskodierung an ihre Grenzen gestoßen sind. Um diese Lücke zu schließen, definiert das ROFORMER-Modell, das auf Rotary Position Embedding (RoPE) basiert, unseren Ansatz zur Positionskodierung neu.

Traditionelle Positionskodierung

Transformer behandeln Text als eine Reihe von Token und ermöglichen die parallele Verarbeitung von Sequenzen für mehr Effizienz. Diese Stärke brachte jedoch eine Herausforderung mit sich: die immanente Agnostizität des Modells gegenüber der Token-Reihenfolge. Positionskodierung war die Antwort, die jedem Token eine eindeutige Signatur verlieh, die seine Sequenzposition angibt.

Absolute Positionseinbettungen

Ursprünglich verwendeten Modelle wie BERT Absolutpositionseinbettungen, die jeder Position in einer Sequenz einen festen Vektor zuwiesen. Obwohl diese Methode einfach ist, fehlt ihr von Natur aus die Fähigkeit, sich an Variationen der Sequenzlänge anzupassen oder die relativen Abstände zwischen Token hervorzuheben, was für das Verständnis vieler sprachlicher Konstrukte von entscheidender Bedeutung ist.

Relative Positionseinbettungen

Um die dynamische Natur der Sprache zu erfassen, wurden Einbettungen relativer Positionen eingeführt, wobei der Schwerpunkt eher auf dem Abstand zwischen Token als auf ihren absoluten Positionen liegt. Trotz ihres konzeptionellen Vorteils führten diese Einbettungen zu rechnerischer Komplexität und konnten sich nicht nahtlos in den Selbstaufmerksamkeitsmechanismus von Transformers integrieren, was ihre Wirksamkeit einschränkte.

ROFORMER und Rotary Position Embedding

ROFORMER erkennt die Einschränkungen bestehender Positionskodierungsstrategien und führt Rotary Position Embedding (RoPE) ein, einen Ansatz, der die Vorteile absoluter und relativer Positionsinformationen ohne deren jeweilige Nachteile kombiniert.

Einbettung der Drehposition

RoPE kodiert Positionsinformationen mithilfe von Rotationsmatrizen, sodass das Modell nicht nur verstehen kann, wo sich ein Token befindet, sondern auch, wie es mit jedem anderen Token in einer Sequenz zusammenhängt.

Reformer.pngCredit: Original Paper

Es arbeitet durch eine geometrische Linse und behandelt Token-Positionen als Punkte in einem mehrdimensionalen Raum, die gedreht werden, um ihre sequentiellen Beziehungen zu markieren. Diese Rotation ermöglicht es dem Modell, innerhalb seines Selbstaufmerksamkeitsmechanismus sowohl absolute als auch relative Positionshinweise zu bewahren und zu nutzen.

Implementierung von RoPE

Die Implementierung von RoPE umfasst das Codieren der Position jedes Tokens in eine Rotationsmatrix und die Anwendung dieser Matrix innerhalb des Selbstaufmerksamkeitsmechanismus des Transformers. Dieser Prozess ermöglicht eine flexible, dynamische Interpretation von Positionsinformationen, berücksichtigt unterschiedliche Sequenzlängen und erfasst das Wesentliche von Token-Wechselbeziehungen ohne nennenswerten Rechenaufwand.

Zuerst benötigen Sie eine Funktion zum Generieren der rotierenden Einbettungen und dann integrieren Sie diese Einbettungen in Ihr Modell. Im folgenden Beispiel wird davon ausgegangen, dass Sie mit der Erstellung benutzerdefinierter Ebenen in Keras vertraut sind.

Schritt 1: Definieren Sie die Rotationseinbettungsfunktion

Diese Funktion generiert die rotierenden Einbettungen unter Berücksichtigung der maximalen Sequenzlänge und der Dimensionalität der Einbettungen.

from tensorflow.keras.layers import Layer
import numpy as np

def get_rotary_embedding(dim, max_seq_len):
    inv_freq = 1.0 / (10000 ** (tf.range(0, dim, 2, dtype=tf.float32) / dim))
    t = tf.range(max_seq_len, dtype=tf.float32)
    freqs = tf.einsum('i,j->ij', t, inv_freq)
    emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)
    return emb

inv_freq = 1.0 / (10000 ** (tf.range(0, dim, 2, dtype=tf.float32) / dim))

Diese Zeile berechnet den Kehrwert exponentiell skalierter Frequenzen basierend auf den Positionsindizes. Diese Frequenzen werden zur Erzeugung sinusförmiger Muster für rotierende Einbettungen verwendet, was bei der Codierung der relativen Positionsinformationen in Sequenzen hilft. Dieser Mechanismus ist besonders nützlich bei Aufgaben, bei denen das Verständnis der Reihenfolge und relativen Positionierung von Elementen von entscheidender Bedeutung ist, beispielsweise bei der Verarbeitung natürlicher Sprache oder der Zeitreihenanalyse.

Im Detail:

  • „tf.range(0, dim, 2, dtype=tf.float32)“ erstellt einen Wertebereich von 0 bis „dim“ (exklusiv) in Schritten von 2. Das Argument „dtype=tf.float32“ gibt an dass die Elemente dieses Tensors 32-Bit-Gleitkommazahlen sind. Wenn „dim“ beispielsweise 8 ist, würde dies „[0, 2, 4, 6]“ ergeben.

  • Der von „tf.range“ erzeugte Tensor wird dann durch die Dimensionalität („dim“) der Einbettungen geteilt. Diese Operation skaliert diese Indizes auf einen Bereich zwischen 0 und 1 (exklusiv, wenn „dim“ gerade ist, leicht inklusive, wenn „dim“ ungerade ist, da der Bereichsschritt jeden zweiten Wert überspringt). Fortsetzung des Beispiels mit „dim“ = 8, Division durch 8 ergibt „[0,0, 0,25, 0,5, 0,75]“.

  • Die Operation „10000 ** (...)“ erhöht jedes Element im zuvor skalierten Tensor um 10.000. Die Basis von 10.000 ist etwas willkürlich, wird aber gewählt, um sicherzustellen, dass die Frequenzen über einen weiten Bereich variieren, was dem Modell hilft, effektiver zwischen verschiedenen Positionen zu unterscheiden. Für „[0,0, 0,25, 0,5, 0,75]“ würde die Potenzoperation auf jedes Element angewendet, was zu viel größeren Werten für höhere Elemente führt.

  • Schließlich wird die Umkehrfrequenz ermittelt, indem der Kehrwert (1/x) der Werte aus dem vorherigen Schritt gebildet wird. Die inversen Frequenzen sind bei höheren Indizes kleiner, was bedeutet, dass Elemente weiter in der Sequenz kleinere Frequenzen haben, was sich darauf auswirkt, wie ihre Positionen im Modell codiert werden. Dadurch können die Einbettungen so skaliert werden, dass relative Positionen durch die Aufmerksamkeitsmechanismen des Modells abgeleitet werden können.

Die Linie:

freqs = tf.einsum('i,j->ij', t, inv_freq)

verwendet die Funktion „tf.einsum“ von TensorFlow, ein Tool, das den präzisen und effizienten Ausdruck von Tensoroperationen mithilfe der Einstein-Summennotation ermöglicht.

Diese Operation berechnet effektiv das äußere Produkt der Vektoren „t“ und „inv_freq“, was zu einer Matrix führt, in der jedes Element „(i, j)“ das Produkt des „i“-ten Elements von „t“ und des „ j-tes Element von inv_freq`. Diese Matrix („freqs“) stellt die Frequenzen dar, die zur Erzeugung der Sinusmuster für die rotierenden Einbettungen verwendet werden.

Schritt 2: Benutzerdefinierte Keras-Ebene für rotierende Einbettungen

Erstellen wir nun eine benutzerdefinierte Keras-Ebene, die rotierende Einbettungen auf den Eingabetensor anwendet. Diese Ebene geht davon aus, dass der Eingabetensor die Form „(batch_size, sequence_length, embedding_dim)“ hat.

class RotaryEmbeddingLayer(Layer):
    def __init__(self, dim, max_seq_len, **kwargs):
        super().__init__(**kwargs)
        self.dim = dim
        self.max_seq_len = max_seq_len
        self.rotary_embeddings = get_rotary_embedding(dim, max_seq_len)

    def call(self, inputs):
        seq_len = tf.shape(inputs)[1]
        embeddings = self.rotary_embeddings[:seq_len]
        
        cos_emb = embeddings[:, None, :self.dim // 2]
        sin_emb = embeddings[:, None, self.dim // 2:]
        
        # Decompose inputs into sine and cosine components
        inputs_cos = inputs[..., :self.dim // 2]
        inputs_sin = inputs[..., self.dim // 2:]
        
        # Apply rotary embeddings
        rotated_cos = inputs_cos * cos_emb - inputs_sin * sin_emb
        rotated_sin = inputs_sin * cos_emb + inputs_cos * sin_emb
        
        return tf.concat([rotated_cos, rotated_sin], axis=-1)

    def get_config(self):
        config = super().get_config()
        config.update({
            "dim": self.dim,
            "max_seq_len": self.max_seq_len
        })
        return config

Die Zeile „embeddings = self.rotary_embeddings[:seq_len]“ wählt die entsprechende Teilmenge vorberechneter rotierender Einbettungen basierend auf der aktuellen Länge der Eingabesequenz aus. Da die Länge der Sequenzen von Stapel zu Stapel variieren kann, stellt dieser Slicing-Vorgang sicher, dass nur die Einbettungen verwendet werden, die der tatsächlichen Sequenzlänge entsprechen.

Die Variable „embeddings“ enthält jetzt einen Tensor der Form „(seq_len, embedding_dim)“, wobei „seq_len“ die Länge der Sequenzen im aktuellen Stapel und „embedding_dim“ die Dimensionalität der Einbettungen ist. Dieser Tensor enthält die rotierenden Positionseinbettungen für jede Position in der Sequenz bis zu „seq_len“.

emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) kombiniert Sinus- und Cosinustransformationen von Positionsfrequenzen in einem einzigen Tensor:

-tf.cos(freqs) und tf.sin(freqs) wenden die Kosinus- bzw. Sinustransformationen auf den „freqs“-Tensor an. Der „freqs“-Tensor enthält Frequenzwerte für jede Position in der Eingabesequenz und jede Dimension des Einbettungsraums, berechnet auf der Grundlage der Sequenzpositionen und der Umkehrfrequenzen der Einbettungsdimensionen. Die Sinus- und Kosinusfunktionen werden elementweise angewendet, was zu zwei Tensoren derselben Form wie „Frequenzen“ führt. Diese Transformationen tragen dazu bei, die Position so zu kodieren, dass sie die zyklische Natur von Positionsbeziehungen erfasst, und erleichtern so die Fähigkeit des Modells, relative Positionen zu verstehen.

-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) verkettet die kosinus- und sinustransformierten Tensoren entlang der letzten Achse (gekennzeichnet durch „axis=-1“). Durch die Verkettung dieser Tensoren nebeneinander wird die Dimensionalität des „freqs“-Tensors effektiv verdoppelt, wobei die erste Hälfte kosinustransformierte Werte und die zweite Hälfte sinustransformierte Werte für jede Position darstellt. Durch die Verkettung wird sichergestellt, dass jede Positionskodierung sowohl Sinus- als auch Kosinusinformationen enthält, wodurch Informationen sowohl über die Amplitude als auch über die Phase der Positionssignale erhalten bleiben.

  • Der verkettete Tensor „emb“ enthält jetzt die vollständigen rotierenden Einbettungen für die Eingabepositionen. Die Form von „emb“ ist in den ersten beiden Dimensionen (entsprechend den Sequenzpositionen und Einbettungsdimensionen) dieselbe wie die von „freqs“, aber die letzte Dimension wird doppelt so groß sein und sowohl Sinus- als auch Kosinuswerte berücksichtigen. Diese Einbettungen werden verwendet, um die Eingabeeinbettungen zu modulieren, indem Positionsinformationen auf rotationsäquivariante Weise hinzugefügt werden.

-cos_emb = embeddings[:, None, :self.dim // 2]:

  1. Der erste Doppelpunkt „:“ bedeutet „alle Elemente in dieser Dimension auswählen“, was sich in diesem Fall auf alle Positionen in der Sequenz bezieht.

  2. „None“ wird verwendet, um eine zusätzliche Dimension hinzuzufügen, wodurch der Tensor dreidimensional wird. Dies geschieht häufig, um die Kompatibilität mit bestimmten Operationen sicherzustellen, die Eingaben einer bestimmten Anzahl von Dimensionen erwarten. Wenn Sie beispielsweise eine elementweise Multiplikation mit einem anderen dreidimensionalen Tensor durchführen, müssen die Formen gemäß den Übertragungsregeln ausgerichtet sein.

  3. :self.dim // 2, wählt die erste Hälfte der Abmessungen in der letzten Achse aus. Da die „Einbettungsdimension“ verdoppelt wird, um sowohl Sinus- als auch Kosinuswerte einzuschließen, werden bei der Division durch 2 effektiv nur die Kosinuskomponenten der Einbettungen ausgewählt.

Schritt 3: Integration mit einem Keras-Modell

Nachdem Sie den „RotaryEmbeddingLayer“ definiert haben, können Sie ihn in Ihr Keras-Modell integrieren. Diese Ebene sollte auf Ihre Einbettungen angewendet werden, bevor sie in Aufmerksamkeitsebenen oder nachfolgende Modellebenen eingespeist werden.

Hier ist ein vereinfachtes Beispiel für die Integration der rotierenden Einbettungen in ein Modell:

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Embedding, Dense

max_seq_len = 512
embedding_dim = 64

inp = Input(shape=(max_seq_len,))
x = Embedding(input_dim=10000, output_dim=embedding_dim)(inp)
x = RotaryEmbeddingLayer(dim=embedding_dim, max_seq_len=max_seq_len)(x)
# Add your model's layers here, e.g., Transformer blocks
x = Dense(1, activation='sigmoid')(x)

model = Model(inputs=inp, outputs=x)
model.summary()

Code Labs Academy © 2025 Alle Rechte vorbehalten.