meta-attention is all you need

Страницы:  1

Ответить
 

Professor Seleznov


Введение
В этой статье я расскажу о интересной находке во время моих экспериментов с языковыми моделями, которую я решил назвать "мета-трансформерами".
Или я нашел реально что-то интересное, или выдал желаемое из действительное, а обьективную оценку может дать только (технически подкованный) внешний наблюдатель, поэтому этот текст и был опубликован. Особенно тут кстати будут спецы по архитектуре трансформеров.
Веса моделей, исходники проекта + вся документация будут приложены в конце статьи (в главе исходники), на Hugging-Face и Codeberg (аналог Github) соответственно. Изначально проект был с русскими доками и комментариями, но я перевел на английский комментарии и доки для global-community через Codex, на Codeberg будет оригинальная версия на RU и переведенная ENG.
Статья будет находится на Codeberg (в рус. и енг. версии) в главной директории как файлmeta-attention-is-all-you-need.md, на англ. и рус. соответственно.
Схему с превью статьи вы можете найти в самом начале главы Архитектурные схемы.
Все главы
1. Важные замечания
Информация в этой главе не требуется для понимания архитектуры, я рекомендую ее все же прочитать, но вы можете сразу приступить к описанию архитектуры в главе Знакомимся с мета-трансформерами, если хотите.
Учитывая крайнюю специфичность проекта и связанных с ней концептов - чтобы не выглядеть очередным сумасшедшим с манией изобретательства, который решил все математические задачи тысячелетия разом, я разместил в этой главе много ремарок, которые рекомендую прочитать перед тем, как переходить к основной части материала. Впрочем,
Это классический проект выходного дня, который я делал в свободное от работы время. Может быть обидно, если идея провалится, но я особо ничего от этого не потеряю, так что, по моему мнению, я тут могу быть вполне обьективен и открыт к критике.
Отсылка в названий статьи
Некоторые сведущие могли заметить, что в названий статьи есть отсылка к статье "Attention is all you need" 2017 года, которая впервые и описала архитектуру трансформеров. Я, конечно, не ставлю свою идею вровень с этой статьей, просто сам механизм и принцип работы довольно схож.
Впрочем, саму значимость (и есть ли она вообще) этой идеи я оценить не могу, не хватает экспертизы, и, самое главное, грамотной обратной связи. Поэтому, опять же, вы этот текст и читаете.
Уникальность
Учитывая, что по сути идея в очень общем виде кажется довольно наводящей и простой - вполне возможно, это уже кто-то испытывал, и я просто недостаточно хорошо искал. Буду рад, если вы на это укажете.
Другой проект с тем же названием
Если вы забьете в гугл, то вы можете найти архитектуру "мета-трансформеров", которая тоже модифицирует трансформеры. На этом сходства заканчиваются, если вкратце, то это фреймворк для унификации 12 модальностей, он как бы предоставляет для них единое общее токен-пространство.
Почему это названо мета-трансформерами одному ежу известно, скорее чисто ради красивого названия, технически верно это было бы назвать мета-модальной архитектурой.
Чтобы убедиться что я прав, статью про эту архитектуру вы можете прочитать здесь.
Метрики экспериментов
Рекомендую не принимать описанные цифры на веру. Я один программист, с не особо выдающимся интеллектом, и с пет-проектом которым занимался в свободное от работы время - я легко мог ошибиться. Если имеете экспертизу и желание провести свои испытания, то буду рад, если поделитесь с этим в комментариях или в ЛС.
Истоки и продолжительность экспериментов
Самые ранние наброски этой архитектуры появились еще в августе 2025 года, но они мало имеют общего с тем куда эта идея развилась, тогда это называлось "рефлексивным ядром", и цель заключалась в том, как научить языковую модель "думать о своем собственном мышлений".
В текущем виде проект появился в марте текущего года, и занял примерно месяц плотной работы с Claude Code на плане max 5x, плюс ~30 баксов на vast.ai для обучения.
2. Знакомимся с мета-трансформерами
Архитектура мета-трансформеров в начале экспериментов и на последней фазе хоть и разделяют общий принцип, в деталях устроены по разному. Это обзорная статья и здесь будет уделено внимание преимущественно последней версий, информацию по всем фазам вы сможете найти в исходниках.
Общий принцип
Представим модель, которая принимает на вход текст и генерирует его продолжение. Когда она принимает токены, на каждом слое внутри возникают векторы чисел — это называется активации. Идея в том, чтобы брать эти активации и проецировать на эти же слои. Фактически, это механизм внимания над вниманием модели, именно этим обьясняется приставка мета в названий архитектуры.
Применение
Предположение заключается в том, что модель на самом деле знает, когда она врет, просто этот "сигнал неуверенности" не доходит до выходных слоев, и можно помочь определять модели неуверенность, подмешивая ее активации ей же.
Основные компоненты
В самом общем виде можно выделить четыре ключевых компонента архитектуры, которые формируют единый конвейер мета-трансформеров.
  • Хуки активации - механизм считывания активации. Срабатывает автоматически когда forward проходит через "свой" слой, извлекает нужную позицию скрытых состояний и складывает в буфер активаций.
  • Когнитивный энкодер - небольшая нейросеть, превращающая активации из буфера в когнитивные токены. Две основные архитектуры - это линейные проекторы со слоя на токен + небольшая MLP голова, и мини-трансформер. Обе сети показывали эффективные результаты но в разных аспектах, об этом будет рассказано позднее.
  • Врата внимания (Gates) - обучаемый скалярный множитель, по одному на слой. Регулирует насколько сильно мета-внимание подмешивается в слой — то есть нужна ли ему интроспекция в принципе.
  • Головы мета-внимания - позволяет отдельно взятому слою выборочно выбирать, к активациям каких других слоёв "прислушиваться" сильнее, а каких слабее. Т.е. он может смотреть на слой A больше чем на слой B.
