В прошлом уроке матрица была движением пространства. Теперь спросим приземлённее: во что это движение обходится. У большой сети почти всё время уходит на умножение матриц, и от его цены зависит, какую модель вообще можно обучить. Причём цена прячется в двух местах: в числе арифметических операций и в том, как данные ходят по памяти.

Три вложенных цикла

Чтобы перемножить ARm×kA\in\mathbb R^{m\times k} и BRk×nB\in\mathbb R^{k\times n}, каждый из mnmn элементов результата собирают как скалярное произведение строки на столбец:

Cij==1kAiBj.C_{ij}=\sum_{\ell=1}^{k}A_{i\ell}B_{\ell j}.

Это mknmkn умножений и примерно столько же сложений. Для квадратных матриц n×nn\times n получается порядка n3n^3 операций.

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

Порядок скобок меняет цену

Умножение матриц ассоциативно: (AB)C=A(BC)(AB)C=A(BC), ответ один. А вот стоимость двух порядков может отличаться в разы. Возьмём цепочку A(40×100)A\,(40\times100), B(100×5)B\,(100\times5), C(5×60)C\,(5\times60).

(AB)C:401005+40560=32000,(AB)C:\quad 40\cdot100\cdot5+40\cdot5\cdot60=32\,000, A(BC):100560+4010060=270000.A(BC):\quad 100\cdot5\cdot60+40\cdot100\cdot60=270\,000.

Разница почти в девять раз — на ровном месте, просто из-за расстановки скобок.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Слева три матрицы цепочки A 40 на 100, B 100 на 5, C 5 на 60 разного размера. Справа два столбца: порядок скобок A B в скобках умножить на C стоит 32 тысячи умножений, а A умножить на B C в скобках — 270 тысяч; разница почти в восемь раз
Рис. 37.1. Порядок умножений меняет цену в разы

Одна цепочка, один ответ, но (AB)C(AB)C и A(BC)A(BC) стоят разного числа умножений. Выгоднее сначала свернуть то, что резко уменьшает размер.

Замерь куб сам

Измерь цену умножения матриц

Загружается живая иллюстрация…

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

Почему замер важнее формулы

Число операций — только половина правды. Процессор часто ждёт не арифметику, а загрузку чисел из памяти: если элемент успел вытесниться из быстрого кэша, его приходится читать заново. Поэтому одинаковое число операций не гарантирует одинаковое время, и цену надо мерить, а не только считать.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Лог-лог график измеренного времени numpy.matmul от размера n. Синие точки — реальные измерения — ложатся ниже красной пунктирной линии закона n в кубе, потому что оптимизированная библиотека распараллеливает работу; общий наклон около 2,5
Рис. 37.2. Кубический закон, измеренный на самом деле

Реальные измерения на этой машине. Оптимизированная библиотека даже обгоняет чистый n3n^3: её точки уходят ниже эталонной линии, потому что она распараллеливает работу и лучше использует память. Наивная же реализация даёт наклон ровно три.

Блоки и кэш

Спасение от лишних чтений — блочное умножение. Матрицы режут на плитки b×bb\times b, которые целиком помещаются в быструю память. Загруженная плитка используется много раз, прежде чем её вытеснят:

CIJ+=AIKBKJ.C_{IJ}\mathrel{+}=A_{IK}B_{KJ}.

Арифметика не меняется, а обмен с медленной памятью резко падает.

Поэтому на практике берут порог: выше него — рекурсия Штрассена, ниже — оптимизированное обычное умножение. Слишком ранняя рекурсия проигрывает из-за временных матриц и лишних сложений.

Точность быстрого умножения

За скорость Штрассен платит и точностью: вычитания близких чисел усиливают относительную ошибку округления. Поэтому быстрый алгоритм нельзя принимать на веру — результат сверяют с эталоном повышенной точности по относительной норме:

CтестCэталонFCэталонF.\frac{\lVert C_{\text{тест}}-C_{\text{эталон}}\rVert_F}{\lVert C_{\text{эталон}}\rVert_F}.

Один случайный пример с равномерными числами не проверяет устойчивость: трудные тесты — это матрицы с числами очень разных масштабов и почти взаимной компенсацией.

Свёртка как умножение матриц

Умножение матриц — не абстракция: в него сворачивается сама свёртка из урока 28. Приём im2col превращает каждое локальное окно картинки в строку матрицы, а ядра — в столбцы; одно матричное умножение сразу выдаёт все позиции и каналы. Платят за это временной памятью: пиксели окон повторяются.

::::

Русская линия здесь ведёт к тензорным методам. Академик Е. Е. Тыртышников и его школа развивают малоранговые и тензорные разложения (в том числе тензорный поезд), которые позволяют работать с матрицами и данными огромной размерности, недоступными прямому кубическому умножению. Поиск быстрых произведений и тензорные разложения — две стороны одной идеи: заменить лобовой счёт учётом скрытой структуры.

Матрицы в обучении

При обучении сети мало одного ABAB: обратный проход из урока 25 требует ещё двух умножений на транспонированные матрицы, Aˉ=CˉB\bar A=\bar C B^\top и Bˉ=ACˉ\bar B=A^\top\bar C. Поэтому один полносвязный слой запускает несколько GEMM за шаг, и ускорение только прямого прохода не ускоряет эпоху целиком. Цена матриц — это цена обучения.

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

Что забрать с собой

Умножение матриц стоит порядка n3n^3 операций, и на нём держится время обучения. Но цена прячется в двух местах: в арифметике и в движении данных по памяти, поэтому её мерят, а не только считают. Ассоциативность даёт бесплатную экономию — правильный порядок скобок меняет цену в разы. Штрассен перебивает кубический показатель, но лишь после порога и ценой точности. А свёртка через im2col сводится к тому же матричному умножению, связывая эту главу с CNN и обратным распространением.

Задачи