加速Matlab到C++的转换

8
我有一些Matlab图像处理代码,运行速度相当慢,我准备将其转换为C / C ++。我不太了解Matlab的工作方式和代码执行过程,但我只是想听听可能会有什么样的加速效果。显然,有许多变量会影响这一点,但我只是希望从您自己的经验中获得指导。

谢谢

Zenna


8
一些代码示例会很不错。您不能指望将Matlab中的慢而糟糕的算法转换为快速算法。问题可能不在于解释器,而在于算法本身。 - Ed S.
7个回答

8
这主要取决于Matlab中您的循环紧密程度。如果您只是调用一系列内置的Matlab图像处理函数,您很可能无法提高性能(最可能会降低性能)。如果您正在循环遍历图像像素或进行某种块处理,您可能会看到巨大的改进。如果您正在做一些循环,但每次迭代中的处理量相当大,则可能只会看到微小或没有改进。
我认为Matlab的每个执行行都有一定的开销。如果您可以将解决方案转化为矩阵乘法或其他向量/矩阵操作形式,则只需承受一次开销,而且它是可以忽略不计的。但是,对于循环,每次循环迭代时都会承受这种开销。此外,大多数Matlab的图像处理函数只是在调用优化库,因此除非您确切地知道它们可以改进的位置,否则不要尝试重新创建它们。
我发现最好的方法是使用C和Matlab的组合。当操作可以轻松地向量化(以向量/矩阵操作的形式表示)时,我使用Matlab。这可能意味着从不同的角度来解决问题,而不是似乎最直接的方式。此外,很难击败Matlab的绘图和可视化,因此除非您有一个用于使用C/C++显示的计划(如果这是您的项目的一部分),否则我绝对不会转移到全C/C++解决方案。
如果我找不到相对容易的向量化方法,我只需在C mex函数中实现需要紧密循环的处理部分,然后可以从Matlab调用该函数。在这种情况下,我倾向于使用C而不是C ++,因为该过程应该相对较小,不需要很多复杂的数据抽象,但C ++也可以正常工作。请确保以列主顺序访问图像数据,以最大化缓存命中,因为这是Matlab组织其矩阵的方式。

2
随着JIT加速器的引入,“for循环惩罚”不再像过去那样令人担忧。使用分析器找到真正的瓶颈。 - MatlabDoug
1
是的,我肯定会首选这种方法,但我仍然发现在某些情况下,使用优化后的 C 语言可能更好。不过这可能只是因为我对 JIT 编译器的利用知识有限。话虽如此,避免在 Matlab 可以做得很好或更好的情况下使用 C/C++ 是一个好主意。 - Jason B
@MatlabDoug:您能否详细介绍一下JIT加速器和分析器?我经常使用MATLAB编程,但从未听说过这些工具,它们听起来很有趣。也许您可以提供几个链接吗?谢谢。 - SSilk

4
这真的取决于您的Matlab代码质量以及您所做的事情。由Matlab专家编写的惯用Matlab代码将很难被超越,特别是如果您不是优化大师,而纯粹是期望通过语言切换来加速。例如,我发现即使一些更受推崇的基于C的FFT库也无法与Matlab的FFT相匹配。
话虽如此,将一个编写不良的Matlab程序与平均编写的c ++程序进行比较,根据我的经验,您将看到一个数量级的差距。