Как происходит обучение
Обучаемые компоненты — когнитивный енкдоер, головы мета-внимания, и врата. На Llama-3.1-8B это около 188M параметров — ~2.3% от 8-миллиардной базы.
Сами веса модели строго заморожены, все эксперименты показывали, что модель вместо обобщения начинает жестко эксплуатировать сигналы, и качество генерации не улучшается или даже становится хуже.
Цикл обучения
Один обучающий шаг — это два forward-прохода одной и той же модели на одном вопросе:
  • Проход 1 — forward без генерации. Хуки активации снимают активации со всех слоёв. Энкодер проецирует их в когнитивные токены и кладёт в буфер.
  • Проход 2 — forward с активной мета-инъекцией. На каждом слое мета-внимание видит когнитивные токены из буфера и подмешивает мета-сигнал в основной поток через врата. Модель генерирует ответ.
Тот же двухпроходный механизм работает и на инференсе — train и eval идентичны по структуре forward'а. Разница только в том что на трейне после двух forward'ов запускается обратный проход (backward): считаются градиенты, и optimizer обновляет веса энкодера, мета-внимания и врат (база при этом остаётся замороженной — градиенты через неё проходят, но её веса не меняются). На инференсе backward не нужен — модель просто генерирует ответ.
3. Подробный разбор компонентов

Будет разобран весь конвейер из 4 компонентов: хуки активаций, когнитивный энкодер, врата и головы мета-внимания.
Хуки активации
Самый низкоуровневый компонент — механизм считывания активации, классическая программа а не нейросеть. Технически это register_forward_hook от PyTorch, навешенный на каждый целевой слой базовой модели.
def hook(module, input, output):
if self._frozen:
return
hidden_states = output[0] if isinstance(output, tuple) else output
# [batch, seq_len, hidden_dim] → берём последний токен
last_token = hidden_states[:, -1, :].detach().clone()
self.activations[f"layer_{layer_idx}"] = last_token.squeeze(0)
Что происходит:
  • Хук срабатывает автоматически когда forward проходит через "свой" слой
  • Получает полный тензор скрытых состояний [batch, seq_len, hidden_dim]
  • Извлекает срез последнего токена [:, -1, :] — для авторегрессивной модели это точка принятия решения, hidden state по которому предсказывается следующий токен
  • .detach() — отвязывает от графа базовой модели (мы не хотим градиенты в базу), .clone() — копия чтобы не держать ссылку на буфер
  • Складывает в словарь по индексу слоя
