GPT-6 Astra поправила 131 072 веса в Qwen руками. Я сравнил чекпойнты и нашёл множитель −5. Часть 1. llm.. llm. mit.. llm. mit. qwen.. llm. mit. qwen. веса нейросети.. llm. mit. qwen. веса нейросети. интерпретируемость.. llm. mit. qwen. веса нейросети. интерпретируемость. редактирование моделей.. llm. mit. qwen. веса нейросети. интерпретируемость. редактирование моделей. трансформеры.
GPT-6 Astra поправила 131 072 веса в Qwen руками. Я сравнил чекпойнты и нашёл множитель −5. Часть 1 - 1

Обложка сгенерирована с помощью ИИ

Я студент РТУ МИРЭА, и мне показалась интересной эта тема, поэтому решил разобрать её подробно.

Статья получилась большой, поэтому я разбил её на две части. Это часть 1 из 2: что именно произошло в экспериментах MIT, что на самом деле лежит в диффе отредактированной модели и какая математика стоит за «вычитанием направления». Во второй части — почему правка лечит зацикливание, почему так нельзя добавить навык, связь с ROME и task arithmetic, как устроены веса Qwen, Gemma, Llama и MoE, риски и открытые вопросы.

2 ноября 2026 года четверо исследователей из MIT CSAIL — Rikiya Takehi, Jayden Teoh, Alex Zhang и Omar Khattab — выложили пост «Sparks of Weight-Space Programming: LLMs can natively read & write neural network weights» [1]. Суть такая: фронтирная LLM (в посте она называется GPT-6 Astra) читает сырые веса чужой нейросети и правит их руками. Без градиентов, без обучения, иногда даже без единого прогона среды.

Чтобы не пересказывать заголовки, я сделал три вещи:

  1. Прочитал сам пост и открытые логи экспериментов [2], включая манифест итоговой правки.

  2. Скачал базовую Qwen3.5-0.8B и опубликованный отредактированный чекпойнт [3] и побитово сравнил их. Оказалось, что правка — это не просто «убрать направление»: коэффициент там ≈ 6, и знак компоненты переворачивается. Подробности ниже.

  3. Вывел математику: почему такая правка вообще работает, почему она минимальна, почему она может вылечить зацикливание и почему не может «вложить» в модель отсутствующий навык.

Дальше в тексте помечаю, что к какому типу относится:

  • [Статья] — эмпирика авторов, цифры дословно из поста или логов;

  • [Доказано] — математический факт с выводом;

  • [Мой замер] — то, что я посчитал сам (код лежит рядом со статьёй);

  • [Модель/интерпретация] — мои допущения и игрушечные модели. Это не результаты.

Математика идёт в два слоя: сначала строгий вариант для тех, кто в теме, затем блок «Если по-простому» для тех, кто не хочет вникать.


Часть 1. Что случилось: три эксперимента

Эксперимент 8: Qwen3.5-0.8B, которая думала до упора

[Статья] Авторы взяли Qwen3.5-0.8B (24 слоя, около 0.8 млрд весов, режим thinking включён) и дали Astra задачу: «сделай модель лучше в математике, редактируя веса напрямую». Были жёсткие ограничения:

  • Python-сессия над весами, только CPU, не больше 300 запусков кода;

  • никакого обучения: запрещены backward, autograd, оптимизаторы и итеративная подгонка весов под лосс;

  • практические задачи: 7 469 из GSM8K train и 7 275 из MATH train. Тестовые бенчмарки Astra не видела;

  • бюджет прогонов модели: 10, 25 или 50 (три разных запуска). Один прогон — это генерация ответов на ≤512 задач или teacher-forced чтение ≤1 024 текстов с логпробами, скрытыми состояниями и активациями MLP;

  • save_edit отклонял правки финальной нормы, эмбеддингов/выходного слоя и умножение целого тензора на константу.

Оценка: vLLM, temperature 0.6, top-p 0.95, top-k 20, presence penalty 1.5, до 32 768 новых токенов.

Astra начала с диагностики. Базовая модель зацикливается: из её первых 96 практических ответов 85 упёрлись в лимит 32 768 токенов. В карточке Qwen об этом есть отдельное предупреждение: модель склонна к thinking loops. Astra нашла направление в residual stream, которое MLP слоёв 15 и 19 записывают при зацикливании, и вычла его из 64 выходных столбцов down_proj в каждом из двух слоёв. Получилось 131 072 веса, 0.016 % модели.

