PyTorch 2.12: 100-кратное ускорение eigendecomposition и конец TorchScript

PyTorch 2.12: 100-кратное ускорение eigendecomposition и конец TorchScript

Каждый релиз PyTorch обещает «производительность и удобство», но 2.12 — особенный. В нём не просто добавили очередной backend или оптимизировали свёртки. Разработчики полностью переписали диспетчеризацию batched eigendecomposition, сделав операцию в сто раз быстрее. Ввели единый device-agnostic API для graph capture, который работает одинаково на CUDA, XPU и кастомных backend'ах. Добавили поддержку Microscaling quantization в torch.export — формата, который сжимает модели до экстремальных размеров. И, наконец, официально похоронили TorchScript, который был главным инструментом деплоя последние семь лет. За релиз отвечали 457 контрибьюторов и 2926 коммитов — и почти каждое изменение касается либо скорости, либо переносимости, либо обоих сразу.

Что такое PyTorch 2.12 и почему он важен

PyTorch 2.12 — это не инкрементальное обновление с парой новых операторов. Это продолжение стратегического перехода фреймворка от research-first инструмента к unified production платформе, которая одинаково хорошо работает в Jupyter-ноутбуке, на кластере из тысяч GPU и на встраиваемом устройстве с Cortex-M. Начиная с 2.10, команда последовательно вычищает backend-специфичные костыли, заменяя их абстракциями, которые масштабируются на любое железо.

Ключевой тренд трёх последних релизов — унификация. PyTorch 2.10 заложил фундамент с cross-backend примитивами и формальной депрекацией TorchScript. PyTorch 2.11 добавил differentiable collectives для распределённого обучения, FlashAttention-4 на новых GPU и расширил покрытие torch.export. PyTorch 2.12 продолжает эту линию: unified graph capture, 100-кратное ускорение линейной алгебры, поддержка агрессивной квантизации и улучшения для AMD, Intel и Apple Silicon — всё в одном релизе.

Batched eigendecomposition: от минут до секунд

Самое заметное число в релизе — 100x. Batched symmetric eigendecomposition на CUDA стал в сто раз быстрее. Раньше PyTorch для linalg.eigh использовал backend MAGMA, который обрабатывал каждую матрицу в батче индивидуально. Для задач с сотнями или тысячами маленьких матриц это означало минуты ожидания, тогда как CuPy справлялся за секунды.

В 2.12 MAGMA депрецирован в пользу cuSolver, а диспетчеризация переписана так, что syevj_batched вызывается unconditionally — то есть PyTorch всегда использует batched kernel от NVIDIA, который обрабатывает множество матриц как единую GPU-операцию. Для scientific computing и ML-задач, где eigendecomposition batched-матриц — рутина, это меняет экономику экспериментов. Workloads, которые раньше занимали минуты, теперь укладываются в секунды. Разрыв с CuPy, который годами был болезненным аргументом в пользу перехода, закрыт.

Практический пример: в физическом симуляторе или дифференцируемом рендеринге batched eigendecomposition используется для диагонализации ковариационных матриц на каждом пикселе или частице. При тысяче частиц и 100 итерациях старая реализация могла съесть полтора часа GPU-времени. Новая — меньше минуты. Это не микрооптимизация, это изменение порядка.

torch.accelerator.Graph: один API для всех backend'ов

Вторая крупная новость — unified API для graph capture и replay. Раньше CUDA Graphs требовали backend-специфичного кода: torch.cuda.CUDAGraph для NVIDIA, torch.xpu.XPUGraph для Intel, и ничего готового для кастомных backend'ов. В 2.12 появился torch.accelerator.Graph — device-agnostic абстракция, которая через GraphImplInterface делегирует реализацию конкретному backend'у.

Что это значит на практике. Разработчик пишет один код для захвата и воспроизведения вычислительного графа, и он работает на CUDA, XPU и любом out-of-tree backend, который зарегистрировал свою реализацию. Параллельно добавлен метод is_capturing() для Stream, заменяющий device-специфичный is_current_stream_capturing. Это не просто удобство — это необходимость для фреймворков вроде Hugging Face Transformers или vLLM, которые поддерживают десятки конфигураций железа и не могут писать отдельные ветки для каждого vendor'а.

