Содержание
- Введение
- Почему эта задача подходит для auto-research
- Изучить достаточно, чтобы задавать правильные вопросы
- (Опционально) Математика QR-разложения: отражения Householder
- Как блочный алгоритм Householder сокращает последовательную работу
- Другие сложности
- Максимальное использование Codex
- Разнообразие идей против локальных максимумов
- Заметки по реализации
- Что можно было сделать лучше
- Заключение
- Источники
- Благодарности
Введение
Конкурс вкратце
GPU Mode совместно с Core Automation провели конкурс на тему auto-research. Задача звучала так: implement batched square compact-Householder QR factorization aka QR decomposition. Итоговый результат — 12-е место из 183 участников и ускорение в 232 раза относительно базового решения. Дальше пойдёт речь о подходе, извлечённых уроках и узких местах, с которыми пришлось столкнуться. Это была первая серьёзная попытка auto-research — кто-то назовёт это «loop engineering», и это тоже честное определение.
Для понимания большей части текста не обязательно вникать в математику и саму задачу в деталях — акцент сделан на подходе, а математика и постановка задачи оставлены на втором плане, поскольку большинство читателей не участвовали в конкурсе.
Полная страница конкурса доступна здесь: ссылка на задачу и таблицу лидеров
Конкурс входил в серию GPU Mode Linear Algebra Kernels in the Age of Research.
Постановка задачи
Участникам давался батч квадратных FP32 CUDA-матриц A формы batch x n x n, и требовалось вернуть такое же компактное Householder-представление QR, как torch.geqrf(A): матрицу H, верхний треугольник которой — это R, а нижний хранит векторы Householder, плюс вектор tau коэффициентов отражателей. Чекер восстанавливал Q через torch.linalg.householder_product(H, tau), брал R = triu(H) и проверял:
Среди корректных решений таблица лидеров ранжировала время выполнения по среднему геометрическому по всем формам и случаям обусловленности. Важнее всего были батчи квадратных матриц вроде 512 x 512, а также более крупные случаи 1024, 2048 и 4096. Внутри разрешалось использовать пониженную точность — FP16, FP8 или NVFP4, — но возвращаемые факторы всё равно должны были проходить проверки QR в стиле FP32.
Небольшой пример 3 x 3:
Здесь Q — ортогональная матрица (её столбцы имеют единичную длину и перпендикулярны друг другу), а R — верхнетреугольная (всё под диагональю — нули). Конкурс не требовал напрямую печатать плотные Q и R; нужна была компактная Householder-версия, из которой чекер восстанавливает Q и читает R из верхнего треугольника.
В примере 3×3 самый первый отражатель переводит первый столбец (12, 6, −4) сразу в (−14, 0, 0) за один шаг. −14 становится . Как это работает — в разделе про математику.
Почему эта задача подходит для auto-research
GPU Mode предоставляет участникам CLI-утилиту popcorn, что делает конкурс дружелюбным к агентам. Агенты могут использовать её для тестирования, бенчмаркинга и отправки решений в таблицу лидеров напрямую. Чекер также давал обратную связь по каждой форме матрицы вместе с итоговым средним геометрическим временем.
Внимательный наблюдатель заметит: это идеальная площадка для написания цикла. Агенты жаждут плотной обратной связи — она позволяет им карабкаться по холму метрик сколько душе угодно.
Конкурсы GPU Mode обычно дают какой-то способ итерировать над ядрами: либо прямая отправка решений, либо кредиты от спонсора вроде Modal. Здесь организаторы фактически разрешили неограниченное число попыток — при условии, что их не слали слишком часто. Если условие нарушалось, очереди росли, и у всех подряд прогоны падали по таймауту. В какой-то момент workspace даже исчерпал кредиты Modal, потому что все одновременно засыпали систему сабмитами. Неплохой способ сделать обучение доступным.
За 14 дней было сделано свыше 1500 отправок решений.
Изучить достаточно, чтобы задавать правильные вопросы

