matlab程序设计语言,浅析MATLAB程序设计语言的效率

在统计学习和计算机视觉领域,MATLAB是进行实验的最主要的工具之一。如果你觉得MATLAB很慢,可是这往往不是MATLAB的问题,而是因为自己程序没有写好。MATLAB是我非常欣赏的一种语言,堪称灵活易用和高效运算的结合典范。

作为一种解释语言,我认为MATLAB进行高效运算的秘诀有几个方面:

(1)

JIT即时编译技术。Matlab在第一次加载运行一个函数的时候,会在后台对它进行某种程度的编译和优化,使得后续运行更快。因此,除了第一次运行需要进行语句解释之外,后面运行的其实是已经放在内存中的经过优化的中间码。所以,很多时候我们可能会看到第一次运行一个新函数,比它后面几次的运行明显慢一些。不过目前的JIT技术还不是非常成熟,和标准的编译语言相比还有相当差距,仅凭这个MATLAB还不能称为高效。

(2)

向量化(Vectorization)。这是MATLAB最著名的特色,尤其对于计算机视觉和图像分析等多个研究领域,利用MATLAB的向量化程序设计有其天然的优势。向量化配合经过高度优化的数值运算引擎,是其高效运算的最重要的基石——很多MATLAB的使用者都明白这一点。能够转化成矩阵操作的规则运算过程,使用MATLAB计算远比自己手工用C/C++实现高效。相比之下,MATLAB在关键的核心运算上的实现往往可以比自己用C/C++按照标准的routine进行实现快几十倍。

不过,这也不能完全归功与MATLAB程序设计平台,其实MATLAB是建基于BLAS和LAPACK等的基础数学运算包的基础上的。Intel和AMD都发布了这些东西的vendor-implementation,并且针对各自的CPU进行了大量的优化。因此,在一般情况下,我们都不会选择使用C/C++去实现数值运算的关键代码(学习数值分析课者除外)。但是,哲学的思想告诉我们世界上没有十全十美的东西,任何事情都是有利有弊的。因此,也不能把MATLAB向量化的优势无限制的扩大,这种优势在某些case下往往变成shortcoming。下面举些例子说明有时for-loop比vectorization更适合:

(a)

粗粒度的算法流程控制。比如,你要实现一个迭代算法,循环做一个事情直到收敛。只要循环几次或者几十次,但是每个循环内部要进行大量的复杂运算,那么你就没有必要费心把这层循环给vectorize掉了。除非收敛结果有某种close-form的解析解。

(b)

如果向量化可能导致产生巨型矩阵,则使用前要三思!这是很头疼的问题,相信大家与我有同感。很多情况下,向量化是一种用空间换时间的行为,就是通过把数据组织成某种方式,从而使得内建的高效引擎能得以应用。但是,有些时候要处理大量的数据(尤其是图像数据),可能导致其组织过程需要耗费额外的数百兆乃至千兆内存空间,那么这有可能造成效率的不升反降。原因有几个方面:

第一,数据组织过程也是需要时间的,最起码它也需要大量的操作进行密集的内存读写和用于定位的偏移量计算。这方面增加的时间

vs. 向量化节省的运算时间,孰轻孰重,需要衡量。

第二,分配额外的大块内存是一件非常耗时的事情,它可能导致虚拟内存的使用,那么当对这块矩阵进行读写和计算时可能涉及频繁的内存与外存交换区的I/O,势必造成效率的严重下降。这时应该做的是对程序进行重新思考和设计,降低其对内存的耗用。

第三,vectorization有些时候还可能增加实际运算次数,这往往出现在不适合的向量化过程中。这样,即使你通过生搬硬套的向量化过程让操作变成矩阵运算,但是增加的无用计算使得即使是更高效的引擎也无法挽回你的损失了。

说了这么多,并不是要把Vectorization贬的一钱不值,而是希望提醒大家在做一些事情的时候,要考虑得周全一些。

(3) Inplace

Operation。这是一个很有趣的事情,MATLAB的对象管理策略是Copy-on-Write,就是说你把一个矩阵传给一个函数的时候,会先传引用,而不产生副本,而当函数要对这个矩阵修改的时候,才会制造出它的副本出来,让函数去修改。这样听上去很完美,既保护了输入矩阵不被改变,又避免了大量无谓的复制。不过,这个策略真的没有缺陷么?可以看看下面的例子

A = rand(2000, 2000);

for i = 1 : 1000

A = f(A);

end

function A = f(A)

A(1) = A(1) + 1; % a temporary copy of A is produced for

modification

return; % the modified temporary copy is assigned to

A

在上面的代码中,只是想对A的第一个元素做1000次加法,结果却导致了对整个有四百万元素的大矩阵做了1000次副本复制!而且这些副本其实没有用,只要f(A)直接对A的原矩阵进行修改,这些巨大的浪费就能避免。你可能跟我argue说,这里完全可以写成A(1)

= A(1) +

1000,不用这么搞。我想说明的是,我只是想举一个简单例子说明,Copy-on-write的策略为什么可能造成巨大的效率浪费。其实,很多小修改没法像上面那么容易合并。

以前,为了解决这个问题,f函数的作者需要自己写一个mex

function来避开MATLAB的保护机制,直接改写A。后来matlab自己也意识到这种策略在实际中的问题,于是他们改写了解释器,采用了一种办法:A

= f(A, ...)

当它发现这样的定义和调用的时候,它会很智能地了解到你其实是想改写A这个输入,于是它就把操作改成inplace,直接对A进行,避免拷贝。这种修改的策略,在2006b后才比较正式的运用,在旧版Matlab中仍旧不同程度地存在上述问题。我在2007a中,测试了两种f的写法:

function

y = f0(x) y = x + 1; end

function

x = f1(x) x = x + 1; end

确实发现大量调用f1比f0快了好多倍。所以,如果确实是想改变input的话,函数定义中要让input

parameter和output

parameter同名,以触发这种智能的解释机制。并且建议升级到最新的2007a版本,这个版本在这方面进行了重要改善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值