Флаг _frozen / freeze-unfreeze. Ключевая деталь для совместимости с model.generate(). На Pass 1 (чтение промпта) хуки активны и снимают активации. Перед Pass 2 их замораживают (freeze()) — иначе на каждом авторегрессивном шаге генерации они перезаписывали бы активации, и мы получили бы не "точку принятия решения по промпту", а активации по последнему сгенерированному токену.
Хуки без обучаемых параметров, чистый passive observer. Поддерживают разные архитектуры (Llama/Gemma/Qwen через model.model.layers, GPT-2 через model.transformer.h).
Что конкретно мы собираем
Когда промпт проходит через слой, слой выдаёт не один вектор, а по одному hidden-вектору на каждый входной токен: тензор [seq_len, hidden_dim]. Например промпт из 20 токенов → слой 15 выдаёт 20 векторов размерности 4096 каждый.
Вопрос: как из этих seq_len векторов сделать один когнитивный токен для этого слоя? Это и есть "tokenization" / "pooling" — способ свернуть последовательность в одно представление.
Last token (базовый вариант)
hidden_states[:, -1, :] — берём вектор последнего токена. Из 20 берём 20-й.
Почему именно он: в авторегрессивной модели следующий токен предсказывается именно из hidden state последнего токена. То есть это прямо то состояние на основе которого модель сейчас будет генерировать. Все предыдущие 19 позиций — контекст, который привёл к этой точке. "Срез самого решения".
Минус: это одна точка. Вся накопленная по последовательности информация сжата в endpoint, и какие-то распределённые сигналы могут в нём не отразиться.
Mean pool
hidden_states.mean(dim=1)усреднение всех позиций. Складываем все 20 векторов и делим на 20 → один "усреднённый" вектор размерности 4096.
Интуиция: вместо "состояния в конечной точке" получаем общий портрет активности слоя по всему входу. Если в промпте было что-то что вызвало неуверенность на 5-м токене, last-token этого может не сохранить (внимание уже ушло дальше), а mean — усреднит и сохранит "фоновый" сигнал.
Минус: размывает decision point. Конкретное "вот здесь я принимаю решение" растворяется в среднем по всем токенам, многие из которых (начало промпта, служебные токены) к финальному решению отношения почти не имеют.
Три варианта Phase 5
Вариант Что берём Размерность входа проектора sel_acc
baseline last token 4096 89.1%
A mean pool 4096 84.1% ↓
B concat(last, mean) 8192 90.1% ⭐
C attention pool 4096 (отложен)

Variant A (только mean): 84.1% — хуже baseline. Потеря decision point дороже чем выигрыш от распределённого контекста. Подтверждает что endpoint критичен.
Variant B (last + mean): склеиваем оба вектора в один [8192], проектор теперь принимает 8192 вместо 4096. Результат — рекорд 90.1%. Логика: last содержит конкретный choice ("я склоняюсь к ответу C"), mean содержит контекст которым этот choice обусловлен ("и вот общий фон рассуждения который к этому привёл"). Вместе несут больше информации чем каждый по отдельности.
Variant C (attention pool): вместо фиксированного усреднения — обучаемые веса над позициями (модель сама учит на какие токены смотреть при пуле). Гибче, но требует больше параметров и обучения; отложили по бюджету.
Главный вывод Phase 5
Richer tokenization помогает accuracy (+1 п.п. рекорд) — значит в активациях есть полезный сигнал помимо одного last-token, и его извлечение улучшает калибровку.
Но — correction не сдвинулась (как было ~0 попыток самокоррекции, так и осталось). Это опровергло гипотезу что correction упирается в недостаток информации в токене. Вывод: чтобы модель научилась исправлять ответы, нужно не богаче считывать активации, а менять архитектуру энкодера (что и подтвердилось в Phase 8 с transformer-энкодером). Tokenization влияет на сколько точно модель калибрует уверенность; correction — на устройство энкодера.
Когнитивный энкодер
Обучаемая нейросеть, превращающая снятые активации в когнитивные токены. В Selective-форме — чистый feedforward.
# Per-layer проектор (один на каждый из 32 слоёв):
nn.Sequential(
nn.LayerNorm(hidden_dim), # 4096
nn.Linear(hidden_dim, bottleneck), # 4096 → 256
nn.GELU(),
)
# Encoder gate (скаляр на слой):
nn.Parameter(torch.tensor([0.3])) # tanh-gated
# Общий output projector:
nn.Sequential(
nn.LayerNorm(bottleneck), # 256
nn.Linear(bottleneck, hidden_dim), # 256 → 4096
nn.GELU(),
nn.Linear(hidden_dim, hidden_dim), # 4096 → 4096
)
Поток данных:
активация слоя i [4096]
→ projector_i (LayerNorm + Linear → 256 + GELU)
→ encoder_gate_i: proj * tanh(gate_i)
→ стек по всем 32 слоям → [batch, 32, 256]
→ output_proj (256 → 4096 → GELU → 4096)
→ output_norm (LayerNorm)
→ когнитивные токены [batch, 32, 4096]
Encoder gates (первый набор врат). Заметь: proj * tanh(gate_i) — каждый per-layer проектор тоже имеет свой gate. Это отдельный механизм от врат инъекции (которые в головах мета-внимания). Encoder gate регулирует "вносит ли этот слой вклад в формирование когнитивных токенов вообще". В Phase 4 эти скалярные gates заменили на input-dependent gate-сети (Linear(4096→1) per layer, sigmoid) — 14 из 32 слоёв стали динамическими (gate зависит от входа, std>0.01).
Почему bottleneck 256. Сжатие 4096→256→4096 заставляет проектор извлекать только существенный сигнал — узкое горло фильтрует шум. И вдвое дешевле full-rank.
Почему per-layer независимые проекторы. Энкодеру не нужно учить отношения между слоями — это сделают головы мета-внимания на стадии инъекции. Достаточно научиться извлекать полезный feature из каждой активации независимо. Эмпирически: простой 1:1 feedforward (52M params, sel_acc 71.4%) победил MultiToken-энкодер с внутренним cross-attention (94M, sel_acc 50.3%).
Probe pretrain. Для 32-слойной архитектуры перед основным обучением каждый проектор отдельно обучается предсказывать P(correct) по своей активации (через временный ConfidenceHead, ~1 мин на CPU). Без этого 32-слойная сеть не сходится. После pretrain каждый проектор уже умеет извлекать сигнал уверенности; основное обучение шлифует.
Эволюция (Phase 8). В Phase 8 энкодер стал mini-transformer: per-layer проекторы → stack из 2 transformer-блоков с self-attention над когнитивными токенами → output projector. Внутренний attention позволяет токенам "разговаривать" (L15 видит L29) до инъекции. Это разблокировало self-correction (50% на Llama-1B) — поведение, отсутствовавшее у feedforward-энкодера.
Врата внимания
Обучаемый скалярный множитель, по одному на каждую голову мета-внимания (= на каждый слой LLM куда инжектируется сигнал). Это второй набор врат — на стадии инъекции, отдельно от encoder gates.
self.gate = nn.Parameter(torch.tensor([gate_init], dtype=torch.float32))  # init 0.3
# ...
gate_value = torch.tanh(self.gate)
return residual + gate_value * cross_attention_output
Формула проста: output = residual + tanh(gate) · CA_output. Gate регулирует громкость подмешиваемого мета-сигнала, не его содержание.
Почему tanh и почему init=0.3. tanh ограничивает множитель в (-1, 1) и даёт гладкий градиент. Критична зона инициализации:
  • tanh'(0.3) = 0.91 — почти линейная зона, градиенты текут свободно
  • tanh'(2.0) = 0.07 — gates замерзают навсегда (мёртвый градиент)
  • init=0.1 в bfloat16: precision ~0.01, мелкие обновления теряются