Базовое понимание оптимизации GPU-ядер (в основном на Triton, с некоторым представлением о CUDA) было накоплено за год до конкурса, но профессионального опыта в этой области не было. Проще говоря, среди окружения на лидерборде это была позиция аутсайдера: участник, расположившийся строчкой выше (CUDA Colonel), — principal engineer в NVIDIA.
Тем не менее, базовые знания и недавнее чтение про GatedDeltaNet дали свежее ощущение общей терминологии GPU-ядер.
Чем лучше человек разбирается в теме, тем лучше он может формулировать запросы для LLM — потому что неизвестные неизвестности превращаются в известные неизвестности.
При этом стоит отметить: конкурс был проходим и без глубокой экспертизы в предметной области — в топ-10 попасть вряд ли получится, но приличное ускорение над baseline достижимо просто за счёт харнесса/агентского цикла.
Первыми шагами в конкурсе стало изучение того, что такое QR-разложение и как его можно выполнить. Способов несколько — например, Грам-Шмидт и отражения Householder. Конкурс требовал именно отражений Householder. Обсуждение с Claude и несколько роликов на YouTube помогли выстроить интуицию. После разговоров с Claude стало ясно, что в качестве основной архитектуры нужен блочный алгоритм Householder с завершающим WY-обновлением. Как оказалось, у GPT-5.5 тоже было верное представление об этом — QR-разложение довольно известная задача.
Тема оказалась интересной ещё и потому, что разложения матриц встречаются во многих современных вариантах оптимизаторов для обучения LLM, особенно в методах с матричным предобуславливанием, таких как оптимизаторы в стиле Shampoo. Muon (используется в Kimi) — ещё один хороший пример: вместо того чтобы рассматривать обновление весов как один гигантский плоский вектор, он сохраняет матричную структуру и ортогонализирует обновление момента, обычно через несколько итераций Ньютона-Шульца, аппроксимирующих полярный фактор.
(Опционально) Математика QR-разложения: отражения Householder
Этот раздел стоит хотя бы пролистать тем, кому интересна математика, остальным можно смело пропустить. Главное, что нужно уяснить: в Householder QR есть последовательная зависимость, которая мешает свести вычисления к GEMM. Блочный вариант Householder делает вычисления более похожими по форме на матричное умножение.
Контракт задачи
Кратко напомним контракт: на вход подаётся батч квадратных FP32-матриц A; на выходе — компактный формат (H, tau), который возвращает torch.geqrf. Верхний треугольник H — это R. Ниже диагонали H хранит векторы Householder, а tau хранит по одному скаляру на столбец. Чекер восстанавливает Q из (H, tau) и проверяет A ≈ QR.
Зеркала
На секунду забудем про матрицы. В ванном зеркале отражение находится ровно настолько же позади стекла, насколько объект — перед ним, по прямой линии.
Если — часть x, торчащая перпендикулярно стеклу, отражение просто вычитает эту часть дважды:
Таким образом, отражение Householder сводится к нахождению перпендикулярной части и вычитанию её дважды.
Хранение зеркала
Вектор Householder — это и есть зеркало, только в компактной форме. В коде не хранится вся плоскость зеркала целиком — хранится один вектор v, торчащий перпендикулярно из неё. Зеркало — это всё, что перпендикулярно v, а отражение движется вдоль v.
Перпендикулярная часть — это просто тень x на v, равная копий v. Подставив это в формулу вычитания выше, получаем:
То есть tau — это просто : коэффициент 2 и длина v, упакованные в одно заранее вычисленное число. v задаёт зеркало, tau масштабирует обновление. (Математический отражатель далее обозначается , а H зарезервировано за компактной выходной матрицей.)
Почему QR заботит зеркала
QR хочет превратить A в верхнетреугольную матрицу R. Столбец 1 должен превратиться во что-то вроде (*, 0, 0), столбец 2 должен иметь нули ниже строки 2, и так далее.
Зеркало Householder полезно тем, что делает это со столбцом за один шаг. Возьмём первый столбец из примера 3×3 выше: (12, 6, -4). Нужно отправить его на ось x, чтобы нижние элементы обнулились. Отражение может менять только направление, но не длину, поэтому цель тоже должна иметь длину 14. Один из допустимых вариантов — (-14, 0, 0). После такого отражения элементы 6 и -4 исчезают — именно этого и требовалось добиться.
Как найти зеркало? Оно располагается посередине между столбцом и его целью, поэтому v, вектор, торчащий сквозь зеркало, — это просто столбец минус его цель:
v = (12, 6, -4) - (-14, 0, 0) = (26, 6, -4)
Обновление Householder
Далее вычисляется tau = 2 / (vᵀv). Сам отражатель:
Это превращает текущий столбец в (-14, 0, 0) и согласованно переписывает остальные столбцы, так что следующий отражатель строится уже из обновлённой матрицы.
Так повторяется по одному разу на каждый столбец. В упрощённой записи повторяющиеся обновления выглядят так:
Каждая строка использует матрицу, полученную из предыдущей. Каждый отражатель обнуляет всё под диагональю своего столбца, не трогая уже завершённые столбцы. После последнего шага A превращается в верхнетреугольную R:
Зеркала не меняют длины и углы, поэтому каждый ортогонален, и их произведение Q тоже. Отсюда бесплатно берётся ортогональность, которую проверяет чекер.
Что такое компактный формат
После обработки столбца j всё, что ниже его диагонали, — мёртвое пространство. geqrf переиспользует эти слоты, чтобы упаковать туда хвост v_j (ведущая единица подразумевается неявно). На диагонали и выше — R, ниже — отражатели, а tau едет отдельным вектором. Поэтому чекеру нужны и H, и tau, чтобы восстановить Q.
Как блочный алгоритм Householder сокращает последовательную работу
Householder QR обнуляет A под диагональю по одному столбцу за раз. Каждый шаг строит отражатель из текущего столбца и применяет его ко всему справа. Проблема в том, что отражатель j+1 строится из матрицы после того, как её уже затронул отражатель j. Поэтому шаги нельзя переупорядочить и нельзя слить. Работа последовательна, и последовательная матрично-векторная работа выполняется в медленных векторных линиях SM, пока тензорные ядра просто простаивают.
Классическое решение — блочный алгоритм. Берётся узкая панель из b столбцов (скажем, 32 или 64), и вся последовательная работа выполняется внутри неё. Это приемлемо, поскольку панель узкая — всего b столбцов, — и остаётся дешёвой. Затем, вместо того чтобы применять b отражателей панели к остальной матрице по одному, они сжимаются в единое обновление ранга b ("WY-представление") и применяются ко всему оставшемуся блоку за один раз тремя последовательными матричными умножениями. Последовательная работа остаётся заперта внутри панели, а всё остальное превращается в GEMM — именно ту форму, которую хотят тензорные ядра.
Конкретно, WY-представление сворачивает отражателей панели в единое обновление ранга . Векторы Householder панели складываются в столбцы , строится небольшая верхнетреугольная матрица , и тогда:
а обновление оставшегося блока превращается в три GEMM-подобных шага:
Панель — это место, где заперта последовательная матрично-векторная работа, но она шириной всего столбцов. Всё, что справа от неё, — большой оставшийся блок, а это уже чистый GEMM. По мере того как панель движется вдоль диагонали, оставшийся блок уменьшается.
Для понимания математики хорошо помогает обсуждение с Claude. Также стоит заглянуть в разбор Майка, где математика изложена более описательно и наглядно. Он занял 5-е место в конкурсе и поделился своими наработками с фокусом именно на задаче.
Другие сложности
Ещё два момента оказались непростыми: надёжное использование пониженной точности внутри вычислений (особенно для плохо обусловленных входных данных) и работа с широким разбросом форм матриц (n = 32, 176, 352, 512, 1024, 2048, 4096) и размеров батча — самые крупные матрицы имели слишком мало батчей, чтобы загрузить тензорные ядра, тогда как n = 32 было настолько малым, что приходилось упаковывать множество матриц в один запуск ядра.
Максимальное использование Codex
Почему выбор пал на Codex
В конкурсе использовались подписки ChatGPT Pro (200 долларов) и Claude Pro (20 долларов), а также Modal для профилирования (там дают 30 долларов кредитов бесплатно каждый месяц).
Codex был выбран в основном потому, что:
- Подписка на него была больше по объёму.
- По прошлому опыту сложилось впечатление, что модели OpenAI лучше справляются с Triton.
/compactionотлично работает в Codex.
Настройка харнесса
После базового понимания задачи Codex получил задание настроить основу: добавить problem_statement.md, описать в AGENTS.md базовые детали о том, как отправлять решения и пользоваться CLI popcorn, и вести log.md с учётом отправленных решений и их статуса (принято/отклонено вместе с таймингами по формам). Если сравнивать с auto-research Карпати, изначальные AGENTS.md и problem_statement.md были аналогом его program.md.
Логи служат доказательством того, какие идеи сработали, а какие нет. Будущие сессии агента могли прочитать логи и быстро проверить, пробовалась ли уже та или иная идея. Инвестиции в логирование выросли после отметки в 3000 мкс, когда всё стало заметно сложнее.
Просто скажи, что делать
Приятная особенность Codex в том, что ему можно просто сказать сделать что-то — и он действительно это сделает. Модель можно заставить работать часами, если дать достаточно подробный промпт с целями. Она знает всю математику и код, и у неё есть вся необходимая обратная связь. Такая интуиция была заранее, но масштаб, до которого GPT-5.5 смог продвинуть производительность за пределы базового решения (которым была функция torch.geqrf/cuSolver), всё равно удивил.
Первые несколько сессий состояли из ручных промптов для реализации решения на Triton и оптимизации под формы n = 512 и n = 1024, поскольку они имели наибольший вес в итоговом среднем геометрическом.
Управление через /goal
Чтобы заставить модель крутиться в цикле до достижения определённой цели, используется /goal. Можно задавать конкретные, достижимые, количественные цели. Хорошо работало формулирование чёткой числовой цели, за которой следуют конкретные критерии.
Пример: «Используй только Triton или CUDA и побей тайминги нашего текущего лучшего решения для n = 512. Попробуй несколько идей — либо отправляя напрямую в таблицу лидеров, либо через профилирование в Modal. В новой серии экспериментов полностью убери cuSolver. Будем использовать его только как запасной вариант». В какой-то момент эта цель выполнялась больше суток.
Каждые 2-3 часа модели давались вводные, чтобы направить её в нужную сторону. В некоторые дни она также работала без присмотра всю ночь. В первые дни инструкции в основном сводились к тому, чтобы направлять модель пробовать разные идеи (подробнее об этом дальше) для разных форм матриц, требовать больше Triton, меньше PyTorch и меньше запасных вариантов! Извлечённый урок: часто возникало желание проверять агентов слишком часто, но нужно довериться и дать им работать. Не мешай агенту — вмешивайся, только когда он застрял.
Проверка без остановки цикла
При использовании /goal можно задавать модели вопросы, не останавливая цикл, с помощью /btw или /side. Это создаёт временный тред с контекстом из основного разговора. Такой способ проверки агента и сохранения контроля оказался удобным.
Типичные вопросы: «Побеждаешь, дружище? Какой алгоритм/изменения в текущем активном решении? Объясни мне эту концепцию. Над какими идеями сейчас работаешь? Как прогресс? Какие недавние прорывы? Можем перенести это на другую форму? Какие следующие лучшие идеи?» По ответам можно было проконсультироваться с Claude, чтобы лучше разобраться в концепциях и узких местах, а затем вернуться в Codex с уже сформированными мыслями. После расспросов оставалось вернуться в основной тред и выгрузить туда мысли, чтобы направить модель.
если запущен /goal или какой-то другой цикл, можно либо поставить инструкцию в очередь в codex, чтобы что-то спросить, либо сделать /btw. (картинка: проверяю codex, спрашивая что он делает, какие следующие идеи и т.д.). если нажать esc, чтобы прервать цикл, то /goal ставится на паузу
sankalp (@dejavucoder), 27 июня 2026
Базовый путь через torch.geqrf занимал около 419 мс (419 000 мкс) в целом. Уже за день удалось выйти на 5000 мкс для формы n = 512 после реализации блочного подхода Householder для этой формы — а именно она имела наибольший вес в среднем геометрическом.
Цифра 232x получается при сравнении примерного базового значения в 419 000 мкс с итоговым зафиксированным результатом в 1805 мкс. Приведённый ниже график происхождения начинается с первой восстановленной точки в истории отправок, поэтому он показывает более позднюю дугу от 108 803 до 1805 мкс, а не полное соотношение от базового решения до финального.
При оптимизации ядер сделать работу более "матричной по форме", чтобы тензорные ядра перестали простаивать, — это и есть смысл всего процесса.
После отметки в 3000 мкс оптимизация стала заметно сложнее. Пришлось глубже погружаться в цикл — как в плане изучения концепций, так и в управлении моделью. Codex получил доступ к профилированию в Modal и мог запускать torch profiling / nsys profiling, чтобы проверять разные идеи, сравнивать реализации и быстрее перебирать параметры. (Позже организаторы также предоставили способ профилирования через NCU.)
Прорывы в прогрессе ядра
Прорывные идеи
Примерная структурная эволюция QR-ядра — от путей с тяжёлой опорой на baseline/библиотеки к кастомной работе с панелями, слитой сборке и оставшимся обновлениям в форме GEMM:
| # | Структурное изменение | Что оно делало | Тип | Среднее геометрическое |
|---|---|---|---|---|
| 1 | torch.geqrf везде |
Универсальный QR для каждой формы | отправная точка | >108.8k мкс |
| 2 | Блочный WY QR на n512 | Факторизация панели + обновление оставшегося блока | алгоритм / маршрутизация | 108.8k мкс |
| 3 | Блочный путь на всех формах | полный QR для n32, обновления LARFB16 | алгоритм / маршрутизация | 10.2k мкс |
| 4 | Panels на Triton + групповой WY | ядра panel16/32, групповые обновления | ядро / рантайм | 4.3k мкс |
| 5 | Cholesky-ORHR для n4096 | Грам, Холецкий, пересобранные отражатели | алгоритм / маршрутизация | 4.0k мкс |
| 6 | Повтор CUDA graph | Захват маршрутов, устранение накладных расходов на запуск | ядро / рантайм | 3.4k мкс |
| 7 | Слитая сборка компоновки V/T | Без копий срезов, конкатенаций, временных объектов | ядро / рантайм | 2.75k мкс |
| 8 | split16 панели + tail-Gram | Пропуск полного WY рядом с хвостами | алгоритм / маршрутизация | 2.5k мкс |
| 9 | Специализация ядра под фиксированную форму | Захардкоженные строки, слитые редукции | ядро / рантайм | 2.0k мкс |
| 10 | Составные суперпанели, кастомный Холецкий | Пакеты V256/T256, прямой возврат H | ядро / рантайм | 1.80k мкс |
Много времени ушло на профилирование всей формы целиком и выявление узких мест. Для этой задачи доминировали накладные расходы на запуск и накладные расходы панели — редко удавалось упереться в память или вычисления. Основные усилия были направлены на сокращение накладных расходов панели и превращение WY-обновления в более "GEMM-совместимое".
Вопросы, которые задавались снова и снова:
Что такое накладные расходы панели/запуска? Как их устранить?
Какой информации не хватает и как её получить?
Какой последний профиль был сделан? Какие выводы из него?
Поищи кандидатов на слияние. Есть ли кандидаты на уровне фьюзинга Triton?
Поищи возможные оптимизации на уровне компилятора. Что можно перевести из сигнала времени выполнения в статический сигнал? Идея была в том, чтобы дать подсказки компилятору. Однажды это дало скачок на 200 мкс
Несколько раз просили изучить сгенерированные Triton скомпилированные артефакты
Какие числовые трюки помогают использовать запас точности?
Можно ли развернуть суб-агентов, чтобы они посчитали математику и нашли возможные оптимизации?
Развернуть агентов для поиска багов, которые могут тормозить процесс
Возможны ли слияния редукций? Codex обнаружил одно такое, и дальше этот вопрос задавался постоянно. Редукции — это операции вроде суммирования или поиска максимума. Поскольку для прохода по всей последовательности всё равно нужна работа, несколько таких операций можно выполнить за один проход.
Разнообразие идей против локальных максимумов
Главной проблемой в диапазоне 3000 → 1800 мкс стало застревание модели в локальных максимумах. Это выглядело как бесконечная ручная подстройка параметров и небольших вариаций одной и той же идеи.
Пару лет назад агенты застревали в (дурных) циклах, потому что были недостаточно умны или просто не обладали нужными знаниями (или цикл верификации был недостаточно надёжным). Тогда люди экспериментировали с сэмплированием, вариацией температуры и разными стратегиями декодирования.
Со временем модели стали достаточно умны, предобучены на более новых знаниях, появилось масштабирование через RL и вычисления времени инференса (обучение модели "думать" большее число токенов).
Теперь модели испытывают трудности с поиском новых идей и "исследовательским вкусом" — какую следующую лучшую идею/эксперимент выбрать, учитывая обратную связь от верификатора, накопленные данные и оценки (в данном случае — обратную связь профилировщика). Хорошая генерация идей — следующее большое приключение в этой области. На эту тему недавно вышла отдельная статья.
Помочь модели выбраться из локальных максимумов удалось следующими стратегиями:
Пучок кандидатов: долгое время практиковался не самый умный подход — держать единственного лучшего кандидата, с которым сравнивались новые. Если агент пробует новую структурную идею или значительное изменение, велика вероятность, что оно наберёт меньше очков, чем текущий лучший результат. Однако после нескольких итераций это изменение может превзойти лучшего кандидата. Учитывая это, были введены инструкции поддерживать пучок из 3-5 кандидатов.
Человек в цикле: роль "секретного ингредиента" для направления модели, когда она долго топталась на месте без улучшений
Поощрение модели к большему риску и амбициозным идеям. Звучит неожиданно, но это сработало. Также Claude часто сдавалась после нескольких раундов, с отговорками вроде «мы исчерпали все оптимизации для достижения такого-то геомин»; Codex, напротив, гораздо настойчивее.
Использование более сильной модели-советчика, которая выдаёт более разнообразные идеи. В харнессе это выглядело как инструкция в AGENTS.md, поощряющая модель использовать headless-вызовы
claude -pдля получения идей, передачи данных профилирования и т.д.Инструкция модели чаще привлекать суб-агентов для проверки амбициозных идей, поиска в интернете блогов и статей, прохода по списку вопросов выше и поиска микрооптимизаций
Профилирование через NCU и Modal, сравнение результатов и работа над узкими местами, на которые указывали оба инструмента
Уборка
- Очистка контекста, начало с чистого листа
- Уборка окружения, перенос старых файлов решений в архив
- Периодические итерации на упрощение кода, удаление мёртвого кода, переименование/рефакторинг
Подход с роем из нескольких агентов приходил в голову, но не был опробован.
Стратегия с сильным советчиком (вроде GPT-5.6 Sol или Fable) видится будущим стандартом в потоках auto-research — очень крупные модели с передовым обучением. Claude Code тоже предоставляет команду /advisor для этого.
Мы приносим стратегию советчика на Claude Platform.
Возьмите Opus в роли советчика вместе с Sonnet или Haiku в роли исполнителя — и получите интеллект почти на уровне Opus в своих агентах за малую долю стоимости.
Claude (@claudeai), 9 апреля 2026
Заметки по реализации
К концу конкурса структура директорий выглядела так:
qr/ ├── submission.py # the live entry ├── submission_*.py (560) # named submission variants (crystal_rain, blue_reply, …) ├── modal_b200_*.py (119) # Modal B200 probe / compare scripts │ ├── AGENTS.md # top-level notes / logs ├── attempts_log.md ├── claude_ideas.md ├── leaps.md ├── problem_statement.md │ ├── docs/ ( 68) # per-experiment writeups & status docs ├── code/ # the actual QR kernel source tree ├── scripts/ # summarizers, timing, submit helpers ├── archive/ # cleaned-out old submissions & probes │ ├── submissions_20260616_17/ │ ├── submissions_20260618_20/ │ ├── probe_scripts_cleanup_20260627/ │ └── … ├── submit_logs/ # logs provided by the evaluator for each submission └── profile.*/ # captured NCU profile runs
Финальная версия AGENTS.md выглядела так:
Leaderboard Agent Notes
This workspace is for leaderboard-style optimization work. Follow these standing instructions unless the user explicitly overrides them.
Submission Discipline
- Don't hesitate to use sub-agents. Give them relevant instructions so they can do their task.
- Profile after major changes or major score gains.
- Use an advisor model when you are stuck or need fresh ideas. It can help break tunnel vision.
- Don't be afraid to implement hard tasks.
- Don't hesitate to take risks.
- Be open to new ideas and search the internet at times for new idea exposure.
- Before submitting, run the cheapest available sanity check for the candidate file.
- Keep submission logs under
submit_logs/.- Always save submit output into a timestamped log.
- Space leaderboard submissions out. Do not stack rapid back-to-back submissions unless explicitly asked.
- Treat a timeout as inconclusive, not as a correctness/performance rejection.
- Treat a completed residual failure or timing regression as real evidence.
- Only completed pass/fail/timing output is evidence.
Beam Search Discipline
Do not optimize as a single-incumbent hill climb. Maintain a small beam of active idea families so that local negative results do not prematurely kill useful ingredients.
- Keep a live beam note in
docs/.- Each beam entry should record the parent candidate, hypothesis, exact changed functions or gates, current best candidate/log, and next singleton, combination, or kill decision.
- Keep at least 3 active beams when there is enough work:
- one exploit beam near the current best,
- one near-miss beam,
- one structural/high-risk beam from profiling or external ideas,
- one cleanup/compile-time beam only if it has not consumed the whole search.
- Use sub-agents to work different beams, not many variants of the same tiny parameter unless explicitly asked for a parallel sweep.
- Do not declare a family dead after isolated singletons fail.
- If two ideas are individually neutral or slightly slower but touch independent costs, try combining them before retiring the family unless correctness risk is high.
- Preserve near-misses as beam material when they show a repeatable isolated win, improve one important case, remove overhead, or change an algorithmic surface that can combine with another beam.
- Kill a beam only with a clear reason: inherent correctness failure, repeated meaningful regression after a reasonable retune, singleton and plausible combinations both lose, profile evidence shows the targeted cost is no longer material, or implementation cost is blocking higher-value beams.
- After every 3-5 submissions, update the beam note with the current beam ranking and next combination candidates.
Promotion / Git Hygiene
- When a new candidate is promoted into the active file, stage the promoted candidate, active file, evidence docs/logs, and any archive moves.
- Commit after promotion unless the user says not to.
- Use a lower-case commit subject and describe both what changed and what made the improvement in the commit body.
Profiling / Evidence Habits
- Prefer current active evidence over older sidecar timings.
- Keep raw profile logs and JSON under
submit_logs/.- When a candidate is rejected or promoted, update the relevant doc in
docs/.- Use
rgfor searching when possible.- Archive older candidates, profile logs, and probe scripts so the root stays navigable.
Known Tried Ideas
- Do not mirror every attempt summary here. Check
docs/before repeating an idea, and update the relevant doc when an idea is rejected or promoted.- Do not repeat rejected ideas as-is. If revisiting one, make the algorithmic difference explicit in the doc/log.
- If a platform or evaluator rule rejects a class of ideas, record it clearly so future agents do not rediscover the same invalid path.
Что можно было сделать лучше
Хотя в простом харнессе есть куда расти, большинство недочётов оказались специфичными для самой задачи. Эти выводы появились после изучения топ-10 решений и разбора от Майка.
Случаи n = 512 и n = 1024 включали несколько распределений входных данных: плотные, кластеризованные, с недостаточным рангом, смешанные и близкие к недостаточному рангу семейства. Более быстрые ядра у конкурентов содержали детекторы данных, эксплуатирующие эти распределения — например, случаи с низким рангом содержат много нулей, и это можно использовать. Стоило сильнее надавить на Codex в этом направлении или хотя бы больше расспросить об этом.
Топ-10 решений более агрессивно избавлялись от библиотечных функций. Например, 2-е и 5-е решения использовали кастомное обращение треугольной матрицы вместо PyTorch triangular solve. В данном же решении было много переключений туда-обратно между PyTorch и Triton.
Стоило держать оставшуюся матрицу постоянно в
fp16, вместо повторных переключений между представлениями. Это была неизвестная неизвестность — чисто пробел в предметной экспертизе.Пучок кандидатов стоило внедрить с самого начала
Написать более надёжный профилировщик для тестирования случаев смешанной точности
Не удалось задействовать инструкции
tcgen05— тензорные инструкции пятого поколения NVIDIA на Blackwell, — чтобы сильнее использовать тензорные ядра B200
Заключение
Итог — 12-е место из 183 и ускорение в 232 раза относительно baseline. Что важнее, конкурс дал много знаний об оптимизации GPU-ядер, основах auto-research (или loop engineering?) и некоторых деталях, специфичных для B200.
Ещё один вывод: предметная экспертиза ускоряет как проектирование харнесса, так и ручное управление в режиме human-in-the-loop. Есть спектр того, как инженеры разной специализации подходят к таким задачам. На одном полюсе — желание сделать общий харнесс, способный к самоулучшению. На другом — интерес к очень специфичным для конкретной задачи/окружения харнессам. Личное предпочтение здесь склоняется к харнессам, заточенным под конкретную задачу.
Второй конкурс в серии, посвящённый разложению на собственные значения, уже идёт.
Источники
Использовались для повторения или изучения новых концепций.
How to Optimize a CUDA Matmul Kernel for cuBLAS-like Performance: a Worklog
Outperforming cuBLAS on NVIDIA B200
Outperforming cuBLAS on H100: a Worklog
Fast QR decomposition on NVIDIA B200 GPUs — разбор Майка помог освежить понимание самой задачи.
Источники, которые ещё предстоит изучить:
блог Саймона — CuteDSL и детали, специфичные для B200.
блог gau-nernst — gau-nernst занял 2-е место.
Благодарности
Mark Saroufim и Rohan Anil — за организацию конкурса. Sinatras — за обнаружение обхода метрик (reward hacks) и поддержку на старте.
Майк занял 5-е место и написал отличный разбор, объясняющий задачу с наглядными иллюстрациями.
Levidiamode — за ценные посты о GPU-ядрах, Tokenbender — за подталкивание написать этот материал, и CUDA colonel — за советы на сервере GPU Mode.
Claude Opus 4.8 и GPT-5.5 (Codex) помогали с редактурой и написанием математической части.