Transformer-pohjaiset mallit ovat kuuluisia kyvystään jäsentää ja tulkita monimutkaista tekstiä. He luottavat sanojen järjestyksen ja kontekstin ymmärtämiseen - tehtäviin, joissa perinteiset paikannuskoodausmenetelmät ovat osoittaneet rajansa. Tämän aukon korjaamiseksi ROFORMER-malli, joka toimii Rotary Position Embeddingin (RoPE) avulla, määrittelee uudelleen lähestymistapamme paikannuskoodaukseen.
Perinteinen paikkakoodaus
Muuntajat käsittelevät tekstiä merkkien sarjana ja mahdollistavat sekvenssien rinnakkaisen käsittelyn tehokkuuden parantamiseksi. Tämä vahvuus toi kuitenkin haasteensa: mallin luontainen agnostismi symboliseen järjestykseen. Paikannuskoodaus oli vastaus, tarjoamalla jokaiselle tunnukselle yksilöllisen allekirjoituksen, joka ilmaisee sen sekvenssin sijainnin.
Absoluuttisen sijainnin upotukset
Aluksi mallit, kuten BERT, käyttivät absoluuttisen sijainnin upotuksia, jotka määrittivät kiinteän vektorin jokaiselle sekvenssin paikalle. Tämä menetelmä, vaikka se onkin yksinkertainen, puuttele kykyä sopeutua sekvenssin pituuden vaihteluihin tai korostaa merkkien välisiä suhteellisia etäisyyksiä, mikä on kriittistä monien kielellisten rakenteiden ymmärtämisen kannalta.
Suhteellisen sijainnin upotukset
Kielen dynaamisen luonteen vangitsemiseksi otettiin käyttöön suhteelliset sijainnit, joissa keskityttiin merkkien väliseen etäisyyteen niiden absoluuttisen sijainnin sijaan. Käsitteellisestä edustaan huolimatta nämä upotukset toivat laskennallista monimutkaisuutta, eivätkä ne onnistuneet integroitumaan saumattomasti Transformersin itsetarkkailumekanismiin, mikä rajoitti niiden tehokkuutta.
ROFORMER ja Rotary Position Upotus
Ymmärtääkseen olemassa olevien paikannuskoodausstrategioiden rajoitukset ROFORMER esittelee Rotary Position Embeddingin (RoPE), joka yhdistää absoluuttisen ja suhteellisen sijaintitiedon edut ilman niiden vastaavia haittoja.
Pyörimisasennon upottaminen
RoPE koodaa sijaintitietoja käyttämällä kiertomatriiseja, jolloin malli ymmärtää paitsi missä merkki on, myös kuinka se liittyy jokaiseen toiseen merkkiin sarjassa.
Credit: ArXiv
Se toimii geometrisen linssin läpi ja käsittelee merkkien paikkoja moniulotteisen tilan pisteinä, joita kierretään merkitsemään niiden peräkkäisiä suhteita. Tämä kierto mahdollistaa sen, että malli säilyttää ja hyödyntää sekä absoluuttisia että suhteellisia sijaintivihjeitä itsetarkkailumekanismissaan.
Köyden käyttöönotto
RoPE:n toteuttaminen sisältää jokaisen merkin sijainnin koodaamisen kiertomatriisiin ja tämän matriisin soveltamisen Transformerin itsetarkkailumekanismiin. Tämä prosessi mahdollistaa paikkatiedon joustavan, dynaamisen tulkinnan, mukautuu vaihteleviin sekvenssien pituuksiin ja vangitsee token-vuorovaikutusten olemuksen ilman merkittäviä laskennallisia lisäkustannuksia.
Ensin tarvitset toiminnon pyörivien upotusten luomiseen, ja sitten integroit nämä upotukset malliisi. Alla olevassa esimerkissä oletetaan, että olet perehtynyt mukautettujen tasojen luomiseen Kerasissa.
Vaihe 1: Määritä Rotary-upotustoiminto
Tämä toiminto luo pyörivät upotukset ottaen huomioon sekvenssin enimmäispituus ja upotusten mittasuhteet.
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ämä rivi laskee eksponentiaalisesti skaalattujen taajuuksien käänteisarvon sijaintiindeksien perusteella. Näitä taajuuksia käytetään luomaan sinimuotoisia kuvioita pyöriville upotuksille, mikä auttaa koodaamaan suhteellista sijaintitietoa sekvensseihin. Tämä mekanismi on erityisen hyödyllinen tehtävissä, joissa elementtien järjestyksen ja suhteellisen sijainnin ymmärtäminen on ratkaisevan tärkeää, kuten luonnollisen kielen käsittelyssä tai aikasarja-analyysissä.
Yksityiskohdissa:
-
tf.range(0, dim, 2, dtype=tf.float32)
luo arvoalueen 0:sta `dim':iin (poissulkeva), askeltaen 2:lla. Argumentti dtype=tf.float32 määrittää että tämän tensorin alkiot ovat 32-bittisiä liukulukuja. Jos "dim" on esimerkiksi 8, tämä tuottaa "[0, 2, 4, 6]". -
"tf.range":n tuottama tensori jaetaan sitten upotusten ulottuvuudella ("dim"). Tämä toiminto skaalaa nämä indeksit alueelle 0–1 (pois lukien, jos "dim" on parillinen, hieman mukaan lukien, jos "dim" on pariton, koska alueen askel ohittaa kaikki muut arvot). Jatkamalla esimerkkiä arvolla "dim" = 8, jakamalla 8:lla saadaan "[0,0, 0,25, 0,5, 0,75]".
-
Operaatio `10000** (...) nostaa 10 000 kunkin elementin potenssiin aiemmin skaalatussa tensorissa. Perusarvo 10 000 on jokseenkin mielivaltainen, mutta se on valittu varmistamaan, että taajuudet vaihtelevat laajalla alueella, mikä auttaa mallia erottamaan eri paikat tehokkaammin. Arvolla "[0,0, 0,25, 0,5, 0,75]" se soveltaisi tehotoimintoa jokaiseen, jolloin arvot olisivat paljon suurempia korkeammille elementeille.
-
Lopuksi käänteinen taajuus saadaan ottamalla edellisen vaiheen arvojen käänteisluku (1/x). Käänteiset taajuudet ovat pienempiä korkeammilla indekseillä, mikä tarkoittaa, että sekvenssissä edelleen olevilla elementeillä on pienempiä taajuuksia, mikä vaikuttaa siihen, miten niiden paikat koodataan malliin. Tämä mahdollistaa upotusten skaalauksen tavalla, jossa suhteelliset sijainnit voidaan päätellä mallin huomiomekanismien kautta.
Linja:
freqs = tf.einsum('i,j->ij', t, inv_freq)
käyttää TensorFlow'n tf.einsum
-funktiota, työkalua, joka mahdollistaa tiiviin ja tehokkaan tensorioperaatioiden ilmaisemisen Einsteinin summausmerkinnällä.
Tämä toiminto laskee tehokkaasti vektorien "t" ja "inv_freq" ulkotulon, mikä johtaa matriisiin, jossa jokainen elementti "(i, j)" on "t":n "i":nnen elementin ja " inv_freq:n j-elementti. Tämä matriisi (
taajuudet`) edustaa taajuuksia, joita käytetään luomaan sinimuotoisia kuvioita pyöriville upotuksille.
Vaihe 2: Mukautettu Keras-kerros pyöriville upotuksille
Luodaan nyt mukautettu Keras-taso, joka käyttää pyöriviä upotuksia syöttötensoriin. Tämä kerros olettaa, että syötetensorin muoto on (erän_koko, sekvenssin_pituus, upotuksen_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
Rivi "embeddings = self.rotary_embeddings[:seq_len]" valitsee sopivan ennalta laskettujen pyörivien upotusten osajoukon nykyisen syötesekvenssin pituuden perusteella. Koska sekvenssien pituus voi vaihdella erästä toiseen, tämä viipalointitoiminto varmistaa, että vain todellista sekvenssin pituutta vastaavia upotuksia käytetään.
Muuttuja "embeddings" sisältää nyt muodon tensorin "(seq_len, embedding_dim)", jossa "seq_len" on nykyisen erän sekvenssien pituus ja "embedding_dim" on upotusten ulottuvuus. Tämä tensori sisältää pyörivät sijainti upotukset jokaiselle sekvenssin kohdalle seq_len
asti.
`emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)' yhdistää sijaintitaajuuksien sini- ja kosinimuunnokset yhdeksi tensoriksi:
- "tf.cos(freqs)" ja "tf.sin(freqs)" soveltavat kosini- ja sinimuunnoksia vastaavasti "freqs"-tensoriin. Freqs-tensori sisältää taajuusarvot jokaiselle syöttösekvenssin kohdalle ja upotusavaruuden kullekin ulottuvuudelle, jotka on laskettu sekvenssipaikkojen ja upotusmittojen käänteisten taajuuksien perusteella. Sini- ja kosinifunktioita sovelletaan elementtikohtaisesti, jolloin tuloksena on kaksi samanmuotoista tensoria kuin taajuudet. Nämä muunnokset auttavat koodaamaan sijaintia tavalla, joka vangitsee paikkasuhteiden syklisen luonteen, mikä helpottaa mallin kykyä ymmärtää suhteellisia paikkoja.
-`tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1)' ketjuttaa kosini- ja sinimuunnostensorit viimeistä akselia pitkin (merkitty akselilla=-1). Näiden tensorien ketjuttaminen vierekkäin kaksinkertaistaa taajuuden tensorin ulottuvuuden siten, että ensimmäinen puoli edustaa kosinimuunnettuja arvoja ja toinen puolisko edustaa sinimuunnettuja arvoja jokaiselle sijainnille. Yhdistäminen varmistaa, että jokainen paikkakoodaus sisältää sekä sini- että kosiniinformaatiota, mikä mahdollistaa informaation säilyttämisen sekä paikkasignaalien amplitudista että vaiheesta.
- Yhdistetty tensori "emb" sisältää nyt täydelliset pyörivät upotukset syöttökohtia varten. Emb:n muoto on sama kuin freqs sen kahdessa ensimmäisessä ulottuvuudessa (vastaa sekvenssin paikkoja ja upotusmittoja), mutta sen viimeinen ulottuvuus on kaksi kertaa suurempi, mikä vastaa sekä sini- että kosiniarvoja. Näitä upotuksia käytetään moduloimaan syöttö upotuksia lisäämällä paikkatietoa rotaatiota vastaavalla tavalla.
-cos_emb = upotukset[:, Ei mitään, :self.dim // 2]
:
-
Ensimmäinen kaksoispiste
:
tarkoittaa "valitse kaikki tämän ulottuvuuden elementit", joka tässä tapauksessa viittaa kaikkiin kohtiin sarjassa. -
"Ei mitään" käytetään lisäämään ylimääräinen ulottuvuus, mikä tekee tensorista kolmiulotteisen. Tämä tehdään usein yhteensopivuuden varmistamiseksi tiettyjen toimintojen kanssa, jotka odottavat syötteitä tietyllä määrällä ulottuvuuksia. Esimerkiksi suoritettaessa elementtikohtaista kertolaskua toisella tensorilla, joka on kolmiulotteinen, muotojen on kohdistettava yleislähetyssääntöjen mukaisesti.
-
:self.dim // 2
, valitsee viimeisen akselin mittojen ensimmäisen puoliskon. Koska "embedding_dimension" kaksinkertaistuu sisältämään sekä sini- että kosiniarvot, jakaminen kahdella valitsee tehokkaasti vain upotusten kosinikomponentit.
Vaihe 3: Integrointi Keras-malliin
Kun olet määrittänyt RotaryEmbeddingLayerin, voit integroida sen Keras-malliisi. Tämä kerros tulee levittää upotuksiisi ennen niiden syöttämistä huomiokerroksiin tai muihin mallikerroksiin.
Tässä on yksinkertaistettu esimerkki siitä, miten pyörivät upotukset integroidaan malliin:
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()