3
在进行FFT时,Matlab使用FFTW(“西方最快的傅立叶变换”,参见http://www.fftw.org),该库是用C实现的(实际上是由Objective Caml生成的C代码,详见http://www.fftw.org/pldi99.pdf)。 - las3rjock

3
你可能得到的加速效果是“取决于具体情况”。Matlab是一种解释器,因此总体上比本地c++代码慢得多。但是,许多Matlab函数已经被优化,最新版本包括JIT。因此,您需要决定是将所有Matlab代码重写为C,仅重写关键部分还是优化Matlab代码本身以实现更快的运行。
建议您首先使用Matlab内置的性能分析工具找出应用程序中的性能瓶颈。也许您可以调整Matlab代码以获得更好的性能。经验法则是避免循环,而是使用向量化数组操作代替逐个元素迭代。

随着JIT加速器的引入,“for循环惩罚”不再像过去那样令人担忧。使用分析器找到真正的瓶颈。 - MatlabDoug

1

例如,Matlab使用FFTW库来实现FFT算法。该库的性能几乎无法超越。我所知道的唯一可比较的是英特尔数学核心库(MKL),但它是商业软件。因此,首先建议使用您可以找到的每个数学库。Matlab在幕后执行此操作。

确实有时很难超越Matlab。但问题在于,Matlab分析器并不总是提供足够的信息来改进代码。您知道某些Matlab方法需要大量时间,但并不总是知道是否有其他方法可以通过以另一种方式调用它们来改善性能,因为该方法是黑盒子。

在C / C ++中,您可以使用像valgirnd这样的工具,甚至可以检查编译器正在生成的汇编程序,从而可以帮助编译器通过内联方法来改进该代码。但是,Matlab在幕后使用专业的数学库,如果执行Matlab代码时大部分时间都花费在这些库上,则难以改进性能。

我建议您尝试不同的方法。您可以使用Matlab分析器分析瓶颈,并查看将该代码移动到本地代码是否值得。Matlab允许您这样做。您也可以反过来做。您可以在C / C ++中实现一些粘合剂,并调用Matlab进行某些操作,其中您已经经历了本机代码比Matlab慢的情况。

1

对于图像处理,您可以获得明显的加速。但这实际上取决于您编写MATLAB代码的熟练程度。许多事情可以向量化或通过内置函数处理。那种代码非常快。

然而,如果您发现自己的代码由许多循环组成(比如说,循环遍历图像中的所有像素),它将变得非常缓慢,而向量化可以提供100倍以上的加速。

如果您的代码在MATLAB中很难做到“正确”,那么切换到C可能是一个可行的选择。我在学校做了一个计算机视觉项目(3D点重建),这清楚地表明了这一点。当我们的项目(使用C++和OpenCV实现)完成计算时,另一个小组的项目还几乎没有加载图像。他们的项目是用MATLAB编写的。我们从未计时过,但我的猜测是我们的版本运行大约快10倍。

但是,他们的MATLAB代码可能根本没有经过优化。因此,它并不真正有用作为基准。


随着JIT加速器的引入,“for循环惩罚”不再像过去那样令人担忧。使用分析器找到真正的瓶颈。 - MatlabDoug
是的,我也听说过。不幸的是,我还没有机会使用最新版本的MATLAB :( - Hannes Ovrén

1

我已经将一个Matlab例程导出为C++,并使用Visual Studio C++编译为Mex。加速比提高了10倍。如果我使用多核心,则可能会有3倍的速度提升。

如果您在斜坡上有斜坡,并对矩阵的单个组件执行某些操作,例如y(m,n) = x(m) * a - x(m-1),并且这是针对斜坡的,则可以获得良好的加速效果。

如果您在计算中使用许多Matlab函数,其中Matlab函数本身执行许多操作,则将代码导出到C++中就没有太多意义。


0

像其他人所说的那样,使用MATLAB分析器查看瓶颈在哪里。如果是矩阵数值计算,你需要跨越一个相当高的门槛才能击败MATLAB。如果有很多条件语句或函数调用,你更有可能提高速度。

确保尝试将MATLAB和C++之间数据传输的次数最小化。如果你一次性发送大量数据数组,这很可能会很快。否则,即使你的C++程序很快,如果来回进行大量数据传输,你可能会失去数据转换的速度优势。

我还会看看你的算法,并考虑使用Java。从MATLAB调用自定义Java代码非常方便,因为MATLAB已经在JRE上运行。我对在MATLAB函数和我的自定义Java代码之间传输大型数据数组的速度印象非常深刻。几年前,我曾考虑使用纯C++(使用MEX或其他方式)实现算法以加速MATLAB,但处理所有数据结构看起来就像噩梦一样。最终我使用了COM/ActiveX,因为我在Windows机器上运行,接口更容易处理。

在解决数值问题时,我经常进行低级编程,这让我更加了解出现的问题,从数值精度到编程维护问题。除非有巨大的性能优势,否则我宁愿选择高级语言而不是C/C++。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接