Modely založené na transformátoroch sú známe svojou schopnosťou analyzovať a interpretovať zložitý text. Spoliehajú sa na pochopenie poradia a kontextu slov – úloh, pri ktorých tradičné metódy pozičného kódovania ukázali svoje limity. Model ROFORMER, poháňaný Rotary Position Embedding (RoPE), rieši túto medzeru a nanovo definuje náš prístup k pozičnému kódovaniu.
Tradičné pozičné kódovanie
Transformátory spracovávajú text ako sériu tokenov a umožňujú paralelné spracovanie sekvencií pre vyššiu efektivitu. Táto sila však priniesla svoju výzvu: vrodený agnosticizmus modelu k symbolickému poriadku. Odpoveďou bolo Pozičné kódovanie, poskytujúce každému tokenu jedinečný podpis označujúci jeho sekvenčnú pozíciu.
Vloženie absolútnej pozície
Spočiatku modely ako BERT používali vloženie absolútnej polohy, pričom každej pozícii v sekvencii priraďovali pevný vektor. Tejto metóde, aj keď je priama, prirodzene chýba schopnosť prispôsobiť sa variáciám dĺžky sekvencie alebo zdôrazniť relatívne vzdialenosti medzi tokenmi, čo je kritické pre pochopenie mnohých lingvistických konštruktov.
Relatívna pozícia vloženia
Aby sa zachytila dynamická povaha jazyka, zaviedli sa vloženia relatívnych pozícií, ktoré sa zamerali skôr na vzdialenosť medzi tokenmi než na ich absolútne pozície. Napriek ich koncepčnej výhode tieto vloženia zaviedli výpočtovú zložitosť a nedokázali sa hladko integrovať do mechanizmu sebapozorovania Transformers, čím sa obmedzila ich účinnosť.
ROFORMER a vloženie s rotačnou polohou
Uznávajúc obmedzenia existujúcich stratégií pozičného kódovania, ROFORMER predstavuje Rotary Position Embedding (RoPE), prístup, ktorý kombinuje výhody absolútnej a relatívnej informácie o polohe bez ich príslušných nevýhod.
Vloženie do rotačnej polohy
RoPE kóduje informácie o polohe pomocou rotačných matíc, čo umožňuje modelu pochopiť nielen to, kde sa token nachádza, ale aj to, ako súvisí s každým ďalším tokenom v sekvencii.
Credit: ArXiv
Funguje cez geometrickú šošovku a zaobchádza s polohami tokenov ako s bodmi vo viacrozmernom priestore, ktoré sa otáčajú, aby sa označili ich sekvenčné vzťahy. Táto rotácia umožňuje modelu zachovať a využiť absolútne aj relatívne pozičné podnety v rámci mechanizmu vlastnej pozornosti.
Implementácia RoPE
Implementácia RoPE zahŕňa zakódovanie pozície každého tokenu do rotačnej matice a aplikáciu tejto matice v rámci mechanizmu sebapozorovania Transformera. Tento proces umožňuje flexibilnú, dynamickú interpretáciu informácií o polohe, prispôsobenie sa rôznym dĺžkam sekvencií a zachytenie podstaty vzájomných vzťahov tokenov bez výraznej výpočtovej réžie.
Najprv budete potrebovať funkciu na generovanie rotačných vložení a potom tieto vloženia integrujete do svojho modelu. Príklad nižšie predpokladá, že ste oboznámení s vytváraním vlastných vrstiev v Kerase.
Krok 1: Definujte funkciu rotačného vkladania
Táto funkcia generuje rotačné vloženia s maximálnou dĺžkou sekvencie a rozmermi vloženia.
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))
Táto čiara vypočítava inverznú hodnotu exponenciálne škálovaných frekvencií na základe indexov polohy. Tieto frekvencie sa používajú pri vytváraní sínusových vzorov pre rotačné vloženia, čo pomáha pri kódovaní informácií o relatívnej polohe v sekvenciách. Tento mechanizmus je užitočný najmä v úlohách, kde je kľúčové pochopiť poradie a relatívne umiestnenie prvkov, ako napríklad pri spracovaní prirodzeného jazyka alebo analýze časových radov.
Detailne:
-
tf.range(0, dim, 2, dtype=tf.float32)
vytvára rozsah hodnôt od 0 podim
(exkluzívne), krokuje po 2. Argumentdtype=tf.float32
určuje že prvky tohto tenzora sú 32-bitové čísla s pohyblivou rádovou čiarkou. Ak je „dim“ napríklad 8, výsledkom by bolo „[0, 2, 4, 6]“. -
Tenzor produkovaný "tf.range" sa potom vydelí rozmerom ("dim") vložených prvkov. Táto operácia zmenší tieto indexy na rozsah medzi 0 a 1 (okrem toho, ak je „dim“ párne, mierne zahŕňa, ak je „dim“ nepárne, pretože krok rozsahu preskakuje každú druhú hodnotu). Ak budeme pokračovať v príklade s „dim“ = 8, vydelením číslom 8 dostaneme „[0,0, 0,25, 0,5, 0,75]“.
-
Operácia „10 000 ** (...)“ zvýši 10 000 na silu každého prvku v predtým upravenom tenzore. Základ 10 000 je do istej miery ľubovoľný, ale je zvolený tak, aby sa frekvencie menili v širokom rozsahu, čo pomáha modelu efektívnejšie rozlišovať medzi rôznymi polohami. Pre „[0,0, 0,25, 0,5, 0,75]“ by sa výkonová operácia použila na každý, čo by viedlo k oveľa väčším hodnotám pre vyššie prvky.
-
Nakoniec sa získa inverzná frekvencia zobratím recipročnej (1/x) hodnôt z predchádzajúceho kroku. Inverzné frekvencie sú menšie pre vyššie indexy, čo znamená, že prvky ďalej v sekvencii budú mať menšie frekvencie, čo ovplyvní spôsob, akým sú ich pozície zakódované do modelu. To umožňuje vložkám škálovať spôsobom, kde je možné odvodiť relatívne polohy prostredníctvom mechanizmov pozornosti modelu.
Čiara:
freqs = tf.einsum('i,j->ij', t, inv_freq)
používa funkciu tf.einsum
TensorFlow, nástroj, ktorý umožňuje stručné a efektívne vyjadrenie tenzorových operácií pomocou Einsteinovej sumačnej notácie.
Táto operácia efektívne vypočíta vonkajší súčin vektorov „t“ a „inv_freq“, výsledkom čoho je matica, kde každý prvok „(i, j)“ je súčinom „i“-tého prvku „t“ a „ j-tý prvok parametra
inv_freq`. Táto matica ("frekvencie") predstavuje frekvencie, ktoré sa používajú na generovanie sínusových vzorov pre rotačné uloženia.
Krok 2: Vlastná vrstva Keras pre rotačné vsadenia
Teraz vytvorte vlastnú vrstvu Keras, ktorá aplikuje rotačné vloženie na vstupný tenzor. Táto vrstva predpokladá, že vstupný tenzor má tvar (veľkosť_dávky, dĺžka_sekvencie, 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
Riadok embeddings = self.rotary_embeddings[:seq_len]
vyberá vhodnú podmnožinu vopred vypočítaných rotačných vložení na základe aktuálnej dĺžky vstupnej sekvencie. Keďže dĺžka sekvencií sa môže líšiť od jednej dávky k druhej, táto operácia krájania zaisťuje, že sa použijú iba vloženia zodpovedajúce skutočnej dĺžke sekvencie.
Premenná „embeddings“ teraz obsahuje tenzor tvaru „(seq_len, embedding_dim)“, kde „seq_len“ je dĺžka sekvencií v aktuálnej dávke a „embedding_dim“ je rozmernosť vložených prvkov. Tento tenzor obsahuje rotačné polohové vloženia pre každú pozíciu v sekvencii až po „seq_len“.
emb = tf.concat((tf.cos(frekv.), tf.sin(frekv.)), axis=-1)
kombinuje sínusové a kosínusové transformácie polohových frekvencií do jedného tenzora:
-tf.cos(freqs)
a tf.sin(freqs)
aplikujú kosínusovú a sínusovú transformáciu na tenzor,frekvencií`. Tenzor "frekvencií" obsahuje frekvenčné hodnoty pre každú pozíciu vo vstupnej sekvencii a každý rozmer vloženého priestoru, vypočítané na základe pozícií sekvencie a inverzných frekvencií rozmerov vkladania. Funkcie sínus a kosínus sa aplikujú po prvkoch, výsledkom čoho sú dva tenzory rovnakého tvaru ako „frekvencie“. Tieto transformácie pomáhajú pri kódovaní pozície spôsobom, ktorý zachytáva cyklickú povahu pozičných vzťahov a uľahčuje schopnosť modelu porozumieť relatívnym pozíciám.
-tf.concat((tf.cos(frekv.), tf.sin(frekv.)), os=-1)
zreťazí kosínusové a sínusové transformované tenzory pozdĺž poslednej osi (označenej os=-1
). Reťazenie týchto tenzorov vedľa seba efektívne zdvojnásobuje dimenzionalitu tenzora "frekvencií", pričom prvá polovica predstavuje kosínusovo transformované hodnoty a druhá polovica predstavuje sínusovo transformované hodnoty pre každú pozíciu. Reťazenie zaisťuje, že každé pozičné kódovanie obsahuje sínusové aj kosínusové informácie, čo umožňuje zachovanie informácií o amplitúde aj o fáze pozičných signálov.
- Zreťazené 'emb' tenzora teraz obsahuje kompletné rotačné vloženia pre vstupné pozície. Tvar „emb“ bude rovnaký ako „freqs“ v jeho prvých dvoch rozmeroch (zodpovedajúcich pozíciám sekvencie a rozmerom vloženia), ale jeho posledný rozmer bude dvakrát taký veľký, pričom bude zodpovedať hodnotám sínus aj kosínus. Tieto vloženia sa používajú na moduláciu vstupných vložení pridaním polohových informácií rotačným ekvivalentným spôsobom.
-cos_emb = embeddings[:, None, :self.dim // 2]
:
-
Prvá dvojbodka „:“ znamená „vybrať všetky prvky v tejto dimenzii“, čo v tomto prípade odkazuje na všetky pozície v sekvencii.
-
„Žiadny“ sa používa na pridanie ďalšieho rozmeru, vďaka čomu je tenzor 3-rozmerný. Často sa to robí, aby sa zabezpečila kompatibilita s určitými operáciami, ktoré očakávajú vstupy určitého počtu rozmerov. Napríklad pri vykonávaní násobenia po prvkoch s iným tenzorom, ktorý je 3-rozmerný, sa tvary musia zarovnať podľa pravidiel vysielania.
-
:self.dim // 2
, vyberie prvú polovicu rozmerov na poslednej osi. Keďže „dimenzia_vloženia“ je zdvojnásobená, aby zahŕňala sínusové aj kosínusové hodnoty, delením 2 sa efektívne vyberú iba kosínusové zložky vloženia.
Krok 3: Integrácia s modelom Keras
Po definovaní RotaryEmbeddingLayer
ju môžete integrovať do svojho modelu Keras. Táto vrstva by mala byť aplikovaná na vaše vložky pred ich vložením do vrstiev pozornosti alebo akýchkoľvek nasledujúcich vrstiev modelu.
Tu je zjednodušený príklad, ako integrovať rotač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()