RoFormer: patobulintas transformatorius su rotacinės padėties įterpimu

RoFormer: patobulintas transformatorius su rotacinės padėties įterpimu

Transformatoriumi pagrįsti modeliai garsėja gebėjimu analizuoti ir interpretuoti sudėtingą tekstą. Jie remiasi žodžių tvarkos ir konteksto supratimu – užduotimis, kurių metu tradiciniai pozicinio kodavimo metodai parodė savo ribas. Išspręsdamas šią spragą, ROFORMER modelis, varomas Rotary Position Embedding (RoPE), iš naujo apibrėžia mūsų požiūrį į padėties kodavimą.

Tradicinis pozicijos kodavimas

Transformatoriai traktuoja tekstą kaip žetonų seriją ir leidžia lygiagrečiai apdoroti sekas, kad būtų didesnis efektyvumas. Tačiau ši jėga atnešė savo iššūkį: modeliui būdingą agnosticizmą pagal simbolinę tvarką. Pozicijos kodavimas buvo atsakymas, kiekvienam prieigos raktui suteikiant unikalų parašą, nurodantį jo sekos vietą.

Absoliučios pozicijos įterpimai

Iš pradžių tokie modeliai kaip BERT naudojo absoliučiosios padėties įterpimą, priskirdami fiksuotą vektorių kiekvienai sekos vietai. Šis metodas, nors ir paprastas, iš prigimties neturi galimybės prisitaikyti prie sekos ilgio svyravimų arba pabrėžti santykinius atstumus tarp žetonų, o tai labai svarbu norint suprasti daugelį kalbinių konstrukcijų.

Santykinės padėties įterpimai

Siekiant užfiksuoti dinamišką kalbos pobūdį, buvo įvestas santykinės padėties įterpimas, sutelkiant dėmesį į atstumą tarp žetonų, o ne į absoliučią jų padėtį. Nepaisant konceptualaus pranašumo, šie įterpimai įvedė skaičiavimo sudėtingumą ir nesugebėjo sklandžiai integruoti į Transformatorių dėmesio į save mechanizmą, todėl buvo apribotas jų efektyvumas.

ROFORMER ir rotacinės padėties įterpimas

Pripažindamas esamų padėties kodavimo strategijų apribojimus, ROFORMER pristato Rotary Position Embedding (RoPE) – metodą, kuris sujungia absoliučios ir santykinės padėties informacijos pranašumus be atitinkamų trūkumų.

Sukamosios padėties įterpimas

RoPE koduoja padėties informaciją naudodama sukimosi matricas, leidžiančią modeliui suprasti ne tik to, kur yra ženklas, bet ir kaip jis susijęs su kiekvienu kitu žetonu sekoje.

Reformer.pngCredit: ArXiv

Jis veikia per geometrinį objektyvą, žetonų pozicijas traktuodamas kaip taškus daugiamatėje erdvėje, kurie pasukami, kad būtų pažymėti jų nuoseklūs santykiai. Šis sukimas leidžia modeliui išsaugoti ir panaudoti tiek absoliučius, tiek santykinius padėties ženklus savo dėmesio mechanizme.

Virvės įgyvendinimas

RoPE įgyvendinimas apima kiekvieno žetono padėties kodavimą į sukimosi matricą ir šios matricos taikymą transformatoriaus dėmesio mechanizme. Šis procesas leidžia lanksčiai, dinamiškai interpretuoti padėties informaciją, prisitaikant prie skirtingų sekos ilgių ir fiksuojant žetonų tarpusavio ryšių esmę be didelių skaičiavimo išlaidų.

Pirma, jums reikės funkcijos, skirtos sukamiesiems įterpimams generuoti, o tada integruosite šiuos įterpimus į savo modelį. Toliau pateiktame pavyzdyje daroma prielaida, kad esate susipažinę su tinkintų sluoksnių kūrimu „Keras“.

1 veiksmas: apibrėžkite sukamąją įterpimo funkciją

Ši funkcija generuoja sukamuosius įterpimus, atsižvelgiant į maksimalų sekos ilgį ir įterpimų matmenis.

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

