我是matlab中使用分布式和分布式数组的新手。我生产的并行代码有效,但比串行版慢得多,我不明白为什么。下面的代码示例根据体积数据计算粗体矩阵的特征值。
串行版:
S = size(D);
Dsmt=imgaussian(D,2,20);
[fx, fy, fz] = gradient(Dsmt);
DHess = zeros([3 3 S(1) S(2) S(3)]);
[DHess(1,1,:,:,:), DHess(1,2,:,:,:), DHess(1,3,:,:,:)] = gradient(fx);
[DHess(2,1,:,:,:), DHess(2,2,:,:,:), DHess(2,3,:,:,:)] = gradient(fy);
[DHess(3,1,:,:,:), DHess(3,2,:,:,:), DHess(3,3,:,:,:)] = gradient(fz);
d = zeros([3 S(1) S(2) S(3)]);
for i = 1 : S(1)
fprintf('Slice %d out of %d\n', i, S(1));
for ii = 1 : S(2)
for iii = 1 : S(3)
d(:,i,ii,iii) = eig(squeeze(DHess(:,:,i,ii,iii)));
end
end
end
并行版本:
S = size(D);
Dsmt=imgaussian(D,2,20);
[fx, fy, fz] = gradient(Dsmt);
DHess = zeros([3 3 S(1) S(2) S(3)]);
[DHess(1,1,:,:,:), DHess(1,2,:,:,:), DHess(1,3,:,:,:)] = gradient(fx);
[DHess(2,1,:,:,:), DHess(2,2,:,:,:), DHess(2,3,:,:,:)] = gradient(fy);
[DHess(3,1,:,:,:), DHess(3,2,:,:,:), DHess(3,3,:,:,:)] = gradient(fz);
CDHess = distributed(DHess);
spmd
d = zeros([3 S(1) S(2) S(3)], codistributor('1d',4));
for i = 1 : S(1)
fprintf('Slice %d out of %d\n', i, S(1));
for ii = 1 : S(2)
for iii = drange(1 : S(3))
d(:,i,ii,iii) = eig(squeeze(CDHess(:,:,i,ii,iii)));
end
end
end
end
如果有人能对这个问题有所了解,我将非常感激
答案 0 :(得分:2)
这是您的代码的重写版本。我已经将工作拆分为最外层循环,而不是在你的情况下 - 最内层循环。我还明确地分配了d
结果向量的局部部分,以及Hessian矩阵的局部部分。
在您的代码中,您依靠drange
来分割工作,并直接访问分布式阵列以避免提取本地部分。不可否认,如果MATLAB正确地完成所有事情,它不会导致如此大的减速。最重要的是,我不知道你的代码为什么这么慢 - 最有可能的原因是,尽管你分发了你的矩阵,MATLAB仍会进行一些远程数据访问。
无论如何,以下代码运行并使用4个实验室在我的计算机上提供了相当不错的加速。我已经生成了合成随机输入数据以便有所作为。看看评论。如果事情不清楚,我可以稍后详细说明。
clear all;
D = rand(512, 512, 3);
S = size(D);
[fx, fy, fz] = gradient(D);
% this part could also be parallelized - at least a bit.
tic;
DHess = zeros([3 3 S(1) S(2) S(3)]);
[DHess(1,1,:,:,:), DHess(1,2,:,:,:), DHess(1,3,:,:,:)] = gradient(fx);
[DHess(2,1,:,:,:), DHess(2,2,:,:,:), DHess(2,3,:,:,:)] = gradient(fy);
[DHess(3,1,:,:,:), DHess(3,2,:,:,:), DHess(3,3,:,:,:)] = gradient(fz);
toc
% your sequential implementation
d = zeros([3, S(1) S(2) S(3)]);
disp('sequential')
tic
for i = 1 : S(1)
for ii = 1 : S(2)
for iii = 1 : S(3)
d(:,i,ii,iii) = eig(squeeze(DHess(:,:,i,ii,iii)));
end
end
end
toc
% my parallel implementation
disp('parallel')
tic
spmd
% just for information
disp(['lab ' num2str(labindex)]);
% distribute the input data along the third dimension
% This is the dimension of the outer-most loop, hence this is where we
% want to parallelize!
DHess_dist = codistributed(DHess, codistributor1d(3));
DHess_local = getLocalPart(DHess_dist);
% create an output data distribution -
% note that this time we split along the second dimension
codist = codistributor1d(2, codistributor1d.unsetPartition, [3, S(1) S(2) S(3)]);
localSize = [3 codist.Partition(labindex) S(2) S(3)];
% allocate local part of the output array d
d_local = zeros(localSize);
% your ordinary loop, BUT! the outermost loop is split amongst the
% threads explicitly, using local indexing. In the loop only local parts
% of matrix d and DHess are accessed
for i = 1:size(d_local,2)
for ii = 1 : S(2)
for iii = 1 : S(3)
d_local(:,i,ii,iii) = eig(squeeze(DHess_local(:,:,i,ii,iii)));
end
end
end
% assemble local results to a codistributed matrix
d_dist = codistributed.build(d_local, codist);
end
toc
isequal(d, d_dist)
输出
Elapsed time is 0.364255 seconds.
sequential
Elapsed time is 33.498985 seconds.
parallel
Lab 1:
lab 1
Lab 2:
lab 2
Lab 3:
lab 3
Lab 4:
lab 4
Elapsed time is 9.445856 seconds.
ans =
1
修改我已在重新整形的矩阵DHess=[3x3xN]
上检查了效果。性能不是很好(10%),所以它并不重要。但也许你可以有点不同地实现eig
?毕竟,这些是您正在处理的3x3
矩阵。
答案 1 :(得分:1)
你没有指明你打开matlabpool的位置,这将是决定你获得什么加速的主要因素。
如果您使用的是“本地”调度程序,那么使用分布式阵列通常没有任何好处。特别是,如果在MATLAB中耗时的操作已经是多线程的,那么在使用本地调度程序时它们几乎肯定会减速,因为matlabpool worker在单线程模式下运行。
如果您在一台单独的计算机上使用其他调度程序,那么您可能可以获得加速,但这取决于您正在做什么。这里有一个例子http://www.mathworks.com/products/parallel-computing/examples.html?file=/products/demos/shipping/distcomp/paralleldemo_backslash_bench.html,它显示了MATLAB的\
运算符的一些基准。
最后,值得注意的是,对分布式数组进行索引的速度相当慢,特别是与MATLAB的内置索引相比。如果您可以在spmd块中提取您的共同分布数组的“本地部分”并专门使用它们,那么这也可能有所帮助。