Qwen3.5-0.8B

MATH-500

GSM8K

IFEval

Упёрлись в лимит токенов (MATH-500)

База

7.9

13.8

21.0

93.0

Правка, 10 прогонов

12.3

25.7

49.0

87.2

Правка, 25 прогонов

14.1

25.1

39.9

86.4

Правка, 50 прогонов

48.1

67.1

62.3

33.1

Из логов [2] видно, что в трёх запусках получились три разные правки:

  • 10 прогонов: вычитание «направления повторов» из 30 выходных матриц (внимание и MLP) слоёв 8–22 по формуле W'=W - 1.5,u(u^top W);

  • 25 прогонов: отключение головы внимания 7 в слое 15 (обнулены её 256 выходных столбцов);

  • 50 прогонов: 64 столбца MLP в слоях 15 и 19.

На других бенчмарках у правки из 50 прогонов тоже рост: AMC23 0.5 → 23.4, Minerva 1.5 → 25.4, OlympiadBench 1.3 → 21.8, MMLU-Pro 40.3 → 45.5, GPQA Diamond 22.7 → 36.6.

Отдельно стоит отметить самопроверку Astra на 1 152 отложенных практических задачах [2, final_answer.md]: 579 «спасённых» задач против 5 регрессий, и 576 из 579 спасённых — это ответы, которые раньше обрывались по лимиту. Точность на ответах, которые и до правки доходили до конца, не изменилась. Запомним этот факт: к нему мы вернёмся во второй части статьи, когда будем разбирать петли.

Независимая проверка: Ahsen Khaliq (Hugging Face) пересобрал чекпойнт из логов со сверкой sha256 и перепрогнал полный MATH-500 (500 × 4 сэмпла) на H200. Вышло 51.0 %, лимит выбили 31.6 % ответов [3].

Эксперимент 4: машинка, которая не умела сдать назад

[Статья] Среда Kinetix, уровень «машинка и рампа». Чтобы перепрыгнуть красную полосу, машине нужно сначала откатиться назад и набрать разгон. Официальный PPO обучался 1 млрд шагов и застрял в локальном минимуме: едет прямо на рампу и глохнет. Успехов 0 из 256 эпизодов.

Сеть — официальный актор Kinetix: 679 → 128 (ReLU) → пять слоёв по 128 (tanh) → 16. Сверим число весов:

679cdot128+128 ;+; 5,(128cdot128+128) ;+; 128cdot16+16 ;=; 87,040+82,560+2,064 ;=; 171,664.

Совпадает с постом. Astra получила все веса, описание сцены и один записанный эпизод. Один ответ, без инструментов. Она изменила 3.5 % весов и добавила маленький обходной путь через несколько юнитов в каждом слое. Этот путь читает позицию и скорость машины, командует «назад, потом полный вперёд», а когда зелёное колесо проезжает красную полосу, отключается, и дальше машину ведёт исходная сеть. Итог: 1 024 из 1 024 успешных эпизодов.

Дополнительный эксперимент: Gemma 3 270M, где всё сломалось

[Статья] Тот же протокол применили к Gemma 3 270M IT. Модель примерно втрое меньше и почти не зацикливается: в лимит (здесь 8 192 токена, сэмплинг из карточки: T = 1.0, top-k 64, top-p 0.95) упираются только 8.5 % ответов. У Qwen таких 93 %.

Gemma 3 270M

MATH-500

База

6.8

5 прогонов

7.0

10 прогонов

7.6

25 прогонов

7.7

50 прогонов

7.0

Читая ошибки Gemma, Astra нашла обычные ошибки рассуждения: неверную арифметику и некорректные алгебраические шаги. Единого компонента, который можно было бы выключить, там не было. Правки получались мелкими (например, удвоить один нейрон, реагирующий на числа), и сама Astra оценила прирост как неустановленный. Вывод авторов: правка весов может убрать препятствие, за которым пряталась способность, но не может добавить способность, которой у модели нет.

Для полноты: в посте есть и «читающие» эксперименты. Astra по весам MLP 500→32→32→5 (17 253 веса — 500cdot32+32+32cdot32+32+32cdot5+5, сходится) угадывает игру, по весам диффузионки — рисуемую фигуру, в char-level трансформере без входного и выходного слоёв находит induction heads. Кроме того, она с нуля пишет сети для MinAtar и для го 9×9. Но дальше нас интересует именно механика правки, поэтому остальное оставлю за кадром.


