RoFormer: transformador millorat amb incrustació de posició rotativa

RoFormer: transformador millorat amb incrustació de posició rotativa

Els models basats en transformadors són famosos per la seva capacitat per analitzar i interpretar textos complexos. Es basen en la comprensió de l'ordre i el context de les paraules, tasques en què els mètodes tradicionals de codificació posicional han mostrat els seus límits. Per abordar aquesta bretxa, el model ROFORMER, impulsat per l'Rotary Position Embedding (RoPE), redefineix el nostre enfocament de la codificació posicional.

Codificació posicional tradicional

Els transformadors tracten el text com una sèrie de fitxes i permeten el processament paral·lel de seqüències per a una major eficiència. No obstant això, aquesta força va comportar el seu repte: l'agnosticisme inherent del model a l'ordre simbòlic. Codificació posicional va ser la resposta, proporcionant a cada testimoni una signatura única que denota la seva posició de seqüència.

Incrustacions de posició absoluta

Inicialment, models com BERT utilitzaven incrustacions de posició absoluta, assignant un vector fix a cada posició en una seqüència. Aquest mètode, tot i que senzill, inherentment no té la capacitat d'adaptar-se a les variacions de la longitud de la seqüència, o d'emfatitzar les distàncies relatives entre fitxes, fonamental per entendre molts constructes lingüístics.

Incrustacions de posició relativa

Per capturar la naturalesa dinàmica del llenguatge, es van introduir incrustacions de posició relativa, centrant-se en la distància entre fitxes en lloc de les seves posicions absolutes. Malgrat el seu avantatge conceptual, aquestes integracions van introduir complexitat computacional i no es van integrar perfectament en el mecanisme d'autoatenció de Transformers, limitant la seva eficàcia.

ROFORMER i incrustació de posicions rotatives

Reconeixent les limitacions de les estratègies de codificació posicional existents, ROFORMER introdueix Rotary Position Embedding (RoPE), un enfocament que combina els avantatges de la informació de posició absoluta i relativa sense els seus respectius inconvenients.

Incrustació de posició rotativa

RoPE codifica la informació de posició mitjançant matrius de rotació, cosa que permet al model entendre no només on és un testimoni, sinó com es relaciona amb tots els altres testimonis d'una seqüència.

Reformer.pngCredit: ArXiv

Funciona a través d'una lent geomètrica, tractant les posicions de fitxes com a punts en un espai multidimensional que es giren per marcar les seves relacions seqüencials. Aquesta rotació permet al model preservar i explotar indicis posicionals absoluts i relatius dins del seu mecanisme d'autoatenció.

Implementació de RoPE

La implementació de RoPE implica codificar la posició de cada testimoni en una matriu de rotació i aplicar aquesta matriu dins del mecanisme d'autoatenció del transformador. Aquest procés permet una interpretació flexible i dinàmica de la informació posicional, adaptant-se a longituds de seqüències variables i capturant l'essència de les interrelacions de testimonis sense una sobrecàrrega computacional significativa.

Primer, necessitareu una funció per generar les incrustacions rotatives i, a continuació, integrareu aquestes incrustacions al vostre model. L'exemple següent suposa que esteu familiaritzat amb la creació de capes personalitzades a Keras.

Pas 1: Definiu la funció d'inserció rotativa

Aquesta funció genera les incrustacions rotatives donada la longitud màxima de la seqüència i la dimensionalitat de les incrustacions.

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

Aquesta línia calcula la inversa de les freqüències escalades exponencialment en funció dels índexs de posició. Aquestes freqüències s'utilitzen per generar patrons sinusoïdals per a incrustacions rotatives, cosa que ajuda a codificar la informació de posició relativa en seqüències. Aquest mecanisme és especialment útil en tasques on la comprensió de l'ordre i el posicionament relatiu dels elements és crucial, com ara el processament del llenguatge natural o l'anàlisi de sèries temporals.