Ši eilutė apskaičiuoja atvirkštinę eksponentinio mastelio dažnių vertę pagal padėties indeksus. Šie dažniai naudojami generuojant sinusoidinius modelius rotaciniams įterpimams, kurie padeda užkoduoti santykinę padėties informaciją sekomis. Šis mechanizmas ypač naudingas atliekant užduotis, kai labai svarbu suprasti elementų tvarką ir santykinę padėtį, pavyzdžiui, apdorojant natūralią kalbą arba analizuojant laiko eilutes.

Išsamiau:

  • „tf.range(0, dim, 2, dtype=tf.float32)“ sukuria reikšmių diapazoną nuo 0 iki „dim“ (išskirtinis), žingsniuojant po 2. Argumentas „dtype=tf.float32“ nurodo kad šio tenzoriaus elementai yra 32 bitų slankiojo kablelio skaičiai. Pavyzdžiui, jei „dim“ yra 8, būtų gauta „[0, 2, 4, 6]“.

– Tada „tf.range“ sukurtas tenzorius padalinamas iš įterpimų matmenų („dim“). Ši operacija sumažina šių indeksų skalę iki diapazono nuo 0 iki 1 (išskyrus, jei „dim“ yra lyginis, šiek tiek įtraukiant, jei „dim“ yra nelyginis, nes diapazono veiksmas praleidžia kiekvieną kitą reikšmę). Tęsiant pavyzdį su „dim“ = 8, padalijus iš 8, gaunama „[0,0, 0,25, 0,5, 0,75]“.

  • Operacija „10 000 ** (...)“ padidina 10 000 iki kiekvieno elemento laipsnio anksčiau pakeistame tenzoryje. 10 000 bazė yra šiek tiek savavališka, bet pasirinkta siekiant užtikrinti, kad dažniai svyruotų plačiame diapazone, o tai padeda modeliui efektyviau atskirti skirtingas pozicijas. Naudojant „[0,0, 0,25, 0,5, 0,75]“, kiekvienam iš jų būtų taikoma galios operacija, todėl aukštesnių elementų vertės būtų daug didesnės.

  • Galiausiai atvirkštinis dažnis gaunamas imant grįžtamąją vertę (1/x) iš ankstesnio žingsnio verčių. Atvirkštiniai dažniai yra mažesni aukštesniems indeksams, o tai reiškia, kad toliau esantys elementai turės mažesnius dažnius, o tai turės įtakos jų pozicijų kodavimui modelyje. Tai leidžia įterpti mastelį taip, kad santykinės padėties būtų galima numanyti naudojant modelio dėmesio mechanizmus.

Linija:

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

naudoja TensorFlow funkciją „tf.einsum“ – įrankį, leidžiantį glaustai ir efektyviai išreikšti tenzoriaus operacijas naudojant Einšteino sumavimo žymėjimą.

Ši operacija efektyviai apskaičiuoja išorinę vektorių „t“ ir „inv_freq“ sandaugą, todėl gaunama matrica, kurioje kiekvienas elementas „(i, j)“ yra „t“ ir „i“ elemento sandauga. j-asis „inv_freq“ elementas. Ši matrica („dažniai“) nurodo dažnius, kurie naudojami sukamųjų įterpimų sinusoidiniams modeliams generuoti.

2 veiksmas: pritaikytas Keras sluoksnis rotaciniams įterpimams

Dabar sukurkime tinkintą „Keras“ sluoksnį, kuris įvesties tensoriui pritaikys rotacinius įterpimus. Šiame sluoksnyje daroma prielaida, kad įvesties tenzoriaus forma yra „(partijos_dydis, sekos_ilgis, įterpimo_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

Eilutėje „embeddings = self.rotary_embeddings[:seq_len]“ parenkamas atitinkamas iš anksto apskaičiuotų rotacinių įterpimų poaibis pagal dabartinį įvesties sekos ilgį. Kadangi sekų ilgis įvairiose partijose gali skirtis, ši pjaustymo operacija užtikrina, kad būtų naudojami tik faktinį sekos ilgį atitinkantys įterpimai.

Kintamasis „embeddings“ dabar turi formos „(seq_len, embedding_dim)“ įtempiklį, kur „seq_len“ yra dabartinės partijos sekų ilgis, o „embedding_dim“ yra įterpimų matmenys. Šiame tenzoryje yra sukamieji padėties įterpimai kiekvienai sekos pozicijai iki „seq_len“.

„emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)“ sujungia pozicinių dažnių sinusus ir kosinusus į vieną tenzorių:

