【发布时间】:2015-10-02 21:48:33
【问题描述】:
我有两段结构相同的 Python 和 Octave 代码。但是,使用 numpy 和 scipy 实现的 Python 版本要快约 5 倍。我对代码做了一个概要分析,发现 Octave 代码中的罪魁祸首是 6 个函数在一个循环中重复调用了数千次。这些函数只计算数值表达式,例如cos,cosh,所以我很惊讶它们消耗了多少时间(作为参考,这两个代码都在 2 秒内运行。)
我在网上研究了这个奇怪的现象并阅读了paper,它表明 Octave 中的函数开销,即函数开始执行函数体中的实际函数代码并随后清理它所需的设置,大约是比 Matlab 大 30 倍,比 Python 大约 100 倍。
这种情况让我很困惑——从 Octave 调用函数怎么可能this比在其他两种类似语言中调用函数慢得多?此外,除了将函数本身复制并粘贴到循环体中之外,还有什么方法可以弥补这种速度下降?
编辑:我已经从我的代码中发布了主 for 循环。这是对多个方程的牛顿法的迭代实现,所以我不确定如何对其进行矢量化。
for k = 1:10
for l = 1:50
% matrix of derivatives of equations with respect to variables
a = [dEq1_dq1(p1, p2, q1, q2, i, j), dEq1_dq2(p1, p2, q1, q2, i, j); dEq2_dq1(p1, p2, q1, q2, i, j), dEq2_dq2(p1, p2, q1, q2, i, j)];
% vector of equations
b = [Eq1(p1, p2, q1, q2, i, j); Eq2(p1, p2, q1, q2, i, j)];
% solution to ax=b
x = a \ b;
% iteratively update q
q1 -= beta*x(1);
q2 -= beta*x(2);
endfor
for l = 1:50
a = [dEp1_dp1(p1, p2, q1, q2, i, j), dEp1_dp2(p1, p2, q1, q2, i, j); dEp2_dp1(p1, p2, q1, q2, i, j), dEp2_dp2(p1, p2, q1, q2, i, j)];
b = [Ep1(p1, p2, q1, q2, i, j); Ep2(p1, p2, q1, q2, i, j)];
x = a \ b;
p1 -= beta*x(1);
p2 -= beta*x(2);
endfor
endfor
...
% derivatives of implicit equations with respect to variables
function val = dEp1_dp1(p1, p2, q1, q2, i, j)
% symmetric
if mod(i, 2) == 1
val = p1/(2*cos(p1/2)**2)+tan(p1/2);
% anti-symmetric
else
val = tan(p1/2)/(p1**2)-1/(2*p1*cos(p1/2)**2);
endif
end
...
function val = Ep1(p1, p2, q1, q2, i, j)
if mod(i, 2) == 1
val = p2*tanh(p2/2)+p1*tan(p1/2);
else
val = (1/p2)*tanh(p2/2)-(1/p1)*tan(p1/2);
endif
end
...
【问题讨论】:
-
所有 3 种语言都是解释性语言,在函数调用时会产生一些开销。考虑到 Python 和 Matlab 都比 Octave 进行了更好的优化,我并不感到惊讶,因为它们是更大的项目(更大的用户群,更多的开发发生等)。特别是,Matlab 使用即时 (JIT) 加速器,在许多情况下会更快。至于如何避免这个问题:矢量化你的代码,除非绝对必要,否则不要使用循环。
-
@rth 感谢您提供有见地的信息。不幸的是,我的代码是牛顿法的迭代实现(有几个方程),所以我不确定如何对其进行矢量化。这种情况有什么可能的解决方案吗?如果我发布我的代码也会有帮助吗?
标签: performance matlab function optimization octave