Поэтому init=0.3 + learning rate ×5 относительно остальных параметров — gates должны учиться быстрее чтобы успеть найти своё значение.
Зачем gate если есть мета-внимание. Кажется дублированием, но роли разные. Softmax внутри головы всегда выдаёт распределение — то есть голова мета-внимания обязана на что-то "смотреть". Gate даёт слою возможность сказать "мне интроспекция вообще не нужна" (gate≈0, инъекция зануляется). Без gate нельзя было бы выучить "этот слой не использует мета-канал". Плюс gate с малым init даёт near-identity старт обучения: модель стартует почти как немодифицированная база и плавно открывает каналы где полезно.
Когнитивная карта инъекции. После обучения значения gate по слоям складываются в стабильную картину (Llama-8B):
Слой      tanh(gate)   Роль
L0-L5 0.01-0.04 токенизация — мета-сигнал не нужен
L6-L12 0.04-0.05 синтаксис, низкоуровневая семантика
L19-L24 0.07-0.09 рассуждение — начинает слушать
L25-L28 0.07-0.11 формирование ответа — активно использует
L29 0.12-0.19 ЛИДЕР — точка принятия решения
L30-L31 0.07-0.08 финальная обработка
Эта карта стабильна cross-domain (одинаковая на MMLU и TriviaQA) — свойство архитектуры базовой модели, а не задачи. Поздние слои "слушают" интроспекцию сильнее всего, ранние почти отключены.
Головы мета-внимания
Собственно механизм, через который слой выбирает к каким когнитивным токенам прислушаться. Устроены по принципу классических attention heads трансформера, но key/value берутся из когнитивных токенов, а не из текста. В коде — BottleneckCrossAttention.
# Проекции (bottleneck_dim=256, num_heads=4, head_dim=64):
self.norm = nn.LayerNorm(hidden_dim) # pre-norm
self.down_proj = nn.Linear(hidden_dim, bottleneck, bias=False) # 4096→256
self.q_proj = nn.Linear(bottleneck, bottleneck, bias=False) # из сжатого hidden
self.k_proj = nn.Linear(hidden_dim, bottleneck, bias=False) # из cog tokens
self.v_proj = nn.Linear(hidden_dim, bottleneck, bias=False) # из cog tokens
self.up_proj = nn.Linear(bottleneck, hidden_dim, bias=False) # 256→4096
self.token_preference = nn.Parameter(torch.zeros(num_cognitive_tokens))
Forward (одна голова на слой LLM):
residual = hidden_states
h = LayerNorm(hidden_states)
h_compressed = down_proj(h) # [batch, seq, 256]
Q = q_proj(h_compressed) # из текущего скрытого состояния
K = k_proj(cognitive_tokens) # из когнитивных токенов
V = v_proj(cognitive_tokens)
# multi-head: разбить на 4 головы по 64
scores = Q · Kᵀ / √64 # [batch, heads, seq, 32]
scores = scores + token_preference # learnable bias на источники
attn = softmax(scores)
out = attn · V # взвешенная сумма cog токенов
out = up_proj(out) # обратно в 4096
output = residual + tanh(gate) · out # ← врата здесь
Bottleneck. Голова работает не в полном 4096-мерном пространстве, а в сжатом 256. Это даёт 32 головы (по одной на слой) общей стоимостью 137M params против 268M у 4 полноразмерных голов — вдвое дешевле, и эмпирически чище (6/6 проверок против 5/5). Узкое горло выкидывает шум.
Multi-head. 4 головы по 64 измерения. Каждая голова может выучить свой "ракурс" — например одна следит за конфликтом между ранними и поздними слоями, другая за общим уровнем уверенности. (Это интерпретация; полноценного head-probing мы не делали — открытое направление для анализа.)
4. Подробный разбор обучения

