跳转到内容

MINC/Tools/emma/emma-speed

来自维基教科书,开放世界中的开放书籍

加速 MATLAB

[编辑 | 编辑源代码]

我们经常听到刚接触 MATLAB 的人抱怨它很慢。MATLAB 本身确实存在速度权衡。由于它是一种解释型语言,而不是编译型语言(如 C 或 FORTRAN),因此它的速度几乎总是落后于用 C 等语言编写的自定义程序。但是,这种速度损失可以通过代码开发的便捷性来弥补。

幸运的是,通过仔细构建脚本可以显著提高 MATLAB 的速度。编写 MATLAB 脚本以提高速度时,需要遵循一条基本规则

  • 在任何情况下,都应避免使用for循环在 MATLAB 中。

这条规则有一个简单的记忆推论

  • 矢量化,矢量化,矢量化。

换句话说,只要有可能,就使用矢量运算。对于许多操作,通过对矢量化进行一些思考,代码速度可以提高几个数量级。不幸的是,对于 MATLAB 新手来说,矢量化可能难以直观地理解。由于大多数人在熟悉传统编程语言后才接触 MATLAB,因此他们倾向于使用for自动循环。

让我们考虑一个简单的例子。我们想要找到图像中值大于 2000 的点有多少个。在传统的编程语言中,我们可能会采用以下方法

j=0;
for i=1:16384;
    if (PET(i)>2000)
        j=j 1;
    end
end

这在 MATLAB 中执行大约需要一秒钟。矢量化的方法是使用 MATLABfind函数

length(find(PET>2000));

这大约需要 0.07 秒才能执行,因此比传统方法快大约 15 倍。现在,考虑以下相关问题。我们希望根据我们刚刚操作的图像创建掩码,其中任何值大于 2000 的点都被设置为 1,所有其他点都被设置为 0。对这个问题的传统解决方案可能类似于

mask=zeros(16384,1);
for i=1:16384;
    if (PET(i)>2000)
        mask(i)=1;
    end;
end;

这大约需要 0.81 秒才能执行。一种更快、矢量化的方法如下

mask2=zeros(16384,1);
index=find(PET>2000);
mask2(index)=ones(size(index));

这大约需要 0.05 秒才能执行,因此比传统方法快大约 16 倍。它还引入了一种在矢量化例程时非常有用的重要技术:使用矢量作为另一个矢量的索引。在上面的代码片段中,变量index包含值的索引。

在尝试加速 MATLAB 代码时,另一件需要记住的事情是,可以在 MATLAB 中调用 FORTRAN 或 C 例程。这些函数被称为 FMEX 或 CMEX 函数,具体取决于它们是用哪种语言编写的,有关创建它们的详细信息可以在 MATLAB 外部接口指南中找到。

EMMA 工具箱包含几个流行 MATLAB 函数的 CMEX 版本

  1. ntrapz是 MATLAB 的替代品trapz梯形积分函数。
  2. nfmins是 MATLAB 的替代品fmins函数最小化例程。
  3. lookup 执行 1-D 线性插值,类似于 MATLAB 的 interp1 例程。
  4. rescale 用于将大型矩阵按常数或按相同大小和形状的另一个矩阵进行缩放。rescale.* 运算符相比没有明显的加速优势,但它在原地执行算术运算,因此不会创建目标矩阵的副本。这可能会导致显著的内存节省。

这些例程在功能上与 MATLAB 例程相同,只是提供了速度提升。

华夏公益教科书