24.05.2016       Выпуск 127 (23.05.2016 - 29.05.2016)       Статьи

Pillow-SIMD

 

Pillow-SIMD — это «форк-последователь» библиотеки работы с изображениями Pillow (которая сама является форком библиотеки PIL, ныне покойной). «Последователь» означает, что проект не становится самостоятельным, а будет обновляться вместе с Pillow и иметь ту же нумерацию версий, только с суффиксом. Я надеюсь более-менее оперативно выпускать версии Pillow-SIMD сразу после выхода версий Pillow.

Читать>>




Экспериментальная функция:

Ниже вы видите текст статьи по ссылке. По нему можно быстро понять ссылка достойна прочтения или нет

Просим обратить внимание, что текст по ссылке и здесь может не совпадать.

Ускорение операций в 2.5 раза по сравнению с Pillow и в 10 по сравнению с ImageMagick

Pillow-SIMD — это «форк-последователь» библиотеки работы с изображениями Pillow (которая сама является форком библиотеки PIL, ныне покойной). «Последователь» означает, что проект не становится самостоятельным, а будет обновляться вместе с Pillow и иметь ту же нумерацию версий, только с суффиксом. Я надеюсь более-менее оперативно выпускать версии Pillow-SIMD сразу после выхода версий Pillow.

Почему SIMD

Есть несколько способов улучшения производительности обработки изображений (да и всех остальных вещей, наверное, тоже).

  1. Можно использовать более лучшие алгоритмы, которые дают такой же результат.
  2. Можно сделать более быструю реализацию существующего алгоритма.
  3. Можно подключить больше вычислительных ресурсов для решения той же задачи: дополнительные ядра CPU, GPU.

Самое классное, когда вы можете использовать более быстрый алгоритм, как когда в Pillow 2.7 Гауссово размытие на основе сверток было заменено размытием последовательностью box-фильтров. К сожалению, число таких фокусов весьма ограничено. Также очень заманчива идея использовать больше вычислительных ресурсов. Но к сожалению, часто их либо нет, либо они стоят дополнительных денег (как в случае с арендуемыми серверами). Использовать же GPU для вычислений вообще нетривиальная задача, связанная с подбором определенного железа и правильной настройкой драйверов. Остается самый надежный способ — попытаться заставить существующий код работать быстрее на существующем железе. И тут SIMD-инструкции подходят как нельзя лучше.

SIMD означает: «одна инструкция, много данных» (single instruction, multiple data). В классических программах мы берем операнды, выполняем операцию, сохраняем результат. В случае SIMD мы берем сразу пачку операндов, делаем одно и то же действие над всеми разом и сохраняем пачку результатов. Для процессора это проще, чем несколько раз выполнить одинаковые действия. Существует огромное количество расширений команд процессоров с SIMD-инструкциями, например: MMX, SSE-SSE4, AVX, AVX2, AVX512, NEON.

В текущей версии Pillow-SIMD может быть скомпилирован с использованием расширений SSE4 (по умолчанию), либо AVX2.

Статус проекта

Pillow-SIMD годится для продакшена. Различные версии Pillow-SIMD уже больше года работают на серверах Uploadcare. Uploadcare — это сервис для хранения и обработки пользовательского контента и главный спонсор Pillow-SIMD.

На текущий момент следующий операции ускорены в SIMD-версии:

  • Ресайз (ресемплинг на основе сверток): SSE4, AVX2
  • Гауссово размытие и box-фильтры: SSE4

Производительность

Цифры означают количество обработанных мегапикселей исходного изображения в секунду. Например, если ресайз изображения размером 7712×4352 был выполнен за 0.5 секунд, производительность будет 67.1 Mpx/s.

Уже в процессе редактирования я понял, что у меня кажется путаница и в мегапикселе для ImageMagick 10^6 пикселей, а в мегапикселе для Pillow — 2^20. Но это не сильно влияет на общую картину.

Протестированы:

  • ImageMagick 6.9.3-8 Q8 x86_64
  • Pillow 3.2.0
  • Pillow-SIMD 3.2.0.post2
SourceOperationFilterIMPillowSIMD SSE4SIMD AVX2
7712×4352 RGBResize to 16x16Bilinear27.0217437710
Bicubic10.9115232391
Lanczos6.676.1157265
Resize to 320x180Bilinear32.0166410612
Bicubic16.592.3211344
Lanczos11.063.2136223
Resize to 2048x1155Bilinear20.787.6229265
Bicubic12.265.7140171
Lanczos8.741.3100126
Blur1px8.117.137.8
10px2.617.439.0
100px0.317.239.0
1920×1280 RGBResize to 16x16Bilinear41.6196426750
Bicubic18.9102221379
Lanczos13.768.6140227
Resize to 320x180Bilinear27.6111303346
Bicubic14.566.3164230
Lanczos9.844.3108143
Resize to 2048x1155Bilinear9.120.771.169.6
Bicubic6.316.953.853.1
Lanczos4.714.640.741.7
Blur1px8.716.235.7
10px2.816.735.4
100px0.416.436.2

