RoFormer: Vylepšený transformátor s rotačním umístěním

RoFormer: Vylepšený transformátor s rotačním umístěním

Modely založené na transformátorech jsou známé svou schopností analyzovat a interpretovat složitý text. Spoléhají na pochopení pořadí a kontextu slov – úkoly, u kterých tradiční metody pozičního kódování ukázaly své limity. Model ROFORMER, poháněný Rotary Position Embedding (RoPE), řeší tuto mezeru a nově definuje náš přístup k pozičnímu kódování.

Tradiční poziční kódování

Transformátory zacházejí s textem jako s řadou tokenů a umožňují paralelní zpracování sekvencí pro větší efektivitu. Tato síla však přinesla svou výzvu: vrozený agnosticismus modelu k symbolickému řádu. Poziční kódování bylo odpovědí, poskytující každému tokenu jedinečný podpis označující jeho sekvenční pozici.

Absolutní pozice vložení

Zpočátku modely jako BERT používaly vložení absolutní pozice, přiřazující pevný vektor každé pozici v sekvenci. Tato metoda, i když je přímočará, ze své podstaty postrádá schopnost přizpůsobit se variacím délky sekvence nebo zdůraznit relativní vzdálenosti mezi tokeny, což je kritické pro pochopení mnoha lingvistických konstruktů.

Vložení relativní pozice

Aby byla zachycena dynamická povaha jazyka, bylo zavedeno vkládání relativních pozic, které se zaměřovalo spíše na vzdálenost mezi tokeny než na jejich absolutní pozice. Navzdory své koncepční výhodě tato vložení zavedla výpočetní složitost a nedokázala se hladce začlenit do mechanismu sebepozorování Transformers, což omezovalo jejich účinnost.

ROFORMER a vložení s rotační polohou

ROFORMER si uvědomuje omezení stávajících strategií pozičního kódování a zavádí Rotary Position Embedding (RoPE), přístup, který kombinuje výhody absolutní a relativní informace o poloze bez jejich příslušných nevýhod.

Otočné zapuštění

RoPE kóduje informace o poloze pomocí rotačních matic, což modelu umožňuje nejen porozumět tomu, kde se token nachází, ale také jak souvisí s každým dalším tokenem v sekvenci.

Reformer.pngCredit: ArXiv

Funguje prostřednictvím geometrické čočky a zachází s pozicemi tokenů jako s body ve vícerozměrném prostoru, které se otáčejí, aby označovaly jejich sekvenční vztahy. Tato rotace umožňuje modelu zachovat a využívat jak absolutní, tak relativní polohové podněty v rámci mechanismu sebepozorování.

Implementace RoPE

Implementace RoPE zahrnuje zakódování pozice každého tokenu do rotační matice a aplikaci této matice v rámci mechanismu sebepozorování Transformeru. Tento proces umožňuje flexibilní, dynamickou interpretaci pozičních informací, přizpůsobení se různým délkám sekvencí a zachycení podstaty vzájemných vztahů tokenů bez významné výpočetní režie.

Nejprve budete potřebovat funkci pro generování otočných vložení a poté tato vložení integrujete do svého modelu. Níže uvedený příklad předpokládá, že jste obeznámeni s vytvářením vlastních vrstev v Kerasu.

Krok 1: Definujte funkci Rotary Embedding

Tato funkce generuje rotační vložení při dané maximální délce sekvence a rozměrech vložení.

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

Tento řádek počítá inverzní hodnotu exponenciálně škálovaných frekvencí na základě pozičních indexů. Tyto frekvence se používají při generování sinusových vzorů pro rotační vkládání, což pomáhá při kódování relativních polohových informací v sekvencích. Tento mechanismus je zvláště užitečný v úlohách, kde je klíčové pochopení pořadí a relativního umístění prvků, jako je zpracování přirozeného jazyka nebo analýza časových řad.

V detailech:

  • tf.range(0, dim, 2, dtype=tf.float32) vytváří rozsah hodnot od 0 do dim (exkluzivní), krokování po 2. Argument dtype=tf.float32 určuje že prvky tohoto tenzoru jsou 32bitová čísla s plovoucí desetinnou čárkou. Pokud je dim například 8, výsledkem by bylo [0, 2, 4, 6].

  • Tenzor vytvořený tf.range je pak vydělen rozměrem (dim) vložení. Tato operace zmenší tyto indexy na rozsah mezi 0 a 1 (neplatí, pokud je „dim“ sudé, mírně zahrnuje, pokud je „dim“ liché, protože krok rozsahu přeskakuje každou další hodnotu). Pokračujeme-li v příkladu s dim = 8, po dělení 8 získáme [0,0, 0,25, 0,5, 0,75].

  • Operace 10000 ** (...) zvýší 10 000 na sílu každého prvku v dříve upraveném tenzoru. Základ 10 000 je poněkud libovolný, ale je zvolen tak, aby se frekvence měnily v širokém rozsahu, což modelu pomáhá efektivněji rozlišovat různé polohy. Pro [0.0, 0.25, 0.5, 0.75] by aplikoval výkonovou operaci na každý, což vedlo k mnohem větším hodnotám pro vyšší prvky.

  • Nakonec se inverzní frekvence získá převrácením (1/x) hodnot z předchozího kroku. Inverzní frekvence jsou menší pro vyšší indexy, což znamená, že prvky dále v sekvenci budou mít menší frekvence, což ovlivní, jak jsou jejich pozice zakódovány do modelu. To umožňuje vložením škálovat způsobem, kdy lze relativní polohy odvodit prostřednictvím mechanismů pozornosti modelu.