Часть 2. Что на самом деле лежит в диффе (мой разбор чекпойнта)

[Мой замер] Опубликованный чекпойнт отличается от Qwen/Qwen3.5-0.8B ровно двумя тензорами [3]: layers.15.mlp.down_proj.weight и layers.19.mlp.down_proj.weight, оба формы 1024times3584. Я посчитал Delta W=W_{text{edit}} - W_{text{base}} (код: code/analyze_edit.py).

D = W2 - W                                   # 1024 x 3584
cols = (D.abs().sum(0) > 0).nonzero().flatten()   # какие столбцы тронуты
S = torch.linalg.svdvals(D[:, cols])          # спектр правки
U, _, _ = torch.linalg.svd(D[:, cols], full_matrices=False)
v = U[:, 0]                                   # направление правки
a = -(v @ D[:, cols]).dot(v @ W[:, cols]) / (v @ W[:, cols]).pow(2).sum()

Что получилось:

слой 15

слой 19

изменённых столбцов

64

64

изменённых bf16-значений

65 260

64 928

доля энергии Delta W в первом сингулярном числе

0.999994

0.999991

sigma_2/sigma_1

5.6·10⁻⁴

6.4·10⁻⁴

подогнанный коэффициент alpha в W'_S=W_S-alpha,vv^top W_S

6.0003

6.0002

относительная невязка такой модели

0.23 %

0.29 %

lVertDelta WrVert_F/lVert WrVert_F

0.106

0.081

Почему 131 072 = 2 × 64 × 1 024, а изменённых значений 130 188: при округлении в bfloat16 часть элементов вернулась к прежнему значению. Это совпадает с манифестом из логов. Направления в двух слоях близки: cos(v_{15},v_{19})=0.85.

Проекции столбцов down_proj на направление правки, слой 15

Проекции столбцов down_proj на направление правки, слой 15

Рис. 1. Слой 15. Слева: langle v,w_irangle для всех 3 584 столбцов (серые), отдельно 64 изменённых до (синие) и после (красные) правки. Справа: «после» против «до» лежат на прямой y=-5x.

То же для слоя 19

То же для слоя 19

Рис. 2. То же для слоя 19.

Спектр ΔW

Спектр ΔW

Рис. 3. Сингулярные числа Delta W (блок 1024×64). Правка — чистый ранг 1, хвост на уровне 10⁻³·σ₁ даёт округление bf16.

Вывод из этих замеров [Мой замер + интерпретация]: на тронутых столбцах правка имеет вид

W'_S=(I - 6,vv^top),W_S,qquad text{то есть}qquad v^top W'_S=-5,v^top W_S.

Это не «обнулить проекцию» (тогда было бы alpha=1). Компонента вдоль v переворачивается и усиливается в 5 раз. В посте и в README это описано словом «subtracted», и формально так и есть: 6,vv^top W вычтено. Но геометрически это сильнее абляции. Тронуты не самые «тяжёлые» нейроны: медианный ранг выбранных столбцов по норме — 2 560 из 3 584 для слоя 15 и 2 245 для слоя 19. Отбор шёл по тому, насколько столбец пишет в v («the 64 output columns per layer … that write it most» [2]), а не по норме.


Часть 3. Как устроен трансформер с точки зрения правки весов

Чтобы понять, почему правка 64 столбцов в двух слоях вообще на что-то влияет, нужна одна картинка: как информация течёт через модель.

3.1. Residual stream: модель как сумма записей

[Доказано, следует из архитектуры] В Qwen, Llama и Gemma каждый слой не заменяет состояние токена, а прибавляет к нему поправку. Состояние x_l — вектор размерности d (у Qwen3.5-0.8B d=1024). Блок внимания и блок MLP читают его и дописывают свой результат:

x_{l+1}=x_l + a_l + m_l,

где a_l — выход внимания слоя l, m_l — выход MLP. Если развернуть эту рекурсию от первого слоя до последнего L, получится просто сумма:

x_L=x_0 + sum_{l<L} (a_l + m_l).

Здесь x_0 — эмбеддинг токена. Отсюда следует главное свойство: если нас интересует, сколько «чего-то» лежит в состоянии вдоль направления u, то это сумма вкладов всех блоков по отдельности, u^top x_L=u^top x_0 + sum_l u^top a_l + sum_l u^top m_l. Elhage и др. назвали этот вектор residual stream — общей шиной, в которую все пишут [4]. Оговорка: перед логитами стоит финальная RMSNorm. Она масштабирует весь вектор целиком, поэтому соотношения вкладов сохраняются, но абсолютные величины — нет.