Особенно интересно для inference-сервисов. CUDA Graphs устраняют overhead launch'а ядер и дают детерминированную задержку — критично для real-time inference. Теперь тот же код можно запускать на Intel Data Center GPU Max сериях или кастомных AI-ускорителях без форка кодовой базы.

Microscaling quantization в torch.export

Третья важная фича — поддержка Microscaling (MX) форматов в torch.export.save и torch.export.load. MXFP4, MXFP6 и MXFP8 — это техники экстремального сжатия моделей, где веса хранятся в 4-, 6- или 8-битных форматах с shared block-scale exponent'ом. Они позволяют уменьшить размер LLM в 2–4 раза при минимальной потере качества, что критично для edge-деплоя и cost-constrained inference.

Проблема до 2.12 была в том, что dtype shared block-scale exponent'а не поддерживался сериализацией torch.export. Модели с MX-квантизацией нельзя было экспортировать через стандартный путь — приходилось обходиться костылями или отказываться от формата. В 2.12 этот dtype корректно сериализуется и десериализуется, разблокируя полный export-to-deployment workflow для aggressively compressed моделей. ARM, Qualcomm и другие edge-вендоры активно продвигают MXFP — теперь PyTorch их поддерживает end-to-end.

torch.cond в CUDA Graphs: control flow на GPU

Ещё одно изменение, которое кажется техническим, но открывает архитектурные возможности: torch.cond теперь можно захватывать внутри CUDA Graph. Раньше data-dependent control force'ил fallback на CPU для ветвления, что разрывало graph capture и ломало детерминизм. В 2.12 ветвления torch.cond исполняются полностью на GPU через conditional IF nodes CUDA 12.4 — в рамках единого graph capture без CPU fallback'ов.

Для динамических моделей, где поведение зависит от входных данных, это означает, что inference можно ускорить через CUDA Graphs без ограничения на статическую топологию. Агентные workflow'ы, tree-of-thought реализации, adaptive depth models — всё это получает прирост от graph capture, который раньше был недоступен.

Fused Adagrad и численная корректность на XPU

Adagrad стал четвёртым оптимизатором с поддержкой fused=True после Adam, AdamW и SGD. Весь шаг оптимизатора теперь выполняется в одном CUDA-ядре вместо отдельных launch'ей для каждой операции. Это снижает overhead launch'а и трафик памяти — особенно заметно на маленьких батчах, где kernel launch overhead доминирует.

Для Intel XPU добавлена FMA-based lowering операции addcdiv через Inductor. addcdiv — fused multiply-add с делением — лежит в основе Adam, AdamW и RMSprop. Раньше Inductor использовал отдельные multiply и divide инструкции, что давало rounding differences по сравнению с eager mode. На тысячах шагов обучения эти различия накапливались и делали невозможным точное воспроизведение результатов compiled vs eager. Теперь на Intel GPU bitwise parity с CUDA достигается автоматически — важно для воспроизводимости исследований и production validation.

ROCm: expandable segments, rocSHMEM и FP8 sparsity

AMD GPU получили три крупных улучшения. Expandable memory segments в caching allocator'е — динамическое расширение allocation'ов через virtual memory API, аналогично CUDA. Это снижает фрагментацию памяти и позволяет обучать большие модели без OOM, которые раньше падали из-за раздробленной памяти.

rocSHMEM support добавляет symmetric memory collectives на AMD: broadcast, all-to-all, 2D AllToAllv для MoE-моделей — всё то, что раньше было доступно только через NVSHMEM на NVIDIA. Портирование коллективных операций на ROCm снимает одно из главных препятствий для распределённого обучения на MI300X/MI350X.

hipSPARSELt включён по умолчанию на ROCm >= 7.12, добавляя semi-structured (2:4) sparsity с FP8 inputs на MI350X. Это тот же acceleration path через torch._cslt_sparse_mm, который ранее был CUDA-only. Для inference sparse моделей на AMD теперь нет penalty — parity с NVIDIA по функциональности.

