PyTorch 2.15 принесёт на Mac FP8 и ускорит MoE-модели в 5-6,5 раза

Команда PyTorch в Hugging Face опубликовала пост о том, что получает бэкенд MPS (запуск вычислений на графическом процессоре Apple) в PyTorch 2.15. Авторы пишут, что к началу 2026 года даже небольшие модели на MPS часто приходилось запускать в обход неподдерживаемых операций, при провалах производительности и неожиданном росте памяти. Поэтому они гоняют реальные модели с Hugging Face Hub (языковые, изображения, видео), находят слабые места MPS и чинят их в самом PyTorch, всё чаще заменяя MPSGraph отдельными ядрами Metal. Работа сделана вместе с мейнтейнерами PyTorch и участниками сообщества.
Главное в релизе. Во-первых, FP8: на MPS появились тензоры torch.float8_e4m3fn, один байт на значение, то есть вдвое меньше места, чем у FP16 или BF16. Умножать их можно через F.scaled_mm, который поддерживает масштабирование и на весь тензор, и по строкам; в посте есть пример кода с одним масштабом на тензор.
Во-вторых, декодинг языковых моделей. Во время декодирования каждый новый токен идёт через модель одной строкой, и большие матричные умножения превращаются в матрично-векторные. Ядра GEMV для torch.mm есть с версии 2.14, но F.linear всё ещё шёл через MPSGraph; в 2.15 их подключили к F.linear, с объединением подходящих прибавок смещения. На 96 формах слоёв BF16 из реальных моделей это даёт среднее геометрическое ускорение 1,23 раза. Наибольший выигрыш, на небольших проекциях вроде гейтов MoE, а большие слои и LM-головы и так упирались в пропускную способность памяти и остаются около 1×.
Для слоёв смеси экспертов (MoE) добавлена нативная реализация grouped matmul: в 2.14 смещения групп копировались на CPU и по группам шёл цикл, теперь новые ядра Metal читают смещения прямо на GPU, а для мелких групп (типичный случай при декодинге) есть отдельное ядро. Итог по заголовочному замеру на M3 Ultra с torch.compile: MoE-модели декодируют в 5-6,5 раза быстрее, чем в 2.14. Qwen3.6-35B-A3B ускоряется с 9,4 до 61,3 токена в секунду, LFM2.5-8B-A1B, с 23,6 до 123,6. Плотные модели тоже выигрывают: softmax и log_softmax переведены на отдельные ядра Metal, и softmax по строке логитов [1, 128256] в FP32 занимает 7 мкс вместо 57 мкс, то есть примерно в 8 раз быстрее версии на MPSGraph.
В-третьих, линейная алгебра на GPU: LU-разложение, решение систем через LU и треугольные решения для complex64 (а с ними комплексные определители и градиенты), быстрое обращение батчей матриц FP32 до 4 × 4 одним ядром, блочные обновления в QR, отдельный быстрый путь для систем 16 × 16, 32 × 32 и 64 × 64 в FP32 (нужен Gated DeltaNet) и более устойчивый SVD на экстремальных значениях.
В-четвёртых, память при работе с видео. Декодирование VAE в Wan-AI/Wan2.2-TI2V-5B-Diffusers делает 8 764 вызова дополняющей операции (padding) за полный 28-плиточный проход; после переноса constant padding на Metal пик памяти драйвера падает примерно с 270 ГиБ до 8 ГиБ. Это же исправление лечит ошибку 2.14: энкодер VAE у Qwen-Image-2.1 на MPS молча портил изображения и ломал правку картинок (сообщение пришло из ComfyUI); теперь цикл «закодировать, декодировать» совпадает с CPU на уровне 29,95 дБ PSNR против прежних 10,06 дБ.
Кроме того: публичные потоки MPS в Python (torch.mps.Stream, контекст torch.mps.stream, Tensor.record_stream) и более надёжный замер времени по событиям; несколько новых операций на MPS (frexp, logspace, take, put_, heaviside, polynomial Лагерра, сравнения беззнаковых целых; logspace пока не умеет целые и булевы выходы длиннее одного элемента); исправлена корректность SDPA при вещании по батчу и головам. Требования: для MPS теперь нужна macOS 15 и новее, для PyTorch 2.15, Python 3.11 и новее, нужен Mac с чипом Apple. Установка в пост показана для выпуска-кандидата в отдельном окружении, команда: uv pip install torch==2.15.0 --index-url https://download.pytorch.org/whl/test/cpu.
На 2.16 авторы дают предварительный взгляд (часть изменений уже в основной ветке и ночных сборках, часть на ревью, детали могут измениться). Сборка командного буфера будет фиксироваться каждые 16 ядер, чтобы GPU начинал работу, пока CPU кодирует остальное. Scaled dot-product attention полностью уходит с MPSGraph на ядра Metal: на M5 Pro декодирование с групповым вниманием (32 головы запросов, 8 голов KV, размер головы 80, контекст 4K) сокращается с 465 до 65 мкс, а префилл 4K × 4K с размером головы 40, с 42 до 6 мс. Продолжается миграция с MPSGraph: MSE loss до 12 раз быстрее на малых входах, std_mean и var_mean до 4 раз, bincount для 4 млн целых, где большинство значений попадает в одну корзину, с 6,8 секунды до полумиллисекунды; batch norm в работе. Шейдеры по умолчанию будут собираться под Metal 3.1 (версии Metal 4, только для ядер, которым они нужны), что уменьшит libtorch_cpu.dylib примерно на 25%, с 384 до 287 МиБ. Текст источника обрывается на этом разделе.
Ключевые факты
- FP8 на Mac: тензоры torch.float8_e4m3fn на MPS занимают один байт на значение (вдвое меньше FP16/BF16) и умножаются через F.scaled_mm с масштабированием на тензор или по строкам.
- MoE-модели декодируют в 5-6,5 раза быстрее, чем в 2.14 (M3 Ultra, torch.compile): Qwen3.6-35B-A3B, с 9,4 до 61,3 токена/с, LFM2.5-8B-A1B, с 23,6 до 123,6; softmax по словарю в FP32 быстрее примерно в 8 раз (57 → 7 мкс).
- Пик памяти драйвера при декодировании VAE у Wan2.2-TI2V-5B падает с примерно 270 до 8 ГиБ; та же правка чинит порчу изображений в VAE Qwen-Image-2.1 (PSNR 29,95 дБ против 10,06 дБ).
- Требования: macOS 15+ и Python 3.11+ на Mac с чипом Apple; пост описывает выпуск-кандидат 2.15, а не финальный релиз.
- Превью 2.16: внимание целиком на Metal (на M5 Pro декодирование 465 → 65 мкс), миграция с MPSGraph, libtorch_cpu.dylib меньше примерно на 25%.
Почему это важно
Mac всё чаще используют для локального запуска моделей, а MPS, основной путь ускорения в PyTorch на чипах Apple. По словам авторов, ещё в начале 2026 года на нём приходилось обходить неподдерживаемые операции, провалы производительности и рост памяти. Релиз закрывает ряд таких мест: быстрый декодинг MoE-моделей, FP8, резкое сокращение памяти при декодировании видео и исправление порчи изображений в Qwen-Image-2.1. Заметен и общий курс: замена MPSGraph на собственные ядра Metal.
Кому это важно
Тем, кто запускает на Mac модели через transformers, diffusers или ComfyUI: владельцам Mac с чипами Apple, работающим с локальными LLM (особенно MoE), генерацией видео и правкой изображений. Также разработчикам, которым нужны публичные потоки MPS, комплексная линейная алгебра на GPU или FP8-веса. Разработчикам библиотек стоит учесть повышенные требования: macOS 15 и Python 3.11.
Как это применить
Выпуск-кандидат ставится в отдельном окружении: uv pip install torch==2.15.0 --index-url https://download.pytorch.org/whl/test/cpu. Для FP8 в посте есть пример: квантизация тензора в float8_e4m3fn с масштабом и умножение через F.scaled_mm. Для декодинга MoE в замерах использовался torch.compile. Если ОС слишком старая или нет GPU с Metal, проверка доступности MPS теперь сообщает причину. Часть изменений 2.16 уже доступна в ночных сборках.
Можно ли доверять
Источник, первоисточник: пост самой команды PyTorch в Hugging Face, то есть авторов описанных правок. Цифры приведены самими авторами и относятся к конкретным условиям: заголовочное ускорение 5-6,5 раза подкреплено в видимом тексте двумя моделями (Qwen3.6-35B-A3B и LFM2.5-8B-A1B) на M3 Ultra с torch.compile. Графики в доступном тексте отсутствуют, поэтому, с чем сравнивается ускорение примерно в 1,3 раза для ядра декодинга MoE, из текста не видно. Независимых замеров нет, а текст источника обрывается в разделе про 2.16.
Риски и подводные камни
Описан выпуск-кандидат, а не финальный релиз; даты выхода 2.15 и 2.16 в видимом тексте не названы. Цифры получены на M3 Ultra (декодинг) и M5 Pro (превью 2.16); на других чипах результат может отличаться. Большие слои и LM-головы остаются около 1×, так что выигрыш неравномерный. Новые требования (macOS 15 и новее, Python 3.11 и новее) отсекут старые системы. Логспейс (logspace) пока не поддерживает целые и булевы выходы длиннее одного элемента. Изменения 2.16 частично ещё на ревью, и детали могут измениться.