Modeli, ki temeljijo na transformatorjih so znani po svoji zmožnosti razčlenjevanja in interpretacije kompleksnega besedila. Zanašajo se na razumevanje vrstnega reda in konteksta besed – naloge, pri katerih so tradicionalne metode pozicijskega kodiranja pokazale svoje meje. Model ROFORMER, ki ga poganja Rotary Position Embedding (RoPE), odpravlja to vrzel, na novo opredeljuje naš pristop k pozicijskemu kodiranju.
Tradicionalno pozicijsko kodiranje
Transformatorji obravnavajo besedilo kot vrsto žetonov in omogočajo vzporedno obdelavo zaporedij za večjo učinkovitost. Vendar pa je ta moč prinesla svoj izziv: model inherentni agnosticizem do žetonskega reda. Pozicijsko kodiranje je bil odgovor, zagotavljanje vsakemu žetonu edinstven podpis, ki označuje njegovo zaporedno pozicijo.
Vdelave absolutnih položajev
Na začetku so modeli, kot je BERT, uporabljali vdelave absolutnih položajev, pri čemer so vsakemu položaju v zaporedju dodelili fiksni vektor. Ta metoda, čeprav je enostavna, sama po sebi nima zmožnosti prilagajanja variacijam dolžine zaporedja ali poudarjanja relativnih razdalj med žetoni, kar je ključnega pomena za razumevanje številnih jezikovnih konstruktov.
Vdelave relativnega položaja
Da bi zajeli dinamično naravo jezika, so bile uvedene vdelave relativnega položaja, ki so se osredotočale na razdaljo med žetoni in ne na njihove absolutne položaje. Kljub svoji konceptualni prednosti so te vdelave uvedle računalniško zapletenost in se niso uspele brezhibno integrirati v mehanizem samopozornosti Transformerjev, kar je omejilo njihovo učinkovitost.
ROFORMER in vgradnja rotacijskega položaja
S priznavanjem omejitev obstoječih strategij pozicijskega kodiranja ROFORMER uvaja Rotary Position Embedding (RoPE), pristop, ki združuje prednosti absolutnih in relativnih informacij o položaju brez njunih pomanjkljivosti.
Vdelava rotacijskega položaja
RoPE kodira informacije o položaju z uporabo matrik vrtenja, kar omogoča modelu, da razume ne samo, kje je žeton, ampak tudi, kako je povezan z vsemi drugimi žetoni v zaporedju.
Credit: ArXiv
Deluje skozi geometrijsko lečo in položaje žetonov obravnava kot točke v večdimenzionalnem prostoru, ki se vrtijo, da označijo svoje zaporedne odnose. Ta rotacija omogoča modelu, da ohrani in izkoristi tako absolutne kot relativne položajne znake znotraj svojega mehanizma samopozornosti.
Implementacija RoPE
Implementacija RoPE vključuje kodiranje položaja vsakega žetona v rotacijsko matriko in uporabo te matrike znotraj mehanizma samoosredotočanja Transformerja. Ta postopek omogoča prilagodljivo, dinamično interpretacijo informacij o položaju, prilagajanje različnim dolžinam zaporedja in zajemanje bistva medsebojnih odnosov žetonov brez znatnih računskih stroškov.
Najprej boste potrebovali funkcijo za ustvarjanje rotacijskih vdelav, nato pa boste te vdelave integrirali v svoj model. Spodnji primer predvideva, da ste seznanjeni z ustvarjanjem plasti po meri v Kerasu.
1. korak: Definirajte funkcijo rotacijskega vdelave
Ta funkcija generira rotacijske vdelave glede na največjo dolžino zaporedja in dimenzionalnost vdelav.
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))
Ta vrstica izračuna obratno vrednost eksponentno skaliranih frekvenc na podlagi indeksov položaja. Te frekvence se uporabljajo pri ustvarjanju sinusnih vzorcev za rotacijske vdelave, kar pomaga pri kodiranju relativnih položajnih informacij v zaporedjih. Ta mehanizem je še posebej uporaben pri nalogah, kjer je razumevanje vrstnega reda in relativnega položaja elementov ključnega pomena, na primer pri obdelavi naravnega jezika ali analizi časovnih vrst.
V podrobnostih:
-
tf.range(0, dim, 2, dtype=tf.float32)
ustvari obseg vrednosti, ki se začne od 0 dodim
(izključno), v korakih po 2. Argumentdtype=tf.float32
določa da so elementi tega tenzorja 32-bitna števila s plavajočo vejico. Če jedim
na primer 8, bi to ustvarilo[0, 2, 4, 6]
. -
Tenzor, ki ga ustvari
tf.range
, se nato deli z dimenzionalnostjo (dim
) vdelav. Ta operacija zmanjša te indekse na obseg med 0 in 1 (izključno, če je »dim« sodo, nekoliko vključuje, če je »dim« liho, ker korak obsega preskoči vse druge vrednosti). Če primer nadaljujemo zdim
= 8, deljenje z 8 da[0.0, 0.25, 0.5, 0.75]
. -
Operacija
10000 ** (...)
dvigne 10.000 na potenco vsakega elementa v predhodno skaliranem tenzorju. Osnova 10.000 je nekoliko poljubna, vendar je izbrana tako, da zagotovi, da se frekvence spreminjajo v širokem razponu, kar pomaga modelu učinkoviteje razlikovati med različnimi položaji. Za »[0,0, 0,25, 0,5, 0,75]« bi za vsakega uporabil operacijo moči, kar bi povzročilo veliko večje vrednosti za višje elemente. -
Inverzno frekvenco dobimo tako, da vzamemo recipročno (1/x) vrednosti iz prejšnjega koraka. Inverzne frekvence so manjše za višje indekse, kar pomeni, da bodo imeli elementi, ki so dlje v zaporedju, manjše frekvence, kar vpliva na to, kako so njihovi položaji kodirani v modelu. To omogoča, da se vdelave merijo na način, kjer je mogoče sklepati o relativnih položajih prek mehanizmov pozornosti modela.
Linija:
freqs = tf.einsum('i,j->ij', t, inv_freq)
uporablja funkcijo TensorFlow tf.einsum
, orodje, ki omogoča jedrnato in učinkovito izražanje tenzorskih operacij z uporabo Einsteinovega zapisa seštevka.
Ta operacija učinkovito izračuna zunanji zmnožek vektorjev t
in inv_freq
, kar ima za posledico matriko, kjer je vsak element (i, j)
zmnožek i
-tega elementa t
in j
-ti element inv_freq
. Ta matrika (freqs
) predstavlja frekvence, ki se uporabljajo za generiranje sinusnih vzorcev za rotacijske vdelave.
2. korak: plast Keras po meri za rotacijske vdelave
Zdaj pa ustvarimo plast Keras po meri, ki uporablja rotacijske vdelave za vhodni tenzor. Ta plast predvideva, da je vhodni tenzor oblike (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
Vrstica embeddings = self.rotary_embeddings[:seq_len]
izbere ustrezno podmnožico vnaprej izračunanih rotacijskih vdelav na podlagi trenutne dolžine vhodnega zaporedja. Ker se lahko dolžina zaporedij razlikuje od enega paketa do drugega, ta operacija rezanja zagotavlja, da se uporabljajo samo vdelave, ki ustrezajo dejanski dolžini zaporedja.
Spremenljivka embeddings
zdaj vsebuje tenzor oblike (seq_len, embedding_dim)
, kjer je seq_len
dolžina zaporedij v trenutnem paketu, embedding_dim
pa je dimenzionalnost vdelav. Ta tenzor vsebuje rotacijske pozicijske vdelave za vsak položaj v zaporedju do seq_len
.
emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)
združuje sinusne in kosinusne transformacije pozicijskih frekvenc v en sam tenzor:
-tf.cos(freqs)
in tf.sin(freqs)
uporabita kosinusno oziroma sinusno transformacijo za tenzor freqs
. Tenzor freqs
vsebuje frekvenčne vrednosti za vsak položaj v vhodnem zaporedju in vsako dimenzijo prostora za vdelavo, izračunane na podlagi položajev zaporedja in inverznih frekvenc dimenzij za vdelavo. Funkciji sinus in kosinus se uporabita elementno, kar ima za posledico dva tenzorja enake oblike kot freqs
. Te transformacije pomagajo pri kodiranju položaja na način, ki zajame ciklično naravo pozicijskih odnosov, kar olajša sposobnost modela, da razume relativne položaje.
-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)
združuje kosinusne in sinusne transformirane tenzorje vzdolž zadnje osi (označeno z axis=-1
). Združevanje teh tenzorjev drug ob drugem učinkovito podvoji dimenzionalnost tenzorja freqs
, pri čemer prva polovica predstavlja kosinusno transformirane vrednosti, druga polovica pa sinusno transformirane vrednosti za vsak položaj. Združevanje zagotavlja, da vsako pozicijsko kodiranje vsebuje tako sinusne kot kosinusne informacije, kar omogoča ohranjanje informacij o amplitudi in fazi pozicijskih signalov.
- Povezani tenzor
emb
zdaj vsebuje celotne rotacijske vdelave za vhodne položaje. Oblikaemb
bo enaka kotfreqs
v svojih prvih dveh dimenzijah (ki ustrezata položajem zaporedja in dimenzijam vdelave), vendar bo njegova zadnja dimenzija dvakrat večja, kar bo upoštevalo sinusne in kosinusne vrednosti. Te vdelave se uporabljajo za modulacijo vhodnih vdelav z dodajanjem informacij o položaju na rotacijsko enakovredni način.
-cos_emb = vdelave[:, Brez, :self.dim // 2]
:
-
Prvo dvopičje
:
pomeni "izberi vse elemente v tej dimenziji," kar se v tem primeru nanaša na vse položaje v zaporedju. -
Brez
se uporablja za dodajanje dodatne dimenzije, zaradi česar je tenzor tridimenzionalen. To se pogosto naredi, da se zagotovi združljivost z določenimi operacijami, ki pričakujejo vnose določenega števila dimenzij. Na primer, pri izvajanju množenja po elementih z drugim tenzorjem, ki je 3-dimenzionalen, se morajo oblike poravnati v skladu s pravili oddajanja. -
:self.dim // 2
, izbere prvo polovico dimenzij na zadnji osi. Ker jevdelana_dimenzija
podvojena, da vključuje sinusne in kosinusne vrednosti, deljenje z 2 učinkovito izbere samo kosinusne komponente vdelav.
3. korak: Integracija z modelom Keras
Ko definirate RotaryEmbeddingLayer
, ga lahko integrirate v svoj model Keras. Ta sloj je treba uporabiti za vaše vdelave, preden jih vnesete v sloje pozornosti ali katere koli naslednje plasti modela.
Tukaj je poenostavljen primer, kako integrirati vrtljive vstavke v 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()