加速MATLAB代码

文章来自微信公众号“科文路”,欢迎关注、互动。转发须注明出处。
来源:MATLAB官网视频 How to speed up MATLAB code?

1 例一 循环条件赋值

有代码,tips3.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
clear('A','B');
numElements = 5000;

for i = 1:numElements
for j = 1:numElements
A(i,j) = rand;

if (A(i,j) > 0.5)
B(i,j) = A(i,j)
else
B(i,j) = -A(i,j)
end
end
end

查看运行时间,使用tictoc

1
2
>> tic; tips3; toc
时间已过 130.978966 秒。

查看右侧滑块条,红色表示错误,橙色表示可改进,绿色表示就绪,

orange

上图可以看出,在有AB的地方有橙色指示,表示每次他们的大小的改变,都是昂贵的。,特别是大矩阵。

1.1 预分配

解决方法是预分配。如加上A = zeros(numElements);

green

再测时间,

1
2
>> tic; tips3; toc
时间已过 1.641815 秒。

1.2 探查器与循环外赋值

现在指示已转为绿色,我们使用**MATLAB探查器(Profiler)**衡量代码核心性能,来进行进一步加速。

转到主页(Home),选择运行并计时(Run and Time),这将打开探查器,使用其进行分析,

我的2019a显示空白

解决方法为:Lxknn 打开主页→预设→字体→自定义,在右侧“桌面工具”中找到“探查器”,修改字体为Segoe UI,之后点击下面的“应用”就好。不行的话试试其他字体。适用于MATLAB R2019a中文版。

profiler

可以查看很多信息。同时,我们在下面逐行分析中发现耗时最多的语句为A(i,j)

timelarge

于是,将rand改为循环外的rand(n),这时,运行探查器的总时间缩短为7s。

1.3 逻辑数组条件赋值

接下来使用逻辑数组改善循环的判断与条件赋值,

1
2
3
4
5
6
7
clear('A','B');
numElements = 5000;

A = rand(numElements);
B = A;
idx = A < 0.5;
B(idx) = -A(idx);

现在的总时长陡降至1s以内,而且可以看到,没有循环。

至此我们的优化使程序从100+s -> 1-s。

2 例二 矩阵最大特征值

复用例一的代码,同时进行矩阵B的最大特征值的计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
clear('A','B','C');
numElements = 5000;
numB = 24;
C = zeros(1, numB);

for i = 1:numB
A = rand(numElements);
B = A;
idx = A < 0.5;
B(idx) = -A(idx);

C(:,i) = max(eig(B));
end

同样的,查看一下运行时间,

1
2
>> tic;tips3;toc
时间已过 1258.652858 秒。

可以看到循环内每次计算特征值都非常耗时,这种情况下可以进行多核的并行计算后合并结果。

使用Parallel Computing Toolbox完成该项工作。

使用parpool创建worker池,worker数量取决于CPU核心数,

1
>> parpool

然后使用parfor代替for,即parfor i = 1:numB,可以看到最终时间,

1
2
3
4
>> tic;tips3;toc
时间已过 813.310429 秒。
IdleTimeout has been reached.
Parallel pool using the 'local' profile is shutting down.

注意,并行计算将带来其他的开销,例如创建worker的时间,并行代码的编写,通信开销等。建议使用时先测试并确定并行计算是值得的。

3 其他方法

https://ww2.mathworks.cn/company/newsletters/articles/accelerating-matlab-algorithms-and-applications.html

都看到这儿了,不如关注每日推送的“科文路”、互动起来~

Author

xlindo

Posted on

2022-03-09

Updated on

2023-05-10

Licensed under

Comments