Если по-простому: у каждого токена есть «рабочая тетрадь» из 1024 чисел. Каждый слой ничего в ней не стирает, а только дописывает свои заметки поверх. Итоговое состояние — это сумма всех заметок, поэтому вклад одного слоя можно рассматривать отдельно от остальных.

3.2. MLP: каждый нейрон пишет один фиксированный вектор

[Доказано] MLP в Qwen устроен как SwiGLU: mathrm{MLP}(x)=W_{text{down}},h(x), где h(x) — вектор из d_{ff}=3584 активаций нейронов. Его считают из двух других матриц, gate и up: h_i(x)=mathrm{SiLU}(g_i^top x),(r_i^top x). Умножение матрицы на вектор — это сумма её столбцов с весами, поэтому

mathrm{MLP}(x)=sum_{i=1}^{3584} h_i(x), w_i ,

где w_i — i-й столбец down_proj. Получается, что нейрон i решает только насколько сильно записать (число h_i(x) зависит от входа), а что записать (вектор w_i) зашито в весах раз и навсегда. Geva и др. описали это как память «ключ → значение»: gate/up — ключи, столбцы down — значения [5, 6].

Если по-простому: у каждого из 3584 нейронов есть свой штамп — фиксированный вектор. Вход определяет только, насколько сильно его нажать. Если поменять столбец down_proj, нейрон будет срабатывать на те же ситуации, но оставлять другой отпечаток. Поэтому Astra правила именно эти столбцы.

3.3. Поведение как направление

[Интерпретация, опирается на литературу] Гипотеза линейного представления говорит, что многие свойства, вроде «это отказ» или «сейчас я повторяюсь», кодируются направлением v в пространстве состояний [7]. Сила свойства — это проекция v^top x. На этом построены activation steering [8, 9], representation engineering [10] и самый близкий к нашему случаю результат: Arditi и др. показали, что отказы в чат-моделях опосредованы одним направлением, и если убрать его из весов, модель перестаёт отказывать [11]. Правка Astra — тот же приём, только направление — «зацикливание», и тронуты лишь 64 столбца в двух слоях.

Если по-простому: считается, что у модели есть «оси» для понятий. Если найти ось «я хожу по кругу» и запретить слоям туда писать, поведение меняется, а остальная модель остаётся как была.


Часть 4. Что делает «вычитание направления» и почему это минимальная правка

4.1. Проекция и ранг 1

[Доказано] Пусть v — единичный вектор направления (lVert vrVert=1), W — матрица, которая пишет в поток (у нас — выбранные столбцы down_proj). Классическая абляция:

W'=(I - vv^top),W=W - v,(v^top W).

Матрица P=I-vv^top — ортогональный проектор: она стирает у вектора компоненту вдоль v и не трогает всё перпендикулярное. Проверка в одну строку: v^top P=v^top - (v^top v)v^top=0. Поэтому для любых активаций h

langle v, W'hrangle=v^top P,W h=0 .

Слой после такой правки не может записать ничего вдоль v ни на каком промпте. Это объясняет, почему эффект переносится с математики на IFEval: правка не зависит от входа. Сама поправка Delta W=-v,(v^top W) — произведение столбца на строку, то есть матрица ранга 1.

Если по-простому: мы берём каждый «штамп» нейрона и вырезаем из него одну конкретную составляющую. Остальное в штампе остаётся. Поскольку вырезается одно и то же направление у всех штампов, вся правка описывается одним вектором — это и есть «ранг 1».

4.2. Что на самом деле сделала Astra: α ≈ 6

[Мой замер] Дифф опубликованного чекпойнта из части 2 точно ложится не на alpha=1, а на

W'_S=(I - 6,vv^top),W_S quadRightarrowquad v^top W'_S=(1-6),v^top W_S=-5,v^top W_S .

Здесь S — 64 выбранных столбца. Множитель 1-alpha — это то, во что превращается компонента вдоль v: при alpha=1 она обнуляется, при alpha=2 отражается, при alpha=6 отражается и усиливается в 5 раз. Так что «вычли направление» — точное описание, но геометрически это не стирание, а разворот сигнала. И ещё одно следствие: матрица I-6vv^top обратима (это не проектор), поэтому формально такая правка информацию не уничтожает.

Если по-простому: Astra не просто заглушила сигнал «повторяйся», а заставила эти нейроны кричать обратное — «не повторяйся» — в пять раз громче, чем раньше звучало исходное.

