Есть ли быстрый способ использовать векторы Clojure в качестве матриц?

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

Используя Jvisual profiler, я получил результаты, показанные ниже. Кто-нибудь может дать мне совет, чтобы улучшить производительность? Я могу дать более подробную информацию, если это необходимо, но, возможно, просто взглянув на стоимость seq и next, кто-то сможет сделать хорошее предположение.

Профилирование результатов операции над вектором векторов.


person boechat107    schedule 30.04.2013    source источник
comment
Просто из любопытства, пробовали ли вы новую библиотеку core.matrix? Это довольно ново, но они пытаются придумать общую схему манипуляций с матрицами, и, возможно, на нее стоит взглянуть.   -  person JohnJ    schedule 01.05.2013


Ответы (3)


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

Любой другой подход, векторы, даже java-коллекции приведут к тому, что все ваши числа будут упакованы по отдельности, что очень расточительно. Массивы примитивов (int, double, byte, что угодно) не имеют этой проблемы, поэтому они и существуют. Люди стесняются использовать массивы в clojure, но для этого есть причина, и это все. И это будет хороший переносимый код clojure — int-array работает как в jvm clojure, так и в clojure-script.

Попробуйте массивы и тест.

person Rob Lachlan    schedule 30.04.2013
comment
лучше было бы использовать библиотеку Clojure, которая обертывает для вас обработку примитивных массивов, например. векторz-clj - person mikera; 01.05.2013

Вы должны проверить core.matrix и связанные с ним библиотеки, чтобы узнать, что делать. с матричным вычислением. core.matrix — это API-интерфейс Clojure общего назначения для матричных вычислений, поддерживающий несколько внутренних реализаций.

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

  • Неизменяемость: обычно это хорошо, но может быть убийцей для низкоуровневого кода, где вам нужно делать такие вещи, как накопление результатов в изменяемый массив из соображений производительности.
  • Упаковка: структуры данных Clojure обычно упаковывают результаты (например, java.lang.Double и т. д.), что добавляет много накладных расходов по сравнению с использованием примитивов.
  • Последовательности: обход большинства структур данных Clojure как последовательностей включал создание временных объектов кучи для хранения элементов последовательности. Обычно это не проблема, но когда вы имеете дело с большими матрицами, это становится проблематичным.

Связанные библиотеки, на которые вы можете посмотреть:

  • vectorz-clj : очень быстрая библиотека матриц, которая работает как полная реализация core.matrix. Базовый код — это чистая Java, но с хорошей оболочкой Clojure. Я считаю, что в настоящее время это самый быстрый способ выполнения матричных вычислений общего назначения в Clojure, не прибегая к собственному коду. Под капотом он использует массивы примитивов Java, но вам не нужно иметь дело с этим напрямую.
  • Clatrix: еще одна библиотека быстрых матриц для Clojure, которая также является реализацией core.matrix. . Использует JBLAS под капотом.
  • image-matrix : представляет Java BufferedImage в качестве ядра. матричная реализация, поэтому вы можете выполнять матричные операции с изображениями. Сейчас немного экспериментально, но должно работать для основных случаев использования.
  • Clisk: библиотека для процедурной обработки изображений. Не столько сама матричная библиотека, сколько очень полезная для создания цифровых изображений и управления ими с использованием DSL на основе Clojure.

В зависимости от того, что вы хотите сделать, лучшим подходом может быть использование матрицы изображений для преобразования изображений в матрицы vectorz-clj и выполнения обработки там. В качестве альтернативы, Clisk может делать то, что вы хотите, из коробки (у него много готовых фильтров/эффектов искажения и т. д.).

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

person mikera    schedule 01.05.2013
comment
Хороший! Мне очень понравилась идея, и я проверю это! Однако, по крайней мере, сейчас я хотел бы работать и с матрицами целых чисел. - person boechat107; 02.05.2013

Clojure Transients предлагает промежуточный вариант между полным сохранением и отсутствием сохранения, как в случае со стандартным массивом Java. Это позволяет вам создавать образ, используя быстрые операции изменения на месте (которые ограничены текущим потоком), а затем вызывать persistent!, чтобы преобразовать его за постоянное время в правильную постоянную структуру для манипуляций в остальной части программы.

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

person Arthur Ulfeldt    schedule 30.04.2013
comment
Под капотом mapv использует переходные процессы для создания новых векторов. Так что в этом смысле мне практически нечего улучшать. Массивы Java кажутся лучшей идеей. - person boechat107; 02.05.2013