R&D · VPL
VPL — браузерный инструмент, в котором архитектура собирается из тензорных примитивов на холсте и сразу превращается в обучаемую модель на PyTorch. Ниже — что он умеет, а затем то, ради чего он делался: 39 конфигураций трансформерного блока, собранных и обученных прямо в нём, и две перепроверки этих измерений, каждая из которых развернула часть выводов.
инструмент
Узлы на холсте — это тензорные операции: linear, matmul,
softmax, rope, alibi_bias, causal_mask,
split_heads/merge_heads, rmsnorm,
conv1d, ssm, а также готовые составные:
attention_block, moe_ffn, memory. Соединяешь их
портами, жмёшь Build — сервер компилирует граф в настоящую модель и обучает её.
Всего 35 типов узлов; вложенные подграфы позволяют свернуть кусок схемы в один узел.
Главное свойство: ошибки формы всплывают при сборке, а не в середине forward-прохода. У каждого порта есть тип, и движок выводит формы по всему графу до того, как создан хоть один параметр. Несходящаяся размерность — это фраза с номером узла, а не стек-трейс из недр PyTorch.
Внимание, собранное из примитивов — так это выглядит на холсте. Порты типизированы, и
формы выводятся по всей цепочке до того, как создан хоть один параметр. Заменить
softmax на что-то другое, убрать маску или вписать ALiBi между
matmul и маской — правка одного узла; в составном sdpa для этого
пришлось бы лезть в код.
Граф из однотипных блоков внимания уходит на быстрый путь, где независимые узлы одной глубины считаются одним вызовом вместо одного вызова на узел (иначе ~2.1 мс накладных на узел). Всё остальное идёт через примитивный движок.
Новый узел добавляется с обучаемым вентилем, инициализированным нулём: в момент роста модель вычисляет ровно то же, что и до него, и уходит от этого обучением. Наивная нулевая инициализация весов самого узла была проверена и оказалась хуже.
Быстровесовая память — не чёрный ящик: та же рекуррентность собирается из отдельных
узлов (elu_feature_map, chunk_kv_accum,
chunk_state_read, …) и совпадает с эталонной реализацией побитово.
Полный MAC-блок — 27 примитивов.
Один долгоживущий процесс на каждое доступное устройство. Прогон ставится сразу тремя сидами — повтор здесь первичное действие, а не ручной цикл: измеренный разброс между сидами (~0.015 val_loss) больше большинства архитектурных различий.
Один forward-проход, и каждый узел на холсте подписывается своей стоимостью —
включая узлы внутри вложенных подграфов. Полезно тем, что регулярно опровергает
интуицию: в блоке Grok-1 два узла RoPE обошлись в 3.6 и 3.8 мс, а sdpa
в 2.0 мс — против 0.6–0.8 мс у любой проекции, при том что параметров
у них нет вовсе.
Выбирается узел, его параметр и список значений — по варианту на значение, каждый со своей свежесобранной моделью и одинаковым числом шагов. Можно взять два параметра сразу. Смысл в том, что меняется ровно одна вещь: именно так выяснилось, что «оптимум ширины на dim=192» был артефактом — в исходном свипе вместе с шириной менялась и глубина.
Последовательность стадий «корпус — сколько шагов» на одной и той же модели: веса, оптимизатор, шедулер и счётчик шагов продолжаются, подменяется только источник данных. Модель не пересобирается между стадиями, поэтому токенизатор остаётся прежним — а значит, стадия на корпусе с символами вне словаря отвергается до запуска, а не молча схлопывает их в один токен.
После сборки граф проверяется эмпирически: меняется вторая половина входа, и если предсказания в первой половине сдвинулись — модель читает будущие токены. Такой результат помечается и физически не может попасть в один рейтинг с каузальными.
Shakespeare, TinyStories, PG-19, книги; посимвольный или BPE-словарь. Плюс не-текстовые: MNIST как «пиксельный корпус» и FSDD как звуковой — движку для этого не понадобилось ни одной правки, только загрузчик и тривиальный токенизатор.
Каждый прогон записывается сам: кривые обучения и валидации, число параметров, токены, оценка FLOPs, скорость, норма градиента, пиковая память, сид, расписание LR. Результат попадает в группу сравнения — ключ из корпуса, длины окна, бюджета, LR, токенизатора, протокола оценки и каузальности. Числа из разных групп несопоставимы, и страница результатов никогда не кладёт их в один список: это то, что мешает сравнить 15-секундный прогон с 1200-шаговым и назвать разницу архитектурой.
почему это важно Всё, что ниже, — следствие этой дисциплины. Оба разворота выводов на этой странице нашлись не потому, что кто-то заметил странное число, а потому что измерение было воспроизведено.
библиотека
Шаблон — это сохранённый граф: открывается на холст одной кнопкой, ставится в очередь
на обучение, и его замеры копятся отдельно от него самого. Сейчас в библиотеке
19 именованных блоков и ещё 50 конфигураций архитектурного поиска
(growth-demo: …), результаты которого — ниже на этой странице.
Числа во второй колонке — сколько узлов в графе. Разброс от 2 до 176 при одном и том же движке и есть ответ на вопрос, зачем нужны и составные узлы, и примитивы: одну и ту же архитектуру можно собрать крупными блоками или разложить до отдельных операций, и второе — единственный способ поменять то, что внутри.
| Шаблон | Узлов | Что в нём интересного |
|---|---|---|
| Настоящие архитектуры — собраны по опубликованным описаниям, каждая обучается как есть | ||
| GPT-2 | 20 | хрестоматийный pre-LN блок: LayerNorm → MHA → residual → GELU-MLP |
| LLaMA / LLaMA-2 | 24 | RMSNorm вместо LayerNorm, RoPE, SwiGLU вместо плотного FFN |
| Mistral | 20 | то же плюс скользящее окно внимания и GQA 8/2 |
| Mixtral 8×7B | 16 | оконное GQA, но SwiGLU заменён разрежённым MoE top-2 из 8 |
| Gemma2 | 26 | норма с обеих сторон каждого подблока — 4 RMSNorm вместо 2 |
| Falcon / GPT-NeoX | 19 | внимание и MLP считаются параллельно из одного входа, а не последовательно |
| PaLM | 19 | параллельный блок + MQA + RoPE + SwiGLU одновременно |
| Grok-1 | 176 | GQA 6:1, 8 экспертов top-2, сэндвич-нормы; 8 слоёв, 19.7 млн параметров |
| BERT | 19 | тот же GPT-2, но без causal_mask — и на этом ловится утечка будущего |
Механизмы внимания, разобранные до примитивов — то же, что делает sdpa, но каждой операцией отдельно | ||
| RoPE self-attention | 16 | проекции, разбиение на головы, поворот Q/K, маска, softmax, сборка |
| GQA | 10 | 8 голов запросов на 2 головы ключей — K/V транслируются вверх |
| MQA | 10 | предельный случай: одна общая K/V-голова, кэш меньше в 8 раз |
| ALiBi | 15 | штраф за расстояние прямо в логитах вместо поворота Q/K |
| Гибриды и не-внимание | ||
| MAC целиком из примитивов | 27 | включая саму рекуррентность быстровесовой памяти — совпадает с эталоном побитово |
| Conv1D + SSM | 3 | последовательность без внимания вообще: свёртка и модель пространства состояний |
| Внимание + память + MoE | 3 | три составных узла подряд — сколько проводов нужно реальному гибриду |
| RoPE + MoE | 18 | ручное внимание, за ним разрежённый FFN со своим residual |
| Учебные | ||
| Стартовый для роста | 2 | два узла с одним портом — на них показывается функционально-сохраняющий рост |
| Вложенный подграф | 2 | два одинаковых подграфа в цепи; профилирование заходит внутрь каждого |
важное следствие BERT-блок отличается от GPT-2 ровно одним отсутствующим узлом — маской. Его val_loss выходит 0.0204 при случайном угадывании 4.17, потому что модель видит ответ. Это не результат, а проверка детектора: такой граф помечается как некаузальный и физически не может попасть в один рейтинг с остальными.
перепроверка
Исходная оценка усредняла 10 случайно выбранных батчей валидации, из-за чего val_loss был случайной величиной даже при неизменных весах. Прямой замер: одна обученная модель, 15 вызовов подряд, веса между ними не менялись — значения от 1.5473 до 1.6034, стандартное отклонение 0.0170. После перехода на фиксированные равномерные окна по всему валидационному сплиту те же 15 замеров дают одинаковый результат до четвёртого знака (стандартное отклонение 0.0000).
Ниже — конфигурации, перезамеренные новой метрикой на трёх фиксированных сидах каждая.
Условия одинаковы: Shakespeare, seq_len=128, lr=0.005,
шедулер constant, бюджет 60 секунд.
| Конфигурация | Params | val_loss (n=3) | Было (шумная метрика) | |
|---|---|---|---|---|
| depth=6, GQA(kv=2), RoPE | 291,584 | 1.5857 ± 0.0068 | 1.5978 | |
| depth=6, MHA(kv=4), RoPE | 316,544 | 1.5902 ± 0.0134 | 1.5840 | |
| depth=6, MQA(kv=1), RoPE | 279,104 | 1.5975 ± 0.0033 | 1.5955 | |
| depth=8, MQA(kv=1), RoPE — прежний «чемпион» | 366,592 | 1.6084 ± 0.0058 | 1.6016 | |
1.581.601.62 | ||||
Конфигурация, объявленная лучшей по исходной таблице (val_loss 1.5737), при усреднении по трём сидам оказалась худшей из четырёх. Значение 1.5737 воспроизвести не удалось ни разу: диапазон её собственных прогонов — 1.6017–1.6118.
Единственное различие внутри этой четвёрки, превышающее шум, — глубина: depth=6 против depth=8 даёт разрыв 0.0227 при стандартной ошибке 0.0052, то есть 4.4 стандартных ошибки. Различия между MQA, GQA и MHA остаются в пределах 1–3 стандартных ошибок и на трёх сидах неразделимы.
перепроверка
Все числа выше получены при бюджете в 60 секунд. Такой бюджет измеряет «что лучше за минуту» — величину, зависящую от стоимости шага, от конкретной машины и от того, что ещё на ней считается. Ниже — те же вопросы при бюджете в 1200 шагов: сколько бы ни стоил
шаг, все конфигурации получают одинаковое число обновлений весов. Такой замер вдобавок
воспроизводим на другом железе. 15 конфигураций, по три сида, детерминированная метрика,
lr=0.005.
| Конфигурация | val_loss (n=3, 1200 шагов) | Что проверяется | |
|---|---|---|---|
| depth=6, MQA + MoE-FFN | 1.5634 ± 0.0055 | тип FFN | |
| depth=6, dim=96 | 1.5773 ± 0.0020 | ширина | |
| depth=8, MQA | 1.5839 ± 0.0051 | глубина | |
| depth=7, MQA | 1.5900 ± 0.0036 | глубина | |
| depth=6, MHA(kv=4) | 1.5905 ± 0.0091 | разделение голов | |
| depth=6, GQA(kv=2) | 1.5968 ± 0.0106 | разделение голов | |
| depth=6, MQA(kv=1) | 1.6033 ± 0.0092 | базовая конфигурация | |
| depth=6, MQA + SwiGLU (param-matched) | 1.6088 ± 0.0039 | тип FFN | |
| depth=5, MQA | 1.6228 ± 0.0143 | глубина | |
| depth=6, ALiBi вместо RoPE | 1.6431 ± 0.0056 | позиционное кодирование | |
| depth=4, MQA | 1.6475 ± 0.0098 | глубина | |
| depth=3, MQA | 1.6800 ± 0.0136 | глубина | |
| depth=2, эффективный блок + память | 1.7108 ± 0.0094 | память | |
| depth=2, тот же блок без памяти | 1.7227 ± 0.0085 | изолированный контроль | |
| depth=2, Falcon-блок (параллельный residual) | 1.7879 ± 0.0145 | топология | |
1.551.681.81 | |||
1.6800 → 1.6475 → 1.6228 → 1.6033 → 1.5900 → 1.5839 на глубинах 3–8, строго монотонно по шести уровням; разрыв depth=6→8 составляет 3.2 стандартных ошибки. При бюджете в 60 секунд та же лестница даёт оптимум на 6 и ухудшение дальше. Оба результата верны: глубокие модели дороже за шаг и за минуту просто не успевают обучиться.
1.5634 против 1.6033 у того же стека с плотным GELU. Графы отличаются ровно одним узлом:
moe_ffn вместо linear+gelu+linear, конфигурация внимания идентична.
Разрыв 0.040 при стандартной ошибке 0.0062 — 6.4 стандартных ошибки. Механизм тот же,
что с глубиной: дороже за шаг, но и даёт за шаг больше.
1.6461 ± 0.0075 против 1.6085 ± 0.0069 — разрыв 0.0376 при 6.40 стандартной ошибки, по три сида на конфигурацию.
Это перемер. Сначала вывод стоял на сравнении, которое его не
выдерживало: ALiBi-граф собран из 126 примитивов вручную, а его «соперник» — из 108 узлов
на фьюзед-ядре sdpa. Различались они всей реализацией внимания, а не
позиционным кодированием. Хуже того, при разборе выяснилось, что ни один из десяти
ручных шаблонов библиотеки не масштабировал логиты на 1/√head_dim — sdpa
делает это внутри себя, а цепочка из matmul выполняет ровно тот matmul,
о котором её попросили. Масштаб дописан во все десять; отдельная проверка показала, что
сам по себе он даёт 0.43 стандартной ошибки, то есть ничего. Затем собран настоящий
однофакторный близнец — тот же ручной блок, тот же MLP, та же глубина, только
alibi_bias заменён на RoPE. Цифра выше — с него. Прежняя оценка (0.0398,
те же 6.4 SE) устояла почти без изменений, но теперь она опирается на пару, которая
действительно изолирует заявленное.
1.6088 против 1.6033 у плотного GELU при совпадающем числе параметров — 0.9 стандартной ошибки. Отрицательный результат, теперь на честной метрике и воспроизводимом бюджете.
MHA(kv=4) 1.5905, GQA(kv=2) 1.5968, MQA(kv=1) 1.6033 — монотонно по числу KV-голов, что согласуется с тем, что при равных шагах преимущество MQA в скорости не работает. Но крайние значения расходятся лишь на 1.7 стандартной ошибки: на трёх сидах утверждать нельзя.
Знак развернулся: 1.7108 с памятью против 1.7227 у изолированного контроля без неё. Разница 1.6 стандартной ошибки, то есть утверждать нельзя ни в одну сторону — но и исходный вывод о вреде памяти данными не поддержан.
Три нижние строки — конфигурации из двух блоков, а не из шести. Их место внизу объясняется глубиной, а не механизмом; сравнивать Falcon-блок с depth=6-строками нельзя. Осмысленно только их сравнение между собой (пара «с памятью / без памяти» — изолированный контроль, отличающийся ровно одним узлом).
перепроверка
В исходном поиске ширина менялась одновременно с глубиной, поэтому вывод «шире — лучше» не был
однофакторным. Здесь глубина зафиксирована на 4, меняется только dim; внимание
(MHA 4 головы + RoPE), FFN (плотный GELU ×4), LR и бюджет 60 с — общие. Бюджет здесь по
времени, то есть вывод относится к вопросу «что лучше за минуту»; при равном числе шагов
ширина не перепроверялась.
| dim | Params | Шагов/60с | val_loss (n=3) | |
|---|---|---|---|---|
| 64 | 216,576 | 2014 | 1.5957 ± 0.0063 | |
| 96 | 472,320 | 2185 | 1.5538 ± 0.0111 | |
| 128 | 826,368 | 2094 | 1.5494 ± 0.0027 | |
| 192 | 1,829,376 | 1891 | 1.5480 ± 0.0188 | |
| 256 | 3,225,600 | 1902 | 1.5370 ± 0.0091 | |
1.521.561.60 | ||||
0.042 при стандартной ошибке 0.0074, то есть 5.7 стандартных ошибки.
Различия 96→128→192 составляют 0.0044 и 0.0014 при разбросе того же порядка и неразделимы. Заявленный ранее «оптимум на dim=192 с разворотом на dim=256» был артефактом шумной метрики и смешанных осей.
2014 шагов при 217 тыс. параметров и 1902 при 3.23 млн — пятнадцатикратный рост числа параметров обходится почти бесплатно по времени. При таких размерах устройство загружено на единицы процентов и упирается в накладные расходы на запуск ядер, а не в вычисления. Оговорка: при равном числе шагов dim=256 потребляет в 15 раз больше вычислений, поэтому «шире лучше» доказано при равном времени, но не при равном бюджете вычислений.
перепроверка
Разброс средних у четырёх лидеров (0.023) сопоставим с их собственными стандартными ошибками. При одном прогоне на конфигурацию порядок в таблице определялся преимущественно случайным сидом и шумом измерения.
Утверждение «при lr=0.005 порядок меняется и depth=8 обходит depth=6» в собственных условиях (60 секунд) опровергнуто: на трёх сидах depth=8 хуже depth=6 с запасом в 4.4 стандартных ошибки. При равном числе шагов картина обратная — depth=8 лучше на 3.2 стандартных ошибки, и глубина улучшает результат монотонно.
Исходный вывод (1.6912 против 1.6022) относился к бюджету по времени. При равном числе шагов MoE-FFN даёт лучший результат из всех перепроверенных конфигураций: 1.5634 против 1.6033 у идентичного стека с плотным GELU, 6.4 стандартных ошибки.
Исходная разница составляла 0.0009 при шуме измерения 0.0170, то есть не была измерима в принципе. При перепроверке знак развернулся (1.7108 с памятью против 1.7227 без), но и эта разница — лишь 1.6 стандартной ошибки.
Гейтинг через silu+mul (стандарт Llama/PaLM), depth=6, три сида.
При бюджете 60 с: 1.5928 ± 0.0236 (hidden=256) и 1.5961 ± 0.0070 (hidden=171, подобрано под
совпадение числа параметров с плотным GELU) против 1.5955 ± 0.0118. При равном числе шагов:
1.6088 ± 0.0039 против 1.6033 ± 0.0092, то есть 0.9 стандартной ошибки. Единственный вывод,
одинаковый в обоих бюджетах и на обеих метриках.
дефект измерения
При сплошной проверке всех сохранённых шаблонов шаблон «BERT-style block (bidirectional)» показал val_loss 0.0204. При словаре из 65 символов случайное угадывание даёт ln(65) ≈ 4.17, а обученные модели здесь дают около 1.5 — то есть результат невозможен.
Причина: шаблон намеренно двунаправленный (нет узла причинной маски, softmax считается по сырым скорам), а обучение идёт на предсказание следующего токена. Позиция i видит токен i+1, который и является её собственной целью, и модель просто считывает ответ. Ошибки в шаблоне нет — он честно описан как encoder-only; ошибка была в том, что инструмент принял такую комбинацию молча и записал результат в общую таблицу, где 0.02 навсегда осталось бы недостижимым «лучшим».
Добавлена проверка при каждой сборке: вторая половина входной последовательности возмущается, и если предсказания в первой половине сдвигаются — граф не причинный. Проверка эмпирическая, а не структурная (не «ищем узел маски»), поэтому ловит и не-каузальную свёртку, и неверно заданную рекуррентность. Такие прогоны выделяются в отдельную группу сравнения и не могут конкурировать с причинными.
исходный поиск
Все значения ниже получены оценкой по 10 случайным батчам, разброс которой на неизменной модели составляет 0.0170 — больше, чем почти любая разница в этой таблице. Каждая строка — один прогон, без повторов по сидам. Таблица оставлена как исходные данные: то, что правдоподобный рейтинг из 39 позиций оказался преимущественно шумом, проверяемо только пока эти числа на виду. Как рейтинг архитектур её читать нельзя.
| Конфигурация | Params | Шагов/60с | val_loss | |
|---|---|---|---|---|
| depth=8, MQA, RoPE, lr=0.005 — перепроверено, см. выше | 366,592 | 990 | 1.5737 | |
| depth=6, MQA, RoPE, lr=0.005 | 279,104 | 1277 | 1.5806 | |
| depth=6, MQA, RoPE, lr=0.006 | 279,104 | 1278 | 1.6060 | |
| depth=7, MQA, RoPE, lr=0.005 | 322,848 | 1143 | 1.5872 | |
| depth=6, GQA(kv=2), RoPE, lr=0.005 | 291,584 | 1265 | 1.5846 | |
| depth=6, MQA, RoPE, lr=0.007 | 279,104 | 1311 | 1.5972 | |
| depth=6, MQA, RoPE, lr=0.01 | 279,104 | 1277 | 1.5885 | |
| depth=6, MQA, RoPE, lr=0.004 | 279,104 | 1351 | 1.6002 | |
| depth=6, dim=96 (ширина), lr=0.003 | 612,192 | 1287 | 1.6027 | |
| depth=6, MQA, RoPE, lr=0.003 (базовый чемпион) | 279,104 | 1298 | 1.6022 | |
| depth=6, GQA(kv=2), RoPE, lr=0.003 | 291,584 | 1263 | 1.6072 | |
| depth=5, MQA, RoPE, lr=0.003 | 235,360 | 1657 | 1.6124 | |
| depth=7, MQA, RoPE, lr=0.003 | 322,848 | 1089 | 1.6223 | |
| depth=6, ALiBi вместо RoPE, lr=0.003 | 279,104 | 1422 | 1.6426 | |
| depth=3, MQA, RoPE, lr=0.003 | 147,872 | 2448 | 1.6370 | |
| depth=2, ALiBi вместо RoPE, lr=0.003 | 104,128 | 3745 | 1.6372 | |
| depth=4, MQA, RoPE, lr=0.003 | 191,616 | 1816 | 1.6433 | |
| depth=2, GQA(kv=2), RoPE, lr=0.003 | 108,288 | 3276 | 1.6468 | |
| depth=2, MoE-FFN вместо dense MLP | 303,168 | 1573 | 1.6486 | |
| depth=6, MoE-FFN вместо dense MLP | 876,224 | 566 | 1.6912 | |
| depth=8, MQA, RoPE, lr=0.003 | 366,592 | 996 | 1.6374 | |
| depth=2, MQA, RoPE, full context (без memory) | 104,128 | 3409 | 1.6716 | |
| depth=2, MQA, RoPE, window=64 + fast-weight memory между блоками | 120,640 | 2547 | 1.6649 | |
| depth=2, MQA, RoPE, window=64, без memory (изолированный контроль для строки выше «MQA + memory») | 104,128 | 3219 | 1.6640 | |
| depth=2, полный MHA (kv=4), RoPE | 116,608 | 3439 | 1.6371 | |
| depth=1, Falcon-style parallel блок | 103,872 | 3427 | 1.7062 | |
| depth=1, attn+memory слиты в 1 блок | 76,896 | 3439 | 1.7369 | |
| depth=1, + pre-norm перед MLP тоже (полный pre-norm блок) | 66,624 | 7277 | 1.7265 | |
| depth=1, + RoPE | 66,624 | 5432 | 1.7249 | |
| depth=1, window=32 | 66,624 | 5545 | 1.7264 | |
| depth=1, window=64 | 66,624 | 5548 | 1.7208 | |
| depth=1, + MLP | 66,496 | 7475 | 1.7171 | |
| depth=1, window=16 | 66,624 | 5574 | 1.7387 | |
| depth=1, MQA (без остальных изменений) | 60,384 | 5577 | 1.7512 | |
| depth=1, голое attention (без norm/MLP) | 33,280 | 9110 | 1.9696 | |
| depth=1, + pre-norm | 33,408 | 8903 | 2.0037 | |
| depth=6, SSM (attention-free), гибрид attn+SSM | 200,640–221,472 | 97–208 | 2.02–2.39 | |
1.561.792.02 | ||||
Полные графы всех 39 конфигураций сохранены как шаблоны в библиотеке VPL
(autoresearch/vpl_templates/, префикс growth-demo:).
наблюдения
Наблюдения ниже сделаны до перепроверки. Помечено, что из них устояло.
SSM-механизм (рекуррентный, не распараллеливается как attention) при равном числе шагов сопоставим с attention, но при равном времени успевает на порядок меньше шагов (97–208 против 1000–9000 у attention-конфигураций). Разрыв здесь на порядок величины, то есть много больше шума измерения. Относится к конкретной нефузированной реализации SSM в VPL.
При 60 секундах оптимум есть: depth=6 лучше depth=8 на 4.4 стандартных ошибки. При равном числе шагов оптимума нет вовсе — улучшение монотонно от depth=3 до depth=8. Утверждение оказалось свойством бюджета, а не архитектуры.
В обоих бюджетах различия между kv=1, kv=2 и kv=4 лежат в пределах 1–3 стандартных ошибок. При равных шагах наметился монотонный порядок (больше KV-голов — лучше), но крайние значения расходятся лишь на 1.7 стандартной ошибки.
ALiBi действительно проигрывает RoPE на depth=6 в обоих бюджетах (6.4 стандартных ошибки при равных шагах). MoE-FFN, напротив, при равном числе шагов даёт лучший результат из всех перепроверенных конфигураций — его исходное отставание объяснялось стоимостью шага.
Исходная разница — 1.6640 против 1.6649, то есть 0.0009 при шуме измерения 0.0170: это различие в принципе не было измеримо. При перепроверке знак развернулся (1.7108 с памятью против 1.7227 без), но и эта разница — лишь 1.6 стандартной ошибки.
Разрыв между train и val у широких конфигураций шире, чем у сопоставимых по параметрам глубоких; при этом val всё равно улучшается (см. однофакторный свип выше).
методика
Корпус — Shakespeare (символьный токенизатор, vocab_size=65), seq_len=128,
LR-шедулер constant. Каждая архитектура собиралась и обучалась напрямую через
VPL: /build → /train/start → /eval.
Исходный поиск: dim=64 если не указано иное, один прогон на конфигурацию,
оценка по 10 случайным батчам валидации.
Перепроверка: два прохода — при бюджете 60 секунд и при бюджете 1200 шагов. Три фиксированных сида на конфигурацию; сид задаётся до сборки модели и определяет как инициализацию весов, так и порядок обучающих батчей. Оценка — по фиксированным равномерно расположенным окнам всего валидационного сплита, то есть val_loss стал функцией модели, а не случайной величиной. Каждый записанный результат хранит протокол, которым он измерен, и результаты разных протоколов не смешиваются в одном сравнении.
«60 секунд» отвечает на вопрос «что лучше за минуту», «1200 шагов» — на вопрос «что лучше за одинаковое число обновлений весов». Оба законны, и всюду, где механизм меняет стоимость шага, они дают разные ответы (глубина, MoE-FFN). Число в секундах вдобавок не воспроизводимо: оно зависит от конкретной машины и от того, что ещё на ней считается — два одновременных прогона одной конфигурации получили 1142 и 990 шагов за те же 30 секунд, и val_loss разошёлся на 0.013. Бюджет в шагах от этого свободен: четыре одновременных прогона по 600 шагов дали разброс 0.0059 со значениями, перемешанными между исполнителями, а не отсортированными по ним. 60-секундные замеры на этой странице сделаны последовательно, 1200-шаговые — параллельно.
Все выводы — для этого конкретного масштаба (tiny-модели, сотни тысяч — единицы миллионов параметров) и бюджета (60 секунд обучения). Ранжирование архитектур на этом масштабе не обязано переноситься на модели с миллиардами параметров и часами обучения — это демонстрация метода поиска через VPL, а не рекомендация по архитектуре для продакшена.
Полный протокол экспериментов (соглашения по разводке портов, чек-лист перед полным прогоном,
формат логирования, требования к воспроизводимости) — в autoresearch/vpl_program.md
репозитория.
ограничения
Главное ограничение исходного поиска, обнаруженное задним числом. Разброс оценки на неизменной модели — 0.0170, тогда как различия, на которых строились выводы, составляли 0.005–0.03. Никакое число повторов не спасло бы сравнение с такой метрикой: усреднение по сидам уменьшает разброс инициализации, но не систематическую случайность самого измерителя. Устранено переходом на фиксированные окна.
Три сида — минимум, позволяющий оценить разброс, но не более того. Различия меньше примерно 0.015 (порядка двух стандартных ошибок при n=3) на этих данных неразделимы; для уверенности в таких эффектах нужно 5–10 сидов.
Исходное «лучшее» значение 1.5737 — максимум из 39 сравнений на одном валидационном сплите. Перепроверка показала это в чистом виде: при повторных прогонах та же конфигурация дала 1.6017–1.6118 и оказалась худшей из четырёх лидеров. Отбор лучшего из многих зашумлённых сравнений систематически завышает оценку победителя.
Глубина одновременно меняет число параметров, стоимость шага и сложность оптимизации. В исходном свипе по ширине вместе с ней менялась и глубина, из-за чего вывод не был однофакторным; это исправлено отдельным свипом при фиксированной глубине. «Шагов/60с» — свойство конкретной машины в конкретный момент, а не универсальная константа.
Масштаб (крошечная модель, char-level Shakespeare, 60 секунд обучения) на 3–4 порядка меньше того, на котором в литературе валидируются реальные архитектурные решения. Известны случаи, когда ранжирование разворачивается при масштабировании (например, MoE обычно нуждается в большем числе токенов на эксперта, чем здесь пройдено). Ни один вывод не стоит переносить на другой масштаб без отдельной проверки.
Страница открывается описанием самого инструмента: что такое VPL, из чего
собираются графы, как устроены группы сравнения. Измерения — под ним, как то, что он
произвёл. Обе страницы переехали в static_site/ и получили общую шапку
с переходом между ними.
Вывод про ALiBi перемерен на однофакторной паре. Прежнее сравнение ставило ручной
граф против графа на sdpa, то есть смешивало позиционное кодирование с
реализацией внимания. По дороге нашлось, что все десять ручных шаблонов библиотеки не
масштабировали логиты на 1/√head_dim; масштаб дописан, его собственный эффект измерен
отдельно и оказался незначимым (0.43 SE). Вывод устоял: 0.0376 при 6.40 SE против
прежних 0.0398. Ни один результат не отозван.
Второй проход перепроверки — 15 конфигураций по три сида при бюджете в 1200 шагов вместо секунд. Два вывода развернулись: глубина улучшает результат монотонно до 8 (оптимум на 6 был свойством бюджета по времени), а MoE-FFN, ранее отброшенный, даёт лучший результат из всех перепроверенных. ALiBi и нулевой эффект SwiGLU подтверждены; вывод о вреде памяти не поддержан.
Перепроверка. Обнаружено, что исходная метрика давала разброс 0.0170 на неизменной модели; оценка переведена на фиксированные окна валидации. Четыре лидера и свип по ширине перезамерены на трёх сидах: прежний «чемпион» оказался худшим из четырёх, «оптимум ширины на dim=192» — артефактом. Добавлены разделы о перепроверке, однофакторном свипе по ширине, неподтверждённых выводах и утечке целевой переменной в двунаправленном блоке. Исходная таблица сохранена как данные, с пометкой о метрике.
Добавлен раздел «Методологические ограничения» (n=1 на конфигурацию, selection bias по 39 сравнениям, смешанные переменные, границы внешней валидности).
Страница создана: 39 конфигураций, обученных напрямую через VPL, лучший результат depth=8/MQA/RoPE/lr=0.005 (val_loss 1.5737).