Основы алгоритмов
Профиль с низкой загрузкой часто ошибочно принимают за аппаратное ограничение, хотя причина алгоритмическая: форма умножения матриц, которая расточает тензорные ядра, раскладка, нарушающая непрерывность, или активации, которые удерживаются в памяти ради обратного распространения. Это приложение собирает модели вычислительной сложности и выводы об объеме занимаемой памяти, на которые опираются главы о производительности, и позволяет читателю оценивать алгоритмические компромиссы до того, как код будет передан ускорителям. Предполагается знакомство с линейной алгеброй и с железным законом, введенным в начале книги.
Как пользоваться этим приложением
Приложение задумано как справочник. Обращайтесь к нему, когда нужно перевести симптом профилировщика («медленное умножение матриц», «несовпадение форм», «нехватка памяти во время обучения») в конкретную причину: вычислительную или связанную с памятью.
Обозначения здесь следуют общекнижным соглашениям (например, зарезервировано за размером батча, а обозначает пропускную способность).
- Когда ядра обобщенного матричного умножения (GEMM) медленные: используйте раздел «Обобщенное матричное умножение (GEMM)» и сравните интенсивность с точкой перехода аппаратуры.
- Когда память взрывается при обучении: используйте раздел «Истинная стоимость памяти обучения» и разложение памяти обучения.
- Когда тензорный код «должен работать», но не работает: используйте разделы «Формы и страйды» и «Broadcasting».
- Когда разреженность предлагают как исправление: используйте раздел «Форматы разреженных матриц», чтобы проверить плотность и накладные расходы метаданных.
- Когда нужно доказать границы вычислений градиента: используйте теорему Баура–Штрассена о сложности автоматического дифференцирования в обратном режиме (AD) из раздела «Теорема Баура–Штрассена о сложности обратного режима AD».
- Когда анализируется узкое место по длине последовательности: используйте раздел «Доказательство тайлинга FlashAttention и рекуррентности online softmax» — рекуррентность online softmax и сокращение обращений к памяти с высокой пропускной способностью (HBM) в FlashAttention.
- Когда распределяют вычисления между параметрами и токенами: используйте раздел «Вывод закона масштабирования Каплана и Chinchilla с оптимальным расходом вычислений».
Нейронные сети превращают линейную алгебру в выученное поведение: матрицы преобразуют активации, раскладки тензоров определяют, как данные перемещаются по памяти, а обратное распространение проводит сигналы ошибки через получившиеся вычисления. Эти основы поддерживают трактовку глубокого обучения в главе «Вычисления в нейронных сетях», внутреннее устройство фреймворков в главе «Фреймворки машинного обучения» и стратегии обучения в главе «Обучение моделей». Архитектуры меняются, но лежащий в основе математический аппарат остается неизменным.
Линейная алгебра
Системы глубокого обучения по своей сути — машины для преобразования огромных матриц. Фреймворки вроде PyTorch скрывают сырую математику, но инженерия производительности по-прежнему зависит от лежащей в основе линейной алгебры. Раздел «Численные представления» описал, как числа хранятся; этот раздел посвящен тому, как с ними работают.
Почему это важно
Многие плотные нейронные сети, особенно трансформеры и большие сверточные сети, тратят большую часть вычислений на матричные умножения или ядра, похожие на GEMM. Блок самовнимания выполняет GEMM для проекций Q, K, V и выхода плюс два матричных умножения внимания: одно для оценок внимания и одно для значений, взвешенных вниманием. Блок прямого распространения слоя добавляет еще GEMM. Понимание характеристик производительности GEMM объясняет, почему размер батча влияет на пропускную способность, почему одни размеры слоев «лучше» других и как читать вывод профилировщика. Рассуждение о размерах матриц и арифметической интенсивности предсказывает, будет ли плотная нагрузка ограничена вычислениями или памятью, еще до того, как запускается какая-либо трасса профилировщика.
Тензорные операции и обозначения
Нотация суммирования Эйнштейна1 делает сложные операции явными на протяжении всей книги (реализована как torch.einsum в PyTorch и np.einsum в NumPy). Матричное умножение записывается так:
В нотации einsum это записывается как ik,kj->ij. Нотация естественно распространяется на многомерные операции в механизмах внимания. Например, батчевое многоголовое внимание записывается как bhid,bhjd->bhij (батч , голова , индекс запроса , индекс ключа и размерность головы ).
Раскладки памяти и производительность
Раскладка данных в памяти (построчная или поколоночная) напрямую влияет на эффективность кэша. При обходе матрицы доступ к непрерывным ячейкам памяти заметно быстрее, чем доступ с шагом.
Типичный прием — однократно материализовать транспонированный тензор перед серией операций, чтобы обеспечить непрерывный доступ в горячем цикле. Одноразовая стоимость копирования распределяется на множество последующих операций.
Скалярное произведение как мера сходства
Скалярное произведение геометрически эквивалентно , что делает его естественной мерой сходства двух векторов: для ненулевых векторов знак различает острые, прямые и тупые углы, а величина зависит и от норм обоих векторов.
Эта геометрическая интерпретация объясняет, почему скалярные произведения встречаются повсюду в современных архитектурах. В механизмах внимания векторы запроса () и ключа () перемножаются скалярно, чтобы получить оценку сходства, которая определяет, насколько каждый токен обращает внимание на каждый другой. Полученные веса внимания затем образуют взвешенную комбинацию векторов значений () — так скалярное произведение становится основой способности трансформера моделировать дальние зависимости.
Обобщенное матричное умножение (GEMM)
GEMM2 — рабочая лошадка глубокого обучения. Для матриц размера и GEMM выполняет операций с плавающей запятой (операция «умножить и накопить» считается как две операции).
Арифметическая интенсивность GEMM линейно растет с размером матрицы. Для квадратных матриц в FP16 (2 байта на элемент) идеальная граница при читает и один раз и записывает один раз:
Чтение старой при меняет интенсивность на FLOP/байт. Исполнение GEMM определяют три системных следствия:
- Большие батчи могут повысить эффективность: батчинг увеличивает эффективные размеры матриц, когда формирует более крупные GEMM или позволяет повторное использование; простая постановка в очередь независимых мелких GEMM интенсивность не повышает.
- Выровненные размеры помогают: тензорные ядра аппаратуры оптимизированы под кратные плитки, специфичные для точности и архитектуры. Размеры, выровненные по этим кратным, избегают накладных расходов на дополнение и улучшают эффективность ядра, но не обязаны быть степенями двойки.
- Малые матрицы неэффективны: квадратный GEMM с 64 имеет интенсивность 64/3 ≈ 21,3 FLOP/байт, что заметно ниже точки перехода (153,0 FLOP/байт). Его потолок Roofline составляет около 13,9 процента пика; накладные расходы запуска и тайлинга могут снизить реально достижимую пропускную способность.
Форматы разреженных матриц
Когда большинство элементов матрицы равны нулю, специализированные форматы хранения не тратят память на нули и позволяют вычисления, которые полностью их пропускают. Формат сжатого разреженного строчного хранения (CSR) использует три массива:
Values: ненулевые элементы, хранящиеся по строкамCol_Idx: индекс столбца каждого ненулевого элементаRow_Ptr: начальная позиция вValuesдля каждой строки (длина = число строк + 1)
CSR полезен для разреженных матриц признаков в конвейерах рекомендаций и для прореженных весов моделей. Для матрицы с элементами, строками и ненулевыми элементами CSR использует памяти вместо ; когда велико относительно , это часто суммируют как .
Чтобы конкретно увидеть компромисс, рассмотрим матрицу эмбеддингов словаря со 100 000 строк и 10 000 столбцов (1 млрд параметров):
- Плотная (FP32): 1 млрд параметров 4 байта каждый = 4 ГБ.
- Разреженная (плотность 1 процент): CSR хранит примерно 10 млн записей (4-байтовое значение + 4-байтовый индекс столбца), плюс один указатель строки на строку и финальный указатель, итого ≈ 80,4 МБ.
- Результат: снижение объема памяти в 50 раз, что позволяет разместить модель, которая иначе вызвала бы нехватку памяти (OOM).
Линейная алгебра говорит нам, что вычислять; следующий вопрос — как выразить эти вычисления в коде. Примитивы тензорного программирования — формы, страйды и broadcasting — соединяют математическую нотацию с операциями над массивами, которые реально исполняются на аппаратуре.
Примитивы тензорного программирования
Падение из-за несовпадения форм, молча неверный broadcast, ядро, работающее на 5 процентах пика из-за прерывистого (non-contiguous) тензора, — все эти распространенные сбои инженерии ML восходят к одному и тому же слою абстракции. Тензорное программирование переводит абстрактную математику линейной алгебры в конкретные манипуляции с массивами, которые исполняются на аппаратуре.
Шпаргалка по вычислительной сложности
«Базовые тензорные примитивы глубокого обучения» дает количественный справочник по самым распространенным строительным блокам. Используйте эти формулы для прикидочной оценки размера модели и требований к вычислениям до того, как будет выделена аппаратура. Зная размеры слоев и формы входов, формулы дают первоприближенные оценки параметров и вычислений. Строка внимания содержит ключевое предупреждение: длина последовательности добавляет член , а скрытая размерность — работу проекций , поэтому модели с длинным контекстом могут сместить доминирующую стоимость без изменения числа параметров.
| Тип слоя | Форма выхода | Параметры () | FLOP (на прямой проход) |
|---|---|---|---|
| Linear | , если включено смещение | ||
| Conv2D | , если включено смещение | ||
| Многоголовое самовнимание | , плюс , если включены смещения проекций | ||
| LayerNorm | , если включены масштаб и смещение |
Базовые тензорные примитивы глубокого обучения: сводка форм, параметров и числа FLOP. Обозначения: — размер батча, — длина последовательности, — размер ядра. Вычисления внимания включают проекции QKV и взаимодействия оценок. Член относится к обучению на полной последовательности и предзаполнению, тогда как генерация с KV-кэшем линейна по кэшированному контексту на каждый токен; при больших скрытых размерностях доминирует работа проекций .
Формы и страйды
Тензор — это представление поверх буфера хранения, описываемое метаданными формы, страйда, типа данных и смещения. Только непрерывные (contiguous) тензоры располагают свои логические элементы одним смежным блоком.
- Форма: размерности тензора (например,
(3, 4)). - Страйд: число элементов, которое нужно пропустить в памяти, чтобы перейти к следующему элементу по данной размерности.
Операции вроде transpose() или view() часто меняют только страйды, а не данные в памяти. Это быстро (), но приводит к прерывистым тензорам, которые падают в ядрах, требующих непрерывных данных. В таких случаях вызов contiguous() принудительно копирует память за , и это может доминировать во времени исполнения, если повторно вызывается внутри цикла.
Broadcasting
Broadcasting позволяет выполнять арифметические операции над тензорами разных форм. Сравнивайте размерности от последней к первой. Две размерности совместимы, когда:
- они равны;
- одна из них равна 1.
Размерность единичного размера «растягивается», чтобы совпасть с другой, как показано на рисунке «Правила broadcasting тензоров». Это растяжение виртуальное: данные в памяти не копируются. Вместо этого страйд для такой размерности задается равным 0, так что аппаратура многократно читает одно и то же значение с накладными расходами памяти .
Правила broadcasting тензоров: столбец (3,1) и строка (1,4) растягиваются по взаимодополняющим размерностям и дают попарные суммы в результате формы (3,4).
Рассмотрим конкретный случай: тензор A имеет форму (32, 1, 64), а тензор B — форму (1, 128, 64). Сравнивая размерности справа налево, видим: 64 совпадает с 64, затем 1 растягивается до 128, затем 1 растягивается до 32, и получается форма результата (32, 128, 64). Визуализация такого расширения предотвращает незаметные логические ошибки, которые случайно выделяют большой тензор (например, матрицу (Batch, Batch) вместо поэлементного вектора (Batch)).
Формы, страйды и broadcasting управляют тем, как тензоры проходят через прямой проход модели. Обучение добавляет второе требование: учиться на ошибках. Обратное распространение делает такое обучение возможным и накладывает стоимость памяти, которую разберем ниже.
Механика обучения
Корректные тензорные программы делают возможными циклы обучения. Обратное распространение организует эти тензоры, чтобы вычислить градиенты и превратить прямое предсказание в обратный сигнал обучения.
Почему это важно
Когда обучение отказывает — функция потерь уходит в NaN, градиенты взрываются или заканчивается память, — понимание того, что на самом деле делает обратное распространение, необходимо для диагностики. Обратный граф дает ментальную модель для рассуждения о потоке градиентов и использовании памяти во время обучения.
Правило цепочки и автоматическое дифференцирование
Для составной функции производная равна . В нейронной сети и — слои, а композиция может быть многоуровневой. Для трехслойной сети правило цепочки дает:
Каждый множитель этого произведения — локальная производная, вычисленная на одном слое только по входам и выходам этого слоя. Именно эта локальность делает алгоритм практичным: всю сеть не нужно дифференцировать как монолитную функцию. Вместо этого каждый слой на обратном проходе вычисляет свою локальную производную и умножает ее на градиент, пришедший от слоя выше.
Современные фреймворки используют автоматическое дифференцирование в обратном режиме, которое вычисляет градиенты для всех параметров за один обратный проход. Ключевая идея: начиная с выхода и двигаясь назад (обратный режим), требуется один проход независимо от числа параметров, тогда как начиная с каждого входа и двигаясь вперед (прямой режим), понадобилось бы проходов — по одному на параметр. Поэтому шаг обучения — это небольшое постоянное кратное вывода: обычно примерно в 2–3 раза дороже прямого прохода для плотных сетей, а не проходов.
Алгоритм обратного распространения
Обратное распространение3 эффективно реализует правило цепочки в два прохода: прямой — для вычисления выходов, обратный — для вычисления градиентов. «Вычислительный граф обратного распространения» иллюстрирует этот процесс для простой двуслойной сети: прямой проход (серые стрелки) вычисляет выходы, а обратный (красные пунктирные стрелки) распространяет градиенты.
Вычислительный граф обратного распространения: сплошные серые стрелки несут прямые вычисления от входа к функции потерь , а пунктирные красные стрелки несут градиенты назад по тем же зависимостям.
Градиентные ребра повторяют прямые зависимости, поэтому каждый обратный шаг требует значений, сохраненных от соответствующей прямой операции.
Прямой проход
Используя активации в виде строковых векторов, опуская смещения и сохраняя промежуточные активации для обратного прохода, начнем с — входа. Умножим его на , чтобы получить скрытую активацию . Сохраним , потому что обратный проход понадобится позже. Умножим на , чтобы получить выход . Сохраним . Сравним с целевой меткой, чтобы вычислить функцию потерь .
К этому моменту потери вычислены, и в памяти содержатся вход , сохраненная активация , сохраненный выход и потери . Для большой модели эти сохраненные активации могут доминировать в использовании памяти.
Обратный проход
Теперь пойдем назад от . Функция потерь дает — градиент потерь по предсказанию. Здесь в сеть входит сигнал ошибки.
Поскольку , правило цепочки дает два градиента на этом слое:
Вычисление требует сохраненной активации из прямого прохода. Активации должны оставаться доступными на обратном проходе, потому что градиент весов каждого слоя зависит от входа этого слоя.
Теперь продолжим назад к первому слою. Поскольку , тот же паттерн дает:
Каждый шаг назад требует две вещи: градиент, пришедший сверху , и вход этого слоя (), который должен быть доступен на обратном проходе. Поэтому обратный проход стоит примерно в 2 раза больше прямого по вычислениям: на каждом слое он выполняет два матричных умножения (одно для градиента весов, одно для градиента входа) против одного на прямом проходе.
Истинная стоимость памяти обучения
Распространенная ошибка — считать, что память обучения равна размеру модели. Это предположение ведет к немедленным ошибкам нехватки памяти (OOM), потому что веса — лишь один из четырех компонентов. Память обучения включает веса, градиенты, состояние оптимизатора и сохраненные активации:
Для стандартного оптимизатора Adaptive Moment Estimation (Adam) (Kingma and Ba, 2015) в смешанной точности (Micikevicius et al., 2017):
- Веса: 2 байта (FP16/BF16) или 4 байта (FP32).
- Градиенты: того же размера, что и веса.
- Состояние оптимизатора: моменты Adam требуют 8 байт на параметр; мастер-копия в FP32 добавляет еще 4 байта, итого 8–12 байт на параметр.
- Активации: главный «гигант». Оценка, дружественная к пересчету или тайловому вниманию, масштабируется как ; полная реализация внимания без пересчета дополнительно материализует тензоры оценок внимания, которые масштабируются с .
Чтобы увидеть, как эти компоненты взаимодействуют на практике, рассмотрим конкретную модель.
Разобранный пример: память обучения GPT-2 (1,5 млрд)
Модель: GPT-2 XL имеет параметров, 48 слоев и скрытую размерность .
Состояние модели (фиксировано на шаг):
- Веса (BF16): 2 байта = 3 ГБ
- Градиенты (BF16): 2 байта = 3 ГБ
- Оптимизатор (мастер FP32 + моменты + дисперсия): 12 байт = 18 ГБ
- Итого состояние модели: 24 ГБ — помещается на ускорителе класса 80 ГБ A100/H100 (85,9 ГБ в десятичных единицах), но оставляет лишь 61,9 ГБ под активации.
Активации (масштабируются с батчем):
Сохраняемые активации слоя для этой быстрой оценки примерно равны элементам BF16, то есть байт, где — размер батча, а — длина последовательности. Множитель двенадцать учитывает основные промежуточные тензоры, сохраняемые для обратного распространения: входные активации, проекции QKV (), выход внимания, промежуточный слой FFN () и маски layer norm/dropout. Оценка предполагает, что реализация не сохраняет полный тензор оценок внимания , как в учете, дружественном к пересчету или тайловому вниманию. При 48 слоях, размере батча 8 и длине последовательности 1024:
Системный вывод: около 39,1 ГБ при этом соглашении учета активаций, что помещается на одном ускорителе 85,9 ГБ. Однако если увеличить батч до 64, активации вырастут примерно до 120,8 ГБ, что превышает оставшуюся емкость. Это порог, за которым становится необходимой контрольная точка градиента или другой метод экономии памяти; ее выигрыш и накладные расходы на пересчет зависят от размещения контрольных точек и реализации.
Взрыв активаций
Пока веса фиксированы (), активации растут линейно с размером батча и как минимум линейно с длиной последовательности; реализации, которые материализуют оценки внимания, добавляют компонент . Как показывает разобранный пример, память активаций может быстро превысить запас, оставшийся после состояния модели. Контрольная точка градиента4 снижает это давление, сохраняя лишь выбранные активации и пересчитывая остальные на обратном проходе (Chen et al., 2016); такие приемы, как FlashAttention, устраняют связанные узкие места памяти внимания тайлингом, сокращая обращения к памяти (Dao et al., 2022).
Та же декомпозиция дает быструю проверку осуществимости: сложите состояние модели по параметрам, добавьте член активаций, подразумеваемый размером батча и длиной последовательности, и сравните итог с емкостью ускорителя.
Вычислительные графы и оптимизация
Структура зависимостей, которую раскрывает обратное распространение, дает компиляторам что оптимизировать. Компиляторы машинного обучения представляют модели ориентированными ациклическими графами (DAG), и это представление позволяет аппаратно-независимые преобразования.
Статическое единственное присваивание
Компиляторы преобразуют графы в форму статического единственного присваивания (SSA), где каждой переменной присваивается значение ровно один раз. Это делает зависимости по данным явными и позволяет безопасные оптимизации — главным образом слияние операторов (operator fusion).
Слияние операторов
Без слияния каждая операция в цепочке вроде MatMul → Add (смещение) → ReLU порождает промежуточный тензор, который записывается в HBM и затем читается обратно для следующей операции. Для поэлементных операций вроде Add и ReLU вычисления тривиальны (один FLOP на элемент), но трафик памяти — нет (прочитать тензор и записать обратно). Поэтому арифметическая интенсивность несливаемых поэлементных операций близка к нулю — они глубоко ограничены памятью.
Слияние объединяет последовательные операции в одно ядро, которое читает вход один раз, применяет все операции в регистрах или общей памяти и записывает конечный результат один раз. Для последовательности из поэлементных операций над тензором размером байт слияние сокращает трафик памяти с байт (каждая операция читает и записывает) до байт (одно чтение, одна запись) — сокращение в раз.
FlashAttention — тайловый алгоритм внимания, учитывающий ввод-вывод: он вычисляет стадии оценок, softmax и произведения на значения в тайлах SRAM, не материализуя полную матрицу внимания в HBM, и снижает трафик HBM и вспомогательную память внимания с до . В исходной работе сообщается об ускорении реального времени до 3 раз на оцениваемых нагрузках (Dao et al., 2022); реальный выигрыш зависит от форм и аппаратуры (пошаговый вывод см. в разделе «Доказательство тайлинга FlashAttention и рекуррентности online softmax»). Вместе основы линейной алгебры, механика тензорного программирования и модель памяти обучения, разобранные в этом приложении, образуют алгоритмический субстрат, на котором строятся все ML-системы.
Теорема Баура–Штрассена о сложности AD в обратном режиме
Современное глубокое обучение масштабируется до сотен миллиардов параметров потому, что вычисление полного вектора градиента скалярной функции потерь требует вычислений, пропорциональных вычислению самой , с границей, которая имеет постоянный коэффициент и не зависит от входной размерности . Баур и Штрассен доказали этот результат о сложности в 1983 году (Baur and Strassen, 1983).
Математическая постановка и формулировка теоремы
Пусть — многомерная скалярная функция, представленная вычислительным графом , состоящим из элементарных операций (сложения, вычитания, умножения, деления и унарных функций вроде ).
Теорема сложности Баура–Штрассена
Если скалярную функцию можно вычислить за элементарных операций, то полный вектор градиента можно вычислить суммарной работой , удовлетворяющей условию: где — универсальная константа, не зависящая от входной размерности . Кроме того, один лишь обратный проход требует работы .
Пошаговое доказательство распространения сопряженных величин по правилу цепочки
Пусть граф топологически упорядочен, узлы , , где входные переменные — при , а конечный выход — . Каждый промежуточный узел вычисляется примитивной операцией:
Определим сопряженную переменную для каждого узла как частную производную скалярного выхода по :
По многомерному правилу цепочки сопряженная величина — сумма частных производных, распространенных от всех последующих узлов (потомков), которые используют :
Автоматическое дифференцирование в обратном режиме задает и для всех , затем проходит узлы в обратном топологическом порядке от до . Для каждого примитивного узла полностью накопленная сопряженная величина передает сигналы ошибки родительским узлам ():
Теперь выполним пооперационный учет микростоимости для всех примитивных узлов, чтобы ограничить работу обратного прохода:
- Сложение/вычитание ():
- Локальные производные: , .
- Обратные обновления: и .
- Стоимость: 2 сложения на обратном проходе на 1 прямую операцию. Отношение работы: .
- Умножение ():
- Локальные производные: , .
- Обратные обновления: и .
- Стоимость: 2 умножения + 2 сложения = 4 операции на обратном проходе на 1 прямую операцию. Отношение работы: .
- Деление ():
- Локальные производные: , .
- Обратные обновления: и .
- Стоимость: 2 умножения/деления + 2 сложения = 4 операции на обратном проходе на 1 прямую операцию. Отношение работы: .
- Унарные трансцендентные операции ():
- Локальная производная: .
- Обратное обновление: .
- Для имеем , что требует 1 умножения + 1 сложения = 2 операции.
- Для имеем , что требует 1 деления + 1 сложения = 2 операции.
Суммируя по всем примитивным узлам , каждая прямая операция порождает не более 4 обратных операций:
Добавив работу прямого прохода , получаем полную границу работы:
Почему можно обучать большие языковые модели на 175 млрд параметров
Независимость от входной размерности — математическая причина, по которой глубокое обучение работает. Рассмотрим обучение трансформера с параметров:
- Прямой проход: матричные умножения требуют FLOP на токен.
- Обратный проход в обратном режиме: вычисляются градиенты весов ( FLOP) и градиенты входных активаций ( FLOP), итого FLOP на токен.
- Полная работа обучения: (прямой) (обратный) FLOP на токен. Коэффициент вычислений обратного прохода равен ровно , что заметно ниже теоретической границы Баура–Штрассена .
Если бы для вычисления использовали прямой режим AD или конечные разности, каждую частную производную пришлось бы вычислять отдельно, и понадобилось бы прямых проходов: FLOP. При такой метод потребовал бы около FLOP на токен — в раз больше работы прямого прохода и, следовательно, непомерно дорого в таком масштабе. Автоматическое дифференцирование в обратном режиме сводит этот множитель к постоянному коэффициенту 2 для учета плотных слоев выше.
Доказательство тайлинга FlashAttention и рекуррентности online softmax
Стандартное самовнимание в трансформерах требует материализовать матрицу оценок внимания в HBM, что создает узкое место пропускной способности памяти . FlashAttention (Dao et al., 2022) устраняет это узкое место: он разбивает матрицы запросов, ключей и значений на тайлы и пересчитывает внимание с помощью рекуррентности online softmax, не записывая промежуточные оценки в HBM.
Узкое место ввода-вывода HBM у стандартного softmax
Пусть даны запросы , ключи и значения при длине последовательности и размерности головы . Стандартное внимание вычисляет:
Чтобы избежать численного переполнения, построчный softmax вычитает максимум строки :
Стандартные реализации на GPU выполняют это в три отдельных запуска ядер:
- Вычислить в SRAM, затем записать в HBM ( записей).
- Прочитать из HBM, вычислить максимум строки и сумму строки , вычислить , записать в HBM ( чтений и записей).
- Прочитать и из HBM, вычислить , записать в HBM ( чтений и записей).
Полный трафик памяти HBM составляет элементов. Для , в FP16 матрица требует на голову на слой. Поскольку современные GPU обладают огромной вычислительной пропускной способностью по сравнению с пропускной способностью HBM, многократное чтение и запись промежуточных матриц и оставляет исполнительные блоки GPU ограниченными памятью.
Доказательство рекуррентности online softmax
Тайлинг softmax труден, потому что вычисление требует глобального максимума по всем ключам. Рекуррентность online softmax решает эту задачу, инкрементально обновляя статистики нормировки по мере поступления подблоков.
Теорема о рекуррентности online softmax
Пусть вектор разбит на два подвектора и , . Локальные статистики блока 1: и блока 2:
Тогда объединенный максимум , сумма нормировки и накопленный выходной вектор удовлетворяют точным соотношениям рекуррентности: где — частичный выход, накопленный из блока 1.
Вывод рекуррентности знаменателя
Раскроем объединенную сумму :
Вывод рекуррентности перемасштабирования выхода
Истинный нормированный выход по объединенной последовательности равен :
Поскольку , подставляем это напрямую:
Формальное доказательство сложности обращений к HBM
Пусть — емкость быстрой памяти SRAM (в словах). Следуя алгоритму 1 из работы Dao et al. (2022), FlashAttention задает и . Доказательство отвлекается от постоянных множителей и повторного использования буферов, используя , и для рабочего набора на кристалле.
Алгоритм выполняет два вложенных цикла:
- Разбить на блоков размера .
- Разбить на блоков размера .
- Внешний цикл по : загрузить и в SRAM.
- Внутренний цикл по : загрузить , и его статистики softmax; вычислить в SRAM; затем обновить и записать и статистики, не материализуя в HBM.
Именно этот порядок циклов дает сокращение ввода-вывода. Тайл «ключ–значение» остается в памяти, пока алгоритм обходит все тайлы запросов, поэтому каждый элемент и пересекает границу HBM один раз. Тайлы запросов и выходов приходится перечитывать для каждого блока ключей и значений, но тайл оценок потребляется на кристалле и отбрасывается. Стандартное внимание, напротив, записывает и заново читает полные матрицы оценок и вероятностей размера .
Учет полного обращения к памяти
- Чтения ключей и значений: каждый элемент и загружается один раз, давая обращений.
- Проходы по запросам, выходам и статистикам: каждый из блоков столбцов читает весь , читает и записывает и обновляет статистик softmax. Матрицы доминируют над статистиками при размерности головы , поэтому каждый проход дает обращений, а все проходы — .
Поскольку , полный объем равен где последнее равенство выполняется при .
Граница учитывает коммуникацию, а не арифметику. FlashAttention по-прежнему вычисляет те же плотные блоки оценок и может пересчитывать промежуточные величины при обратном распространении; его преимущество возникает из-за того, что эти промежуточные величины не выходят за пределы HBM.
Коэффициент сокращения ввода-вывода
Сравнивая ввод-вывод стандартного внимания и FlashAttention:
Сокращение ввода-вывода на A100
Асимптотическое отношение предсказывает, как большая емкость SRAM может снизить трафик HBM, но скрытые константы и детали ядер не позволяют использовать его как точный подсчет переносов. В измерении на NVIDIA A100 Dao et al. (2022) приводят эффект для нагрузки внимания в прямом и обратном проходах с длиной последовательности 1024, размерностью головы 64, 16 головами, размером батча 64, маской заполнения ключей и без dropout:
- Стандартное внимание: 35,3 ГБ чтений и записей HBM; время выполнения 35,1 мс.
- FlashAttention: 4,4 ГБ чтений и записей HBM; время выполнения 11,7 мс.
Измерения показывают системное следствие ограничения по вводу-выводу: существенно меньший трафик HBM совпадает с меньшим временем выполнения, хотя FlashAttention выполняет дополнительный пересчет. Они не означают, что каждая конфигурация становится ограниченной вычислениями; реальный режим определяют размер тайла, длина последовательности и реализация ядра.
Вывод законов масштабирования Каплана и Chinchilla с оптимальным расходом вычислений
Определение оптимального по вычислениям распределения между параметрами модели и обучающими токенами набора данных при заданном бюджете операций с плавающей запятой — центральное решение при проектировании систем больших языковых моделей. Этот раздел дает строгий математический вывод законов масштабирования с оптимальным расходом вычислений методом множителей Лагранжа и сопоставляет первоначальные результаты Kaplan et al. (2020) с поправками Hoffmann et al. (2022).
Постановка параметрической поверхности потерь
Перекрестная энтропия на оценочной выборке для авторегрессионной трансформерной языковой модели, обученной с параметрами без учета эмбеддингов на токенах, моделируется степенной зависимостью: где:
- : неустранимая потеря, отражающая энтропию данных естественного языка.
- : потеря из-за узкого места емкости, возникающая из-за конечного числа параметров .
- : потеря из-за узкого места размера набора данных, возникающая из-за конечного числа обучающих токенов .
- : эмпирические константы масштабирования.
- : показатели степенного масштабирования для размера модели и размера набора данных соответственно.
Условная оптимизация методом множителей Лагранжа
Полное число операций с плавающей запятой, необходимых для обучения трансформера с параметрами без учета эмбеддингов на токенах, задается формулой:
где учитывает прямой проход, а — обратный.
При заданном бюджете обучения сформулируем задачу условной оптимизации: минимизировать устранимую потерю :
Построим функцию Лагранжа :
Берем частные производные по , и и приравниваем их нулю:
Умножим уравнение (1) на , а уравнение (2) на :
Приравнивая эти выражения, получаем фундаментальное условие оптимальности степенного типа:
Это условие показывает, что в точке оптимального по вычислениям распределения предельное снижение потерь на относительный прирост числа параметров должно равняться предельному снижению потерь на относительный прирост числа токенов набора данных.
Аналитический вывод оптимальных по вычислениям показателей
Из выражаем через :
Подставляем в ограничение по вычислениям :
Явно выражаем оптимальное по вычислениям число параметров :
По симметрии находим оптимальное по вычислениям число токенов :
Эмпирические показатели и правило D/N ≈ 20
Подгоняя параметрическую поверхность потерь под более чем 400 экспериментальных запусков, Hoffmann et al. (2022) оценили и . Подстановка этих значений дает показатели, близкие к результату параметрической модели в статье:
Таким образом, параметрическая модель предсказывает:
Два прямых эмпирических подхода в статье дают почти сбалансированные показатели и , на которых основано распространенное сокращение через квадратный корень. Однако при параметрической подгонке отношение растет медленно с вычислениями, а не остается строго постоянным. В изученном режиме примерно 20 обучающих токенов на параметр — полезная эвристика Chinchilla, а не универсальный инвариант.
Масштабирование Каплана и Chinchilla
Различие между Kaplan et al. (2020) и Hoffmann et al. (2022) показывает, как выбор гиперпараметров в эмпирическом бенчмаркинге может менять выводы о проектировании систем:
- Kaplan et al. (2020) оценили и , предсказав и . Это подтолкнуло область к агрессивному росту размеров моделей при относительно небольших наборах обучающих данных (например, GPT-3 с 175 млрд параметров обучили на 300 млрд токенов, что дает ).
- Методологическое различие: Kaplan et al. (2020) использовали фиксированный бюджет токенов и расписание скорости обучения для всех моделей. Hoffmann et al. (2022) подобрали расписание под каждый горизонт обучения и обнаружили, что прежняя постановка занижала ценность обучения меньших моделей на большем объеме данных.
- Hoffmann et al. (2022) обнаружили почти сбалансированное масштабирование параметров и токенов: их три подхода дают пары показателей , и , а не одно точное универсальное отношение.
- Практическое влияние: Chinchilla (70 млрд параметров, обученных на 1,4 трлн токенов, ) превзошла GPT-3 (175 млрд параметров, обученных на 300 млрд токенов) на последующих бенчмарках, требуя при выводе в 2,5 раза меньше вычислений и при той же точности — в 2,5 раза меньше памяти весов (Hoffmann et al., 2022).
Итоги
Алгоритм становится системной нагрузкой через свои формы, граф операций, зависимости по данным и численное представление. Примитивы линейной алгебры, раскладки памяти, broadcasting и разреженные форматы определяют работу, трафик, локальность и доступный параллелизм. Автоматическое дифференцирование и обратное распространение добавляют сохраненные активации и вычисления обратного прохода; вычислительные графы затем открывают возможности слияния и пересчета. Результат Баура–Штрассена ограничивает накладные расходы обратного режима, а FlashAttention показывает, как тайлинг и рекуррентность online позволяют сокращать трафик HBM без изменения семантики внимания.
Тот же учет связывает ядра с решениями о масштабировании. Масштабирование с оптимальным расходом вычислений превращает фиксированный бюджет в распределение между моделью и данными, но подогнанные показатели остаются эмпирическими, а не универсальными. Для всех этих моделей повторно используемый метод — выявить операции, байты, сохраненное состояние, зависимости и асимптотические ограничения, прежде чем выбирать оптимизацию.
-
Соглашение о суммировании Эйнштейна: повторяющиеся индексы в произведении неявно суммируются, поэтому явные знаки суммирования не нужны. Фреймворки машинного обучения приняли это соглашение, потому что оно кратко выражает произвольные свертки тензоров одной строкой. ↩
-
Обобщенное матричное умножение (GEMM): семейство BLAS (Basic Linear Algebra Subprograms) началось с векторных подпрограмм, стандартизованных в 1979 году (Lawson et al., 1979); GEMM позднее была стандартизована как подпрограмма уровня 3 (Dongarra et al., 1988). Приставка «GE» означает «general» — в противоположность симметричным или треугольным формам. GEMM вычисляет и является критичной для производительности подпрограммой в глубоком обучении. «Матричные операции» объясняет, как формы GEMM определяют пропускную способность обучения. ↩
-
Обратное распространение: сокращение от «обратное распространение ошибки». Алгоритм независимо открывали несколько раз: Вербос (Werbos, 1974) и Линнаинмаа (Linnainmaa, 1970) — для дифференцирования в обратном режиме, а Румельхарт и соавторы (Rumelhart et al., 1986) — для обучения нейронных сетей. Его ключевая идея: вычисление градиентов для всех параметров требует одного обратного прохода по графу, а не одного прохода на параметр. «Теорема Баура–Штрассена о сложности AD в обратном режиме» выводит границу работы с постоянным коэффициентом и типичную стоимость плотного слоя. ↩
-
Контрольная точка градиента: обменивает вычисления на память. Вместо хранения всех активаций сохраняется только подмножество (контрольные точки), а недостающие пересчитываются на обратном проходе. Это снижает использование памяти примерно с хранения активаций каждого слоя до порядка квадратного корня из числа слоев ценой около 33 процентов дополнительных вычислений (Chen et al., 2016). ↩