Pillow всегда быстрее, чем ImageMagick, а Pillow-SIMD быстрее чем Pillow примерно в 2-2.5 раза для SSE4-версии. В основном, AVX2-версия оказывается быстрее чем ImageMagick в 10-15 раз.

Тесты выполнялись на Ubuntu 14.04 64-bit, запущенной на процессоре Intel Core i5 4258U с AVX2. Все тесты использовали только одно ядро процессора.

Производительность ImageMagick была измерена утилитой командной строки convert с аргументами -verbose и -bench. Выбранные фильтры в точности соответствуют существующим в Pillow фильтрам:

  • PIL.Image.BILINEAR == Triangle
  • PIL.Image.BICUBIC == Catrom
  • PIL.Image.LANCZOS == Lanczos

Для тестирования были использованы такие скрипты.

Почему Pillow такой быстрый

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

Почему Pillow-SIMD еще быстрее

Конечно же из-за использования SIMD-команд. Но у меня еще несколько мыслей, как можно улучшить этот результат.

  • Эффективная работа с памятью В настоящий момент каждый пиксель загружается в SSE-регистр из памяти по отдельности, в то время как в один SSE-регистр возможно прочитать 4 пикселя за раз.
  • Вычисления на целых числах Не смотря на то, что современные процессоры очень эффективно работают с числами с плавающей точкой, есть две причины полагать, что работа с целыми числами будет эффективнее: операции над целыми алгоритмически проще; для работы с ними не требуется дополнительных ковертаций.
  • Выравнивание данных в памяти загрузка и выгрузка данных из SIMD-регистров выполняется быстрее, если адреса в памяти, с которыми идет обмен, выровнены.

Почему бы не влить изминения обратно в Pillow

Если коротко — это очень сложно. Pillow поддерживает большой количество архитектур, не только x86. Но даже на x86 Pillow для некоторых платформ распространяется в виде скомпилированных исполняемых файлов. Чтобы иметь возможность использовать SIMD-команды в коде, нужно передавать компилятору аргументы, разрешающие использование самых продвинутые инструкций, которые мы хотим использовать: -mavx2. После этого нужно делать проверку возможностей процессора во время выполнения и включать ту или иную ветку кода в зависимости от них. Проблема в том, что такие аргументы автоматически компируют код, спрятанный под условия препроцессора if (__AVX2__) и ниже, который может ни иметь никаких проверок времени выполнения. Самое печальное, что такой код действительно находится, по крайней мере при компиляции GCC и исполняемые файлы без явного использования AVX2, но собранные с -mavx2, начинают вылетать. Разумеется, можно собирать разные версии библиотеки с разными опция компилятора и динамическим их подключать, но это [см. начало этого параграфа].

Установка

Хорошие новости, что для установки SSE4 версии достаточно написать как обычно pip install pillow-simd и если ваш процессор умеет в SSE4 (думаю, вероятность этого около 95%), все пойдет замечательно. Не забудьте удалит оригинальный пакет Pillow.

Если вы хотите собрать AVX2 версию, то нужно передать компилятору дополнительные флаги. Проще всего это сделать задав переменную окружения CC во время установки и компиляции.

$ pip uninstall -y pillow-simd ; CC="cc -mavx2" pip install pillow-simd

Иногда бывает, что зависимость от Pillow есть не только у вас, но и у других пакетов, которые вы используете. И даже если эти пакеты не особо нуждаются в быстром ресемплинге, они все равно устанавливают Pillow без SIMD, который может импортироваться первым. Для этого может пригодиться такой хак при установке с Гитхаба:

$ pip install -e git+https://github.com/uploadcare/pillow-simd.git@v3.2.0.post3#egg=pillow

Тогда во время установки другого пакета с зависимостью от Pillow, еще одна версия Pillow ставиться не будет:

$ pip install xhtml2pdf -e git+https://github.com/uploadcare/pillow-simd.git@v3.2.0.post3#egg=pillow





Разместим вашу рекламу

Пиши: mail@pythondigest.ru

Нашли опечатку?

Выделите фрагмент и отправьте нажатием Ctrl+Enter.

Система Orphus