Linie:

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

používá funkci tf.einsum TensorFlow, nástroj, který umožňuje stručné a efektivní vyjádření tenzorových operací pomocí Einsteinovy ​​sumační notace.

Tato operace efektivně vypočítá vnější součin vektorů t a inv_freq. Výsledkem je matice, kde každý prvek (i, j) je součinem i-tého prvku t a j-tý prvek inv_freq. Tato matice ("freqs") představuje frekvence, které se používají ke generování sinusových vzorů pro rotační vestavby.

Krok 2: Vlastní vrstva Keras pro rotační vložení

Nyní vytvoříme vlastní vrstvu Keras, která aplikuje rotační vložení do vstupního tenzoru. Tato vrstva předpokládá, že vstupní tenzor má tvar (velikost_dávky, délka_sekvence, 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

Řádek embeddings = self.rotary_embeddings[:seq_len] vybere vhodnou podmnožinu předem vypočítaných rotačních vložení na základě aktuální délky vstupní sekvence. Protože se délka sekvencí může u jednotlivých dávek lišit, tato operace dělení zajišťuje, že se použijí pouze vložení odpovídající skutečné délce sekvence.

Proměnná embeddings nyní obsahuje tenzor tvaru (seq_len, embedding_dim), kde seq_len je délka sekvencí v aktuální dávce a embedding_dim je rozměrnost vložení. Tento tenzor obsahuje rotační polohové vložení pro každou pozici v sekvenci až po seq_len.

emb = tf.concat((tf.cos(frekvence), tf.sin(frekvence)), axis=-1) kombinuje sinusové a kosinové transformace polohových frekvencí do jediného tenzoru:

-tf.cos(freqs) a tf.sin(freqs) aplikují kosinusovou a sinusovou transformaci na tenzor,freqs. Tenzor "freqs" obsahuje hodnoty frekvence pro každou pozici ve vstupní sekvenci a každý rozměr vkládacího prostoru, vypočítané na základě pozic sekvence a inverzních frekvencí rozměrů vkládání. Funkce sinus a kosinus jsou aplikovány po prvcích, výsledkem jsou dva tenzory stejného tvaru jako freqs`. Tyto transformace pomáhají při kódování pozice způsobem, který zachycuje cyklickou povahu pozičních vztahů a usnadňuje schopnost modelu porozumět relativním pozicím.

-tf.concat((tf.cos(frekv.), tf.sin(frekv.)), osa=-1) zřetězí tenzory transformované na kosinus a sinus podél poslední osy (označené osa=-1). Zřetězení těchto tenzorů vedle sebe efektivně zdvojnásobuje dimenzionalitu tenzoru 'freqs', přičemž první polovina představuje kosinusově transformované hodnoty a druhá polovina představuje sinusově transformované hodnoty pro každou pozici. Zřetězení zajišťuje, že každé polohové kódování obsahuje sinusovou i kosinovou informaci, což umožňuje uchování informací o amplitudě i fázi polohových signálů.

  • Zřetězené tenzorové „emb“ nyní obsahuje kompletní rotační vložení pro vstupní pozice. Tvar emb bude stejný jako freqs v jeho prvních dvou dimenzích (odpovídajících pozicím sekvence a rozměrům vkládání), ale jeho poslední rozměr bude dvakrát tak velký, což bude odpovídat hodnotám sinus i cosinus. Tato vložení se používají k modulaci vstupních vložení přidáním informací o poloze rotačně ekvivalentním způsobem.

-cos_emb = embeddings[:, Žádné, :self.dim // 2]:

  1. První dvojtečka „:“ znamená „vyberte všechny prvky v této dimenzi“, což v tomto případě odkazuje na všechny pozice v sekvenci.

  2. „Žádný“ se používá k přidání dalšího rozměru, čímž se tenzor stane 3-rozměrným. To se často provádí za účelem zajištění kompatibility s určitými operacemi, které očekávají vstupy určitého počtu dimenzí. Například při provádění násobení po prvcích s jiným tenzorem, který je 3-rozměrný, se tvary musí zarovnat podle pravidel vysílání.

  3. :self.dim // 2, vybere první polovinu rozměrů na poslední ose. Vzhledem k tomu, že embedding_dimension je zdvojnásoben, aby zahrnoval hodnoty sinus i kosinus, dělení 2 efektivně vybere pouze kosinové složky vložení.

Krok 3: Integrace s modelem Keras

Po definování RotaryEmbeddingLayer ji můžete integrovat do svého modelu Keras. Tato vrstva by měla být aplikována na vaše vložení před jejich vložením do vrstev pozornosti nebo jakýchkoli následujících vrstev modelu.

Zde je zjednodušený příklad, jak integrovat otočné vložky do modelu:

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 Všechna práva vyhrazena.