Обучение мета-трансформера разбивается на три стадии: сбор активаций (построение датасета), предобучение проекторов, и основное обучение. Разберём каждую. Все конкретные цифры — по Phase 2 Selective на Llama-3.1-8B (наш рекорд калибровки).
Стадия 1 — сбор активаций (датасет)
Прежде чем обучать энкодер, нужны сырые активации базовой модели. Это делается один раз и кэшируется (повторный inference дорогой — 60-70 минут GPU).
Для каждого вопроса из обучающей выборки:
  • Прогоняем базовую (замороженную) модель forward'ом на промпте
  • Хуки снимают активации последнего токена со всех 32 слоёв → [32, 4096]
  • Записываем активации + правильный ответ + флаг pass1_correct (угадала ли модель сама, без рефлексии)
Итоговый датасет: 12042 train / 1000 val / 1000 test на полном MMLU (57 предметов). Активации сохраняются на диск — дальше обучение работает с ними напрямую, не пересчитывая каждый раз forward базовой модели.
Стадия 2 — pretrain проекторов
Ключевой шаг для 32-слойной архитектуры. Перед основным обучением каждый из 32 per-layer проекторов обучается отдельно на маленькой вспомогательной задаче:
активация слоя i [4096]
→ LayerNorm + Linear(4096 → 256)
→ ConfidenceHead (256 → 1)
→ P(ответ правильный)
Обучаем бинарной cross-entropy на флаге pass1_correct. Около минуты на CPU. ConfidenceHead после этого выбрасывается — нам нужен только обученный проектор.
Зачем: без pretrain'а 32-слойная сеть не сходится — модели слишком сложно одновременно научиться и проектировать активации, и пользоваться ими. После pretrain каждый проектор уже умеет извлекать сигнал уверенности из своего слоя (на лучших слоях — L15, L25 — probe accuracy 77.6%). Основное обучение это шлифует.
Эмпирика: random projectors дали 2/5 проверок, pretrained — 5/5. Pretrain превратил 32-слойную архитектуру из неработающей в рабочую.
Стадия 3 — основное обучение
Один обучающий шаг = два forward'а одной модели + backward сверху:
Pass 1 (read):
base_model.forward(prompt) # хуки активны, генерации нет
activations ← хуки [32 × 4096]
cognitive_tokens ← encoder(activations) # [32, 4096]
buffer.fill(cognitive_tokens)
Pass 2 (write + loss):
хуки замораживаются (freeze)
logits ← base_model.forward(prompt + target,
cross_attention=active) # головы видят буфер
loss = CrossEntropy(logits, target_text)
Backward:
loss.backward() # через frozen base → CA → cog tokens → encoder
optimizer.step() # обновляет ТОЛЬКО обвязку
Loss — обычная language modeling cross-entropy на target text. Никаких экзотических objective'ов. Маскируется так: токены промпта помечаются -100 (не входят в loss), считается только на target-части.
Куда течёт градиент — главная идея. Backward проходит через замороженную базу в обратном направлении: output → головы мета-внимания → когнитивные токены → энкодер. Веса базы при этом не обновляются (requires_grad=False), но computational graph через них существует, и градиент течёт сквозь как через "пассивный передатчик".
Это значит: база работает proxy-loss функцией для интроспекции. Энкодер не учится напрямую "предсказывать правильный ответ" — он учится производить такие когнитивные токены, при инъекции которых замороженная база сама выдаёт правильный ответ / уместный отказ. Мы используем саму базовую модель как функцию потерь для обвязки.
Self-correction targets (Phase 2)
В Phase 1 target — просто правильный ответ или "I'm not sure". В Phase 2 target принимает один из трёх форматов, выбираемый по результату Pass 1:
if pass1_correct:
# CONFIRM: модель сама угадала → подтверждаем
target = " B) 4 Hz"
action = "confirm"
else:
if random() < 0.5:
# CORRECT: модель ошиблась → учим исправлять
target = " Wait, the correct answer is B) 4 Hz."
action = "correct"
else:
# REFUSE: модель ошиблась → учим отказываться
target = " I'm not confident enough to answer this question accurately."
action = "refuse"
Логика: на вопросах где модель сама права — учим confirm (уверенный ответ). На вопросах где сама ошиблась — половину учим correct (исправиться: "Wait, actually..."), половину refuse (честно отказаться). Соотношение correct/refuse = 50/50 (correction_ratio=0.5).
Критично: модель не получает явной метки "этот вопрос лёгкий — делай confirm". Action type определяет только КАКОЙ target подаётся при обучении. На инференсе модель должна сама по когнитивным токенам понять, позволяет ли её собственная уверенность ответить, или нужно отказаться/пересмотреть. Это и есть тренировка использования интроспекции по назначению.
Optimizer — пять групп параметров
Не все обучаемые параметры равны. Веса (проекторы, QKV) и скаляры (gates, preferences) имеют разную природу, поэтому разные learning rate:
Группа Что LR
1 Веса энкодера (проекторы, output_proj) 2e-4
2 Веса голов мета-внимания (down/q/k/v/up proj) 2e-4
3 Encoder gates (32 скаляра) 1e-3 (×5)
4 CA gates (32 скаляра) 1e-3 (×5)
5 Token preferences (32×32 = 1024) 1e-3 (×5)

