Scala:有没有办法提高卷积码的时序性能



大家好。我一直在努力提高Scala:中这段代码的执行时间

def TwoDimensionalConvolution(Input: => Array[Int], Height: => Int, Width: => Int, Kernel: => Array[Int]): Array[Int] = {
val R = (Kernel.length - 1) >> 1
val result = Array.ofDim[Int](Input.length)
for (i <- 0 until Height) {
for (j <- 0 until Width) {
var acc = 0
for (k <- j - R to j + R)
if (k >= 0 && k < Width)
acc += Input(i * Width + k) * Kernel(k + R - j)
result(j * Height + i) = acc >> 8
}
}
val Output = Array.ofDim[Int](Input.length)
for (i <- 0 until Width) {
for (j <- 0 until Height) {
var acc = 0
for (k <- j - R to j + R)
if (k >= 0 && k < Height)
acc += result(i * Height + k) * Kernel(k + R - j)
Output(j * Width + i) = acc >> 8
}
}
Output
}

我的代码使用行和列的线性卷积来执行二维卷积。请注意,输入数组不是二维的,但访问它的方式是线性的。k的for循环允许您对每一行或每一列进行迭代,而不必对边进行零填充。

我也尽量避免存储中间结果,但正如您所看到的,保存卷积行的result变量对于执行列的卷积是必要的。

我不认为自己是Scala的专家,尽管我在C/C++方面有一些经验,但我无法进一步改进时间安排。

事实是,我想不出用我仅有的几门函数编程知识还能做什么。

某位Scala专家可以向我提出一些建议吗?提前感谢大家的阅读。

我建议的一个优化方法是用k优化循环。您有:

for (k <- j - R to j + R)
if (k >= 0 && k < Height)
acc += result(i * Height + k) * Kernel(k + R - j)

但是,如果是k is < 0 || k >= Height,则循环将不执行任何操作,并且您正在进行不必要的迭代。

也许改为:

for (k <- (j - R max 0) to (j + R min Height - 1))
acc += result(i * Height + k) * Kernel(k + R - j)

这消除了if语句,并确保不会消耗额外的迭代。

一定要从去掉按名称参数(: => ...(开始。它们变成了函数,在方法的每次使用中都会对其进行评估,即使您只是将变量和文字传递给方法调用,仍然存在不小的开销。

尝试用while替换for循环。这将产生多大的影响取决于Scala版本以及是否将优化标志传递给编译器。参见例如。http://dynamicsofprogramming.blogspot.com/2017/01/performance-of-scala-for-loops.html包括Scala 2.12。

在测量性能时也需要小心:使用Scalameter或JMH。

最新更新