Расскажи про виды позиционного кодирования, в частности про Rotary Positional Encoding (RoPE).
Ответ от нейросети
sobes.tech AI
Позиционное кодирование — это способ добавить информацию о порядке элементов в последовательности, что важно для моделей трансформеров, которые сами по себе не учитывают порядок слов.
Виды позиционного кодирования:
-
Синусоидальное позиционное кодирование (Sinusoidal PE) — классический метод из статьи Vaswani et al. (2017). Каждому положению соответствует вектор, элементы которого вычисляются через синусы и косинусы с разными частотами. Это позволяет модели обобщать на последовательности большей длины.
-
Обучаемое позиционное кодирование (Learned PE) — позиционные векторы инициализируются случайно и обучаются вместе с моделью. Позволяет модели адаптироваться к конкретной задаче, но хуже обобщает на длинные последовательности.
-
Relative Positional Encoding (Относительное позиционное кодирование) — кодирует относительные расстояния между элементами, а не абсолютные позиции. Это улучшает способность модели учитывать контекст.
-
Rotary Positional Encoding (RoPE) — относительно новый метод, который внедряет позиционную информацию через вращение (ротацию) векторов признаков. Идея в том, что позиционная информация кодируется как вращение векторного пространства, что позволяет эффективно учитывать относительные позиции и сохранять свойства трансляционной инвариантности.
Как работает RoPE?
- Каждому элементу последовательности соответствует позиционный индекс.
- Векторы признаков разбиваются на пары и к каждой паре применяется двумерное вращение на угол, зависящий от позиции.
- Это вращение реализуется через умножение на матрицу поворота, параметризованную синусами и косинусами, аналогично синусоидальному PE, но применяется к самим признакам, а не добавляется.
RoPE хорошо интегрируется с механизмом внимания, позволяя модели учитывать относительные позиции без явного вычисления разностей индексов.
Пример применения RoPE в трансформерах:
import torch
import math
def rotary_positional_encoding(x):
# x: [seq_len, dim]
seq_len, dim = x.shape
assert dim % 2 == 0
pos = torch.arange(seq_len).unsqueeze(1) # [seq_len, 1]
dim_range = torch.arange(dim // 2) # [dim/2]
inv_freq = 1.0 / (10000 ** (2 * dim_range / dim))
angles = pos * inv_freq # [seq_len, dim/2]
sin, cos = angles.sin(), angles.cos()
x1, x2 = x[:, 0::2], x[:, 1::2]
x_rotated = torch.stack([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
return x_rotated.flatten(1)
Таким образом, RoPE обеспечивает более гибкое и эффективное позиционное кодирование, особенно полезное для длинных последовательностей и задач, где важны относительные позиции.