Почему gates получают ×5 learning rate: их мало (по одному скаляру на слой), и они проходят через tanh который сжимает градиент. Чтобы gate успел дойти от init=0.3 до своего рабочего значения за то же число эпох что и большие весовые матрицы — ему нужен ускоренный LR. Без этого gates "не успевают" найти своё значение и остаются около инициализации.
Оптимизатор — AdamW. Schedule — cosine с 5% warmup. Effective batch size = 2 × 16 (grad accumulation) = 32.
Гиперпараметры (Phase 2 Selective, рекорд)
base model:        Llama-3.1-8B-Instruct (bf16, frozen)
learning rate: 2e-4 (×5 для gates/preferences)
batch size: 2, grad accumulation 16 → effective 32
epochs: 10 (early stop patience 5)
max_seq_len: 256
scheduler: cosine, warmup 5%
dataset: full MMLU, 12042 train / 1000 val / 1000 test
correction ratio: 0.5
init: из Phase 1 Selective checkpoint (warm start)
trainable params: ~188M (encoder 51.7M + 32 CA 136.5M)
frozen: 8.0B base
Динамика обучения
Лучшая эпоха — 2-я (val_loss 0.1044), early stop на 7-й. То есть модель сходится очень быстро — за пару эпох находит хорошую конфигурацию интроспекции, дальше начинается overfitting.
Это характерная черта: мы обучаем тонкую обвязку поверх уже мощной замороженной базы. Базе не нужно "переучиваться" — обвязке достаточно научиться правильно читать и подмешивать уже существующий сигнал. Поэтому 2 эпохи, а не 20.
Warm start из Phase 1. Phase 2 инициализируется из чекпоинта Phase 1 Selective (init_from_phase1=True) — энкодер и головы уже умеют делать калиброванные отказы, Phase 2 только добавляет correction-поведение поверх. Это важный нюанс: загружаются все веса включая gates (ранний баг где gates переинициализировали с нуля стоил информации о том насколько модель нуждается в канале).
Ключевые инсайты обучения
  • Frozen base обязателен. Любая разморозка базы (LoRA, partial unfreeze) даёт shortcut: модель оптимизирует loss напрямую через свои веса, минуя мета-канал. Refusal rate коллапсирует с 9.2% до 0.4%. Опровергнуто 10 экспериментами на Gemma-2B.
  • Gate init в линейной зоне tanh. init=0.3 → tanh'(0.3)=0.91 (градиент течёт). init=2.0 → tanh'(2.0)=0.07 (gates замерзают навсегда). Критичная деталь которая определяет учатся gates вообще или нет.
  • Pretrain проекторов = обязательное предварительное условие для глубоких энкодеров. Без него 32-слойная архитектура не сходится.
  • Сложность задачи как гиперпараметр. На лёгких задачах (TriviaQA, baseline 76%) gates закрываются до 0.01 — канал не нужен. На сложных (MMLU Hard, baseline 40%) gates стабилизируются на 0.08-0.12. Модель адаптивно регулирует использование интроспекции в зависимости от того, нужна ли она.
  • Быстрая сходимость. 2 эпохи до лучшего результата. Обучаем проводку, не знания — поэтому быстро.
