VKВлад КуликовОткрытые лекции
Современные LLM4 / 20

Модуль 4. Позиционные представления: от синусоид к нескольким осям

Курс «Modern LLMs» · лекция модуля 4 · редакция 2026.10.6 · 10 октября 2026 года

В М3 мы собирали внимание из запросов, ключей и значений. Теперь оставим содержимое запроса и ключа неизменным и спросим: как изменится их взаимодействие, если переставить токены или увеличить расстояние между ними? Этот вопрос приведёт нас от синусоидального вектора к вращению RoPE, а затем — к расширению контекста и координатам изображения, видео и аудио.

Понадобятся скалярное произведение и механизм внимания из М3. Синус, косинус и матрицу поворота разберём на одной паре координат; комплексные числа останутся дополнительным способом записать то же вычисление.

Как читать модуль

  • Первый проход — понять геометрию. Прочитайте §§1–10 по порядку. В §2 достаточно карты методов; подробности истории и код в §4 раскрываются отдельно. В §7 следите за тем, какие частоты меняются и почему; вывод границ можно разобрать позже. Затем прочитайте §§13 и 17 и ответьте на вопросы §15.
  • Второй проход — посчитать и реализовать. Воспроизведите пример §5, рампу §7 и код §§4 и 11. Пройдите ноутбук (§12), особенно проверку кэша и точности позиций, затем упражнения §16.
  • Справочный проход. Формы и спаривание координат — §4; спектр — §6; PI/NTK/YaRN — §7; конфигурация — §10; несколько осей — §13; карта проверенных реализаций — §14. Следующий модуль, М5, посвящён устройству и исполнению внимания.

1. Мотивация: от содержания к порядку

Возьмём последовательность скрытых состояний X=(x1,…,xT)X=(x_1,\ldots,x_T) и обычный двунаправленный self-attention без позиционного сигнала и ограничивающей маски, с отключённым dropout. Если переставить строки XX одной и той же матрицей перестановки PP, то запросы, ключи и значения переставятся так же, а выход удовлетворит

Attn⁡(PX)=PAttn⁡(X).\operatorname{Attn}(PX)=P\operatorname{Attn}(X).

Это свойство называется перестановочной эквивариантностью (permutation equivariance). Оно не означает, что выход полностью инвариантен к перестановке: строки результата тоже переставляются. Но содержательная операция не различает две последовательности, если отличается только порядок их элементов.

Каузальная маска уже задаёт порядок доступа: позиция ii видит только разрешённый префикс. Такой декодер не сохраняет симметрию относительно произвольной перестановки. Через маску и слои модель может научиться различать позиции и без отдельного кодирования — к этому мы вернёмся в §9. Явная позиционная схема даёт более прямой способ задать расстояние и направление между двумя токенами.

Позиционная схема решает именно эту задачу. Она должна сообщить модели как минимум три вида информации:

  1. порядок — что было раньше, а что позже;
  2. расстояние — насколько далеко расположены элементы;
  3. структуру координат — для изображения и видео одной линейной оси уже недостаточно.

При этом желательно не превращать максимальную длину последовательности в жёсткий размер таблицы параметров. Отсюда и исторический переход от обучаемых абсолютных векторов к формулам, относительным смещениям и вращениям.

VIZ m4/01 — от перестановочной симметрии к позиции Без позиционного сигнала двунаправленный self-attention перестановочно-эквивариантен. Каузальная маска нарушает полную симметрию, но не заменяет богатую позиционную геометрию.

2. Карта методов: где появляется позиция

Позиционное кодирование (Positional Encoding, PE) — способ внести координаты токена в вычисление. Один из вариантов — RoPE (Rotary Position Embedding), вращение пар координат.

Позицию можно добавить к входному вектору, учесть при вычислении запроса и ключа или внести как отдельное смещение логита. Логит здесь — число до softmax, определяющее вес связи между позициями. Это три разных места вмешательства в уже знакомое вычисление из М3.

Где появляется сигналЧто меняетсяПример и продолжение
Во входном векторек эмбеддингу прибавляется вектор позициисинусоидальное PE, §§3–4
В запросе и ключе после проекциипары координат поворачиваются на угол, зависящий от позицииRoPE, §§4–7
В логите перед softmaxдобавляется слагаемое, зависящее от расстоянияALiBi, §8
Отдельного сигнала нетпорядок может усваиваться через каузальную маску и слоиNoPE, §9

Имена PI, NTK-aware и YaRN обозначают способы изменения частот RoPE (§7). M-RoPE распределяет пары координат между несколькими осями (§13). Пока достаточно знать, к какому вопросу относится каждое имя; определения появятся перед формулами.

VIZ m4/02 — ветви позиционных представлений Методы разветвляются по месту и способу внесения позиции. Более поздняя ветвь не отменяет предыдущие.

Исторические связи — дополнительное чтение

Оригинальный Transformer использовал детерминированное синусоидальное позиционное кодирование (Positional Encoding, PE). Для каждой позиции вычислялась лестница синусов и косинусов с геометрически распределёнными частотами. Таблица не обучалась и могла быть вычислена для позиции за пределами исходного контекста.

Параллельно распространились обучаемые абсолютные эмбеддинги. Они просты: позиция mm индексирует строку матрицы. Но таблица имеет конечную длину, а значение позиции за пределами обученного диапазона не определено без отдельного расширения.

Следующий шаг — относительные представления. Shaw et al. добавили обучаемые представления относительного смещения непосредственно в механизм внимания. Transformer-XL использовал относительную формулировку, чтобы согласовать повторно используемую память сегментов. ALiBi — Attention with Linear Biases пошла ещё проще: вместо вращения или таблицы к логиту добавляется линейный штраф за расстояние.

