Vibecoding: ядра GPU

@maharshii
АНГЛИЙСКИЙ09 авг. 2026 г.
118K
408
30
11
593

Суть

Махарши объясняет рабочий процесс использования LLM для генерации ядер GPU, опираясь на верифицируемый цикл проверок компиляции, тестирования корректности на основе эталонных реализаций и итеративной оптимизации.

Написание GPU-ядер вручную требует терпения, усилий и, чего уж там, нервов. Я экспериментировал с современными LLM (Claude Opus 5, GPT 5.6 Sol), чтобы они буквально печатали для меня ядра. Расскажу, что я из этого вынес.

Если честно, написание GPU-ядер — это задача, которую до неприличия легко проверять.

Сначала ты решаешь, для каких операций будешь писать ядро. Затем пишешь первую версию и убеждаешься, что она компилируется без очевидных ошибок. Потом проверяешь корректность на медленной эталонной реализации. Если результат не сходится, пытаешься исправить проблему с корректностью. Когда это готово, ты бенчмаркаешь время выполнения ядра. Последующие версии строятся поверх этого, и ты продолжаешь оптимизировать, пока не достигнешь roofline-метрик или не удовлетворишься результатом.

maharshi - inline image

Проверяемый цикл: разработка GPU-ядер

На изображении выше это показано как проверяемый цикл:

  • Проверка компиляции — это быстрый локальный цикл (B <-> C), который выполняется ещё до того, как ты вообще задумываешься о корректности.
  • Проверка корректности (D <-> E <-> F) — основной цикл проверки и вознаграждения. Именно эта часть делает написание ядер хорошей задачей для автоматизированной проверки, ведь у тебя есть эталон, с которым можно сверяться.
  • Оптимизация (G -> H -> обратно к D) переиспользует тот же цикл проверки корректности для каждой новой версии: быстрое, но неправильное ядро ничего не стоит, поэтому корректность нужно проверять для каждой версии.
  • Проверка roofline/удовлетворённости (I) — это внешний цикл, который решает, продолжать ли оптимизацию или остановиться.

Первая версия

Изображение выше — это всё ещё общий взгляд, а дьявол кроется в деталях. Нужно убедиться, что у нашего LLM-агента есть весь необходимый контекст, чтобы вообще начать писать хорошую первую версию.

Здесь в игру вступают CUDA-DSL. Triton, CuTeDSL и Tilelang — это те, с которыми очень легко начать работать на Python. Кривая обучения здесь не такая крутая, как в CUDA C++, однако абстракции в этих DSL могут ещё сильнее запутать нашего агента. Нужен способ передать агенту контекст этих абстракций.

Современные LLM уже умеют писать «хороший» Triton. Они отлично работают с абстракциями Triton даже без какого-либо контекста. Однако для других DSL, таких как CuTeDSL (который даёт гораздо больше контроля, чем Triton), я обнаружил, что наличие директории с контекстом, в которой агент может разобраться в абстракциях DSL, очень помогает.

Например, клонирование репозитория

NVIDIA cutlass

в директорию с контекстом — хороший способ дать агенту возможность искать абстракции, связанные с

Layout Algebra, Copy/GEMM atoms, иерархией памяти, примерами ядер

и так далее, при написании ядер на CuTeDSL.

По моему опыту, хорошая первая версия ядра компилируется без очевидных ошибок и проходит тест на корректность, о котором я расскажу ниже.

Тестирование, бенчмаркинг и профилирование

Когда агенту дан достаточный контекст, настоящее узкое место смещается на валидацию. Сама эталонная реализация и сверка с ней становятся всё важнее. Я называю этот этап тестированием корректности или просто тестированием. Скорость эталонной реализации не так важна, как её назначение. То, что ты собираешься измерять и проверять, — это то, что твой агент будет оптимизировать.

Обычно, когда вычисления не должны выполняться в пониженной точности, я измеряю максимальную абсолютную/относительную ошибку (MAE), среднеквадратичную ошибку (MSE/RMSE) и PSNR (пиковое отношение сигнала к шуму). Когда задействованы пониженные точности, я обычно измеряю PSNR и косинусное сходство (cossim).

