ROFORMER: TRANSFORMADOR MEJORADO CON EMPOTRAR EN POSICIÓN GIRATORIA

ROFORMER: TRANSFORMADOR MEJORADO CON EMPOTRAR EN POSICIÓN GIRATORIA

Los modelos basados ​​en transformadores son famosos por su capacidad para analizar e interpretar textos complejos. Se basan en la comprensión del orden y el contexto de las palabras, tareas en las que los métodos tradicionales de codificación posicional han mostrado sus límites. Para abordar esta brecha, el modelo ROFORMER, impulsado por Rotary Position Embedding (RoPE), redefine nuestro enfoque de codificación posicional.

Codificación posicional tradicional

Los transformadores tratan el texto como una serie de tokens y permiten procesamiento paralelo de secuencias para una mayor eficiencia. Sin embargo, esta fortaleza trajo su desafío: el agnosticismo inherente del modelo al orden simbólico. Codificación posicional fue la respuesta, proporcionando a cada token una firma única que denota su posición en la secuencia.

Incrustaciones de posición absoluta

Inicialmente, modelos como BERT usaban incrustaciones de posiciones absolutas, asignando un vector fijo a cada posición en una secuencia. Este método, aunque sencillo, inherentemente carece de la capacidad de adaptarse a las variaciones en la longitud de la secuencia o de enfatizar las distancias relativas entre tokens, algo fundamental para comprender muchas construcciones lingüísticas.

Incrustaciones de posición relativa

Para capturar la naturaleza dinámica del lenguaje, se introdujeron incorporaciones de posiciones relativas, centrándose en la distancia entre tokens en lugar de sus posiciones absolutas. A pesar de su ventaja conceptual, estas incorporaciones introdujeron complejidad computacional y no lograron integrarse perfectamente en el mecanismo de autoatención de Transformers, lo que limitó su eficacia.

ROFORMER e incrustación de posición rotativa

Al reconocer las limitaciones de las estrategias de codificación posicional existentes, ROFORMER presenta la incrustación de posición rotativa (RoPE), un enfoque que combina los beneficios de la información de posición absoluta y relativa sin sus respectivos inconvenientes.

Incrustación de posición rotativa

RoPE codifica información posicional utilizando matrices de rotación, lo que permite que el modelo comprenda no solo dónde está un token, sino también cómo se relaciona con todos los demás tokens en una secuencia.

Reformer.pngCredit: Original Paper

Opera a través de una lente geométrica, tratando las posiciones de los tokens como puntos en un espacio multidimensional que giran para marcar sus relaciones secuenciales. Esta rotación permite al modelo preservar y explotar señales posicionales tanto absolutas como relativas dentro de su mecanismo de autoatención.

Implementación de RoPE

La implementación de RoPE implica codificar la posición de cada token en una matriz de rotación y aplicar esta matriz dentro del mecanismo de autoatención del Transformer. Este proceso permite una interpretación flexible y dinámica de la información posicional, acomodando longitudes de secuencia variables y capturando la esencia de las interrelaciones de tokens sin una sobrecarga computacional significativa.

Primero, necesitará una función para generar las incrustaciones rotativas y luego integrará estas incrustaciones en su modelo. El siguiente ejemplo supone que está familiarizado con la creación de capas personalizadas en Keras.

Paso 1: Definir la función de incrustación rotativa

Esta función genera las incrustaciones rotativas dada la longitud máxima de secuencia y la dimensionalidad de las incrustaciones.

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

Esta línea calcula la inversa de las frecuencias escaladas exponencialmente en función de los índices de posición. Estas frecuencias se utilizan para generar patrones sinusoidales para incrustaciones rotativas, lo que ayuda a codificar la información posicional relativa en secuencias. Este mecanismo es particularmente útil en tareas donde la comprensión del orden y la posición relativa de los elementos es crucial, como en el procesamiento del lenguaje natural o el análisis de series temporales.

En detalles:

  • tf.range(0, dim, 2, dtype=tf.float32) crea un rango de valores desde 0 hasta dim (exclusivo), pasando a 2. El argumento dtype=tf.float32 especifica que los elementos de este tensor son números de punto flotante de 32 bits. Si "dim" es 8, por ejemplo, esto produciría "[0, 2, 4, 6]".

  • El tensor producido por tf.range se divide luego por la dimensionalidad (dim) de las incrustaciones. Esta operación reduce estos índices a un rango entre 0 y 1 (exclusivo si "dim" es par, ligeramente inclusivo si "dim" es impar, porque el paso del rango omite todos los demás valores). Continuando con el ejemplo con dim = 8, dividir por 8 produce [0.0, 0.25, 0.5, 0.75].

  • La operación 10000**(...) eleva 10.000 a la potencia de cada elemento en el tensor previamente escalado. La base de 10.000 es algo arbitraria, pero se elige para garantizar que las frecuencias varíen en un amplio rango, lo que ayuda al modelo a diferenciar entre diferentes posiciones de manera más efectiva. Para "[0,0, 0,25, 0,5, 0,75]", aplicaría la operación de potencia a cada uno, lo que daría como resultado valores mucho mayores para elementos superiores.

  • Finalmente, la frecuencia inversa se obtiene tomando el recíproco (1/x) de los valores del paso anterior. Las frecuencias inversas son más pequeñas para índices más altos, lo que significa que los elementos más adelante en la secuencia tendrán frecuencias más pequeñas, lo que afecta la forma en que se codifican sus posiciones en el modelo. Esto permite que las incrustaciones se escalen de una manera en la que se puedan inferir posiciones relativas a través de los mecanismos de atención del modelo.

