Transformator-gebaseerde modelle is bekend vir hul vermoë om komplekse teks te ontleed en te interpreteer. Hulle maak staat op die begrip van die volgorde en konteks van woorde - take waarby tradisionele posisionele enkoderingsmetodes hul grense getoon het. Deur hierdie gaping aan te spreek, herdefinieer die ROFORMER-model, aangedryf deur die Rotary Position Embedding (RoPE), ons benadering tot posisionele enkodering.
Tradisionele Posisionele Enkodering
Transformators behandel teks as 'n reeks tekens, en laat parallelle verwerking van rye toe vir groter doeltreffendheid. Hierdie krag het egter sy uitdaging gebring: die model se inherente agnostisisme tot tekenorde. Posisionele enkodering was die antwoord, wat elke teken 'n unieke handtekening verskaf wat sy volgordeposisie aandui.
Absolute Posisie-inbeddings
Aanvanklik het modelle soos BERT absolute posisie-inbeddings gebruik, wat 'n vaste vektor aan elke posisie in 'n volgorde toegewys het. Hierdie metode, alhoewel eenvoudig, het inherent nie die vermoë om aan te pas by variasies in volgordelengte nie, of om die relatiewe afstande tussen tekens ** te beklemtoon, van kritieke belang vir die verstaan van baie linguistiese konstrukte.
Relatiewe posisie-inbeddings
Om die dinamiese aard van taal vas te vang, is relatiewe posisie-inbeddings ingestel, met die fokus op die afstand tussen tekens eerder as hul absolute posisies. Ten spyte van hul konseptuele voordeel, het hierdie inbeddings rekenkundige kompleksiteit ingebring, en het nie daarin geslaag om naatloos in die self-aandagmeganisme van Transformers te integreer nie, wat hul doeltreffendheid beperk het.
ROFORMER en Rotary Position Inbedding
Met erkenning van die beperkings van bestaande posisionele enkoderingstrategieë, stel ROFORMER Rotary Position Embedding (RoPE), 'n benadering wat die voordele van absolute en relatiewe posisie-inligting kombineer sonder hul onderskeie nadele.
Roterende posisie-inbedding
RoPE kodeer posisionele inligting deur rotasiematrikse te gebruik, wat die model in staat stel om nie net te verstaan waar 'n teken is nie, maar hoe dit met elke ander teken in 'n volgorde verband hou.
Credit: ArXiv
Dit werk deur 'n geometriese lens, en behandel tekenposisies as punte in 'n multi-dimensionele ruimte wat geroteer word om hul opeenvolgende verwantskappe te merk. Hierdie rotasie laat die model toe om beide absolute en relatiewe posisionele leidrade binne sy self-aandagmeganisme te bewaar en te ontgin.
Implementering van RoPE
Implementering van RoPE behels die enkodering van elke teken se posisie in 'n rotasiematriks, en die toepassing van hierdie matriks binne die self-aandagmeganisme van die Transformator. Hierdie proses maak voorsiening vir 'n buigsame, dinamiese interpretasie van posisionele inligting, wat wisselende volgordelengtes akkommodeer en die essensie van token-interverwantskappe vaslê sonder noemenswaardige berekeningsbokoste.
Eerstens het jy 'n funksie nodig om die roterende inbeddings te genereer, en dan sal jy hierdie inbeddings in jou model integreer. Die voorbeeld hieronder neem aan dat jy vertroud is met die skep van pasgemaakte lae in Keras.
Stap 1: Definieer die Rotary Embedding-funksie
Hierdie funksie genereer die roterende inbeddings gegewe die maksimum volgorde lengte, en die dimensionaliteit van die inbeddings.
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))
Hierdie lyn bereken die inverse van eksponensieel geskaalde frekwensies gebaseer op die posisie-indekse. Hierdie frekwensies word gebruik om sinusvormige patrone vir roterende inbeddings te genereer, wat help om die relatiewe posisionele inligting in rye te enkodeer. Hierdie meganisme is veral nuttig in take waar begrip van die volgorde en relatiewe posisionering van elemente van kardinale belang is, soos in natuurlike taalverwerking of tydreeksanalise.
In besonderhede:
-
tf.range(0, dim, 2, dtype=tf.float32)
skep 'n reeks waardes vanaf 0 tot en metdim
(eksklusief), met 2 stapsgewys. Diedtype=tf.float32
-argument spesifiseer dat die elemente van hierdie tensor 32-bis swaaipuntgetalle is. Asdim
byvoorbeeld 8 is, sal dit[0, 2, 4, 6]
produseer. -
Die tensor wat deur
tf.range
geproduseer word, word dan gedeel deur die dimensionaliteit (dim
) van die inbeddings. Hierdie bewerking skaal hierdie indekse af na 'n reeks tussen 0 en 1 (eksklusief asdim
ewe is, effens inklusief asdim
vreemd is, want die reeksstap slaan elke ander waarde oor). Deur die voorbeeld voort te sit metdim
= 8, deling deur 8 lewer[0.0, 0.25, 0.5, 0.75]
. -
Die
10000 ** (...)
bewerking verhoog 10 000 tot die krag van elke element in die voorheen geskaalde tensor. Die basis van 10 000 is ietwat arbitrêr, maar word gekies om te verseker dat die frekwensies oor 'n wye reeks verskil, wat die model help om meer effektief tussen verskillende posisies te onderskei. Vir[0.0, 0.25, 0.5, 0.75]
sal dit die kragbewerking op elkeen toepas, wat lei tot waardes wat baie groter is vir hoër elemente. -
Laastens word die omgekeerde frekwensie verkry deur die resiproke (1/x) van die waardes van die vorige stap te neem. Die inverse frekwensies is kleiner vir hoër indekse, wat beteken dat elemente verder in die volgorde kleiner frekwensies sal hê, wat beïnvloed hoe hul posisies in die model geënkodeer word. Dit laat die inbeddings toe om te skaal op 'n wyse waar relatiewe posisies deur die model se aandagmeganismes afgelei kan word.
Die lyn:
freqs = tf.einsum('i,j->ij', t, inv_freq)
gebruik TensorFlow se tf.einsum
-funksie, 'n instrument wat dit moontlik maak vir bondige en doeltreffende uitdrukking van tensor-bewerkings deur die Einstein-opsommingsnotasie te gebruik.
Hierdie bewerking bereken effektief die buitenste produk van die t
en inv_freq
vektore, wat lei tot 'n matriks waar elke element (i, j)
die produk is van die i
-de element van t
en die j
-de element van inv_freq
. Hierdie matriks (freqs
) verteenwoordig die frekwensies wat gebruik word om die sinusvormige patrone vir die roterende inbeddings te genereer.
Stap 2: Pasgemaakte Keras-laag vir roterende inbeddings
Kom ons skep nou 'n pasgemaakte Keras-laag wat roterende inbeddings op die invoertensor toepas. Hierdie laag neem aan dat die invoertensor van vorm (batch_size, sequence_length, embedding_dim)
is.
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
Die reël inbeddings = self.rotary_embeddings[:seq_len]
kies die toepaslike subset van voorafberekende roterende inbeddings gebaseer op die huidige invoervolgordelengte. Aangesien die lengte van reekse van een bondel na 'n ander kan wissel, verseker hierdie snybewerking dat slegs die inbeddings wat met die werklike reekslengte ooreenstem, gebruik word.
Die veranderlike "inbeddings" het nou 'n tensor van vorm '(seq_len, embedding_dim)', waar 'seq_len' die lengte van die rye in die huidige bondel is, en 'embedding_dim' is die dimensionaliteit van die inbeddings. Hierdie tensor bevat die roterende posisionele inbeddings vir elke posisie in die volgorde tot en met seq_len
.
emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), as=-1)
kombineer sinus- en cosinustransformasies van posisionele frekwensies in 'n enkele tensor:
-tf.cos(freqs)
en tf.sin(freqs)
pas die cosinus- en sinustransformasies onderskeidelik toe op die freqs
-tensor. Die freqs
tensor bevat frekwensiewaardes vir elke posisie in die invoervolgorde en elke dimensie van die inbeddingspasie, bereken op grond van die volgordeposisies en die omgekeerde frekwensies van die inbeddingdimensies. Die sinus- en cosinusfunksies word elementgewys toegepas, wat lei tot twee tensors van dieselfde vorm as freqs
. Hierdie transformasies help om die posisie te enkodeer op 'n manier wat die sikliese aard van posisionele verhoudings vasvang, wat die model se vermoë om relatiewe posisies te verstaan, vergemaklik.
-tf.concat((tf.cos(freqs), tf.sin(freqs)), as=-1)
verbind die cosinus- en sinus-getransformeerde tensors langs die laaste as (aangedui deur as=-1
). Die samevoeging van hierdie tensors langs mekaar verdubbel effektief die dimensionaliteit van die freqs
tensor, met die eerste helfte wat cosinus-getransformeerde waardes verteenwoordig en die tweede helfte wat sinus-getransformeerde waardes vir elke posisie verteenwoordig. Die aaneenskakeling verseker dat elke posisionele enkodering beide sinus- en cosinus-inligting bevat, wat die behoud van inligting oor beide die amplitude en fase van die posisionele seine moontlik maak.
- Die aaneengeskakelde tensor
emb
hou nou die volledige roterende inbeddings vir die invoerposisies. Die vorm vanemb
sal dieselfde wees asfreqs
in sy eerste twee dimensies (wat ooreenstem met ryposisies en inbeddingsdimensies), maar sy laaste dimensie sal twee keer so groot wees, wat beide sinus- en cosinuswaardes in ag neem. Hierdie inbeddings word gebruik om die insetinbeddings te moduleer deur posisionele inligting op 'n rotasie-ekwivariante wyse by te voeg.
-cos_emb = inbeddings[:, Geen, :self.dim // 2]
:
-
Die eerste dubbelpunt
:
beteken "kies alle elemente in hierdie dimensie," wat, in hierdie geval, verwys na alle posisies in die ry. -
Geen
word gebruik om 'n bykomende dimensie by te voeg, wat die tensor 3-dimensioneel maak. Dit word dikwels gedoen om versoenbaarheid te verseker met sekere bewerkings wat insette van 'n spesifieke aantal dimensies verwag. Byvoorbeeld, wanneer elementsgewyse vermenigvuldiging uitgevoer word met 'n ander tensor wat 3-dimensioneel is, moet die vorms in lyn wees volgens uitsaaireëls. -
:self.dim // 2
, kies die eerste helfte van die afmetings in die laaste as. Aangesien die 'inbedding_dimensie' verdubbel word om beide sinus- en cosinuswaardes in te sluit, kies deling deur 2 effektief net die cosinuskomponente van die inbeddings.
Stap 3: Integrasie met 'n Keras-model
Nadat jy die RotaryEmbeddingLayer
gedefinieer het, kan jy dit in jou Keras-model integreer. Hierdie laag moet op jou inbeddings aangebring word voordat dit in aandaglae of enige daaropvolgende modellae ingevoer word.
Hier is 'n vereenvoudigde voorbeeld van hoe om die roterende inbeddings in 'n model te integreer:
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()