То, как ты будешь запускать версии ядра на GPU, зависит от того, доступен ли GPU локально или через облако. В любом случае наш агент должен иметь возможность так или иначе получить доступ к своим результатам.

Я считаю описанную ниже методологию rung хорошим способом организовать N тестовых функций:

python
1def rung(name):
2 def deco(fn):
3 try:
4 out = fn()
5 results[name] = {"ok": True, **(out or {})}
6 print(f"[{name}] ok " + " ".join(f"{k}={v}" for k, v in (out or {}).items()))
7 except Exception as e:
8 results[name] = {"ok": False, "err": f"{type(e).__name__}: {e}"}
9 print(f"[{name}] FAILED {type(e).__name__}: {e}")
10 traceback.print_exc()
11 return fn
12 return deco

которую можно вызывать так:

python
1out = {}
2
3@rung("pre-checks")
4def _():
5 run_pure_checks()
6 run_dsl_checks()
7
8@rung("run")
9def _():
10 out["o"] = custom_kernel(*inputs)
11 torch.cuda.synchronize()
12 return {"shape": tuple(out["o"].shape),
13 "finite": bool(torch.isfinite(out["o"]).all())}

Для бенчмарк-ступени (rung) можно сделать несколько вещей:

  • Замерять полное время выполнения ядра от начала до конца, чтобы оценить общее затраченное время
  • Использовать внутриядерную трассировку для замера секций внутри ядра и выгружать их в вывод (с помощью кастомного трейсера или CUPTI)
  • Сохранять сгенерированные IR, PTX, SASS и CUBIN в директорию dumps и позволять агенту их изучать

Последний пункт можно раскрыть немного подробнее. Иногда случается, что DSL в процессе lowering генерирует неоптимальный PTX (а затем и SASS), и ты находишь более удачные инструкции или формы, которые можно использовать вместо этого. Наш агент может читать текстовые файлы PTX/SASS и встраивать код более низкого уровня напрямую, не позволяя DSL обрабатывать неоптимальную часть. Опять же, здесь очень полезно передавать документацию по PTX в качестве контекста, чтобы агент мог по ней искать.

Последнее, что связывает всё воедино, — это профилирование. Если твой агент имеет доступ к CLI утилиты NCU (Nsight Compute Systems), ты можешь попросить его профилировать ядро и сгенерировать отчёт в рамках описанного выше проверяемого цикла обратной связи.

Заключительные мысли

«Значит, разработка GPU-ядер мертва?»

«Ну да, но вообще-то нет»

Да, потому что сложная часть — лейауты, индексация, абстракции и общая структура — во многом решается агентами с достаточным контекстом. Ты легко можешь сократить объём работы с 2–3 недель до 1–2 дней. Нет, потому что реальное узкое место сместилось с ядер на валидацию. Теперь нет одного-единственного способа действовать: чем лучше твой контекст и обвязка (harness), тем быстрее идёт процесс. Специализированные случаи выиграют ещё больше, и всё, что тебе понадобится, — это хорошая обвязка.

И наконец, вместо того чтобы относиться к агентам как к автономным, их всё ещё нужно воспринимать как по-настоящему умных ассистентов, которыми ты можешь управлять. Именно здесь пригодится твоё фундаментальное понимание GPU и ядер. Человеческая часть (ты) здесь всё ещё нужна.

Это горько-сладкое чувство, я знаю :)

Сохранение в один клик

Используйте YouMind для глубокого чтения вирусных статей с помощью ИИ

Сохраняйте источники, задавайте точные вопросы, обобщайте аргументы и превращайте вирусные статьи в полезные заметки в одном рабочем пространстве ИИ.

Исследовать YouMind
Для авторов

Превратите ваш Markdown в аккуратную статью для 𝕏

Когда вы публикуете длинные тексты, изображения, таблицы и блоки кода, форматирование в 𝕏 становится мучением. YouMind превращает полный черновик в Markdown в чистую статью, готовую к публикации в 𝕏.

Попробовать Markdown для 𝕏

Другие паттерны для анализа

Недавние виральные статьи

Смотреть другие виральные статьи