5. Эксперименты
Рекомендую не принимать описанные цифры на веру. Я один программист с пет-проектом в свободное от работы время, и легко мог ошибиться. Если имеете экспертизу и желание провести свои испытания, то буду рад, если поделитесь с этим в комментариях или в ЛС.
Какие метрики мы измеряем
Это специфические метрики калибровки — не путать со стандартными ML-метриками точности. Они описывают поведение модели в условиях неуверенности, а не просто "правильность ответа".
Selective accuracy (sel_acc) — из тех вопросов, на которые модель решила ответить (не отказалась), какая доля правильных. Считается только по non-refusal samples. Формула: correct_among_answered / total_answered. По-русски: "когда модель отвечает — насколько часто она права".
Refusal rate — доля вопросов на которых модель отказалась отвечать ("I'm not sure", "I don't know"). Формула: refused / total. Базовая Llama без рефлексии почти не отказывается — она всегда что-то генерирует, даже когда не знает.
Refusal precision (ref_prec)главная метрика калибровки отказов. Из тех случаев где модель отказалась, какая доля отказов была оправданной (то есть модель действительно бы ошиблась, если бы попыталась ответить). 100% = модель отказывается только тогда когда реально не знает. <100% означает "ошибочные отказы" — модель отказалась от вопросов которые могла бы решить. Формула: refused_AND_would_be_wrong / refused.
Correction accuracy (correction_acc) — из попыток модели исправить собственный ответ (когда после изначального варианта она пишет "wait, actually..." и предлагает другой), какая доля закончилась правильным финальным ответом. Формула: successful_corrections / correction_attempts. Самокоррекция в LLM практически не работает в стандартных моделях — это самый сложный режим для измерения.
Total recovery — интегральная метрика "защиты от ошибки". Из вопросов где модель в первом проходе была НЕ ПРАВА, какая доля закончилась хорошо — либо через успешную correction (исправилась), либо через smart refusal (отказалась вместо ложного уверенного ответа). Формула: (successful_corrections + smart_refusals) / wrong_in_first_pass. По смыслу: "сколько ошибок не превратилось в галлюцинации".
Рекорды по экспериментам
Эксперимент Базовая модель sel_acc ref_prec Дополнительно
Phase 2 Selective (full MMLU) Llama-3.1-8B-Instruct 89.1% 99.84% total_recovery 90.7%
Phase 5 Multi-Position B Llama-3.1-8B-Instruct 90.1% ⭐ 98.7% val_loss 0.1124
Cross-Domain (MMLU → TriviaQA, zero-shot) Llama-3.1-8B-Instruct 91.1% 100% без обучения на выбранном датасете показывает очень высокие результаты, обобщение
Phase 4 Dynamic Gates Llama-3.1-8B-Instruct 88.9% 99.0% 14/32 слоёв input-dependent
Phase 8 Transformer Encoder Llama-3.2-1B-Instruct 27.7% 100% correction_acc 50% (огромный разрыв с остальными экспериментами)
Phase 1 Revised (baseline) Gemma-2-2B-IT 62.4% 81.0% первый рабочий цикл

