RoFormer: Forbedret transformer med roterende positionsindlejring

RoFormer: Forbedret transformer med roterende positionsindlejring

Transformer-baserede modeller er berømte for deres evne til at parse og fortolke kompleks tekst. De er afhængige af at forstå ordenes rækkefølge og kontekst - opgaver, hvor traditionelle positionskodningsmetoder har vist deres begrænsninger. For at løse dette hul, redefinerer ROFORMER-modellen, drevet af Rotary Position Embedding (RoPE), vores tilgang til positionskodning.

Traditionel positionskodning

Transformere behandler tekst som en række tokens og tillader parallel behandling af sekvenser for større effektivitet. Denne styrke bragte imidlertid sin udfordring: modellens iboende agnosticisme til symbolsk orden. Positionel kodning var svaret, forsynede hvert token med en unik signatur, der angiver dens sekvensposition.

Absolutte Position Indlejringer

Oprindeligt brugte modeller som BERT absolut positionsindlejringer, der tildelte en fast vektor til hver position i en sekvens. Selvom denne metode er ligetil, mangler den i sagens natur evnen til at tilpasse sig sekvenslængdevariationer eller at understrege de relative afstande mellem tokens**, hvilket er afgørende for at forstå mange sproglige konstruktioner.

Relative Position Embeddings

For at fange sprogets dynamiske karakter blev relative positionsindlejringer introduceret, med fokus på afstanden mellem tokens frem for deres absolutte positioner. På trods af deres konceptuelle fordel introducerede disse indlejringer beregningskompleksitet, og de formåede ikke at integreres problemfrit i Transformerss selvopmærksomhedsmekanisme, hvilket begrænsede deres effektivitet.

ROFORMER og Rotary Position Embedding

I erkendelse af begrænsningerne ved eksisterende positionsindkodningsstrategier introducerer ROFORMER Rotary Position Embedding (RoPE), en tilgang, der kombinerer fordelene ved absolut og relativ positionsinformation uden deres respektive ulemper.

Indlejring af roterende position

RoPE koder positionsinformation ved hjælp af rotationsmatricer, hvilket gør det muligt for modellen ikke blot at forstå, hvor et token er, men hvordan det relaterer til hvert andet token i en sekvens.

Reformer.pngCredit: ArXiv

Den opererer gennem en geometrisk linse, der behandler token-positioner som punkter i et multidimensionelt rum, der roteres for at markere deres sekventielle forhold. Denne rotation gør det muligt for modellen at bevare og udnytte både absolutte og relative positionelle signaler inden for dens selvopmærksomhedsmekanisme.

Implementering af RoPE

Implementering af RoPE involverer indkodning af hver tokens position til en rotationsmatrix og anvendelse af denne matrix inden for transformatorens selvopmærksomhedsmekanisme. Denne proces giver mulighed for en fleksibel, dynamisk fortolkning af positionsinformation, der rummer varierende sekvenslængder og fanger essensen af ​​token-sammenhænge uden væsentlige beregningsmæssige overhead.

Først skal du bruge en funktion til at generere de roterende indlejringer, og derefter skal du integrere disse indlejringer i din model. Eksemplet nedenfor antager, at du er bekendt med at oprette brugerdefinerede lag i Keras.

Trin 1: Definer Rotary Embedding-funktionen

Denne funktion genererer de roterende indlejringer givet den maksimale sekvenslængde og dimensionaliteten af ​​indlejringerne.

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))

Denne linje beregner den inverse af eksponentielt skalerede frekvenser baseret på positionsindekserne. Disse frekvenser bruges til at generere sinusformede mønstre til roterende indlejringer, hvilket hjælper med at indkode den relative positionsinformation i sekvenser. Denne mekanisme er især nyttig i opgaver, hvor det er afgørende at forstå rækkefølgen og den relative placering af elementer, såsom i naturlig sprogbehandling eller tidsserieanalyse.

I detaljer:

  • tf.range(0, dim, 2, dtype=tf.float32) opretter et interval af værdier, der starter fra 0 op til dim (eksklusivt), trinvis 2. Argumentet dtype=tf.float32 specificerer at elementerne i denne tensor er 32-bit flydende kommatal. Hvis "dim" er 8, for eksempel, vil dette producere "[0, 2, 4, 6]".

  • Tensoren produceret af tf.range divideres derefter med dimensionaliteten (dim) af indlejringerne. Denne operation skalerer disse indekser ned til et interval mellem 0 og 1 (eksklusivt hvis 'dim' er lige, lidt inklusive hvis 'dim' er ulige, fordi intervaltrinnet springer hver anden værdi over). Hvis du fortsætter eksemplet med "dim" = 8, dividerer du med 8, får du "[0,0, 0,25, 0,5, 0,75]".

  • Operationen 10000 ** (...) hæver 10.000 til styrken af ​​hvert element i den tidligere skalerede tensor. Basen på 10.000 er noget vilkårlig, men er valgt for at sikre, at frekvenserne varierer over et bredt område, hvilket hjælper modellen til at differentiere mellem forskellige positioner mere effektivt. For [0.0, 0.25, 0.5, 0.75] vil den anvende effektdriften til hver, hvilket resulterer i meget større værdier for højere elementer.

  • Til sidst opnås den inverse frekvens ved at tage den reciproke (1/x) af værdierne fra det foregående trin. De omvendte frekvenser er mindre for højere indekser, hvilket betyder, at elementer længere i sekvensen vil have mindre frekvenser, hvilket påvirker, hvordan deres positioner indkodes i modellen. Dette gør det muligt for indlejringerne at skalere på en måde, hvor relative positioner kan udledes gennem modellens opmærksomhedsmekanismer.