En detalls:

  • tf.range(0, dim, 2, dtype=tf.float32) crea un rang de valors des de 0 fins a dim (exclusiu), avançant en 2. L'argument dtype=tf.float32 especifica que els elements d'aquest tensor són nombres de coma flotant de 32 bits. Si "dim" és 8, per exemple, això produiria "[0, 2, 4, 6]".

  • El tensor produït per tf.range es divideix llavors per la dimensionalitat (dim) de les incrustacions. Aquesta operació redueix aquests índexs a un rang entre 0 i 1 (exclusiu si dim és parell, lleugerament inclòs si dim és senar, perquè el pas d'interval salta tots els altres valors). Continuant amb l'exemple amb dim = 8, dividint per 8 s'obté [0,0, 0,25, 0,5, 0,75].

  • L'operació 10000 ** (...) eleva 10.000 a la potència de cada element del tensor escalat anteriorment. La base de 10.000 és una mica arbitrària, però s'escull per garantir que les freqüències varien en un ampli rang, la qual cosa ajuda el model a diferenciar les diferents posicions de manera més eficaç. Per a [0,0, 0,25, 0,5, 0,75], aplicaria l'operació de potència a cadascun, donant lloc a valors molt més grans per als elements superiors.

  • Finalment, la freqüència inversa s'obté prenent la recíproca (1/x) dels valors del pas anterior. Les freqüències inverses són més petites per als índexs més alts, és a dir, els elements més enllà de la seqüència tindran freqüències més petites, afectant com es codifiquen les seves posicions al model. Això permet que les incrustacions s'escalin de manera que es puguin inferir posicions relatives mitjançant els mecanismes d'atenció del model.

La línia:

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

utilitza la funció tf.einsum de TensorFlow, una eina que permet l'expressió concisa i eficient de les operacions de tensor mitjançant la notació de suma d'Einstein.

Aquesta operació calcula eficaçment el producte exterior dels vectors t i inv_freq, donant com a resultat una matriu on cada element (i, j) és el producte de l'element i-è de t i el j-èm element de inv_freq. Aquesta matriu ('freqs') representa les freqüències que s'utilitzen per generar els patrons sinusoïdals per a les incrustacions rotatives.

Pas 2: Capa Keras personalitzada per a incrustacions rotatives

Ara, creem una capa Keras personalitzada que aplique incrustacions rotatives al tensor d'entrada. Aquesta capa suposa que el tensor d'entrada té la forma `(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

La línia embeddings = self.rotary_embeddings[:seq_len] selecciona el subconjunt adequat d'embeddings rotatius precalculats en funció de la longitud de la seqüència d'entrada actual. Atès que la longitud de les seqüències pot variar d'un lot a un altre, aquesta operació de tall garanteix que només s'utilitzen les incrustacions corresponents a la longitud real de la seqüència.

La variable embeddings ara conté un tensor de forma (seq_len, embedding_dim), on seq_len és la longitud de les seqüències del lot actual, i embedding_dim és la dimensionalitat de les incrustacions. Aquest tensor conté les incrustacions posicionals rotatives per a cada posició de la seqüència fins a seq_len.

emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) combina transformacions sinus i cosinus de freqüències posicionals en un sol tensor:

-tf.cos(freqs) i tf.sin(freqs) apliquen les transformacions cosinus i sinus, respectivament, al tensor freqs. El tensor "freqüències" conté valors de freqüència per a cada posició de la seqüència d'entrada i cada dimensió de l'espai d'incrustació, calculats a partir de les posicions de la seqüència i de les freqüències inverses de les dimensions d'incrustació. Les funcions sinus i cosinus s'apliquen per elements, donant com a resultat dos tensors de la mateixa forma que freqs. Aquestes transformacions ajuden a codificar la posició d'una manera que captura la naturalesa cíclica de les relacions posicionals, facilitant la capacitat del model d'entendre les posicions relatives.

-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) concatena els tensors transformats cosinus i sinus al llarg de l'últim eix (indicat per axis=-1). La concatenació d'aquests tensors un al costat de l'altre duplica efectivament la dimensionalitat del tensor "freqs", amb la primera meitat que representa valors transformats en cosinus i la segona meitat representants valors transformats en sinus per a cada posició. La concatenació garanteix que cada codificació posicional contingui informació tant de sinus com de cosinus, la qual cosa permet conservar la informació tant sobre l'amplitud com la fase dels senyals posicionals.

  • El tensor concatenat emb ara conté les incrustacions rotatives completes per a les posicions d'entrada. La forma de "emb" serà la mateixa que "freqs" en les seves dues primeres dimensions (corresponent a les posicions de la seqüència i les dimensions d'incrustació), però la seva darrera dimensió serà el doble de gran, tenint en compte tant els valors del sinus com del cosinus. Aquestes incrustacions s'utilitzen per modular les incrustacions d'entrada afegint informació posicional d'una manera equivariant rotacionalment.

-cos_emb = incrustacions[:, Cap, :self.dim // 2]:

  1. El primer dos punts : significa "selecciona tots els elements d'aquesta dimensió", que, en aquest cas, es refereix a totes les posicions de la seqüència.

  2. "Cap" s'utilitza per afegir una dimensió addicional, fent que el tensor sigui tridimensional. Això es fa sovint per garantir la compatibilitat amb determinades operacions que esperen entrades d'un nombre específic de dimensions. Per exemple, quan es realitza la multiplicació d'elements amb un altre tensor que és tridimensional, les formes s'han d'alinear segons les regles de difusió.

  3. :self.dim // 2, selecciona la primera meitat de les dimensions a l'últim eix. Atès que la embedding_dimension es duplica per incloure els valors tant del sinus com del cosinus, dividir per 2 selecciona efectivament només els components del cosinus de les incrustacions.

Pas 3: Integració amb un model Keras

Després de definir el "RotaryEmbeddingLayer", podeu integrar-lo al vostre model Keras. Aquesta capa s'ha d'aplicar a les incrustacions abans d'introduir-les en capes d'atenció o capes de model posteriors.

Aquí teniu un exemple simplificat de com integrar les incrustacions rotatives en un 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 Tots els drets reservats.