⭐ = проектный рекорд по selective accuracy.
Что эти цифры означают
Refusal precision 99.84% (Phase 2 Selective MMLU) — это главное достижение проекта по калибровке. Из ~354 случаев когда модель отказалась отвечать на вопрос, она ошиблась в отказе только 1 раз (то есть один раз отказалась от вопроса который могла бы решить). Это интерпретируется так: модель практически идеально различает "я знаю" от "я не знаю" — и когда говорит "не знаю", она почти всегда права в этом признании.
Trade-off: чтобы достичь такой точности отказов, модель отказывается часто — refusal rate 63.3% на MMLU. То есть она признаётся "не уверена" примерно на двух третях вопросов.
Selective accuracy 90.1% (Phase 5 Variant B) — на ТЕХ ВОПРОСАХ (≈37% от всех), на которые модель решает ответить, она правильна в 90.1% случаев. Сравнение: базовая Llama-3.1-8B на MMLU Hard выдаёт ~40% accuracy (отвечает на все, часто неверно). Мета-трансформер не повышает "знания" модели — он переключает режим: с "ответить наугад" на "ответить когда уверена, отказаться когда нет".
Cross-domain 91.1% sel_acc + 100% ref_prec (zero-shot) — самый сильный результат для верификации гипотезы. Чекпоинт Phase 2 Selective MMLU, обученный исключительно на MMLU, прогнан на TriviaQA — совсем другой домен (фактологические open-ended вопросы вместо STEM/гуманитарных multiple choice). Refusal precision = 100% — модель ни разу не отказалась от вопроса который могла решить. Карта когнитивной инъекции (какие слои какие сигналы пропускают) стабильна между MMLU и TriviaQA.
Это значит: энкодер выучил не паттерны MMLU, а общий "язык неуверенности" самой базовой модели.
Correction accuracy 50% (Phase 8 Transformer Encoder, Llama-1B) — за 22 предыдущих эксперимента на MLP-энкодере correction attempts были ровно ноль. Модель либо отвечала, либо отказывалась — никогда не пересматривала собственный ответ. С transformer-энкодером в Phase 8 впервые появилось self-correction поведение: 4 попытки исправления, 2 из которых успешные (50%). На 1B accuracy в целом упала (overfitting на маленьком trainset), но появилось качественно новое поведение, которого раньше просто не было.
Это сигнал что внутреннее устройство энкодера определяет какие свойства модели может выразить интроспекция. Чисто feedforward энкодер даёт калибровку отказов; transformer-энкодер — самокоррекцию. Phase 8 на 8B — следующий шаг roadmap'а.
Главное наблюдение
Все эти числа подкрепляют одну гипотезу: базовая модель уже "знает" свою неуверенность, она кодируется в активациях. Мета-трансформер не учит модель новым фактам — он строит канал по которому уже существующий внутренний сигнал доходит до выхода и начинает влиять на генерацию. Поэтому архитектура переносится между задачами и доменами (cross-domain zero-shot работает), и поэтому она дёшевая (188M trainable params против 8B замороженной базы — 2.3%).
6. Архитектурные схемы

Тут будут представлены основные концепции мета-трансформеров в графическом виде.
Обзор архитектуры
pic
Обзор архитектуры
Формирование когнитивного токена
pic
Формирование когнитивного токена
Поток градиентов при обучений
pic
Поток градиентов при обучений
7. Заключение

Если вы после прочтения статьи посчитаете идею интересной, но при этом чувствуете, что вам (как и мне) не хватает экспертизы, чтобы ее обьективно оценить, то рекомендую поставить лайк и добавить в закладки.
Мне внимание само по себе не нужно, но это повысит шансы, что на статью натолкнулся люди, шарящие в глубоком обучений и архитектуре трансформеров. Если у вас есть такие знакомые то поделитесь этой статьей с ними - в первую очередь мне важно услышать мнение от этих людей.
У этого проекта есть крайне интересная предыстория, которая началась в августе 2025 года, когда я на выходных из-за скуки решил посмотреть, что случится если дать двум ChatGPT-4o свободно общаться между собой. Но я намеренно здесь ее не упомянул, чтобы не перегружать и так обьемный текст. Если эта идея окажется хоть сколько нибудь новаторской, то я обязательно напишу об этом отдельную статью.
А пока до новых встреч!
8. Исходники

Исходники

Англ.версия кодовой базы (с документацией) - https://codeberg.org/imperius/meta-transformers-ENG.git
Рус.версия кодовой базы (с документацией) - https://codeberg.org/imperius/meta-transformers-RU.git
Веса, логи и результаты на hugging-face - https://huggingface.co/Imperius/meta-transformers
-Источник
 
Loading...
Error