RoFormer. Ընդլայնված տրանսֆորմատոր՝ պտտվող դիրքի ներկառուցմամբ

RoFormer. Ընդլայնված տրանսֆորմատոր՝ պտտվող դիրքի ներկառուցմամբ

Տրանսֆորմատորների վրա հիմնված մոդելները հայտնի են բարդ տեքստը վերլուծելու և մեկնաբանելու ունակությամբ: Նրանք հիմնվում են բառերի կարգն ու համատեքստը հասկանալու վրա. առաջադրանքներ, որոնցում ավանդական դիրքային կոդավորման մեթոդները ցույց են տվել իրենց սահմանները: Անդրադառնալով այս բացը, ROFORMER մոդելը, որը սնուցվում է Պտտվող դիրքի ներկառուցմամբ (RoPE), վերասահմանում է դիրքային կոդավորման մեր մոտեցումը:

Ավանդական դիրքային կոդավորում

Տրանսֆորմատորները տեքստը վերաբերվում են որպես նշանների շարք և թույլ են տալիս հաջորդականությունների զուգահեռ մշակումը ավելի մեծ արդյունավետության համար: Այնուամենայնիվ, այս ուժը բերեց իր մարտահրավերը՝ մոդելի բնորոշ ագնոստիցիզմը խորհրդանշական կարգի: Դիրքային կոդավորումը-ը պատասխանն էր՝ յուրաքանչյուր նշանի տրամադրելով եզակի ստորագրություն, որը ցույց է տալիս իր հաջորդականության դիրքը:

Բացարձակ դիրքի ներկառուցումներ

Սկզբում BERT-ի նման մոդելներն օգտագործում էին բացարձակ դիրքի ներկառուցումներ՝ յուրաքանչյուր դիրքի հաջորդականությամբ հատկացնելով ֆիքսված վեկտոր: Այս մեթոդը, թեև պարզ է, ի սկզբանե չունի հաջորդականության երկարության տատանումներին հարմարվելու կամ նշանների միջև հարաբերական հեռավորությունն ընդգծելու կարողությունը, ինչը կարևոր է լեզվական շատ կառուցվածքներ հասկանալու համար:

Հարաբերական դիրքի ներկառուցումներ

Լեզվի դինամիկ բնույթը պատկերելու համար ներդրվեցին հարաբերական դիրքի ներկառուցումներ՝ կենտրոնանալով նշանների միջև հեռավորության վրա, այլ ոչ թե դրանց բացարձակ դիրքերի վրա: Չնայած իրենց հայեցակարգային առավելությանը, այս ներկառուցումները ներկայացրեցին հաշվողական բարդություն և չհաջողվեց անխափան կերպով ինտեգրվել տրանսֆորմերների ինքնորոշման մեխանիզմին` սահմանափակելով դրանց արդյունավետությունը:

ROFORMER և Rotary Position Embedding

Ճանաչելով առկա դիրքային կոդավորման ռազմավարությունների սահմանափակումները՝ ROFORMER-ը ներկայացնում է Rotary Position Embedding (RoPE) մոտեցումը, որը միավորում է բացարձակ և հարաբերական դիրքի տեղեկատվության առավելությունները՝ առանց դրանց համապատասխան թերությունների:

Պտտվող դիրքի ներդրում

RoPE-ը կոդավորում է դիրքային տեղեկատվությունը, օգտագործելով պտտման մատրիցաներ՝ հնարավորություն տալով մոդելին հասկանալ ոչ միայն, թե որտեղ է նշանը, այլ ինչպես է այն առնչվում հաջորդականությամբ յուրաքանչյուր այլ նշանի հետ:

Reformer.pngCredit: 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]:

  1. Առաջին կետը : նշանակում է «ընտրել բոլոր տարրերը այս հարթության մեջ», որը, այս դեպքում, վերաբերում է հաջորդականության բոլոր դիրքերին:

  2. «Ոչ մեկը» օգտագործվում է լրացուցիչ չափում ավելացնելու համար՝ թեզորը դարձնելով եռաչափ: Սա հաճախ արվում է որոշակի գործողությունների հետ համատեղելիություն ապահովելու համար, որոնք ակնկալում են որոշակի քանակի չափերի մուտքեր: Օրինակ, երբ տարրի իմաստով բազմապատկում ենք կատարում մեկ այլ տենզորի հետ, որը եռաչափ է, ձևերը պետք է համապատասխանեցվեն հեռարձակման կանոններին համապատասխան:

  3. :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()

Code Labs Academy © 2025 Բոլոր իրավունքները պաշտպանված են.