4.3. Почему именно такая правка — самая маленькая

[Доказано] Поставим вопрос: какую наименьшую по норме Фробениуса поправку Delta надо внести, чтобы проекция на v стала равна ccdot v^top W? Разложим Delta на часть вдоль v и перпендикулярную. Условие касается только первой части, поэтому она определена однозначно: v^topDelta=(c-1)v^top W. Вторая часть на условие не влияет и лишь добавляет норму:

lVertDeltarVert_F^2=underbrace{lVert v^top DeltarVert^2}_{text{фиксировано условием}} + underbrace{lVert (I-vv^top)DeltarVert_F^2}_{ge 0, text{лишнее}} .

Минимум достигается, когда лишняя часть равна нулю, то есть Delta=-(1-c),vv^top W. Это ровно семейство (I-alpha vv^top)W с alpha=1-c, а у Astra c=-5. ∎

Если по-простому: если нужно изменить только «громкость по одной оси», любая правка в других осях — лишний шум. Самая аккуратная правка трогает ровно одну ось и ничего больше. Реальный дифф выглядит именно так: вся его энергия, 99.999 %, сидит в одном направлении.

4.4. Откуда 131 072

Нейрон пишет столбец длины d. В config.json Qwen3.5-0.8B указано hidden_size 1024 и intermediate_size 3584. Значит, 2 слоя × 64 столбца × 1024 = 131 072 веса, или 64/3584 ≈ 1.8 % столбцов каждой из двух матриц и 0.016 % всей модели. Арифметика поста сходится точно. Выбирали не самые большие нейроны, а те, что сильнее всего пишут в v (см. часть 2 этой статьи).


Что дальше

Итак, в диффе лежит одна ось на двух слоях, и вдоль неё вклад MLP не обнуляется, а разворачивается с множителем −5. Этого хватило, чтобы доля ответов, упёршихся в лимит, упала с 93 % до 33.1 %, а MATH-500 вырос с 7.9 % до 48.1 %. И почти все «спасённые» задачи — те, что раньше просто обрывались. Но остаются три вопроса, на которые математика выше не отвечает:

  • почему поворот одной оси из 1024 меняет вероятность зацикливания на порядок, а не на проценты;

  • почему тот же приём не помог Gemma, и почему так в принципе нельзя «вложить» в модель отсутствующий навык, хотя машинке в Kinetix схему добавить удалось;

  • насколько это вообще новое — ведь ROME, refusal direction и task arithmetic правят веса похожим образом уже несколько лет.

Об этом — во второй части: там будет простая вероятностная модель петли, мой зонд по слоям, неравенство обработки данных и конструкция «обходного пути» для машинки.


Источники

  1. Takehi R., Teoh J., Zhang A., Khattab O. Sparks of Weight-Space Programming: LLMs can natively read & write neural network weights. MIT CSAIL, 2 Nov 2026. https://rikiyat.github.io/blog/weight-space-programming/

  2. Логи экспериментов: https://github.com/RikiyaT/lm_understand-logs (каталог exp8_math/)

  3. Отредактированный чекпойнт и независимая перепроверка: https://huggingface.co/RikiyaT/Qwen3.5-0.8B-weight-space-programming

  4. Elhage N. et al. A Mathematical Framework for Transformer Circuits. 2021. https://transformer-circuits.pub/2021/framework/index.html

  5. Geva M. et al. Transformer Feed-Forward Layers Are Key-Value Memories. https://arxiv.org/abs/2012.14913

  6. Geva M. et al. Transformer Feed-Forward Layers Build Predictions by Promoting Concepts in the Vocabulary Space. https://arxiv.org/abs/2203.14680

  7. Park K., Choe Y. J., Veitch V. The Linear Representation Hypothesis and the Geometry of Large Language Models. https://arxiv.org/abs/2311.03658

  8. Turner A. et al. Steering Language Models With Activation Engineering. https://arxiv.org/abs/2308.10248

  9. Rimsky N. et al. Steering Llama 2 via Contrastive Activation Addition. https://arxiv.org/abs/2312.06681

  10. Zou A. et al. Representation Engineering: A Top-Down Approach to AI Transparency. https://arxiv.org/abs/2310.01405

  11. Arditi A. et al. Refusal in Language Models Is Mediated by a Single Direction. https://arxiv.org/abs/2406.11717

Автор: maxim_lomakin

Источник