Какой кодер, такой и result, друзья.
При проектировании эксперимента мы тестируем разные архитектуры. В прикладном применении нам важен выход и побочные характеристики (скорость, поддержка фреймворками, современность), а вот в теоретическом — мы пробуем найти интересный результат.
Как не найти результат там, где его нет, сравнивая модели разных архитектур? Что существует в архитектуре по её определению? Этим чудесным вопросам и посвящена статья.

Привет читателям!
Меня зовут Сабрина, и это очередной туториал из серии про то, как заглядывать моделям внутрь. Я пишу эту статью в месте, где многие хайкают. И как у хорошего хайка — у этой статьи будет несколько view points!: )
Что будет:
Теория трёх масок — одна формула внимания, три способа её замаскировать.
Информативность токенов и нюансы оценки.
Геометрия (основная часть) — метрики анизотропия, спектр, participation ratio, CKA и что они покажут из‑за архитектуры.
Вывод — а зачем это на практике.
Рассмотрим четыре модели, малюсенькие, всё посчитается на CPU за несколько минут и, как всегда, лежит в ноутбуке на github. Берите воду, кофе, снеки и вперед!
Рассматриваемые архитектуры
Классические архитектуры языковых моделей обычно делят на три семейства: encoder‑only, decoder‑only и encoder‑decoder. На схемах (и мемах) они выглядят по‑разному и решают разные задачи, но внутри они, вообще говоря, устроены очень похоже.

Общее: Attention
Для каждого семейства основной вычислительный механизм — это attention с фиксированной и знакомой формулой, вида:
Здесь ,
,
— линейные проекции входа, а
— аддитивная маска: матрица из нулей и
. Ноль означает «смотреть можно»,
после softmax превращается в нулевой вес и означает «смотреть нельзя».
Если формула вам не знакома или забылась
Рассмотрим классический пример, когда на вход пришло предложение «the cat sat», и каждый токен уже превратился в вектор . Слой внимания делает из каждого вектора три векторочка:
— запрос: «что я ищу в контексте»;
— ключ: «по какому признаку меня можно найти»;
— значение: «что я отдам тому, кто меня нашёл».
Шаг 1. Совместимость. Скалярное произведение каждого запроса с каждым ключом: . Получается матрица
— «насколько токен
заинтересован в токене
».
Шаг 2. Масштаб. Делим на . Без этого при больших
скалярные произведения растут по величине, softmax уходит в насыщение (один вес ≈ 1, остальные ≈ 0), а градиенты умирают.
Шаг 3. Маска. Прибавляем . Ноль ничего не меняет;
гарантирует нулевой вес после экспоненты, потому что
.
Шаг 4. Softmax по строке. Каждая строка превращается в распределение: веса неотрицательны и суммируются в единицу. Ключевое слово — по строке: токен распределяет свою единицу внимания между всеми доступными ему
.
Шаг 5. Взвешенная сумма. — новое представление токена есть смесь значений всех, на кого он посмотрел, с весами из шага 4.
Дальше это делается параллельно раз (многоголовость), результаты склеиваются и проходят ещё одну линейную проекцию, а вокруг всего — residual‑связь, нормализация и MLP. Эффекты, которые мы будем эксплуатировать в туториале расположены в шагах 3–5.