Linjen:

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

bruger TensorFlows tf.einsum-funktion, et værktøj, der giver mulighed for kortfattet og effektivt udtryk for tensor-operationer ved hjælp af Einstein-summeringsnotationen.

Denne operation beregner effektivt det ydre produkt af "t" og "inv_freq" vektorerne, hvilket resulterer i en matrix, hvor hvert element "(i, j)" er produktet af "i"-te element af "t" og " j-te element af inv_freq`. Denne matrix ("freqs") repræsenterer de frekvenser, der bruges til at generere de sinusformede mønstre for de roterende indlejringer.

Trin 2: Brugerdefineret Keras-lag til roterende indlejringer

Lad os nu oprette et brugerdefineret Keras-lag, der anvender roterende indlejringer på inputtensoren. Dette lag antager, at inputtensoren har formen "(batch_size, sequence_length, embedding_dim)".

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

Linjen embeddings = self.rotary_embeddings[:seq_len] vælger det passende undersæt af forudberegnet roterende indlejringer baseret på den aktuelle inputsekvenslængde. Da længden af ​​sekvenser kan variere fra en batch til en anden, sikrer denne udskæringsoperation, at kun de indlejringer, der svarer til den faktiske sekvenslængde, bruges.

Variablen 'embeddings' har nu en tensor af form '(seq_len, embedding_dim)', hvor 'seq_len' er længden af ​​sekvenserne i den aktuelle batch, og 'embedding_dim' er dimensionaliteten af ​​indlejringerne. Denne tensor indeholder de roterende positionelle indlejringer for hver position i sekvensen op til seq_len.

emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) kombinerer sinus- og cosinustransformationer af positionsfrekvenser til en enkelt tensor:

-tf.cos(freqs) og tf.sin(freqs) anvender henholdsvis cosinus- og sinustransformationerne til freqs-tensoren. "freqs"-tensoren indeholder frekvensværdier for hver position i inputsekvensen og hver dimension af indlejringsrummet, beregnet ud fra sekvenspositionerne og de inverse frekvenser af indlejringsdimensionerne. Sinus- og cosinusfunktionerne anvendes elementmæssigt, hvilket resulterer i to tensorer med samme form som "freqs". Disse transformationer hjælper med at indkode positionen på en måde, der fanger den cykliske karakter af positionsrelationer, hvilket letter modellens evne til at forstå relative positioner.

-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) sammenkæder de cosinus- og sinustransformerede tensorer langs den sidste akse (angivet med akse=-1). Sammenkædning af disse tensorer side om side fordobler effektivt dimensionaliteten af ​​"freqs"-tensoren, hvor den første halvdel repræsenterer cosinus-transformerede værdier og den anden halvdel repræsenterer sinus-transformerede værdier for hver position. Sammenkædningen sikrer, at hver positionsindkodning indeholder både sinus- og cosinusinformation, hvilket muliggør bevarelse af information om både amplitude og fase af positionssignalerne.

  • Den sammenkædede tensor 'emb' holder nu de komplette roterende indlejringer til inputpositionerne. Formen på "emb" vil være den samme som "freqs" i de to første dimensioner (svarende til sekvenspositioner og indlejringsdimensioner), men dens sidste dimension vil være dobbelt så stor, hvilket tager højde for både sinus- og cosinusværdier. Disse indlejringer bruges til at modulere inputindlejringerne ved at tilføje positionsinformation på en rotationsækvivariant måde.

-cos_emb = indlejringer[:, Ingen, :self.dim // 2]:

  1. Det første kolon : betyder "vælg alle elementer i denne dimension", som i dette tilfælde refererer til alle positioner i sekvensen.

  2. Ingen bruges til at tilføje en ekstra dimension, hvilket gør tensoren 3-dimensionel. Dette gøres ofte for at sikre kompatibilitet med visse operationer, der forventer input af et bestemt antal dimensioner. For eksempel, når du udfører element-vis multiplikation med en anden tensor, der er 3-dimensionel, skal formerne justeres i henhold til udsendelsesregler.

  3. :self.dim // 2, vælger den første halvdel af dimensionerne i den sidste akse. Da indlejringsdimensionen er fordoblet til at inkludere både sinus- og cosinusværdier, vælger dividering med 2 effektivt kun cosinuskomponenterne af indlejringerne.

Trin 3: Integration med en Keras-model

Efter at have defineret RotaryEmbeddingLayer, kan du integrere det i din Keras-model. Dette lag skal påføres dine indlejringer, før de føres ind i opmærksomhedslag eller eventuelle efterfølgende modellag.

Her er et forenklet eksempel på, hvordan man integrerer de roterende indlejringer i en model:

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 rettigheder forbeholdes.