La línea:

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

utiliza la función tf.einsum de TensorFlow, una herramienta que permite la expresión concisa y eficiente de operaciones tensoriales utilizando la notación de suma de Einstein.

Esta operación calcula efectivamente el producto externo de los vectores t e inv_freq, lo que da como resultado una matriz donde cada elemento (i, j) es el producto del i-ésimo elemento de t y el j-ésimo elemento de inv_freq. Esta matriz ("freqs") representa las frecuencias que se utilizan para generar los patrones sinusoidales para las incrustaciones rotativas.

Paso 2: Capa Keras personalizada para incrustaciones rotativas

Ahora, creemos una capa de Keras personalizada que aplique incrustaciones rotativas al tensor de entrada. Esta capa supone que el tensor de entrada tiene la forma (batch_size, secuencia_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ínea embeddings = self.rotary_embeddings[:seq_len] selecciona el subconjunto apropiado de incrustaciones rotativas precalculadas en función de la longitud de la secuencia de entrada actual. Dado que la longitud de las secuencias puede variar de un lote a otro, esta operación de corte garantiza que solo se utilicen las incrustaciones correspondientes a la longitud real de la secuencia.

La variable incrustaciones ahora contiene un tensor de forma (seq_len, embedding_dim), donde seq_len es la longitud de las secuencias en el lote actual y embedding_dim es la dimensionalidad de las incrustaciones. Este tensor contiene las incrustaciones posicionales rotativas para cada posición en la secuencia hasta seq_len.

emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) combina transformaciones de seno y coseno de frecuencias posicionales en un solo tensor:

-tf.cos(freqs) y tf.sin(freqs) aplican las transformaciones coseno y seno, respectivamente, al tensor freqs. El tensor freqs contiene valores de frecuencia para cada posición en la secuencia de entrada y cada dimensión del espacio de incrustación, calculados en función de las posiciones de la secuencia y las frecuencias inversas de las dimensiones de incrustación. Las funciones seno y coseno se aplican elemento por elemento, lo que da como resultado dos tensores de la misma forma que "freqs". Estas transformaciones ayudan a codificar la posición de una manera que captura la naturaleza cíclica de las relaciones posicionales, facilitando la capacidad del modelo para comprender posiciones relativas.

-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) concatena los tensores transformados en coseno y seno a lo largo del último eje (indicado por axis=-1). La concatenación de estos tensores uno al lado del otro duplica efectivamente la dimensionalidad del tensor de "frecuencias": la primera mitad representa valores transformados en coseno y la segunda mitad representa valores transformados en seno para cada posición. La concatenación asegura que cada codificación posicional contenga información tanto de seno como de coseno, lo que permite la preservación de información sobre la amplitud y la fase de las señales posicionales.

  • El tensor concatenado emb ahora contiene las incrustaciones rotativas completas para las posiciones de entrada. La forma de "emb" será la misma que "freqs" en sus dos primeras dimensiones (correspondientes a posiciones de secuencia y dimensiones de incrustación), pero su última dimensión será dos veces más grande, teniendo en cuenta los valores de seno y coseno. Estas incorporaciones se utilizan para modular las incorporaciones de entrada agregando información posicional de una manera rotacionalmente equivariante.

-cos_emb = incrustaciones[:, Ninguna, :self.dim // 2]:

  1. Los primeros dos puntos : significan "seleccionar todos los elementos en esta dimensión", que, en este caso, se refiere a todas las posiciones en la secuencia.

  2. "Ninguno" se utiliza para agregar una dimensión adicional, haciendo que el tensor sea tridimensional. Esto suele hacerse para garantizar la compatibilidad con determinadas operaciones que esperan entradas de un número específico de dimensiones. Por ejemplo, al realizar una multiplicación de elementos con otro tensor tridimensional, las formas deben alinearse de acuerdo con las reglas de transmisión.

  3. :self.dim // 2, selecciona la primera mitad de las dimensiones en el último eje. Dado que embedding_dimension se duplica para incluir valores de seno y coseno, dividir entre 2 selecciona efectivamente solo los componentes coseno de las incrustaciones.

Paso 3: Integración con un modelo Keras

Después de definir RotaryEmbeddingLayer, puede integrarlo en su modelo de Keras. Esta capa debe aplicarse a sus incrustaciones antes de introducirlas en las capas de atención o en cualquier capa de modelo posterior.

A continuación se muestra un ejemplo simplificado de cómo integrar las incrustaciones rotativas en un modelo:

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 Todos los derechos reservados.