Исследование · NVIDIA Technical Blog

24 GPU-оператора на Rust: агентам помог общий язык компилятора

NVIDIA описала агентный перенос 24 операторов TileGym из Python в Rust с почти равной скоростью исполнения GPU-ядер. Главная особенность работы — возможность сравнить промежуточный код компилятора и проверить каждый этап автоматически. Для команды, поддерживающей собственные вычислительные операции, это меняет требования к подготовке локального помощника по программированию.

Что это меняет для покупателя

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

Почти паритет, но у конкретного измерения

Команда NVIDIA перенесла все 24 публичных оператора TileGym в cuTile Rust: примерно 40 GPU-ядер, включая нормализацию, операции внимания и вычисления для MoE. Итоговый геометрический средний коэффициент скорости относительно cuTile Python составил 0,995. Результат получен на NVIDIA DGX B200: отдельная GPU для каждого бэкенда, 347 парных конфигураций, лучшие измерения из четырёх запусков CI. Это сильный результат внутри определённой задачи переноса. Разбор NVIDIA.

Использовался CUPTI device time — время работы самого ядра на GPU. Пользовательское время включает также запуск и планирование, что особенно заметно для очень коротких операций. Поэтому коэффициент 0,995 описывает вычислительные ядра, а не скорость написания программы агентом или ускорение целого локального сервера. Авторы измеряли время по часам, но для итогового сравнения операторов публиковали именно время устройства.

Почему такой перевод можно проверить

cuTile Python, Triton-TileIR и cuTile Rust сходятся в CUDA Tile IR — промежуточном представлении программы. Затем один компилятор tileiras оптимизирует операции и создаёт GPU-бинарник. Перенос здесь воспроизводит вычисление через другой языковой интерфейс. У команды есть более точная опора, чем внешнее сходство исходников: можно сравнивать формы блоков данных, операции памяти и свёртки в представлении компилятора.

Основная трудность заключается в специализации. Python подстраивает ядро под параметры вызова неявно; Rust требует объявить такие параметры в сигнатуре. Например, ветка Python может исчезнуть до компиляции, тогда как обе ветки Rust должны проходить проверку типов. Из-за этого одному исходному ядру иногда соответствуют разные структурные варианты. Агенту нужно восстановить скрытый контракт программы, а не просто заменить синтаксис.

Ошибку ловят до общего запуска

Процесс начинается с анализа эталона и формирования analysis.json: вариантов, типов данных, допусков, параметров запуска и других условий. Автор ядра работает только над kernel.rs. Сначала результат проверяется отдельным тестом на Rust без Python и промежуточного интерфейса, затем сравнивается Tile IR. Такая последовательность помогает отличить ошибку вычисления от ошибки соединения компонентов, когда готовое расширение ещё не собрано.

Следующий этап добавляет интерфейс C ABI — соглашение, позволяющее вызывать Rust из другого языка, — и обёртку Python. Проверяются реальные формы и типы данных в тестах TileGym. Только успешный машинно проверяемый результат допускает измерение производительности. Авторы отдельно подчёркивают: правдоподобное ядро может пройти обычные тесты и всё же потерять важный атрибут или использовать другую операцию памяти. Сравнение IR расширяет проверку за пределы примеров.

Граница Rust не отменяет опасных стыков

cuTile Rust переносит модель владения Rust на GPU-ядра и разделяет изменяемые результаты на непересекающиеся части. Однако некоторые опубликованные переносы используют непроверяемый интерфейс, поскольку именно он воспроизводит эталонный IR; миграция на безопасную поверхность продолжается. Кроме того, за границей C ABI неправильный шаг между элементами массива может привести к тихому повреждению данных. Обёртка и интерфейс поэтому имеют собственные проверки.

В описанном соединении с PyTorch запускающий слой не копирует и не выделяет память, не забирает владение чужим буфером и использует CUDA-поток вызывающей стороны. Эти детали важны для интеграции в существующий код. Но они также объясняют, почему перенос нельзя оценивать только по правильности математической формулы: нужно сохранить форму данных, способ обращения к памяти и договорённости между языками.

Основная покупка — подготовленное окружение

Описанный комплект требует CUDA 13.1+, Rust 1.89+, компилятора tileiras и Blackwell GPU для проверки производительности. По словам авторов, полный перенос расходует порядка миллионов токенов. Процесс ограничивает число повторных попыток и сохраняет диагностику, если задача не сходится. Для команды это ощутимая подготовительная работа: нужны эталоны и подходящий инструментарий, а также человек, способный различить ошибку переноса и проблему компилятора.

Этот результат полезен прежде всего тем, кто действительно поддерживает собственные GPU-операторы. Общий IR сделал проверяемую автоматизацию возможной в конкретном семействе инструментов; перенос произвольного Python-проекта не получает такую опору автоматически. Разумное решение — сначала заложить стоимость воспроизводимого окружения для одного нужного оператора. Именно подготовка определит пользу локального агента, прежде чем возникнет основание расширять его сервер.

Что проверить до выбора системы

  • Какие собственные GPU-операторы команда регулярно меняет и действительно хочет переносить?
  • Кто сможет разобрать расхождение IR и возможную ошибку исходного компилятора?
  • Как в бюджете учитываются первый запуск с компиляцией и последующее использование кэша?
  • Какой предел расходов на токены установлен для одного законченного переноса?

Выводы для покупателя — наша редакционная интерпретация. Публикация не подтверждает скорость или совместимость конкретной сборки из каталога.