ROFORMER: VERBETERDE TRANSFORMATOR MET DRAAIPOSITIE-INBEDDING

ROFORMER: VERBETERDE TRANSFORMATOR MET DRAAIPOSITIE-INBEDDING

Op Transformer gebaseerde modellen staan ​​bekend om hun vermogen om complexe tekst te ontleden en te interpreteren. Ze vertrouwen op het begrijpen van de volgorde en context van woorden – taken waarbij traditionele positionele coderingsmethoden hun grenzen hebben laten zien. Door deze leemte aan te pakken, herdefinieert het ROFORMER-model, mogelijk gemaakt door de Rotary Position Embedding (RoPE), onze benadering van positionele codering.

Traditionele positionele codering

Transformers behandelen tekst als een reeks tokens en maken parallelle verwerking van reeksen mogelijk voor grotere efficiëntie. Deze kracht bracht echter ook een uitdaging met zich mee: het model's inherente agnosticisme tegenover symbolische orde. Positionele codering was het antwoord, waardoor elk token een unieke handtekening kreeg die de positie van de reeks aangeeft.

Absolute positie-inbedding

Aanvankelijk gebruikten modellen zoals BERT absolute positie-inbedding, waarbij aan elke positie in een reeks een vaste vector werd toegewezen. Deze methode, hoewel eenvoudig, mist inherent het vermogen om zich aan te passen aan variaties in de lengte van de reeks, of om de relatieve afstanden tussen tokens te benadrukken**, wat van cruciaal belang is voor het begrijpen van veel taalkundige constructies.

Relatieve positie-inbedding

Om de dynamische aard van taal vast te leggen, werden relatieve positie-inbedding geïntroduceerd, waarbij de nadruk lag op de afstand tussen tokens in plaats van op hun absolute posities. Ondanks hun conceptuele voordeel introduceerden deze inbeddingen computationele complexiteit, en slaagden ze er niet in naadloos te integreren in het zelfaandachtsmechanisme van Transformers, waardoor hun doeltreffendheid werd beperkt.

ROFORMER en roterende positie-inbedding

ROFORMER erkent de beperkingen van bestaande positionele coderingsstrategieën en introduceert Rotary Position Embedding (RoPE), een benadering die de voordelen van absolute en relatieve positie-informatie combineert zonder de respectieve nadelen ervan.

Roterende positie inbedden

RoPE codeert positionele informatie met behulp van rotatiematrices, waardoor het model niet alleen begrijpt waar een token zich bevindt, maar ook hoe deze zich verhoudt tot elk ander token in een reeks.

Reformer.pngCredit: Original Paper

Het werkt via een geometrische lens en behandelt symbolische posities als punten in een multidimensionale ruimte die worden geroteerd om hun opeenvolgende relaties te markeren. Door deze rotatie kan het model zowel absolute als relatieve positionele signalen behouden en exploiteren binnen zijn zelfaandachtsmechanisme.

RoPE implementeren

Het implementeren van RoPE omvat het coderen van de positie van elk token in een rotatiematrix, en het toepassen van deze matrix binnen het zelfaandachtsmechanisme van de Transformer. Dit proces maakt een flexibele, dynamische interpretatie van positionele informatie mogelijk, waarbij verschillende sequentielengtes worden geaccommodeerd en de essentie van token-interrelaties wordt vastgelegd zonder noemenswaardige computeroverhead.

Eerst hebt u een functie nodig om de roterende insluitingen te genereren, en vervolgens integreert u deze insluitingen in uw model. In het onderstaande voorbeeld wordt ervan uitgegaan dat u bekend bent met het maken van aangepaste lagen in Keras.

Stap 1: Definieer de roterende inbeddingsfunctie

Deze functie genereert de roterende inbedding op basis van de maximale sequentielengte en de dimensionaliteit van de inbedding.

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

Deze lijn berekent de inverse van exponentieel geschaalde frequenties op basis van de positie-indices. Deze frequenties worden gebruikt bij het genereren van sinusoïdale patronen voor roterende inbedding, wat helpt bij het coderen van de relatieve positionele informatie in reeksen. Dit mechanisme is vooral nuttig bij taken waarbij het begrijpen van de volgorde en de relatieve positionering van elementen cruciaal is, zoals bij natuurlijke taalverwerking of tijdreeksanalyse.

In detail:

  • tf.range(0, dim, 2, dtype=tf.float32) creëert een bereik van waarden beginnend bij 0 tot dim (exclusief), stapsgewijs met 2. Het argument dtype=tf.float32 specificeert dat de elementen van deze tensor 32-bit drijvende-kommagetallen zijn. Als dim bijvoorbeeld 8 is, zou dit [0, 2, 4, 6] opleveren.

  • De door tf.range geproduceerde tensor wordt vervolgens gedeeld door de dimensionaliteit (dim) van de inbedding. Deze bewerking schaalt deze indices terug naar een bereik tussen 0 en 1 (exclusief als 'dim' even is, enigszins inclusief als 'dim' oneven is, omdat de bereikstap elke andere waarde overslaat). Als we het voorbeeld voortzetten met dim = 8, levert delen door 8 [0,0, 0,25, 0,5, 0,75] op.

  • De bewerking 10000 ** (...) verhoogt 10.000 tot de macht van elk element in de eerder geschaalde tensor. De basis van 10.000 is enigszins willekeurig, maar is gekozen om ervoor te zorgen dat de frequenties over een groot bereik variëren, waardoor het model effectiever onderscheid kan maken tussen verschillende posities. Voor '[0,0, 0,25, 0,5, 0,75]' zou het de machtsbewerking op elk toepassen, wat resulteert in waarden die veel groter zijn voor hogere elementen.

  • Ten slotte wordt de inverse frequentie verkregen door het omgekeerde (1/x) van de waarden uit de vorige stap te nemen. De inverse frequenties zijn kleiner voor hogere indices, wat betekent dat elementen verder in de reeks kleinere frequenties zullen hebben, wat van invloed is op de manier waarop hun posities in het model worden gecodeerd. Hierdoor kunnen de inbeddingen worden geschaald op een manier waarbij relatieve posities kunnen worden afgeleid via de aandachtsmechanismen van het model.

