有一种快速的方法可以使用Clojure向量作为矩阵吗?

时间:2013-04-30 16:53:30

标签: performance clojure profiling

我正在尝试使用Clojure处理图像,我想使用Clojure数据结构来表示图像。基本上,我的第一种方法是使用向量矢量和mapv来操作每个像素值,并返回具有相同数据结构的新图像表示。但是,一些基本操作需要花费太多时间。

使用Jvisual分析器,我得到的结果如下所示。有人可以给我一个改善表现的小费吗?如果有必要,我可以提供更多详细信息,但也许只是查看seqnext的成本可以让人有个好猜测。

Profiling results of an operation over the vector of vectors.

3 个答案:

答案 0 :(得分:7)

您应该查看 core.matrix 和相关库,了解与矩阵计算有关的任何内容。 core.matrix是一种用于矩阵计算的通用Clojure API,支持多种后端实现。

Clojure的持久数据结构非常适合大多数用途,但实际上并不适合快速处理大型矩阵。主要问题是:

  • 不变性:通常是一件好事,但对于低级代码而言可能是一个杀手,因为出于性能原因,你需要做一些事情,例如在可变数组中累积结果。
  • 拳击:Clojure数据结构通常是盒子结果(如java.lang.Double等),与使用原语相比增加了很多开销
  • 序列:遍历大多数Clojure数据结构作为序列涉及创建临时堆对象以保存序列元素。通常不是问题,但是当你处理大型矩阵时,它会成为问题。

您可能想要查看的相关库是:

  • vectorz-clj :一个非常快速的矩阵库,可作为完整的core.matrix实现。底层代码是纯Java,但有一个很好的Clojure包装器。我相信它是目前在Clojure中进行通用矩阵计算的最快方法,而不需要使用本机代码。在引擎盖下,它使用Java原语数组,但您不需要直接处理它。
  • Clatrix :Clojure的另一个快速矩阵库,也是core.matrix实现。在引擎盖下使用JBLAS。
  • image-matrix :将Java BufferedImage表示为core.matrix实现,因此您可以对图像执行矩阵运算。现在有点实验,但应该适用于基本用例
  • Clisk :用于程序图像处理的库。与基质库本身无关,但对于使用基于Clojure的DSL创建和操作数字图像非常有用。

根据您的想法,最佳方法可能是使用图像矩阵将图像转换为vectorz-clj矩阵并在那里进行处理。或者,Clisk可能能够开箱即用(它有很多现成的滤镜/失真效果等)。

免责声明:我是上述大部分图书馆的首席开发人员。但是我自己一直在使用它们来做认真的工作,所以非常愿意保证它们的实用性,并帮助解决你发现的任何问题。

答案 1 :(得分:3)

我真的认为你应该为此使用基元数组。 Clojure内置阵列支持,即使它没有突出显示,也适用于这样的情况,你有大量的数值数据。

任何其他方法,向量,甚至是java集合都会导致所有数字被单独装箱,这非常浪费。基元的数组(int,double,byte,任何合适的)都没有这个问题,这就是为什么它们存在的原因。人们对在clojure中使用数组感到害羞,但他们出于某种原因,这就是它。并且它将是好的可用的clojure代码 - int-array在jvm clojure和clojure-script中都有效。

尝试数组和基准测试。

答案 2 :(得分:1)

Clojure的Transients提供了完全持久性和无持久性之间的中间地带,就像使用标准java数组一样。这允许您使用快速mutate-in-place操作(仅限于当前线程)构建映像,然后调用persistent!将其在常量时间转换为适当的持久性结构,以便在其余部分中进行操作程序

看起来你也看到了使用序列覆盖图像内容的大量开销,如果瞬态没有产生足够的差异,你可能想要接下来考虑使用普通的java数组并构建访问权限直接访问数组元素。