RoFormer: удосконалений трансформатор із вбудованим поворотним положенням

RoFormer: удосконалений трансформатор із вбудованим поворотним положенням

Моделі на основі трансформаторів відомі своєю здатністю аналізувати та інтерпретувати складний текст. Вони покладаються на розуміння порядку та контексту слів - завдання, у яких традиційні методи позиційного кодування показали свої межі. Усуваючи цю прогалину, модель ROFORMER на базі Rotary Position Embedding (RoPE) переосмислює наш підхід до позиційного кодування.

Традиційне позиційне кодування

Transformers розглядають текст як серію токенів і дозволяють паралельну обробку послідовностей для більшої ефективності. Однак ця перевага принесла свій виклик: притаманний моделі агностицизм до символічного порядку. Позиційне кодування було відповіддю, забезпечуючи кожному маркеру унікальний підпис, що позначає його позицію в послідовності.

Вбудовування абсолютної позиції

Спочатку такі моделі, як BERT, використовували вбудовування абсолютної позиції, призначаючи фіксований вектор для кожної позиції в послідовності. Цей метод, хоч і простий, за своєю суттю не має можливості адаптуватися до варіацій довжини послідовності або підкреслювати відносні відстані між лексемами, критичні для розуміння багатьох лінгвістичних конструкцій.

Вбудовування відносної позиції

Щоб відобразити динамічну природу мови, було запроваджено вбудовування відносної позиції, зосереджуючись на відстані між лексемами, а не на їхній абсолютній позиції. Незважаючи на свою концептуальну перевагу, ці вбудовування створили обчислювальну складність і не змогли бездоганно інтегруватися в механізм самоуважності Трансформерів, обмежуючи їхню ефективність.

ROFORMER і поворотне положення

Визнаючи обмеження існуючих стратегій позиційного кодування, ROFORMER представляє Rotary Position Embedding (RoPE), підхід, який поєднує в собі переваги абсолютної та відносної інформації про позицію без відповідних недоліків.

Вбудовування поворотної позиції

RoPE кодує позиційну інформацію за допомогою матриць обертання, що дає змогу моделі зрозуміти не лише те, де знаходиться маркер, а й те, як він пов’язаний з усіма іншими маркерами в послідовності.

Reformer.pngCredit: ArXiv

Він діє через геометричну лінзу, розглядаючи позиції токенів як точки в багатовимірному просторі, які обертаються, щоб позначити їхні послідовні відносини. Це обертання дозволяє моделі зберігати та використовувати як абсолютні, так і відносні позиційні ознаки в рамках механізму самоуважності.

Впровадження RoPE

Реалізація RoPE передбачає кодування позиції кожного маркера в матрицю обертання та застосування цієї матриці в механізмі самоуважності Transformer. Цей процес забезпечує гнучку, динамічну інтерпретацію позиційної інформації, враховуючи різну довжину послідовності та фіксуючи суть взаємозв’язків маркерів без значних обчислювальних витрат.

По-перше, вам знадобиться функція для генерації поворотних вбудовань, а потім ви інтегруєте ці вбудовані елементи у свою модель. У прикладі нижче передбачається, що ви знайомі зі створенням власних шарів у 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, потім ділиться на розмірність (dim) вкладень. Ця операція масштабує ці індекси до діапазону від 0 до 1 (за винятком, якщо dim є парним, трохи включає, якщо dim є непарним, оскільки крок діапазону пропускає кожне інше значення). Продовжуючи приклад із «dim» = 8, ділення на 8 дає «[0.0, 0.25, 0.5, 0.75]».

  • Операція 10000 ** (...) підносить 10 000 до степеня кожного елемента в попередньо масштабованому тензорі. База 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) є добутком i-го елемента t і j-й елемент inv_freq. Ця матриця (freqs) представляє частоти, які використовуються для генерації синусоїдальних візерунків для поворотних вставок.

Крок 2: Користувацький шар Keras для поворотних вставок

Тепер давайте створимо спеціальний шар Keras, який застосовує поворотні вбудовування до вхідного тензора. Цей рівень передбачає, що вхідний тензор має форму (batch_size, sequence_length, embedding_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

Рядок 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)), axis=-1) поєднує перетворення синусів і косинусів позиційних частот в один тензор:

-tf.cos(freqs) і tf.sin(freqs) застосовують перетворення косинуса та синуса відповідно до тензора freqs. Тензор "freqs" містить значення частоти для кожної позиції у вхідній послідовності та кожного виміру простору вбудовування, обчислені на основі позицій послідовності та зворотних частот вимірів вбудовування. Функції синус і косинус застосовуються поелементно, у результаті чого утворюються два тензори такої самої форми, як і freqs. Ці перетворення допомагають кодувати позицію таким чином, щоб відобразити циклічний характер позиційних зв’язків, сприяючи здатності моделі розуміти відносні позиції.

-tf.concat((tf.cos(freqs), tf.sin(freqs)), axis=-1) об’єднує перетворені косинус і синус тензори вздовж останньої осі (позначається axis=-1). Об’єднання цих тензорів пліч-о-пліч ефективно подвоює розмірність тензора «freqs», причому перша половина представляє значення, перетворені в косинус, а друга половина — значення, перетворені в синус для кожної позиції. Конкатенація гарантує, що кожне позиційне кодування містить як синусну, так і косинусну інформацію, що дозволяє зберегти інформацію як про амплітуду, так і про фазу позиційних сигналів.

— Конкатенований тензор emb тепер містить повні поворотні вкладення для вхідних позицій. Форма emb буде такою самою, як freqs, у своїх перших двох вимірах (що відповідають позиціям послідовності та розмірам вбудовування), але його останній вимір буде вдвічі більшим, враховуючи як значення синуса, так і косинуса. Ці вбудовування використовуються для модуляції вхідних вбудовувань шляхом додавання позиційної інформації ротаційно-еквіваріантним способом.

-cos_emb = embeddings[:, None, :self.dim // 2]:

  1. Перша двокрапка : означає «вибрати всі елементи в цьому вимірі», що в даному випадку відноситься до всіх позицій у послідовності.

  2. None використовується для додавання додаткового виміру, що робить тензор тривимірним. Це часто робиться для забезпечення сумісності з певними операціями, які очікують введення певної кількості розмірів. Наприклад, під час виконання поелементного множення з іншим тривимірним тензором фігури мають вирівнюватися відповідно до правил трансляції.

  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 Всі права захищені.