-„tf.cos(freqs)“ ir „tf.sin(freqs)“ atitinkamai taiko kosinuso ir sinuso transformacijas „freqs“ tenzoriui. „Freqs“ tensoryje yra kiekvienos įvesties sekos padėties ir kiekvieno įterpimo erdvės dimensijos dažnio reikšmės, apskaičiuotos pagal sekos pozicijas ir įterpimo matmenų atvirkštinius dažnius. Sinuso ir kosinuso funkcijos taikomos pagal elementus, todėl gaunami du tenzoriai, kurių forma yra tokia pati kaip ir „freqs“. Šios transformacijos padeda užkoduoti padėtį taip, kad užfiksuotų pozicinių santykių cikliškumą, palengvinant modelio gebėjimą suprasti santykines pozicijas.

-`tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)' sujungia kosinuso ir sinuso transformuotus tenzorius išilgai paskutinės ašies (žymima 'axis=-1'). Šių tenzorių sujungimas vienas šalia kito veiksmingai padvigubina „dažnių“ tenzoriaus matmenis, o pirmoji pusė reiškia kosinusu transformuotas reikšmes, o antroji – sinusu transformuotas kiekvienos padėties vertes. Sujungimas užtikrina, kad kiekvienoje padėties koduotėje būtų ir sinusinė, ir kosinusinė informacija, o tai leidžia išsaugoti informaciją apie padėties signalų amplitudę ir fazę.

  • Sujungtas tensorinis „emb“ dabar turi visas sukamąsias įvesties pozicijas. „emb“ forma bus tokia pati kaip „freqs“ pirmuosiuose dviejuose matmenyse (atitinka sekos pozicijas ir įterpimo matmenis), tačiau paskutinis jo matmuo bus dvigubai didesnis, atsižvelgiant į sinuso ir kosinuso reikšmes. Šie įterpimai naudojami įvesties įterpimams moduliuoti, pridedant padėties informaciją sukimosi lygiaverčiu būdu.

-cos_emb = įterpimai[:, Nėra, :self.dim // 2]:

  1. Pirmasis dvitaškis „:“ reiškia „pasirinkti visus šio aspekto elementus“, o tai šiuo atveju nurodo visas sekos vietas.

  2. „Nėra“ naudojamas papildomam matmeniui pridėti, todėl tenzorius tampa trimatis. Tai dažnai daroma siekiant užtikrinti suderinamumą su tam tikromis operacijomis, kurios tikimasi tam tikro matmenų skaičiaus įvesties. Pavyzdžiui, atliekant elementų dauginimą su kitu trimačiu tenoriumi, figūros turi būti suderintos pagal transliavimo taisykles.

  3. :self.dim // 2, pasirenka pirmąją paskutinės ašies matmenų pusę. Kadangi „įterpimo_dimensija“ padvigubinamas, kad būtų įtrauktos ir sinuso, ir kosinuso reikšmės, padalijus iš 2 efektyviai pasirenkami tik įterpimo kosinuso komponentai.

3 veiksmas: integravimas su Keras modeliu

Apibrėžę „RotaryEmbeddingLayer“, galite integruoti jį į savo Keras modelį. Šį sluoksnį reikia užtepti ant įterptų elementų prieš įterpiant juos į dėmesio sluoksnius arba kitus modelio sluoksnius.

Štai supaprastintas pavyzdys, kaip integruoti sukamuosius įterpimus į 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()

Code Labs Academy © 2025 Visos teisės saugomos.