RoPE — Rotary Position Embedding кодирует абсолютную позицию как вращение, но в скалярном произведении запроса и ключа оставляет только их относительную фазу. Этот механизм оказался особенно удобным для языковых моделей с декодерной архитектурой: он не добавляет обучаемых позиционных параметров и совместим с кэшем ключей и значений (KV-cache).

Когда контекст начал расти с тысяч до сотен тысяч токенов, возникла отдельная линия расширения RoPE:

  • PI — Position Interpolation сжимает новые позиции в прежний диапазон;
  • статическое и динамическое NTK-aware масштабирование меняют спектр частот более неравномерно;
  • YaRN — Yet another RoPE extensioN соединяет интерполяцию и сохранение части исходных частот;
  • LongRoPE и родственные методы ищут коэффициенты по отдельным размерностям или стадиям длины;
  • Llama3-style scaling, partial RoPE, interleaved RoPE/NoPE, локальное внимание и настройка температуры образуют другие ветви.

Мультимодальные модели добавили ещё одно измерение проблемы. Для изображения важны высота и ширина, для видео — ещё и время, а потоковые аудио-видео системы должны синхронизировать разные временные сетки. Так появились M-RoPE и TMRoPE.

3. Мостик к классике: Фурье, комплексные числа и относительная фаза

Пусть mm — целочисленная позиция, отсчитываемая с нуля, а θi\theta_i — угловая частота пары координат: число радиан на один шаг позиции. Произведение mθim\theta_i — фаза, то есть угол на этой позиции. При увеличении позиции на один частота задаёт величину поворота.

Синусоидальное кодирование часто сравнивают с Fourier features. Аналогия полезна: положение mm отображается в набор периодических координат

(sin⁡mθi,cos⁡mθi).(\sin m\theta_i,\cos m\theta_i).

Для одной пары координат скалярное произведение точно, а не приблизительно, зависит от разности позиций:

sin⁡(mθ)sin⁡(nθ)+cos⁡(mθ)cos⁡(nθ)=cos⁡((m−n)θ).\sin(m\theta)\sin(n\theta)+ \cos(m\theta)\cos(n\theta) = \cos((m-n)\theta).

Но в классическом аддитивном PE позиционный вектор складывается с содержательным эмбеддингом до обучаемых проекций. Появляются перекрёстные слагаемые «содержание–позиция», и итоговый логит внимания уже не обязан быть чистой функцией m−nm-n.

RoPE помещает фазу в другое место: после проекции скрытого состояния в запрос и ключ. Пару координат можно воспринимать как стрелку на плоскости. Поворот обеих стрелок на одинаковый угол сохраняет угол между ними и их скалярное произведение.

Дополнительная запись через комплексные числа. Если записать пару как z=x1+ix2z=x_1+ix_2, где здесь ii — мнимая единица, поворот задаётся умножением на

eimθ.e^{im\theta}.

Обозначим через RmR_m поворот на позицию m для всех пар координат. В произведении повёрнутых запроса и ключа общий сдвиг фазы сокращается:

⟨Rmq,Rnk⟩=⟨q,Rn−mk⟩.\langle R_m q,R_n k\rangle = \langle q,R_{n-m}k\rangle.

Именно поэтому относительное смещение входит в логит напрямую. RoPE не требует, чтобы произвольный линейный слой коммутировал с вращением. Реальная последовательность операций другая: скрытое состояние сначала проецируется в QQ и KK, а затем уже полученные координатные пары поворачиваются.

Случайные Fourier features обычно выбирают частоты как стохастическую аппроксимацию заданного ядра. В Transformer частоты детерминированы геометрической прогрессией. Поэтому связь с ядрами — объясняющая аналогия, а не утверждение, что RoPE является конкретной случайной аппроксимацией ядра.

4. Формализм: от синусоид к вращению запроса и ключа

В формулах ниже DD — чётное число вращаемых координат, а не ширина всей модели dmodeld_{model}. Для обычной RoPE на всей голове D=dkD=d_k. В аддитивном PE тот же вид формулы применяется к ширине входного вектора. Частоту в коде часто называют inv_freq: она обратна масштабу, стоящему в знаменателе фазы. База base>1 задаёт, как быстро уменьшаются частоты от пары к паре.

Для размерности DD определим D/2D/2 обратных частот

θi=base−2i/D,i=0,…,D/2−1.\theta_i=\mathrm{base}^{-2i/D}, \qquad i=0,\ldots,D/2-1.

Соответствующая длина волны, измеряемая в позициях, равна

λi=2πθi.\lambda_i=\frac{2\pi}{\theta_i}.

В синусоидальном PE позиция mm получает координаты

PE(m,2i)=sin⁡(mθi),PE(m,2i+1)=cos⁡(mθi).PE(m,2i)=\sin(m\theta_i), \qquad PE(m,2i+1)=\cos(m\theta_i).

VIZ m4/03 — sinusoidal PE Каждая строка — одна координата позиционного вектора. Соседние строки образуют синусно-косинусную пару; высокие индексы меняются медленнее.

В RoPE та же фаза используется как матрица вращения пары:

Rm,i=(cos⁡(mθi)−sin⁡(mθi)sin⁡(mθi)cos⁡(mθi)).R_{m,i}= \begin{pmatrix} \cos(m\theta_i)&-\sin(m\theta_i)\\ \sin(m\theta_i)&\cos(m\theta_i) \end{pmatrix}.

Запрос и ключ поворачиваются независимо:

qm′=Rmqm,kn′=Rnkn.q'_m=R_m q_m, \qquad k'_n=R_n k_n.

