Տրանսֆորմատորների վրա հիմնված մոդելները հայտնի են բարդ տեքստը վերլուծելու և մեկնաբանելու ունակությամբ: Նրանք հիմնվում են բառերի կարգն ու համատեքստը հասկանալու վրա. առաջադրանքներ, որոնցում ավանդական դիրքային կոդավորման մեթոդները ցույց են տվել իրենց սահմանները: Անդրադառնալով այս բացը, ROFORMER մոդելը, որը սնուցվում է Պտտվող դիրքի ներկառուցմամբ (RoPE), վերասահմանում է դիրքային կոդավորման մեր մոտեցումը:
Ավանդական դիրքային կոդավորում
Տրանսֆորմատորները տեքստը վերաբերվում են որպես նշանների շարք և թույլ են տալիս հաջորդականությունների զուգահեռ մշակումը ավելի մեծ արդյունավետության համար: Այնուամենայնիվ, այս ուժը բերեց իր մարտահրավերը՝ մոդելի բնորոշ ագնոստիցիզմը խորհրդանշական կարգի: Դիրքային կոդավորումը-ը պատասխանն էր՝ յուրաքանչյուր նշանի տրամադրելով եզակի ստորագրություն, որը ցույց է տալիս իր հաջորդականության դիրքը:
Բացարձակ դիրքի ներկառուցումներ
Սկզբում BERT-ի նման մոդելներն օգտագործում էին բացարձակ դիրքի ներկառուցումներ՝ յուրաքանչյուր դիրքի հաջորդականությամբ հատկացնելով ֆիքսված վեկտոր: Այս մեթոդը, թեև պարզ է, ի սկզբանե չունի հաջորդականության երկարության տատանումներին հարմարվելու կամ նշանների միջև հարաբերական հեռավորությունն ընդգծելու կարողությունը, ինչը կարևոր է լեզվական շատ կառուցվածքներ հասկանալու համար:
Հարաբերական դիրքի ներկառուցումներ
Լեզվի դինամիկ բնույթը պատկերելու համար ներդրվեցին հարաբերական դիրքի ներկառուցումներ՝ կենտրոնանալով նշանների միջև հեռավորության վրա, այլ ոչ թե դրանց բացարձակ դիրքերի վրա: Չնայած իրենց հայեցակարգային առավելությանը, այս ներկառուցումները ներկայացրեցին հաշվողական բարդություն և չհաջողվեց անխափան կերպով ինտեգրվել տրանսֆորմերների ինքնորոշման մեխանիզմին` սահմանափակելով դրանց արդյունավետությունը:
ROFORMER և Rotary Position Embedding
Ճանաչելով առկա դիրքային կոդավորման ռազմավարությունների սահմանափակումները՝ ROFORMER-ը ներկայացնում է Rotary Position Embedding (RoPE) մոտեցումը, որը միավորում է բացարձակ և հարաբերական դիրքի տեղեկատվության առավելությունները՝ առանց դրանց համապատասխան թերությունների:
Պտտվող դիրքի ներդրում
RoPE-ը կոդավորում է դիրքային տեղեկատվությունը, օգտագործելով պտտման մատրիցաներ՝ հնարավորություն տալով մոդելին հասկանալ ոչ միայն, թե որտեղ է նշանը, այլ ինչպես է այն առնչվում հաջորդականությամբ յուրաքանչյուր այլ նշանի հետ:
Credit: ArXiv
Այն գործում է երկրաչափական ոսպնյակի միջոցով՝ նշանային դիրքերը դիտարկելով որպես կետեր բազմաչափ տարածության մեջ, որոնք պտտվում են՝ նշելու իրենց հաջորդական հարաբերությունները: Այս ռոտացիան թույլ է տալիս մոդելին պահպանել և շահագործել ինչպես բացարձակ, այնպես էլ հարաբերական դիրքային ազդանշանները իր ինքնորոշման մեխանիզմի շրջանակներում:
Իրականացնող RoPE
RoPE-ի ներդրումը ներառում է յուրաքանչյուր նշանի դիրքի կոդավորումը պտտվող մատրիցայի մեջ և այս մատրիցայի կիրառումը տրանսֆորմատորի ինքնորոշման մեխանիզմում: Այս գործընթացը թույլ է տալիս ճկուն, դինամիկ մեկնաբանել դիրքային տեղեկատվությունը՝ հարմարեցնելով տարբեր հաջորդականությունների երկարությունները և ֆիքսելով նշանների փոխհարաբերությունների էությունը՝ առանց զգալի հաշվողական ծախսերի:
Սկզբում ձեզ անհրաժեշտ կլինի պտտվող ներդիրներ ստեղծելու գործառույթ, այնուհետև դուք կինտեգրեք այդ ներդիրները ձեր մոդելի մեջ: Ստորև բերված օրինակը ենթադրում է, որ դուք ծանոթ եք Keras-ում հատուկ շերտեր ստեղծելուն:
Քայլ 1. Սահմանեք պտտվող ներկառուցման գործառույթը
Այս ֆունկցիան առաջացնում է պտտվող ներդիրներ՝ հաշվի առնելով հաջորդականության առավելագույն երկարությունը և ներդիրների ծավալայինությունը:
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))
Այս տողը հաշվարկում է էքսպոնենցիալ մասշտաբային հաճախությունների հակադարձությունը՝ հիմնվելով դիրքի ինդեքսների վրա: Այս հաճախականություններն օգտագործվում են պտտվող ներդիրների համար սինուսոիդային նախշեր ստեղծելու համար, որն օգնում է կոդավորել հարաբերական դիրքային տեղեկատվությունը հաջորդականությամբ: Այս մեխանիզմը հատկապես օգտակար է այն առաջադրանքներում, որտեղ կարևոր է տարրերի կարգի և հարաբերական դիրքի ըմբռնումը, օրինակ՝ բնական լեզվի մշակման կամ ժամանակային շարքերի վերլուծության ժամանակ:
Մանրամասն՝
-
tf.range(0, dim, 2, dtype=tf.float32)
ստեղծում է արժեքների տիրույթ՝ սկսած 0-ից մինչև «dim» (բացառիկ), քայլելով 2-ով: «dtype=tf.float32» արգումենտը սահմանում է. որ այս թենզորի տարրերը 32-բիթանոց լողացող կետով թվեր են։ Եթե «dim»-ը 8 է, օրինակ, սա կառաջացնի «[0, 2, 4, 6]»: -
«tf.range»-ի կողմից արտադրված տենզորն այնուհետև բաժանվում է ներկառուցումների չափականության («մութ») վրա: Այս գործողությունը նվազեցնում է այս ցուցանիշները մինչև 0-ի և 1-ի միջակայքը (բացառությամբ, եթե «մութը» զույգ է, թեթևակի ներառում է, եթե «մութ» կենտ է, քանի որ միջակայքի քայլը բաց է թողնում բոլոր մյուս արժեքները): Օրինակը շարունակելով «dim» = 8-ով, բաժանելով 8-ի, ստացվում է «[0.0, 0.25, 0.5, 0.75]»:
-
«10000 ** (...)» օպերացիան բարձրացնում է 10000-ը յուրաքանչյուր տարրի հզորության նախկինում չափված թենզորում: 10,000-ի հիմքը որոշ չափով կամայական է, բայց ընտրված է ապահովելու համար, որ հաճախականությունները տատանվում են լայն տիրույթում, որն օգնում է մոդելին ավելի արդյունավետ տարբերակել տարբեր դիրքերը: «[0.0, 0.25, 0.5, 0.75]»-ի համար այն կկիրառի հզորության գործողությունը յուրաքանչյուրի վրա, ինչը կհանգեցնի ավելի մեծ արժեքների ավելի բարձր տարրերի համար:
-
Ի վերջո, հակադարձ հաճախականությունը ստացվում է նախորդ քայլի արժեքների փոխադարձ (1/x) հաշվի առնելով: Հակադարձ հաճախականությունները ավելի փոքր են ավելի բարձր ինդեքսների համար, ինչը նշանակում է, որ հաջորդականության հետագա տարրերը կունենան ավելի փոքր հաճախականություններ՝ ազդելով, թե ինչպես են դրանց դիրքերը կոդավորվում մոդելում: Սա թույլ է տալիս ներկառուցումները մասշտաբավորվել այնպես, որ հարաբերական դիրքերը կարելի է եզրակացնել մոդելի ուշադրության մեխանիզմների միջոցով:
Գիծ.
freqs = tf.einsum('i,j->ij', t, inv_freq)
օգտագործում է TensorFlow-ի «tf.einsum» ֆունկցիան, գործիք, որը թույլ է տալիս տենզորի գործողությունների հակիրճ և արդյունավետ արտահայտումը՝ օգտագործելով Էյնշտեյնի գումարման նշումը:
Այս գործողությունը արդյունավետորեն հաշվարկում է «t» և «inv_freq» վեկտորների արտաքին արտադրյալը, ինչի արդյունքում ստացվում է մատրից, որտեղ «(i, j)» յուրաքանչյուր տարր «t» և «i» -րդ տարրի արտադրյալն է: «inv_freq»-ի j`-րդ տարրը: Այս մատրիցը («freqs») ներկայացնում է այն հաճախականությունները, որոնք օգտագործվում են պտտվող ներդիրների համար սինուսոիդային նախշեր ստեղծելու համար:
Քայլ 2. Պատվերով Keras շերտ պտտվող ներկառուցումների համար
Այժմ եկեք ստեղծենք հատուկ Keras շերտ, որը կիրառում է պտտվող ներկառուցումներ մուտքային թենզորի վրա: Այս շերտը ենթադրում է, որ մուտքային տենզորը ունի «խմբաքանակի_չափ, հաջորդականության_երկարություն, ներկառուցման_մթամոտ)» ձևը:
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
«embeddings = self.rotary_embeddings[:seq_len]» տողը ընտրում է նախապես հաշվարկված պտտվող ներդիրների համապատասխան ենթաբազմությունը՝ հիմնվելով ընթացիկ մուտքային հաջորդականության երկարության վրա: Քանի որ հաջորդականությունների երկարությունը կարող է տարբեր լինել մեկ խմբաքանակից մյուսը, այս կտրման գործողությունը ապահովում է, որ օգտագործվում են միայն իրական հաջորդականության երկարությանը համապատասխանող ներդիրները:
«Embeddings» փոփոխականն այժմ ունի «(seq_len, embedding_dim)» ձևի թենզոր, որտեղ «seq_len»-ը ընթացիկ խմբաքանակի հաջորդականությունների երկարությունն է, իսկ «embedding_dim»-ը ներկառուցումների չափսերն է: Այս թենզորը պարունակում է պտտվող դիրքային ներկառուցումներ յուրաքանչյուր դիրքի համար մինչև «seq_len» հաջորդականության համար:
emb = tf.concat((tf.cos(freqs), tf.sin(freqs)), առանցք=-1)
միավորում է դիրքային հաճախությունների սինուսի և կոսինուսի փոխակերպումները մեկ տենզորի մեջ.
-tf.cos(freqs)
և tf.sin(freqs)
համապատասխանաբար կիրառում են կոսինուսի և սինուսի փոխակերպումները` «freqs» տենզորի նկատմամբ: «Հաճախականությունների» տենզորը պարունակում է հաճախականության արժեքներ մուտքային հաջորդականության յուրաքանչյուր դիրքի և ներկառուցման տարածության յուրաքանչյուր չափման համար, որը հաշվարկվում է հաջորդականության դիրքերի և ներկառուցման չափերի հակադարձ հաճախականությունների հիման վրա: Սինուսի և կոսինուսի ֆունկցիաները կիրառվում են տարրական առումով, ինչի արդյունքում ստացվում են «հաճախականների» նույն ձևի երկու տենզորներ: Այս փոխակերպումները օգնում են կոդավորել դիրքը այնպես, որ գրավի դիրքային հարաբերությունների ցիկլային բնույթը՝ հեշտացնելով հարաբերական դիրքերը հասկանալու մոդելի կարողությունը:
-tf.concat((tf.cos(freqs), tf.sin(freqs)), առանցք=-1)
միացնում է կոսինուսի և սինուսի փոխակերպված թենզորները վերջին առանցքի երկայնքով (նշվում է առանցք=-1
): Այս տենզորների միացումը կողք կողքի արդյունավետորեն կրկնապատկում է «հաճախականությունների» տենզորի չափսերը, ընդ որում առաջին կեսը ներկայացնում է կոսինուսի փոխակերպված արժեքները, իսկ երկրորդ կեսը ներկայացնում է սինուսային փոխակերպված արժեքները յուրաքանչյուր դիրքի համար: Միացումն ապահովում է, որ յուրաքանչյուր դիրքային կոդավորում պարունակում է և՛ սինուսային, և՛ կոսինուսային տեղեկատվություն, ինչը թույլ է տալիս պահպանել տեղեկատվությունը դիրքային ազդանշանների և՛ ամպլիտուդության, և՛ փուլի մասին:
- Համակցված տենզորի «emb» այժմ պահում է ամբողջական պտտվող ներդիրները մուտքային դիրքերի համար: «Emb»-ի ձևը կլինի նույնը, ինչ «freqs»-ն իր առաջին երկու չափումներում (համապատասխանում է հաջորդականության դիրքերին և ներդրման չափերին), սակայն վերջին չափը կլինի երկու անգամ ավելի մեծ՝ հաշվի առնելով և՛ սինուսի, և՛ կոսինուսի արժեքները: Այս ներկառուցումները օգտագործվում են մուտքային ներդիրները մոդուլացնելու համար՝ ավելացնելով դիրքային տեղեկատվություն ռոտացիոն համարժեք եղանակով:
-cos_emb = embeddings[:, None, :self.dim // 2]
:
-
Առաջին կետը
:
նշանակում է «ընտրել բոլոր տարրերը այս հարթության մեջ», որը, այս դեպքում, վերաբերում է հաջորդականության բոլոր դիրքերին: -
«Ոչ մեկը» օգտագործվում է լրացուցիչ չափում ավելացնելու համար՝ թեզորը դարձնելով եռաչափ: Սա հաճախ արվում է որոշակի գործողությունների հետ համատեղելիություն ապահովելու համար, որոնք ակնկալում են որոշակի քանակի չափերի մուտքեր: Օրինակ, երբ տարրի իմաստով բազմապատկում ենք կատարում մեկ այլ տենզորի հետ, որը եռաչափ է, ձևերը պետք է համապատասխանեցվեն հեռարձակման կանոններին համապատասխան:
-
:self.dim // 2
, ընտրում է չափերի առաջին կեսը վերջին առանցքում: Քանի որ «embedding_dimension»-ը կրկնապատկվել է՝ ներառելով և՛ սինուսի, և՛ կոսինուսի արժեքները, 2-ի բաժանելով արդյունավետորեն ընտրվում են ներկառուցումների միայն կոսինուսային բաղադրիչները:
Քայլ 3. Ինտեգրում Keras մոդելի հետ
«RotaryEmbeddingLayer»-ը սահմանելուց հետո կարող եք այն ինտեգրել ձեր Keras մոդելին: Այս շերտը պետք է կիրառվի ձեր ներկառուցվածքների վրա՝ նախքան դրանք սնուցել ուշադրության շերտերի կամ որևէ հաջորդ մոդելի շերտերի մեջ:
Ահա մի պարզեցված օրինակ, թե ինչպես կարելի է ինտեգրել պտտվող ներդիրները մոդելի մեջ.
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()