De lijn:

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

maakt gebruik van de tf.einsum-functie van TensorFlow, een hulpmiddel dat een beknopte en efficiënte uitdrukking van tensorbewerkingen mogelijk maakt met behulp van de Einstein-sommatienotatie.

Deze bewerking berekent effectief het buitenste product van de vectoren t en inv_freq, resulterend in een matrix waarin elk element (i, j) het product is van het i-de element van t en de j-de element van inv_freq. Deze matrix ("freqs") vertegenwoordigt de frequenties die worden gebruikt om de sinusoïdale patronen voor de roterende inbedding te genereren.

Stap 2: Aangepaste Keras-laag voor roterende insluitingen

Laten we nu een aangepaste Keras-laag maken die roterende inbedding toepast op de invoertensor. Deze laag gaat ervan uit dat de invoertensor de vorm '(batch_size, sequence_length, embedding_dim)' heeft.

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

De regel `embeddings = self.rotary_embeddings[:seq_len]' selecteert de juiste subset van vooraf berekende roterende insluitingen op basis van de huidige lengte van de invoerreeks. Omdat de lengte van sequenties van batch tot batch kan variëren, zorgt deze snijbewerking ervoor dat alleen de inbedding die overeenkomt met de feitelijke sequentielengte worden gebruikt.

De variabele 'embeddings' bevat nu een tensor van vorm '(seq_len, embedding_dim)', waarbij 'seq_len' de lengte is van de reeksen in de huidige batch, en 'embedding_dim' de dimensionaliteit van de inbedding is. Deze tensor bevat de roterende positionele inbedding voor elke positie in de reeks tot aan seq_len.

emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) combineert sinus- en cosinustransformaties van positionele frequenties in een enkele tensor:

-tf.cos(freqs) en tf.sin(freqs) passen respectievelijk de cosinus- en sinustransformaties toe op de freqs-tensor. De 'freqs'-tensor bevat frequentiewaarden voor elke positie in de invoerreeks en elke dimensie van de inbeddingsruimte, berekend op basis van de reeksposities en de inverse frequenties van de inbeddingsdimensies. De sinus- en cosinusfuncties worden elementair toegepast, wat resulteert in twee tensoren met dezelfde vorm als freqs. Deze transformaties helpen bij het coderen van de positie op een manier die de cyclische aard van positionele relaties vastlegt, waardoor het vermogen van het model om relatieve posities te begrijpen wordt vergemakkelijkt.

-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) voegt de cosinus- en sinus-getransformeerde tensoren aan elkaar langs de laatste as (aangegeven met axis=-1). Het naast elkaar aaneenschakelen van deze tensoren verdubbelt effectief de dimensionaliteit van de 'freqs'-tensor, waarbij de eerste helft cosinus-getransformeerde waarden vertegenwoordigt en de tweede helft sinus-getransformeerde waarden voor elke positie vertegenwoordigt. De aaneenschakeling zorgt ervoor dat elke positionele codering zowel sinus- als cosinusinformatie bevat, waardoor informatie over zowel de amplitude als de fase van de positionele signalen behouden blijft.

  • De aaneengeschakelde tensor emb bevat nu de volledige roterende inbedding voor de invoerposities. De vorm van 'emb' zal hetzelfde zijn als 'freqs' in de eerste twee dimensies (overeenkomend met reeksposities en inbeddingsdimensies), maar de laatste dimensie zal twee keer zo groot zijn, rekening houdend met zowel sinus- als cosinuswaarden. Deze inbedding wordt gebruikt om de invoerinbedding te moduleren door positionele informatie op een rotatie-equivariante manier toe te voegen.

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

  1. De eerste dubbele punt : betekent 'selecteer alle elementen in deze dimensie', wat in dit geval verwijst naar alle posities in de reeks.

  2. 'Geen' wordt gebruikt om een ​​extra dimensie toe te voegen, waardoor de tensor driedimensionaal wordt. Dit wordt vaak gedaan om compatibiliteit te garanderen met bepaalde bewerkingen waarbij invoer van een specifiek aantal dimensies wordt verwacht. Wanneer u bijvoorbeeld elementgewijze vermenigvuldiging uitvoert met een andere tensor die driedimensionaal is, moeten de vormen worden uitgelijnd volgens de uitzendregels.

  3. :self.dim // 2, selecteert de eerste helft van de afmetingen in de laatste as. Omdat de 'inbeddingsdimensie' wordt verdubbeld om zowel sinus- als cosinuswaarden op te nemen, selecteert delen door 2 effectief alleen de cosinuscomponenten van de inbedding.

Stap 3: Integratie met een Keras-model

Nadat u de RotaryEmbeddingLayer hebt gedefinieerd, kunt u deze in uw Keras-model integreren. Deze laag moet op uw inbedding worden toegepast voordat u deze in aandachtslagen of eventuele volgende modellagen invoert.

Hier is een vereenvoudigd voorbeeld van hoe u de roterende inbedding in een model kunt integreren:

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 rechten voorbehouden.