Поскольку RmTRn=Rn−mR_m^TR_n=R_{n-m},

(qm′)Tkn′=qmTRn−mkn.(q'_m)^T k'_n =q_m^T R_{n-m}k_n.

Абсолютные позиции нужны, чтобы вычислить повороты, но при фиксированных содержательных qmq_m и knk_n позиционная часть билинейного скалярного произведения входит через относительное смещение n−mn-m. Полный логит зависит и от содержания запроса и ключа.

Две конвенции спаривания

Формулы часто записывают через соседние пары (x0,x1),(x2,x3),…(x_0,x_1),(x_2,x_3),\ldots. Реализации Llama/Hugging Face обычно используют rotate_half, где первая половина вектора спаривается со второй: (xj,xj+D/2)(x_j,x_{j+D/2}). Обе схемы математически эквивалентны после фиксированной перестановки координат, но веса одной модели нельзя интерпретировать другой схемой без этой перестановки.

RoPE сохраняет норму каждой пары и не увеличивает размер тензора. Но это не означает, что он «бесплатен»: нужно вычислить или получить sin/cos, применить их в нужной точности и правильно согласовать позиции с KV-cache.

VIZ m4/04 — где RoPE входит во внимание Сначала получаем Q/K/V линейными проекциями. Затем вращаем Q и K, вычисляем масштабированные логиты и смешиваем V. В показанном варианте V не вращается.

Частичная RoPE. Иногда вращается только часть головы: D<dkD<d_k, а остальные координаты проходят без изменения. В формуле частот используется вращаемая ширина D; при нормировке логитов внимания — полная ширина ключа dkd_k. Если дополнительный множитель применяется только к вращаемой части, он не масштабирует весь логит одинаково.

Реализация на NumPy и PyTorch — второй проход

NumPy → PyTorch · B02 — RoPE: вращение пар координат

Код для второго прохода. Здесь вход x[..., T, D] уже проверен: непустой вещественный тензор, чётная ширина D, целочисленные неотрицательные позиции [T], конечная база больше 1. Соседние координаты образуют пары. Полные проверки входа находятся в ноутбуке (§12).

import numpy as np
import torch

1. Явная NumPy-реализация

def numpy_rope_explicit(
    x: np.ndarray,
    position_ids: np.ndarray,
    *,
    base: float = 10_000.0,
) -> np.ndarray:
    dim = x.shape[-1]
    inv_freq = base ** (-np.arange(0, dim, 2) / dim)
    angles = position_ids[:, None] * inv_freq[None, :]
    shape = (1,) * (x.ndim - 2) + angles.shape
    cos, sin = np.cos(angles).reshape(shape), np.sin(angles).reshape(shape)
    even, odd = x[..., 0::2], x[..., 1::2]
    out = np.empty_like(x, dtype=np.result_type(x.dtype, np.float64))
    out[..., 0::2] = even * cos - odd * sin
    out[..., 1::2] = even * sin + odd * cos
    return out

NumPy явно строит обратные частоты, углы для абсолютных позиций и две координаты каждого двумерного вращения. Благодаря этому видно, где именно позиция входит в оператор.

2. Та же математика явными операциями PyTorch

def torch_rope_explicit(
    x: torch.Tensor,
    position_ids: torch.Tensor,
    *,
    base: float = 10_000.0,
) -> torch.Tensor:
    dim = x.shape[-1]
    work_dtype = torch.float64 if x.dtype == torch.float64 else torch.float32
    inv_freq = base ** (-torch.arange(0, dim, 2, device=x.device, dtype=work_dtype) / dim)
    angles = position_ids.to(device=x.device, dtype=work_dtype)[:, None] * inv_freq[None, :]
    shape = (1,) * (x.ndim - 2) + tuple(angles.shape)
    cos, sin = angles.cos().reshape(shape), angles.sin().reshape(shape)
    even, odd = x[..., 0::2].to(work_dtype), x[..., 1::2].to(work_dtype)
    out = torch.stack((even * cos - odd * sin, even * sin + odd * cos), dim=-1).flatten(-2)
    return out.to(x.dtype)

PyTorch вычисляет фазы и вращения как минимум в float32, затем возвращает тип входа. Это предотвращает раннее округление позиций в FP16/BF16. Для больших индексов и точного эталона используется float64; целочисленное хранение само по себе не устраняет погрешность последующего преобразования. Градиенты проходят по входным векторам.

АспектNumPyPyTorch
Частотыnp.arange + обычный массивtorch.arange(..., device=x.device)
Тригонометрияnp.cos, np.sinTensor.cos, Tensor.sin
УстройствоCPUCPU/CUDA/MPS
Градиентынетautograd по входу
Точностьвычисления и выход float64фазы float32/64; выход как у входа
Абсолютная позицияявный position_idsсогласована с позициями ключей в кэше

Исполняемая проверка эквивалентности и граничных случаев

rng = np.random.default_rng(2)
x_np = rng.standard_normal((2, 5, 8))
pos_np = np.arange(5, dtype=np.int64) + 11
np_out = numpy_rope_explicit(x_np, pos_np)
x = torch.tensor(x_np, dtype=torch.float64, requires_grad=True)
t_out = torch_rope_explicit(x, torch.tensor(pos_np))
np.testing.assert_allclose(np_out, t_out.detach().numpy(), rtol=1e-12, atol=1e-12)
t_out.square().sum().backward()
# A rotation is orthogonal: d ||R x||^2 / dx = 2 x.
torch.testing.assert_close(x.grad, 2 * x.detach(), rtol=1e-12, atol=1e-12)
# Half-precision IDs would merge 2048 and 2049 before the rotation.
long_ids = torch.tensor([2048, 2049], dtype=torch.int64)
half_x = torch.ones((2, 8), dtype=torch.float16)
half_out = torch_rope_explicit(half_x, long_ids)
expected = numpy_rope_explicit(half_x.numpy(), long_ids.numpy())
np.testing.assert_allclose(half_out.numpy(), expected, rtol=1e-3, atol=1e-3)
assert not torch.equal(half_out[0], half_out[1])
assert long_ids.to(torch.float16)[0] == long_ids.to(torch.float16)[1]
print("B02 outputs, analytic gradient, and float16 positions: PASS")

Полный исполняемый файл: m04_rope_bridges.py

5. Решённый пример: один и тот же относительный сдвиг

Возьмём

q=(1,0,0.5,0.5),k=(0,1,1,−0.5),q=(1,0,0.5,0.5), \qquad k=(0,1,1,-0.5),

D=4D=4 и base = 10000. Обратные частоты:

θ0=1,θ1=0.01.\theta_0=1, \qquad \theta_1=0.01.

Поместим запрос на позицию 3, а ключ — на позицию 1. Используем соседние пары координат. После двух независимых вращений получаем скалярное произведение до масштабирования логита внимания:

⟨R3q,R1k⟩≈1.144248.\langle R_3q,R_1k\rangle \approx1.144248.

Теперь одновременно сдвинем обе позиции: (3,1)→(7,5)(3,1)\to(7,5). Разность остаётся равной 2, и численный результат не меняется. То же происходит для пары (2,0)(2,0).

Позиция запросаПозиция ключаm−nm-nСкалярное произведение
3121.144248
7521.144248
2021.144248

VIZ m4/05 — RoPE на четырёх координатах Ручная трассировка двух координатных пар: абсолютные углы различаются, а общий относительный сдвиг даёт одинаковое скалярное произведение.

Для обычного внимания из М3 нужно ещё разделить результат на dk=4=2\sqrt{d_k}=\sqrt4=2: логит равен примерно 0.572124. Маску и softmax применяют после этого. При сравнении общего сдвига постоянный множитель ничего не меняет.

Этот пример показывает точную алгебру относительности. Он не утверждает, что внимание всегда является функцией только расстояния: qq и kk зависят от содержания токенов, слоя, головы и контекста.

6. Спектр частот: что действительно выбирает rope_theta

Параметр rope_theta, или base, определяет геометрическую лестницу частот. Самая быстрая пара при i=0i=0 имеет

θ0=1,λ0=2π\theta_0=1, \qquad \lambda_0=2\pi

для любой базы. Увеличение base не удаляет эту локальную частоту. Оно сильнее замедляет пары с большими индексами и тем самым перераспределяет спектральный бюджет в сторону длинных волн.

В таблице Lθi/(2π)L\theta_i/(2\pi) — число оборотов на интервале длины L. Это соглашение формулы YaRN. У последовательности из L токенов с индексами 0,…,L−10,\ldots,L-1 расстояние между крайними индексами равно L−1; не смешивайте эти две величины. Здесь длины волн измеряются в шагах позиции.

Для D=64D=64 получаем:

baseминимальная длина волнымаксимальная длина волныпар с ≥1 оборотом при L=4096
10 0006.2847 11723 из 32
150 0006.28649 40918 из 32
500 0006.282 084 76516 из 32

VIZ m4/06 — спектр длин волн Лестница длин волн для трёх баз. Горизонтали контекста помогают диагностировать, какие пары успели пройти значительную часть цикла, но не задают жёсткую границу различимости всей позиции.

Здесь особенно важна осторожная интерпретация. Каждая отдельная пара периодична. Но полный RoPE-вектор содержит много частот с разными периодами. Возврат одной пары в похожую фазу не означает, что весь позиционный код повторился. Поэтому максимальная длина волны одной координатной пары не является физическим пределом контекста, а число полных оборотов — не теорема о том, какие позиции модель способна различить.

Эти величины всё же полезны как диагностика. Пары, которые многократно вращались в обучающем диапазоне, хорошо покрыли свою фазу. Медленные пары видели лишь небольшой участок окружности; при экстраполяции они попадают в новую геометрию. Качество зависит от всего спектра, обучения, схемы внимания и задачи.

7. Расширение контекста: PI, NTK-aware scaling, YaRN и другие ветви

Обозначим через L0L_0 исходную длину, относительно которой настроены частоты, и захотим обрабатывать sL0sL_0 токенов, где s≥1s\ge1 — коэффициент расширения. В исследованиях это часто обучающая длина; в конфигурации модели смысл поля нужно проверять отдельно (§10).

Position Interpolation

PI заменяет позицию mm на m/sm/s. Эквивалентно можно разделить все обратные частоты на ss:

θi′=θis.\theta_i' = \frac{\theta_i}{s}.

Новые позиции попадают в диапазон углов, знакомый модели. Цена — сжатие и локальных фаз: соседние позиции становятся ближе по всем вращаемым координатам. Поэтому исходная работа использует дообучение, чтобы модель адаптировалась к новой геометрии.

Static NTK-aware scaling

Популярная статическая эвристика меняет базу:

base′=base sD/(D−2).\mathrm{base}' = \mathrm{base}\,s^{D/(D-2)}.

Быстрые частоты меняются слабее, медленные — сильнее. Название связано с NTK-мотивацией, но формула не является универсальной теоремой о безопасном расширении. Результат без дополнительного обучения зависит от модели и длины; его нужно измерять.

Здесь s≥1s\ge1, D>2D>2. При подстановке новой базы отношение частот равно θi′/θi=s−2i/(D−2)\theta_i^\prime/\theta_i=s^{-2i/(D-2)}: пара i=0 не меняется, а последняя пара замедляется ровно в s раз. При D=2 эта формула не определена. NTK — Neural Tangent Kernel, теоретическая модель поведения широких сетей; для нашего расчёта нужен только приведённый закон изменения базы.

YaRN

YaRN строит две версии спектра:

  • исходную — для экстраполяции;
  • интерполированную — θi/s\theta_i/s.

Затем по числу оборотов на исходном интервале вычисляется плавная рампа между ними. Пусть ri=L0θi/(2π)r_i=L_0\theta_i/(2\pi) — число оборотов на исходном интервале. Параметры βfast>βslow>0\beta_{fast}>\beta_{slow}>0 задают границы по оборотам: быстрые пары сохраняют исходную частоту, медленные получают интерполяцию. Решая ri=βr_i=\beta, находим дробный индекс пары:

b(β)=Dln⁡[L0/(2πβ)]2ln⁡(base),low=b(βfast),high=b(βslow).b(\beta)=\frac{D\ln[L_0/(2\pi\beta)]}{2\ln(\mathrm{base})},\qquad \mathrm{low}=b(\beta_{fast}),\quad \mathrm{high}=b(\beta_{slow}).

Рампа — линейный переход, обрезанный до диапазона от 0 до 1:

wi=clip⁡ ⁣(i−lowhigh−low,0,1),θi′=(1−wi)θi+wiθis.w_i=\operatorname{clip}\!\left(\frac{i-\mathrm{low}}{\mathrm{high}-\mathrm{low}},0,1\right),\qquad \theta_i^\prime=(1-w_i)\theta_i+w_i\frac{\theta_i}{s}.

При wi=0w_i=0 частота исходная, при wi=1w_i=1 — полностью интерполированная. Промежуточные пары смешивают два значения. Далее рассматриваем невырожденные границы внутри спектра; код отклоняет схлопнувшийся диапазон.

Для учебного сценария

head_dim = 64
base = 150000
original_context = 4096
factor = 32
beta_fast = 32
beta_slow = 1

оригинальная реализация gpt-oss использует непрерывные границы

low≈8.0928,high≈17.3980.\mathrm{low}\approx8.0928, \qquad \mathrm{high}\approx17.3980.

По целочисленным индексам это всё равно даёт три группы:

  • 9 пар остаются без изменения;
  • 9 находятся на переходной рампе;
  • 14 полностью интерполируются.

Универсальная реализация YaRN в Hugging Face также поддерживает режим truncate=True, который округляет эти границы до low=8, high=18. Для GptOssConfig по умолчанию задано truncate=False, поэтому при разборе именно gpt-oss корректнее сохранять непрерывные значения.

В данном сценарии полностью интерполированная зона совпадает с парами, не совершившими полного оборота на 4096. Это следствие выбранной формулы границ и параметров, а не общий закон «полный оборот разрешает экстраполяцию».

VIZ m4/07 — диагностические зоны YaRN Число оборотов используется как диагностический параметр YaRN-рампы: исходная зона, переход и интерполяция. Подписи не означают математическое «разрешено/запрещено».

YaRN также меняет концентрацию весов внимания. Температура — делитель логитов перед softmax: меньшая температура при тех же логитах усиливает различия весов. В YaRN это можно реализовать через масштаб attention_factor. И исходная реализация gpt-oss, и её адаптация в Hugging Face используют при s>1s>1 правило

a=0.1ln⁡s+1.a=0.1\ln s+1.

При s=32s=32:

a=1.346574.a=1.346574.

Важно понимать место применения. В обоих проверенных путях этот множитель применяется к вычисленным cos/sin. Если одинаковый множитель фактически входит и в повернутый qq, и в повернутый kk, их скалярное произведение получает фактор

a2≈1.813260.a^2\approx1.813260.

Равенство для всего скалярного произведения предполагает масштабирование всех координат Q и K. При частичной RoPE масштабируется только соответствующая сумма, если остальные координаты отдельно не изменены. Формула для a эмпирическая, а не следствие тождества вращения.

Другие реализации могут переносить эквивалентное масштабирование в запрос, ключ или непосредственно в логит внимания. Поэтому поле attention_factor нужно читать вместе с кодом реализации.

LongRoPE и современное ветвление

LongRoPE ищет коэффициенты масштабирования по отдельным размерностям и допускает разные режимы на разных длинах. LongRoPE2 добавляет более явную привязку к критериям, учитывающим обучение. Llama3-style scaling по-разному обрабатывает диапазоны длин волн. Другие модели сочетают RoPE с NoPE-слоями, локальным вниманием, разбиением на блоки или динамической температурой.

VIZ m4/08 — способы масштабирования спектра Один исходный спектр и три учебные трансформации: равномерная PI, статическая NTK-aware эвристика и кусочная YaRN. График сравнивает геометрию, а не гарантированное качество.

8. ALiBi: линейное позиционное смещение

ALiBi — Attention with Linear Biases не поворачивает QQ и KK. Для головы hh к содержательному логиту добавляется штраф

Sij(h)=qiTkjdk−mh(i−j)S_{ij}^{(h)} = \frac{q_i^T k_j}{\sqrt{d_k}} -m_h(i-j)

в причинной области j≤ij\le i, где mh>0m_h>0 — фиксированный наклон для головы h, измеряемый в единицах логита на шаг позиции. Будущие ключи по-прежнему запрещает маска; конечный штраф ALiBi её не заменяет. У разных голов разные наклоны mhm_h, поэтому одна голова сильнее ориентируется на близкий контекст, другая — слабее штрафует дальние позиции.

Если содержательная часть временно зафиксирована, после softmax линейный штраф соответствует экспоненциальному априорному предпочтению ближних позиций:

exp⁡[−mh(i−j)].\exp[-m_h(i-j)].

Полное внимание по-прежнему зависит от qiTkjq_i^Tk_j и нормировки по всем доступным ключам, поэтому не сводится к одному стационарному ядру расстояния.

Преимущество ALiBi — отсутствие таблицы позиций и естественное продолжение линейного штрафа на новые длины. Ограничение — форма этого позиционного предпочтения задана заранее.

Качество предсказания следующего токена часто измеряют перплексией (perplexity): PPL=exp⁡(NLL‾)\mathrm{PPL}=\exp(\overline{\mathrm{NLL}}), где средняя NLL из М3 вычислена в натах на оцениваемый токен. Чем меньше перплексия на одном и том же наборе при одинаковой токенизации и маске оценки, тем выше вероятность, которую модель в среднем назначает верным продолжениям. Сохранение этой метрики на большей длине ещё не гарантирует надёжного извлечения из середины огромного контекста или решения длинной причинной цепочки: для них нужны отдельные тесты.

9. NoPE: позиция без явного позиционного кодирования

NoPE — No Positional Encoding оставляет attention без отдельного абсолютного или относительного позиционного слагаемого. В каузальном декодере маска уже несёт часть информации: позиция видит префикс определённой длины, а скрытые состояния предыдущих слоёв зависят от порядка вычисления.

Эксперименты показывают, что Transformer способен изучать существенную позиционную структуру и без явного PE. Но отсюда не следует, что позиция стала не нужна. Скорее, информация приходит через маску, глубину, статистику данных и краевые эффекты.

Нужно различать два режима:

  • чистый NoPE — все слои работают без явного позиционного кодирования;
  • гибрид — часть слоёв использует RoPE, часть NoPE, либо разные слои имеют разные схемы внимания.

Llama 4 — пример второго режима: конфигурация предусматривает NoPE-слой через заданный интервал, а также блочное внимание (chunked attention) и настройку температуры на длинных позициях. В реализации Llama 4 эта настройка применяется при включённом attn_temperature_tuning именно к NoPE-слоям. Она меняет масштаб запросов и является отдельным механизмом, отличным от частотной рампы YaRN.

10. Разбор конфигурации: что говорит gpt-oss и чего она не говорит

Используем исходную конфигурацию gpt-oss-120b, зафиксированную ревизией b5c939de…. Полная копия и хеш входят в материалы модуля; вычисление не зависит от изменения ветки main. Читаем её вместе с реализацией OpenAI 7b583341… и Transformers 536ecc007…, проверенными 10 октября 2026 года.

Опубликованные поля:

{
  "head_dim": 64,
  "initial_context_length": 4096,
  "rope_theta": 150000,
  "rope_scaling_factor": 32.0,
  "rope_ntk_alpha": 1,
  "rope_ntk_beta": 32
}

Эти поля позволяют восстановить геометрию позиционного масштабирования:

  • 32 вращаемые пары на голову;
  • исходная база 150 000;
  • опорная длина 4096;
  • целевой коэффициент 32;
  • границы частотной коррекции, соответствующие параметрам 1 и 32.

Эти параметры воспроизводятся в учебном расчёте с непрерывными границами low≈8.0928, high≈17.3980 и attention_factor≈1.346574. Округлённая пара 8/18 относится к отдельному режиму truncate=True, а не к исходной реализации gpt-oss.

Конфигурация описывает параметры позиционного механизма. Поле initial_context_length задаёт длину, относительно которой настроена формула. Чтобы установить, на каких длинах модель обучалась и когда расширяла контекст, нужен технический отчёт или опубликованная схема обучения.

При преобразовании модели в Hugging Face те же идеи могут быть представлены более общим словарём rope_parameters/rope_scaling: тип, коэффициент расширения, исходная длина, границы β и масштаб внимания. Названия полей между оригинальным и библиотечным форматом различаются, поэтому конфигурацию всегда читают вместе с кодом модели и версией библиотеки.

VIZ m4/09 — чтение RoPE-конфигурации Конфигурация gpt-oss как паспорт позиционной геометрии: base, опорная длина, factor и границы рампы. Отдельно показано, какие выводы она не подтверждает.

11. Код первого уровня: формы, позиции и масштабирование

Ниже — учебное ядро, а не оптимизированное объединённое вычислительное ядро (fused kernel). Оно проверяет чётность head_dim, формы Q/KQ/K, целочисленность позиций, положительность частот и корректность YaRN-рампы. Конвенция спаривания — split-half rotate_half, используемая в Llama-подобных реализациях.

Функция apply_rope ниже принимает Q и K одинаковой формы и один вектор позиций: это пример поворота полного блока последовательности. Для разных длин запросов и ключей ноутбук вращает каждый тензор отдельно. Вычисления ядра выполняются в float64; общий масштаб a применяется снаружи. YaRN-функция воспроизводит рассматриваемый сценарий, а не все режимы всех библиотек.

import math
import numpy as np

def rope_inv_freq(head_dim: int, base: float = 150_000.0) -> np.ndarray:
    """Return theta_i = base**(-2i/D) for D/2 rotary pairs."""
    if isinstance(head_dim, bool) or not isinstance(head_dim, int):
        raise TypeError("head_dim must be an integer")
    if head_dim < 2 or head_dim % 2:
        raise ValueError("head_dim must be positive and even")
    if not math.isfinite(base) or base <= 1.0:
        raise ValueError("base must be finite and greater than 1")
    i = np.arange(head_dim // 2, dtype=np.float64)
    return base ** (-2.0 * i / head_dim)

def rotate_half(x: np.ndarray) -> np.ndarray:
    """Quarter-turn the split-half coordinate pairs."""
    if x.ndim < 2 or x.size == 0 or x.shape[-1] % 2:
        raise ValueError("x must have shape [..., T, D] with even D")
    half = x.shape[-1] // 2
    return np.concatenate((-x[..., half:], x[..., :half]), axis=-1)

def apply_rope(q, k, positions, inv_freq):
    """Apply split-half RoPE to q/k of shape [..., T, D]."""
    if any(np.iscomplexobj(x) for x in (q, k, inv_freq)):
        raise TypeError("q, k and inv_freq must be real")
    q = np.asarray(q, dtype=np.float64)
    k = np.asarray(k, dtype=np.float64)
    positions = np.asarray(positions)
    inv = np.asarray(inv_freq, dtype=np.float64)
    if q.shape != k.shape or q.ndim < 2 or q.size == 0 or q.shape[-1] % 2:
        raise ValueError("q and k must share shape [..., T, D], with even D")
    if not np.isfinite(q).all() or not np.isfinite(k).all():
        raise ValueError("q and k must be finite")
    if positions.ndim != 1 or positions.dtype.kind not in "iu":
        raise ValueError("positions must be an integer vector [T]")
    if positions.size != q.shape[-2] or np.any(positions < 0):
        raise ValueError("positions do not match the sequence axis")
    if inv.shape != (q.shape[-1] // 2,) or not np.isfinite(inv).all() or np.any(inv <= 0):
        raise ValueError("inv_freq must be positive and have shape [D/2]")

    angles = positions.astype(np.float64)[:, None] * inv[None, :]
    angles = angles.reshape((1,) * (q.ndim - 2) + angles.shape)
    if not np.isfinite(angles).all():
        raise FloatingPointError("phase overflow")
    full = np.concatenate((angles, angles), axis=-1)
    cos, sin = np.cos(full), np.sin(full)
    qr, kr = q * cos + rotate_half(q) * sin, k * cos + rotate_half(k) * sin
    if not np.isfinite(qr).all() or not np.isfinite(kr).all():
        raise FloatingPointError("rotation overflow")
    return qr, kr

def yarn_inv_freq(head_dim, base, factor, original_context,
                  beta_fast=32.0, beta_slow=1.0, *, truncate=False):
    """Blend original and interpolated frequencies with a YaRN-style ramp."""
    inv = rope_inv_freq(head_dim, base)
    if not math.isfinite(factor) or factor < 1.0:
        raise ValueError("factor must be at least 1")
    if isinstance(original_context, bool) or not isinstance(original_context, int):
        raise TypeError("original_context must be an integer")
    if not math.isfinite(beta_fast) or not math.isfinite(beta_slow):
        raise ValueError("beta parameters must be finite")
    if original_context <= 0 or beta_fast <= beta_slow or beta_slow <= 0:
        raise ValueError("invalid context or beta parameters")
    if not isinstance(truncate, bool):
        raise TypeError("truncate must be bool")

    def correction_dim(turns: float) -> float:
        return head_dim * math.log(
            original_context / (turns * 2 * math.pi)
        ) / (2 * math.log(base))

    pair_count = head_dim // 2
    low_raw = correction_dim(beta_fast)
    high_raw = correction_dim(beta_slow)
    low = math.floor(low_raw) if truncate else low_raw
    high = math.ceil(high_raw) if truncate else high_raw
    low = min(max(float(low), 0.0), float(pair_count - 1))
    high = min(max(float(high), 0.0), float(pair_count - 1))
    if high <= low:
        raise ValueError("the YaRN ramp collapsed")

    ramp = np.clip(
        (np.arange(pair_count, dtype=np.float64) - low) / (high - low),
        0.0,
        1.0,
    )
    scaled = inv * (1.0 - ramp) + (inv / factor) * ramp
    attention_factor = 1.0 if factor <= 1 else 1.0 + 0.1 * math.log(factor)
    return scaled, attention_factor, attention_factor**2, low, high

Для нашего сценария функция возвращает непрерывные границы low≈8.0928, high≈17.3980, attention_factor≈1.346574 и множитель скалярного произведения ≈1.813260, если масштаб одинаково входит во все координаты повёрнутых запроса и ключа. Параметр truncate=True можно включить отдельно, чтобы получить целочисленные границы 8/18.

13. Мультимодальная позиция: M-RoPE и TMRoPE

M-RoPE — Multimodal Rotary Position Embedding делит вращаемые координаты головы на секции, связанные со временем (temporal), высотой (height) и шириной (width). Это не три независимых механизма внимания: одна операция использует разные идентификаторы позиций для разных групп координат.

Для текста все три ряда ID одинаковы:

(m,m,m).(m,m,m).

Поэтому текстовая часть M-RoPE функционально совпадает с обычной одномерной RoPE: каждая частотная пара получает один и тот же индекс mm независимо от своей секции.

Для неподвижного изображения временной ID остаётся постоянным, а пространственные координаты меняются:

(t0,h,w).(t_0,h,w).

Например, сетка 2×22\times2 может получить

(0,0,0),(0,0,1),(0,1,0),(0,1,1).(0,0,0), (0,0,1), (0,1,0), (0,1,1).

Для видео изменяются все три оси. В Qwen2.5-VL шаг по временной оси может учитывать реальное время между элементами сетки, а не просто номер кадра.

TMRoPE — Time-aligned Multimodal Rotary Position Embedding опубликована в техническом отчёте Qwen2.5-Omni в марте 2025 года. Она синхронизирует аудио и видео по времени. В описанной модели один временной ID соответствует 40 мс; это характеристика конкретной временной сетки Qwen2.5-Omni, а не универсальная константа TMRoPE.

VIZ m4/10 — M-RoPE и TMRoPE Текст использует одинаковые ID по трём осям; изображение фиксирует время и меняет h/w; видео и синхронизированное аудио используют временную ось.

Чередование осей в Qwen3-VL

В исходной секционной M-RoPE время, высота и ширина получают отдельные группы частот. В Qwen3-VL, §2.1 оси чередуются по частотным парам: так каждой оси достаются и быстрые, и медленные компоненты. Это Interleaved-MRoPE. Не путайте чередование осей с соседним или split-half спариванием двух координат одной пары: это разные решения.

Тот же отчёт описывает явные текстовые отметки времени для видео (§2.3). Поэтому сетку 40 мс из Qwen2.5-Omni нельзя автоматически переносить на всю семью Qwen. Наш пример сетки 2×2 показывает секционную M-RoPE, а не полную реализацию Qwen3-VL. Для смешанной последовательности также нужно согласовать начало координат и позиции последующего текста; маленькая сетка здесь начинается с нуля только ради наглядности.

14. Современный ландшафт: методы сосуществуют

Ниже — выборочная карта реализаций, проверенная 10 октября 2026 года. Она показывает разные способы работы с позицией. Это справочный раздел: механизмы уже объяснены, а строки помогают найти соответствующий первоисточник.

Семейство или работаПозиционный механизмКонтекст/цельОснование
Transformerдетерминированное синусоидальное PEисходная архитектурастатья
RoFormer / RoPEвращательная фаза в Q/KQ/Kотносительная зависимость в механизме вниманиястатья
ALiBiлинейное позиционное смещениеэкстраполяция по длине без позиционных эмбеддинговстатья
Position Interpolationравномерное сжатие позиций + дообучениерасширение RoPE-контекстастатья
YaRNкусочное смешение исходного и интерполированного спектров с дополнительным масштабированиемработа с более длинным контекстомстатья и библиотеки
LongRoPE / LongRoPE2коэффициенты по размерностям и стадиямэкстремально длинный контекстстатьи
gpt-ossbase=150K, опорная длина 4096, factor=32, параметры β\betaпозиционная геометрия до 128Kофициальная конфигурация; полное расписание обучения этим файлом не раскрывается
Llama 4чередующиеся RoPE/NoPE, блочное внимание, настройка температурыгибридная архитектура длинного контекстаоткрытая конфигурация/реализация
Qwen2-VL / Qwen2.5-VLM-RoPEкоординаты текста, изображения и видеостатья и код
Qwen2.5-OmniTMRoPEсинхронизация аудио и видеотехнический отчёт
Qwen3-VLInterleaved-MRoPE и текстовые отметки временираспределение частот между осями и привязка событий видеоотчёт, §2 и открытая реализация
Inklingотносительное позиционное представление, скользящие/глобальные слоиконтекст 1Mофициальный технический анонс
Закрытые модели с API-доступоммеханизм может быть не опубликованзаявленное окно не раскрывает формулудокументация API, если доступна

Таблица показывает не рейтинг методов, а разнообразие инженерных решений. Номинальная длина контекста также не доказывает рабочее качество на всей длине; это отдельная задача оценки, к которой курс вернётся в модуле 19.

17. Ключевые выводы модуля

VIZ m4/11 — позиционные схемы на одной странице Шпаргалка: перестановочная симметрия, тождество RoPE, диагностика спектра, семейства масштабирования, ALiBi/NoPE и мультимодальные оси.

  • Без позиционного сигнала двунаправленный self-attention перестановочно-эквивариантен; каузальная маска добавляет порядок доступа, но не полноценную геометрию расстояний.
  • Синусоидальные пары уже имеют точную зависимость от относительного смещения, однако аддитивное PE смешивает позицию с содержанием. RoPE помещает относительную фазу непосредственно в QKTQK^T.
  • rope_theta управляет распределением частот. Большая база добавляет медленные компоненты, не удаляя самую быструю пару.
  • Длина волны одной пары и число оборотов — диагностические величины, а не жёсткая граница контекста.
  • PI равномерно сжимает спектр; static NTK-aware scaling — эвристика; YaRN смешивает исходные и интерполированные частоты; LongRoPE и современные гибриды предлагают другие компромиссы.
  • attention_factor нужно читать вместе с местом применения в коде.
  • ALiBi задаёт линейное позиционное смещение; NoPE полагается на маску и динамику сети; гибриды могут чередовать разные схемы.
  • M-RoPE использует одинаковые три ID для текста и разные оси для визуальных токенов. TMRoPE синхронизирует время аудио и видео.
  • config.json описывает архитектурную геометрию, но не заменяет отчёт об обучении.

Дальше: модуль 5 — механизмы внимания. Позиция уже вошла в Q/K или логит; теперь разберём, как организовать головы и вычислить это внимание с разумными затратами памяти.

18. первоисточники

Основные источники:

Углубление. Признаки Фурье, ядра и информационная геометрия подробнее разбираются в Information Theory for ML. Рекуррентные архитектуры и модели пространства состояний, которые учитывают порядок через обновление состояния, рассматриваются в М8 Modern LLMs.


Выборочная карта реализаций сверена: 10 октября 2026 года. Числа спектра и YaRN относятся к явно заданному учебному сценарию. Для закрытых моделей неизвестный позиционный механизм не реконструируется по размеру контекстного окна.