Статья Автор: Деникина Н.В., Деникин А.В.

Векторизация вычислений

Почему цикл — это дорого

Четыре заказа — цикл незаметен. Но сервис доставки пересчитывает время для десятков тысяч заказов в секунду, а при обучении прогоняет миллионы строк истории десятки тысяч раз. Разница между «минута» и «неделя» появляется именно здесь.

Умножение матриц (300, 300) на (300, 100) — девять миллионов умножений.

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

numpy отдаёт ту же работу библиотеке на C, которая считает блоками и укладывает данные в кэш процессора.

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


Три вложенных цикла перебирают 300 примеров, 100 нейронов и 300 входов. Сколько умножений выполнится?

Три версии одного и того же

Три цикла, один цикл по примерам и ни одного цикла. Результат обязан быть одинаковым.



Вывод
True
True

Обе проверки True: числа совпадают с точностью до последнего знака.


Сколько это стоит по времени


Вывод на нашей машине
три цикла, с: 2.91
без циклов, с: 0.00081
во сколько раз быстрее: 3575

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

Цикл по примерам — почти всегда лишний.


Как убирать циклы

Правило простое: если внутри цикла одна и та же операция над разными элементами, в numpy она уже есть.

Сумма — sum. Максимум с нулём — maximum. Сумма произведений — @. Среднее по столбцам — mean с axis.

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

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

Убрав цикл, обязательно сверь результат через allclose. Векторная версия часто считает не совсем то же самое, и без сверки ты этого не заметишь.

И не оставляй np.append внутри цикла: он копирует весь массив на каждом шаге, и цикл становится медленнее, а не быстрее.

Загрузка...
Чтобы оставить комментарий, необходимо авторизоваться
💬
Пока нет комментариев. Будьте первым!
Печать