Заметим, что:
Строка softmax обязана просуммироваться в единицу. Голова не умеет «не смотреть никуда»: если ей на этом шаге ничего не нужно, массу внимания всё равно придётся куда‑то положить.
Маска стоит внутри softmax, а не после него. Запрет «смотреть вперёд» — это перераспределение: оставшиеся веса нормируются заново.
Обобщая, можно сказать, что в основном в семействах меняется то каким токенам разрешено видеть какие другие токены и откуда берётся контекст для внимания. Иными словами, изначально геометрически мы сводим (грубо, но право имеем) архитектурные различия к двум вещам:
маске внимания
источнику (Q, K, V)
Архитектура | Источник | Источник | |
|---|---|---|---|
encoder‑only (BERT) | 0 везде | сам слой | сам слой |
decoder‑only (GPT-2) | 0 при | сам слой | сам слой |
enc‑dec: encoder (T5, BART) | 0 везде | encoder | encoder |
enc‑dec: self‑attn декодера | треугольная | decoder | decoder |
enc‑dec: cross‑attention | 0 везде | decoder | encoder |
Спасибо LLM за таблицы, которые учишься делать, чтобы представлять информацию компактно и сжато.
Из этой таблицы мы можем достать три важных для нас сейчас факта:
Следствие 1. Кто что видел. В каузальной модели (decoder) представление токена на позиции — функция только префикса
. Формально:
Тогда по построению видим: токены внутри одной последовательности несут разный объём контекста: первый видел одно слово, последний — всё предложение.
Следствие 2. Где «смысл целого». У encoder‑only он размазан по всем позициям (плюс [CLS], который обучен агрегировать — но обучен под задачу Next Sentence Prediction). У decoder‑only — строго в последнем токене, единственном, кто видел всё. У encoder‑decoder — в выходе энкодера; а вот состояние декодера — это уже не «смысл входа», а «состояние генерации».
Следствие 3. Сколько пространств. Одно, одно и два. У encoder‑decoder пространство энкодера и пространство декодера обучались под разные роли: у них разные нормы, разные базисы и разный смысл координат.
Каждое следствие порождает геометрические нюансы и беды. На них мы и будем смотреть.
Различие: Objective
Окей, маской мы завладели, но это только половина необходимого. Справедливо заметить, что модели по постановке учатся разным задачам:
MLM (BERT, encoder): маскируем случайные токены и восстанавливаем их из двустороннего контекста. Каждая позиция обязана быть самодостаточной — из неё должны восстановить конкретное слово. Это давление «размазывает» информацию по всем позициям и по многим направлениям.
CLM (GPT-2, decoder): предсказываем следующий токен. Оптимизируется, по сути, одна функция — распределение над словарём на выходе. Пространство схлопывается вдоль направлений, полезных для next‑token‑предсказания; всё, что для этого не нужно, сжимается. Как мы увидим, схлопывание получается буквальным.
Span corruption (T5, encoder‑decoder) и denoising / text infilling (BART, encoder‑decoder): портим текст — выкидываем куски — и восстанавливаем его целиком. Энкодер работает двунаправленно, но его выход должен быть удобен для потребления декодером через cross‑attention. Это отдельное, третье давление на геометрию, и у T5 с BART оно реализовано по‑разному.
Напоминание постановок задач
MLM (BERT) — случайные 15% токенов по двустороннему контексту (из них 80% заменяются на
[MASK], 10% на случайный токен, 10% остаются как есть).Пример:
The doctor told the [MASK] that the surgery was successful.—patient.NSP (BERT) — задача идут ли два куска текста подряд
Пример:
[CLS] The doctor told the patient … [SEP] The surgery took three hours. [SEP]—IsNextCLM (GPT-2) — прогнозирование следующего токена по левому контексту.
Пример:
The doctor told the→patient.Span corruption (T5) — обучение через выкинутые спаны, каждый под своим sentinel‑токеном.
Пример: вход
The doctor told the <X> that the surgery <Y> successful.— таргет<X> patient <Y> was <Z>Denoising / text infilling (BART) — задача восстановить текст целиком после произвольной порчи: спаны схлопываются в один
<mask>, предложения переставляются, токены удаляются.Пример:
The doctor <mask> the surgery was successful.— полный оригинал
Потом это, конечно, видоизменилось (ELECTRA, DeBERTa, ALBERT — уже имеют поправки разной силы в постановке). Но основа до сих пор такая.
Запомним, что MLM требует, чтобы каждая позиция была самодостаточной — из неё восстанавливают конкретное слово. CLM оптимизирует одну позицию под одно распределение над словарём. Span corruption и denoising делают выход энкодера удобным не для классификатора, а для чтения декодером через cross‑attention. Это, вообще говоря, три разных давления на геометрию.
Отдельно нам также важен будет [CLS]: он единственная позиция BERT, которую явно учили агрегировать, — но учили под NSP, то есть под «идут ли эти два куска подряд», а это в основном решается совпадением темы.
К практике готовы
Итак, из абзацев выше мы увидели, что маска определяет, какой токен куда смотрит, а objective давит на форму, которое может принять облако из токенов. Три факта из определения маски, три задачи под семейства, а мы всё ещё ничего не проверили. Чешем руки в предвкушении и смотрим эксперимент.
Setup
Ноутбук писался на маке (MPS), тестировался на CPU. Все модели маленькие, полный прогон занимает мало минут.
Данные:
English Web Treebank — английские тексты из веба (блоги, отзывы, письма, форумы) с синтаксической разметкой, сделанной людьми. Из него мы возьмём и предложения для экспериментов.
Зависимости: torch: 2.8.0 | transformers: 5.10.2
Предложений в корпусе: 12544 Пример: 'You wonder if he was manipulating the market with his bombing targets.'
Модели
Семейство | Модель | Слои | Внимание | Objective | |
|---|---|---|---|---|---|
encoder‑only |
| 12 | 768 | двунаправленное | MLM + NSP |
decoder‑only |
| 12 | 768 | каузальное | CLM |
encoder‑decoder |
| 6 + 6 | 768 | enc: двунапр. / dec: кауз. + cross | denoising (text infilling) |
encoder‑decoder |
| 6 + 6 | 512 | enc: двунапр. / dec: кауз. + cross | span corruption |
Список моделей, которые будут нашими объектами анализа выше. Он собран так, чтобы:
покрыть все три семейства в сопоставимых размерностях и при сопоставимом числе голов (первые три);
обеспечить контроль над другими свободными параметрами внутри encoder‑decoder (у T5: RMSNorm без сдвига, relative position bias, span corruption, у BART обычный LayerNorm, выученные абсолютные позиции, denoising‑objective)
Резонный вопрос: контроль внутри encoder‑decoder есть (две модели), а где контроль для encoder‑only и для decoder‑only? Мы схитрим, и достанем их отсюда же:
Контроль для encoder‑only — это энкодеры T5 и BART. Двунаправленных моделей у нас три: BERT, энкодер T5, энкодер BART.
Контроль для decoder‑only — это декодеры T5 и BART. Каузальных моделей у нас тоже три: GPT-2, декодер T5, декодер BART.
Они различаются размерностью, глубиной, objective, токенизатором и корпусом претрейна — то есть дают в целом достаточную вариативность.
Примечание техническое. В
transformers5.x по умолчанию используется SDPA‑реализация внимания, и при нейoutput_attentions=Trueвозвращает пустой список (бага). Для любого анализа внимания нуженattn_implementation="eager".
Тип Модель Слоёв D Голов Параметров Словарь Что на позиции 0 BERT (enc-only) bert-base-uncased 12 768 12 109M 30522 [CLS] GPT-2 (dec-only) gpt2 12 768 12 124M 50257 You T5-enc (enc-dec) t5-small 6 512 8 35M 32100 ▁You BART-enc (enc-dec) facebook/bart-base 6 768 12 82M 50265 <s> T5-dec (enc-dec) t5-small 6 512 8 42M 32100 <pad> BART-dec (enc-dec) facebook/bart-base 6 768 12 96M 50265 </s>
Примечание: колонка «Параметров» считает только ту часть, которую мы в моменте анализируем: для T5 и BART это энкодер, а не вся seq2seq‑модель. Поэтому числа меньше тех, что указаны на карточках моделей.
Соблазн потрогать декодеры мы, конечно, не сдерживаем — но декодер не запускается так же просто, как энкодер. Энкодеру хватает одного входа: подали текст, забрали состояния. Декодеру нужны два сразу — что прочитал энкодер (это придёт через cross‑attention) и decoder_input_ids, то есть «что уже сгенерировано». Без второго forward просто не посчитается.
Интуиция «энкодер сжал текст в один вектор, декодер его принял» — из seq2seq на RNN тут не применима. В трансформере никакого одного вектора нет: декодер вычитывает все выходные векторы энкодера через cross‑attention, заново на каждом своём слое и на каждом шаге генерации, и параллельно смотрит на то, что сам уже написал.
Состояния «для текста X» у декодера не существует — есть состояние «для пары (вход X, история Y)». Мы будем смотреть на teacher forcing: тот же текст, сдвинутый на одну позицию вправо.
Чтоб удобно было
Технически в коде мы заворачиваем декодер в обёртку с тем же интерфейсом, что у обычной модели: вызвали — получили last_hidden_state, hidden_states, attentions. После этого весь остальной код ноутбука работает с декодерными частями просто удобнее.
class DecoderStack: """A decoder stack with the interface of an ordinary encoder model. Calling it runs the FULL seq2seq model — the decoder does not exist without the encoder — and returns the DECODER side of the output. Everything downstream (influence matrices, saturation, clouds, CKA) therefore works with a decoder without a single change. """ def __init__(self, model): self.model = model self.config = model.config def parameters(self): return self.model.get_decoder().parameters() def __call__(self, input_ids=None, attention_mask=None, output_hidden_states=False, output_attentions=False, **_ignored): with torch.no_grad(): out = self.model( input_ids=input_ids, attention_mask=attention_mask, decoder_input_ids=shift_right(input_ids, self.model), output_hidden_states=output_hidden_states, output_attentions=output_attentions, ) return SimpleNamespace( last_hidden_state=out.last_hidden_state, # decoder side hidden_states=out.decoder_hidden_states, attentions=out.decoder_attentions, # decoder self-attention cross_attentions=out.cross_attentions, encoder_last_hidden_state=out.encoder_last_hidden_state, encoder_attentions=out.encoder_attentions, )
Часть 1. Проверим маску
Раз мы сказали, что attention общий, но разный, покажем это — проверим Attention интервенцией (проще говоря — вмешательством).
Как: Берём предложение. Портим токен на позиции (заменяем на
[UNK]). Смотрим, насколько изменилось скрытое состояние на каждой позиции :
Это матрица . Что мы ожидаем
когда модель двунаправленная, порча любого токена меняет всё
когда модель каузальная, порча токена
физически не может повлиять на позиции
(
зависит от прошлых, а прошлые не менялись), отсюда верхний треугольник обязан быть нулевым.

Что мы видим
BERT — залитый квадрат. Влияние идёт в обе стороны, причём «из будущего» даже чуть сильнее, чем «из прошлого» (5.73 против 4.37).
GPT-2 — идеальный нижний треугольник. Влияние будущего — 0. Треугольная маска в чистом виде.
Энкодеры T5 и BART — снова квадраты, как и положено двунаправленным энкодерам: у обоих влияние будущего и прошлого одного порядка.

Ненормальные нормы
Внимательный читатель заметит, что у GPT-2 абсолютная величина влияния прошлого — десятки, у BERT, BART, T5 — единицы. Соблазнительно прочитать это эффектом, но так нельзя. Почему — увидим.
Что у декодера в encoder‑decoder (нюансы)
Со стандартными энкодерами и декодерами всё понятно — мы сейчас меняли только вход. Сделать так в декодере мы не можем: у него две маски сразу. Своя история закрыта треугольником (self‑attention) и вход энкодера (cross‑attention). Проверим, для полноты тем же самым методом.
Матриц теперь две на модель:
порча входа энкодера — меняем токен
в тексте, который читает энкодер, декодерную историю не трогаем. Смотрим
;
порча истории декодера — текст на входе энкодера тот же, портим токен
в том, что декодер «уже написал».
Ожидание: первая матрица — залитый квадрат (cross‑attention без маски), вторая — нижний треугольник (self‑attention каузален).

Что мы видим
Self‑attention декодера действительно каузален — масса внимания на будущем ровно 0.0 у обеих моделей. То есть внутри себя декодер ведёт себя как GPT-2.
А вот доступ ко входу у него не каузальный. Форма cross‑attention — [batch, heads, позиции декодера, позиции энкодера], и маски там нет: каждое состояние декодера видит весь вход целиком, с самого первого шага генерации. То есть фраза «декодер каузален» верно только про его собственную историю Y, но не про вход.
На правой колонке heatmap видно, как это работает: строки — позиции декодера, столбцы — позиции энкодера, и каждая строка распределяет внимание по всему входу.
К сноске заходите, когда будете трогать код. Из неё важен факт:
В encoder‑decoder “эмбеддинг текста” — это выход энкодера. Состояние декодера — не смысл входа, а указатель в пространство энкодера плюс состояние генерации. Анализ
decoder_hidden_statesкак анализ эмбеддингов предложения в чистом виде уже не совсем корректен. Это анализ decoder_hidden_states с учетом того, что было в энкодере (истинных эмбеддингов предложения в этом смысле).
Часть 2. Измерим маску
Следствие 1: информативность — кто сколько видел и кто сколько весит
Маску мы проверили. Теперь рассмотрим Следствие 1 из теории.
2.1 Насыщение контекстом
Обозначим за — состояние токена
в момете, где модель видела все токены до
‑го. Тогда представление токена
, когда модель впервые его увидела есть
и
, когда модель увидела все токены.
Пример на трёх токенах
Пусть текст — «she saw ducks», и нас интересует средний токен, saw.
Каузальная модель. На входе
she sawона считает. Даём ей всё предложение целиком,
she saw ducks— на позиции 2 она посчитает ровно то же самое: токенducksстоит справа, а справа она не смотрит. Два вектора совпадают, угол между ними нулевой,.
Двунаправленная модель. На входе
she sawона строитиз двух слов, на входе
she saw ducks— из трёх. Иducksменяет прочтениеsaw: это глагол «увидела», а не существительное «пила». Вектор поворачивается,.
Если нарисовать эти два вектора из начала координат, у каузальной модели они лягут друг на друга, а у двунаправленной между ними будет видимый угол.
Состояние токена в каждый момент времени — это вектор. У вектора есть норма и направление — эксплуатируем их для анализа. Во‑первых, чтобы сравнить два вектора (состояние токена при полном тексте и при обрезанном ровно на нём) рассмотрим:
Как читать:
— косинус нуля. То есть вектора схлопнулись. Правый контекст ничего не поменял с точки зрения направления.
— представление токена переписывается тем, что идёт после него (движется по направлению).
Для каузальной модели ответ известен заранее аналитически — там вообще не зависит от
, значит должно быть ровно 1.

тип последний слой min по позициям мин. по слоям BERT (enc-only) 0.4320 0.1755 0.4320 GPT-2 (dec-only) 1.0000 1.0000 1.0000 T5-enc (enc-dec) 0.4892 0.0534 0.4892 BART-enc (enc-dec) 0.5771 -0.0428 0.5771 T5-dec (enc-dec) 0.9426 0.8381 0.7607 BART-dec (enc-dec) 0.8061 0.5368 0.8061
Что мы видим
GPT-2 даёт 1 на всех позициях. Это и есть смысл фразы «в каузальной модели ранние токены недоконтекстуализированы». Каждый токен получает своё направление и никак не меняет его при дальнейшем добавлении контекста.
Все три двунаправленные модели дают заметно меньше единицы: 0.432 у BERT, 0.489 у энкодера T5, 0.577 у энкодера BART, а на отдельных позициях значения проваливаются к нулю и даже уходят в минус. То есть правый контекст переписывает представление токена почти полностью.
А декодеры T5 и BART дают меньше единицы — и это не противоречие. Обрезая текст, мы обрезаем вход энкодера, а его декодер читает через cross‑attention без всякой маски. Каузальна у него только собственная история (мы это проверили в части 1), поэтому в этом тесте он ведёт себя как двунаправленная модель. Ровно то же самое произойдёт с любым RAG‑подобным пайплайном: «декодерная модель» и «модель, у которой представление не зависит от правого контекста» — не синонимы.
По глубине картина одинаковая у всех: на нулевом слое (эмбеддинги) насыщение равно единице у всех типов просто потому, что эмбеддинг токена контекста ещё не видел, а дальше двунаправленные типы уезжают вниз с первого же слоя. То есть «недоконтекстуализированность» — свойство не выхода, а всей глубины.
Практическое следствие:
Среднее
.mean(dim=1)по токенам декодер модели (у нас — GPT-2), усредняет векторы, часть которых физически не содержит информации о тексте. Первый токен видел одно слово. Второй — два. Это усреднение систематически смещено в сторону начала текста.Для encoder моделей BERT та же операция осмысленна: там все позиции видели всё.
2.2 Attention sink: первый токен как сливной клапан
Второй фактор информативности — не «что токен видел», а «сколько внимания он получил.»
При анализе attention существует эффект: первая позиция собирает непропорционально большую долю внимания (Xiao et al., 2023, StreamingLLM). Такой эффект называется Attention sink. Он возникает потому что softmax по строке обязан просуммироваться в единицу — голова не может «не смотреть никуда». Когда голове на данном шаге нечего искать, ей нужно куда‑то слить массу внимания, и самая удобная свалка — позиция, которая видна отовсюду и не несёт содержания. Отсюда название — attention sink.
Формально оно определяется так. Пусть — вес внимания головы
слоя
из позиции‑запроса
в позицию‑ключ
. Мерой стока назовём
— медиану доли внимания, уходящей в позицию 0, по всем головам и всем запросам слоя. Медиана, а не среднее, и это важно: доли по головам распределены крайне несимметрично, одна голова‑сливщик с долей 0.95 утаскивает среднее вверх, и получается впечатление, будто течёт весь слой. Медиана отвечает на честный вопрос — «как ведёт себя типичная голова».
Toy‑пример
Строка softmax нормирована при любых логитах: . Пусть у запроса
нет ни одного содержательного совпадения — все
, — но у позиции 0 логит равен
(ключ там всегда один и тот же, модели ничего не стоит его выучить). Тогда
При достаточно
, чтобы в позицию 0 ушло больше 80% внимания. Никакой семантики: голове просто некуда деть массу, а нулевая позиция — единственный всегда доступный адрес. Эту кривую мы нарисуем рядом с реальными долями.
Обычно этот эффект описывают как свойство декодерных моделей. Проверим, так ли это и как в энкодерах — посчитаем долю массы внимания, уходящую на позицию 0, усреднив по головам и запросам, по слоям.

Что мы видим
Медианно для GPT-2: к глубоким слоям до 93% всего внимания уходит в первый токен. Модель почти перестаёт «смотреть на текст» и сливает внимание в сток.
Энкодер BART — модель двунаправленная — показывает сток почти такой же силы: 0.61–0.75 начиная со второго слоя. Отсюда мы видим, что следствие слития зависит не только от архитектуры, а зависит ещё и от наличия служебного токена. А именно, для наших моделей справедливо следующее:
Тип | маска | первый токен | сток (медиана по головам и запросам) |
|---|---|---|---|
GPT-2 | каузальная | BOS (мы добавили) | до 0.93 |
энкодер BART | двунаправленная |
| до 0.75 |
BERT | двунаправленная |
| 0.36 в начале, затем 0.01–0.03 |
энкодер T5 | двунаправленная | отсутствует | 0.00–0.01, стока нет |
декодер T5 | каузальная |
| до 0.93 |
декодер BART | каузальная |
| до 0.97 |
У GPT-2 и BART он есть и работает свалкой на всей глубине. У BERT
[CLS]есть, но сток держится только в первых слоях. У T5 начального служебного токена нет — и стока нет.Энкодер T5 и декодер T5 — это одна модель: один претрейн, один токенизатор, одна схема нормализации, одинаковое число слоёв и голов. Разница между ними — маска и наличие стартового токена. У энкодера начального служебного токена нет, и стока нет: 0.00–0.01 на всех шести слоях. Декодер той же самой T5 начинает последовательность с
<pad>— и сток доходит до 0.93. Эффект снова включается там, где появляется постоянная пустая позиция.Cross‑attention не маскирован ни у T5, ни у BART — маска здесь не участвует. И тем не менее: у BART в нулевую позицию энкодера утекает до 0.51, а у T5 — 0.00–0.01. Разница между ними ровно та же, что между их энкодерами, и объясняется тем же: у BART на позиции 0 стоит
<s>, у T5 — обычное слово.
Отсюда: механизм такой: голове нужно место, куда слить лишнюю массу внимания, и лучший кандидат — позиция, которая всегда присутствует, видна отовсюду и не несёт содержания. А значит, наш служебный первый токен — часть механизма внимания, а не носитель смысла. Включать его в mean‑pooling не очень корректно — там мы подмешиванием в «эмбеддинг текста» вектор со служебной ролью и, как мы ниже увидим, аномальной величиной. Касается это и GPT-2, и BART, и BERT, и обоих декодеров — то есть всех, у кого такой токен есть.
2.3 Нормы: два порядка разницы
Attention sink имеет геометрического близнеца — аномально большие нормы на служебных позициях (их называют massive activations, Sun et al., 2024).
Посмотрим на эффект в действии.

Что мы видим
У T5 нормы внутри огромные — эмбеддинги 378, к предпоследнему слою до 2 тысяч у энкодера и до 7 тысяч у декодера, — а на выходе обрушиваются до 3.3 и 14.9. Это финальный RMSNorm. То есть «у T5 самые маленькие нормы» — свойство последнего слоя, а не модели: внутри у него как раз самые большие числа из всех шести.
У GPT-2 рост монотонный: 5.2 → 262.9, в 51 раз, без единого перелома. Вот это и правда «модель копит массу в residual stream».
У BERT и энкодера BART профиль плоский — 14 и 5 от входа до выхода.
У декодера BART всё интересное на последнем слое: 10.8 держится всю глубину и скачком уходит в 50.7.
Причина в схеме нормализации: BERT использует post‑LayerNorm, GPT-2 — pre‑LayerNorm с финальным ln_f, T5 — RMSNorm без обучаемого сдвига, BART — обычный LayerNorm. Это архитектурная деталь, которая должна, в идеале, учитываться при анализе везде, где вы применяете нормы (а ещё важно смотреть на изменение по слоям).

Мне на практике помогает правило: любая метрика, чувствительная к масштабу, между архитектурами требует нормировки. И кроме того, любая метрика требует baseline.
Помимо статистик с частных примеров, мы можем анализировать и более общие вещи. Давайте посмотрим на структуры/облака точек, которые может триггерить архитектура.
Часть 3. Геометрия
Облака точек можно характеризовать разными способами. Я субъективно выбрала три красивые. Три — чтобы туториал не был очень широким, а то мы итак расползлись.
Я допускаю, что математика вам не знакома или знакома не вся. Поэтому сейчас зафиксируем интуицию и потом — формальные определения. Итак, рассмотрим:
Анизотропию в общем смысле — это зависимость математических свойств объекта, функции, пространства или модели от направления. Мы будем оценивать изотропность пространства — то есть наоборот — одинаковость всех направлений в модели. Сложного слова не пугайтесь — с нами тут просто будет попарный косинус.
Спектр и Participation ratio — характеристики матрицы, которые скажут, сколько в ней наиболее эффективных направлений.
CKA — метрика, позволяющая проанилизровать похожесть моделей между собой (в смысле организации пространств).
Если стало сложно, то сейчас по секциям всё уложим. Наши подопытные:
BERT (enc-only) облако: 11924 токенов x 768 измерений GPT-2 (dec-only) облако: 11676 токенов x 768 измерений T5-enc (enc-dec) облако: 13113 токенов x 512 измерений BART-enc (enc-dec) облако: 12220 токенов x 768 измерений T5-dec (enc-dec) облако: 13113 токенов x 512 измерений BART-dec (enc-dec) облако: 12220 токенов x 768 измерений
Разное количество токенов — следствие словаря модели. Слово коровник, например, может кодироваться в модели номер 1 — одним токеном, а в модели номер два — двумя.
3.1 Анизотропия
Теория. Пространство называется изотропным, если случайно взятые из него векторы почти ортогональны. Для гауссова облака в это так: при большом
косинус двух случайных векторов концентрируется около нуля.
Мера отклонения от изотропии — средний попарный косинус (Ethayarajh, 2019):
Здесь мы берём токены из разных предложений. Внутри одного предложения токены могут быть похожи естественным образом.
Как читать:
— изотропно, косинус информативен: если два вектора похожи, это что‑то значит;
— все векторы смотрят примерно в одну сторону; косинус любой пары ≈ 1, и он не несёт информации.
Нашим контролем будет baseline — та же самая оценка для гауссова облака той же размерности. Без него мы не сможем сказать, много/мало, случайно или не случайно. А ещё это поможет нам корректнее оценить с
.
тип анизотропия baseline BERT (enc-only) 0.227 -0.000 GPT-2 (dec-only) 0.945 -0.000 T5-enc (enc-dec) 0.098 -0.000 BART-enc (enc-dec) 0.184 -0.000 T5-dec (enc-dec) 0.868 -0.000 BART-dec (enc-dec) 0.096 -0.000

Что мы видим
Смотрите как это красиво! У GPT-2 лучи собраны в узкий пучок — любая пара векторов почти сонаправлена, — а у BERT и энкодера T5 они расходятся по всей окружности. Справа то же самое в виде распределения: у GPT-2 гистограмма косинусов прижата к единице, у остальных сидит около нуля с длинными хвостами.
GPT-2: 0.945. Следствие — вектора чаще сонаправлены. Отсюда косинусная близость на выходе GPT-2 почти не несёт информации.
BERT: 0.227. Следствие — вектора сонаправлены реже.
Энкодер T5: 0.098 и энкодер BART: 0.184 — самые «круглые» облака.
Гауссов baseline: ~0.00 для обеих размерностей. Именно он говорит нам, что 0.227 у BERT — это много, а не «почти ноль».
А декодеры разъехались: 0.868 у декодера T5 — почти как GPT-2, и 0.096 у декодера BART — как самые «круглые» энкодеры. Маска у них одна и та же, каузальная, а анизотропия различается в девять раз.
Уже здесь виден отпечаток типа модели: единственный decoder‑only схлопывает пространство сильнее всех, а три двунаправленных энкодера держатся в диапазоне 0.10–0.23 — при том, что objective у них три разных.
Декодеры enc‑dec ставят объяснению границу: они оба каузальные, а лежат по разные стороны диапазона. Значит, «каузальность» сама по себе анизотропию не объясняет.
Что можно сделать с высокой анизотропией
У высокой анизотропии есть две принципиально разные возможные причины.
Гипотеза А: облако правда сплющено. Векторы лежат в узком конусе, направления внутри него скоррелированы, геометрия действительно вырождена.
Гипотеза Б: облако нормальное, но сдвинуто. Представьте шар единичного радиуса с центром в точке , где
. Все точки такого шара имеют почти одинаковое направление — просто потому, что шар далеко от начала координат. Косинус между ними будет ≈ 1, хотя внутренняя структура облака совершенно нормальная.
Разница между А и Б:
если А — с пространством действительно беда, и информации в нём мало;
если Б — вся «беда» лечится одним вычитанием среднего, и информация никуда не девалась.
Различить их можно, сделав простой хинт — посчитать анизотропию после центрирования . На наших данных, мы получим следующее.
модель сырая после центрирования BERT (enc-only) 0.227 -0.000 GPT-2 (dec-only) 0.945 0.007 T5-enc (enc-dec) 0.098 0.000 BART-enc (enc-dec) 0.184 -0.000 T5-dec (enc-dec) 0.868 0.007 BART-dec (enc-dec) 0.096 -0.000
Что мы видим
Анизотропия схлопывается до нуля от одного вычитания среднего — у всех шести стеков. У GPT-2: 0.945 → 0.007. У BERT: 0.227 → −0.000. У энкодера BART: 0.184 → −0.000. И у самого «конусного» из декодеров, T5: 0.868 → 0.007.
Отсюда у нас верна гипотеза Б. Пресловутый «конус представлений» — это не вырожденная геометрия, а смещение облака от начала координат. Информация внутри облака была на месте всё это время; просто косинус, который меряет углы из начала координат, смотрел не туда.
К сноске вновь возвращайтесь, когда сядете за код. Компактное наше следствие из неё для работы:
Центрируем перед косинусом. Всегда. Причём среднее надо считать по тому же распределению текстов, на котором работаем. Без этого измеряется не похожесть текстов, а положение общего центра масс — одинаковое для всех пар.
И тут также видно почему, например,
[CLS]‑эмбеддинги «без нормализации плохо работают», а после центрирования считаются нормально.
3.2 Спектр: сколько измерений модель использует
Теперь зайдём с другой стороны. У облака есть ковариационная матрица, у неё — собственные значения . Их профиль говорит, по скольким направлениям размазана дисперсия.
По ним мы можем посчитать две (вообще говоря, не две, но две « наиболее популярные) статистики. Обе устроены так, чтобы не зависеть от общего масштаба:
Participation ratio — “эффективное число активных направлений”:
Если вся дисперсия в одном направлении, . Если она поровну размазана по
направлениям,
.
Effective rank — то же самое по смыслу, но через энтропию спектра (Roy & Vetterli, 2007):
Обе метрики зависят от , поэтому снова считаем гауссов baseline: для изотропного облака в
обе величины должны быть порядка
.
модель D PR erank var@PC1 var@10PC PR/D BERT (enc-only) 768 86.295 276.577 0.068 0.247 0.112 GPT-2 (dec-only) 768 1.856 3.640 0.723 0.961 0.002 T5-enc (enc-dec) 512 174.653 289.630 0.027 0.160 0.341 BART-enc (enc-dec) 768 112.859 307.103 0.051 0.226 0.147 T5-dec (enc-dec) 512 3.377 9.482 0.515 0.874 0.007 BART-dec (enc-dec) 768 67.769 197.841 0.079 0.276 0.088 гаусс D=512 512 453.917 480.284 0.004 0.035 0.887 гаусс D=768 768 644.736 697.919 0.003 0.026 0.839
Что мы видим
GPT-2: PR ≈ 1.9 при
. Первая главная компонента объясняет 72% дисперсии, первые десять — 96%. Облако тысяч токенных состояний, живущее формально в 768-мерном пространстве, по дисперсии вообще‑то упаковало всё примерно в два направления.
BERT: PR ≈ 86, effective rank ≈ 277, и энкодер BART: PR ≈ 113 при той же
. Моделька на два порядка «объёмнее» GPT-2 при той же самой размерности.
Энкодер T5: PR ≈ 175 при
— относительно своей размерности самый распределённый.
Гауссов baseline: PR ≈ 645 при
и ≈ 454 при
.
Декодеры снова разъехались: PR ≈ 3.4 у декодера T5 (PR/D = 0.007, то есть почти GPT-2) и PR ≈ 68 у декодера BART (PR/D = 0.088, то есть почти его собственный энкодер).
Колонка PR/D делает сравнение чуть более корректным между разными : 0.002 у GPT-2 против 0.112 у BERT, 0.147 у энкодера BART и 0.341 у энкодера T5.
Разница объясняется маской внимания и objective.
Objective решает, во что упирается выход. У CLM последний слой читается ровно одним линейным отображением —
lm_head, то естьс завязанными весами эмбеддингов. Всё, что не помогает разложить
по строкам
, дисперсии не получает: направление, полезное для предсказания следующего токена, усиливается, остальные ужимаются. Плюс к этому pre‑LN архитектура GPT-2 накапливает в residual stream несколько координат‑гигантов (те самые massive activations из раздела 2.3), и они забирают почти весь след ковариации. Отсюда
: это «вся дисперсия сложена в пару служебных направлений».
У MLM давление обратное: из каждой позиции нужно восстановить её собственный токен, то есть каждая позиция обязана нести и идентичность слова, и контекст. Одно направление такое не вместит — дисперсия расползается по десяткам.
У span corruption и denoising выход энкодера не читается линейным классификатором: его читает декодер через cross‑attention, на всех позициях и на всех слоях сразу. Такое представление выгоднее держать «широким» — отсюда самые большие PR/D у энкодеров T5 и BART.
Маска определяет, сколько независимых ролей у позиций. В двунаправленном типе все позиции равноправны и каждая видит весь текст, поэтому облако токенов — это облако разных контекстуализированных смыслов. В каузальном типе позиция
видит только префикс, и соседние позиции отличаются ровно на один токен: состояния идут почти вложенной цепочкой, сильно скоррелированной вдоль текста.
Отсюда полное следствие: форму облака задаёт не маска, а то, что читает выход, плюс схема нормализации. Маска сюда входит только косвенно — через то, что каузальный выход обычно читается одной линейной головой.
Что тогда вообще определяется маской? Не форма, а структура сходств — «какие тексты эта модель считает похожими». Поехали к финалу.
3.3 Сравнивать два пространства между собой
Мы описали каждое облако по отдельности. Перейдем к финальной части — оценим насколько похожи пространства двух разных моделей?
Наивный ответ — «посчитаем косинус между эмбеддингами BERT и GPT-2» — не просто плох, он не определён. Координаты и
— это разные числа про разные вещи; между базисами двух независимо обученных моделей нет никакого соответствия. А для T5 ещё и размерности не совпадают.
Самый классический вариант корректно померить два пространства Linear CKA (Centered Kernel Alignment, Kornblith et al., 2019):
CKA сравнивает не координаты, а матрицы попарных сходств объектов: «одинаково ли эти два пространства считают, какие тексты похожи друг на друга». Отсюда инвариантность к ортогональным поворотам и к изотропному масштабированию и работоспособность при разных .
Linear CKA, n=2000 текстов, mean pooling: BERT (enc-only) GPT-2 (dec-only) T5-enc (enc-dec) BART-enc (enc-dec) T5-dec (enc-dec) BART-dec (enc-dec) BERT (enc-only) 1.000 0.125 0.653 0.721 0.146 0.673 GPT-2 (dec-only) 0.125 1.000 0.206 0.228 0.235 0.278 T5-enc (enc-dec) 0.653 0.206 1.000 0.779 0.307 0.711 BART-enc (enc-dec) 0.721 0.228 0.779 1.000 0.270 0.823 T5-dec (enc-dec) 0.146 0.235 0.307 0.270 1.000 0.378 BART-dec (enc-dec) 0.673 0.278 0.711 0.823 0.378 1.000 Шумовая нижняя граница — CKA той же модели против гауссова облака: BERT (enc-only) vs шум: 0.087 GPT-2 (dec-only) vs шум: 0.019 T5-enc (enc-dec) vs шум: 0.082 BART-enc (enc-dec) vs шум: 0.086 T5-dec (enc-dec) vs шум: 0.022 BART-dec (enc-dec) vs шум: 0.085 Зависимость шума от размера выборки (шум против шума, D=768): n= 300: 0.717 n= 600: 0.563 n= 2000: 0.278
Что мы видим
По baseline:
У CKA есть сильное конечно‑выборочное смещение. Два полностью случайных облака при
дают CKA около 0.72, при
— около 0.56, и даже при
— всё ещё около 0.28. Причина в том, что при
, сравнимом с
, у двух случайных облаков неизбежно находится много совпадающих направлений просто по определению.
Это ловушка: нельзя посчитать CKA на паре сотен примеров, получить 0.6 и написать «пространства похожи». Поэтому мы взяли для этого раздела 2000 текстов и посчитали шумовую нижнюю границу для каждой модели отдельно — CKA той же модели против гауссова облака той же формы.
По результатам моделей:
пара | CKA | что общего |
|---|---|---|
энкодер T5 ↔ энкодер BART | 0.779 | двунаправленность |
BERT ↔ энкодер BART | 0.721 | двунаправленность |
BERT ↔ энкодер T5 | 0.653 | двунаправленность |
GPT-2 ↔ энкодер BART | 0.228 | — |
GPT-2 ↔ энкодер T5 | 0.206 | — |
GPT-2 ↔ BERT | 0.125 | одинаковые |
декодер BART ↔ энкодер BART | 0.823 | самая похожая пара во всей матрице |
декодер BART ↔ энкодер T5 | 0.711 | каузальный тип внутри «двунаправленного» кластера |
декодер BART ↔ BERT | 0.673 | и с BERT тоже |
декодер T5 ↔ энкодер T5 | 0.307 | тут собственный энкодер далеко |
декодер T5 ↔ GPT-2 | 0.235 | «сосед по маске» тоже далеко |
декодер T5 ↔ BERT | 0.146 | при шумовой границе 0.022 |
Три двунаправленных энкодера — плотный кластер 0.65–0.78. У них разные
, глубина, objective, токенизатор и корпус претрейна. Общее ровно одно — двунаправленная маска.
GPT-2 стоит в стороне от каждого из них (0.13–0.23) при шуме 0.02–0.09. Причём самая низкая похожесть во всей матрице — 0.125 у пары BERT/GPT-2, то есть у пары, которая совпадает по
, по глубине и по числу голов. Различаются они только маской.
А декодеры enc‑dec вносят вопросы. BART‑dec попал внутрь кластера двунаправленных (0.823 со своим энкодером, 0.673 с BERT), а T5-dec лежит сам по себе (0.15–0.38). Маска у них при этом одна и та же, каузальная.
Понять результат
Причин у этого расхождения может быть две:
Протокол. Мы сами подали декодеру тот же текст teacher forcing‑ом, так что он прочитал его дважды: через cross‑attention и как собственную историю. Соблазнительно объявить, что вся похожесть отсюда, — но не совсем. Проверка в ноутбкуке: те же CKA, но декодеру подаётся либо фиксированный нейтральный префикс, либо вообще один стартовый токен. В обоих случаях единственный канал к тексту — cross‑attention.
Вырожденность пространства. Шум метрики у декодера T5 — 0.022, как у GPT-2 (0.019), а у декодера BART — 0.085, как у энкодеров. Это схлопнутые пространства из 3.1–3.2: у декодера T5 анизотропия 0.868 и PR 3.4, совпадать ему просто нечем. Низкий CKA у вырожденного стека читается как «мало измеримых направлений», а не как «другая структура».
Проверка в ноутбуке дала следующее: Teacher forcing завысил, но эффект не создал. Когда декодер текста не видел вовсе, BART‑dec держит 0.664 со своим энкодером и 0.655 с BERT — то есть остаётся внутри двунаправленного кластера (0.65–0.78). Значит, дело не в протоколе, а в cross‑attention: декодер читает выход энкодера без маски и наследует его структуру сходств. Версия «виновата подача данных» не подтвердилась.
А вот вторая причина, геометрическая, работает. Шумная граница по baseline у декодера T5 — 0.022, как у GPT-2 (0.019), а у декодера BART — 0.085, как у энкодеров. Это те же самые схлопнутые пространства из 3.1–3.2: у декодера T5 анизотропия 0.868 и PR 3.4, совпадать ему просто нечем. Низкий CKA у вырожденного стека читается как «мало измеримых направлений», а не как «другая структура».
Отсюда версия тезиса:
> Среди типов, чья геометрия не вырождена, тип внимания — самый сильный группирующий фактор: три двунаправленных энкодера дают 0.65–0.78, а GPT-2 отстоит от каждого из них на 0.13–0.23 при шумовом пороге 0.02–0.09. Но маска не единственный фактор: вырожденность пространства обрубает измеримую похожесть (декодер T5), а cross‑attention возвращает декодеру структуру входа (декодер BART).
Я не выношу однозначного вывода из сноски, ибо мы работаем с маленькими моделями. Для обобщения всего здесь должны быть масштабы (и данных, и моделей). Цель моих туториалов — показать эффекты и анализ.
Вывод
Мы посмотрели много картинок и почитали много чисел. Возникает вопрос: зачем это нужно? Ответ: чтобы понимать, откуда брать вектор и как агрегировать токены.
Вообще, общие правила такие:
центрируем и стандартизируем перед любой метрикой над эмбеддингами — раздел 3.1 показал, что иначе меряется положение общего центра масс, а не похожесть текстов;
служебный первый токен в пулинг не кладём — по разделам 2.2 и 2.3 это элемент механизма внимания с аномальной нормой, а не смысл;
у каузального типа не берём
first, у encoder‑decoder берём выход энкодера, а если декодера — то с оговорками, о которых ниже;а дальше выбираем пулинг sweep‑ом на своей задаче.
Почему не всегда последний токен для декодерных моделей?
Расхожий совет «у каузальной модели берите last» держится на наблюдении: последний токен — единственный, кто видел весь текст. Но оптимизирован он под предсказание следующего токена, а не под описание прочитанного: его состояние отвечает на вопрос «что я скажу дальше». Усреднение же собирает сигнал со всех позиций, и обычно этого хватает с запасом — даже с поправкой на разную экспозицию контекста из части 2. Плюс техническая ловушка (я так первую статью чуть не проср...чуть не потеряла!): H[:, -1, :] при right padding возьмёт padding, а не последний токен.
Но: если модель дообучали под эмбеддинги с пулингом по последнему токену, брать надо именно его — там objective выровнен под вашу задачу специально.
Почему не всегда первый для энкодерных моделей?
Потому что «первый токен» — это три разные вещи в трёх моделях, и это видно прямо в таблице типов: у BERT на позиции 0 стоит [CLS], у BART — <s>, а у энкодера T5 никакого начального служебного токена нет вовсе, там обычное слово. [CLS] действительно обучен агрегировать, но под NSP — под «идут ли эти два куска текста подряд», а не под «о чём этот текст».
И первая позиция может дать attention sink с аномальной нормой (до 0.75 медианной массы внимания у энкодера BART), то есть служебный элемент механизма, а не носитель смысла.
Но: если модель дообучали агрегации в служебном токене — забываем это и берем его.
Почему нужно быть осторожным с токенами декодера в encoder‑decoder моделях?
Потому что состояние декодера — это не представление входа, а смесь «что я прочитал через cross‑attention» и «что я уже написал». Две причины держаться от него подальше:
Другой масштаб. Медианные нормы могут быть больше энкодерных. Складывать и считать косинус состояния без нормализации нельзя.
Похожесть на энкодер частично создаётся подачей. Мы подаём декодеру тот же текст teacher forcing‑ом, и контроль из 3.3 показал, во что это обходится: без подачи текста CKA декодера BART со своим энкодером падает с 0.823 до 0.664. Эффект не исчезает — структуру входа декодер наследует через cross‑attention, — но часть числа всё‑таки про наш способ подачи, а не про модель.
Итого: если нужен вектор текста из encoder‑decoder — это выход энкодера. Состояния декодера имеют смысл, когда вас интересует именно генерация, а не текст.

Уносим самое-самое главное
Архитектура говорит, какие позиции могли что‑то узнать. Природа свойства говорит, где оно живёт. Токенизатор говорит, что вообще лежит на позиции 0. Для выбора пулинга нужны все три — и дешёвый sweep на своих данных честнее любого общего совета.
И шпору ниже тоже уносим. Первое сентября на носу — куда без шпор.
encoder‑only | decoder‑only | encoder‑decoder | |
|---|---|---|---|
Маска | полная | треугольная | enc: полная / dec: треуг. + cross без маски |
Кто видел весь текст | все позиции | только последняя | все позиции энкодера |
Откуда брать эмбеддинг текста |
|
|
|
Чего избегать |
|
| состояния декодера как «смысл входа» |
Обязательная обработка | центрирование | центрирование | центрирование, раздельно для enc и dec |
Какой слой | проверить sweep‑ом | проверить sweep‑ом | проверить sweep‑ом |
Сравнение с другой моделью | CKA с шумовым анализом | CKA с шумовым анализом | CKA, раздельно enc/dec |
Чего не делать
Косинус без центрирования.
firstу каузального типа и служебный первый токен в пулинге, если этого не требует задача.[CLS]как готовый эмбеддинг предложения , если этого не допускает задача.H[:, -1, :]при right padding. Возьмёте padding вместо последнего токена — молча, без ошибки. Толькоattention_mask.sum(1) - 1.Нормы, анизотропия и PR между моделями разной
без baseline. Без гауссова контроля числа несопоставимы.
Косинус между эмбеддингами разных моделей. Общего базиса у независимо обученных моделей не существует — нужен CKA.
CKA на маленькой выборке. При
два случайных облака дают 0.5–0.7. Берите
и считайте шумовую нижнюю границу для каждой модели отдельно.
Смешивание энкодера и декодера — и состояние декодера как «эмбеддинг входа».
Спасибо, что дочитали!
Потыкать дальше предлагаю:
Повторить на
roberta-base,pythia-410m,mt5-small— и проверить, держится ли кластеризация по типу маски на других семействах и языках.
Посмотреть, как метрики ведут себя с ростом масштаба: massive activations и attention sink на моделях от 1B выражены резче (Sun et al., 2024).

И как всегда зову к себе за новыми материалами и страданиями
Присоединяйтесь к Just Data Blog, ставьте лайки и я буду лайкать на выходных, чтобы писать дальше!: )
До встречи!