FlexAttention на AMD получил двухстадийный pipelining в Triton backend'е — прирост 5–26% на MI350X для causal, alibi и sliding window паттернов. Изменение буквально в одну строку конфигурации, но эффект заметен на реальных workload'ах.

Apple Silicon: ahead-of-time Metal shader compilation

Для Apple Silicon бинарные wheel'ы теперь поставляются с предкомпилированными Metal-4 шейдерами, собранными на macOS 26. Это устраняет runtime shader compilation overhead на первом запуске — раньше первый inference прогрев мог занимать секунды, пока Metal компилировал шейдеры. Теперь cold start latency снижается до уровня warm start. Для MPS backend'а, который активно используется в ML на Mac, это заметное UX-улучшение.

TorchScript официально deprecated

Начиная с 2.10 TorchScript был помечен как deprecated, а в 2.12 команда подтвердила окончательный переход. torch.export заменяет jit.trace и jit.script для сериализации моделей, а ExecuTorch — для embedded runtime. Семь лет TorchScript был де-факто стандартом деплоя PyTorch-моделей в production, но его ограничения — статический typing, сложность отладки, плохая совместимость с dynamo — делали его всё более болезненным.

Переход на torch.export + ExecuTorch даёт динамические shapes, лучшую совместимость с Python control flow и единый путь от research до edge. Для команд, которые до сих пор используют TorchScript, 2.12 — сигнал начать миграцию: в 2.13+ поддержка может быть полностью удалена.

Что это значит для разработчиков

PyTorch 2.12 продолжает три тренда, которые определяют фреймворк в 2026 году. Первый — скорость на уровне примитивов. 100x на eigendecomposition, FMA parity на XPU, двухстадийный pipelining на ROCm — всё это делает PyTorch быстрее не через магию компилятора, а через оптимизацию конкретных операций, от которых зависят реальные workload'ы.

Второй — переносимость. Unified graph capture, поддержка MX-квантизации, rocSHMEM коллективы, Metal shader precompilation — всё это означает, что код, написанный на PyTorch, требует всё меньше vendor-специфичных адаптаций. Фреймворк становится тем, чем NumPy был для CPU: единым интерфейсом над разнородным железом.

Третий — production readiness. Deprecation TorchScript, полная поддержка torch.export, CUDA Graphs с control flow, expandable memory segments — всё это говорит о том, что PyTorch больше не «фреймворк для исследований, который можно натянуть на продакшен». Он становится фреймворком для продакшена, в котором удобно исследовать.

Часто задаваемые вопросы

Стоит ли обновляться с PyTorch 2.11?

Если вы используете batched eigendecomposition, CUDA Graphs, Intel XPU или AMD ROCm — однозначно да. Приросты измеряются в разах, а не процентах. Для стандартного CV/NLP на CUDA 13.0 обновление даёт менее драматичный, но всё же заметный прирост от fused Adagrad и graph capture improvements.

Что делать с legacy TorchScript моделями?

Начинайте миграцию на torch.export + ExecuTorch. torch.export поддерживает динамические shapes и большинство Python control flow, которые TorchScript ломал. Для edge-деплоя ExecuTorch предоставляет runtime, который по размеру и latency превосходит TorchScript на порядок.

Работает ли PyTorch 2.12 на старых GPU?

CUDA 12.6 wheel остаётся поддерживаемым для Pascal и Volta. CUDA 12.8 wheel deprecated. Для Blackwell и новее требуется CUDA 13.0+ wheel и драйвер >= 580.65.06. AMD MI300X и MI350X поддерживаются на ROCm >= 7.02.

Итог

PyTorch 2.12 — это релиз о зрелости. 100-кратное ускорение линейной алгебры, unified graph capture, поддержка экстремальной квантизации, полноценная поддержка AMD и Intel на parity с NVIDIA, и окончательный отказ от устаревшего TorchScript. 457 контрибьюторов и почти три тысячи коммитов направлены на одно: чтобы PyTorch работал быстро, одинаково и предсказуемо на любом железе. Если вы ещё на 2.10 или 2.11 — обновление стоит затраченного времени. Если вы на 1.x — пора.

← Все записи