5

我不熟悉在 matlab 中使用分布式和协同分布式数组。我生成的并行代码有效,但比串行版本慢得多,我不知道为什么。下面的代码示例根据体积数据计算 hessian 矩阵的特征值。

系列版本:

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

如果有人能对这个问题有所了解,我将不胜感激

4

2 回答 2

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您正在处理的矩阵。

于 2012-10-26T13:12:22.213 回答
1

您没有指定打开 matlabpool 的位置,这将是决定您获得何种加速的主要因素。

如果您使用的是“本地”调度程序,那么使用分布式数组通常没有任何好处。特别是,如果耗时的操作在 MATLAB 中已经是多线程的,那么在使用本地调度程序时它们几乎肯定会变慢,因为 matlabpool 工作程序以单线程模式运行。

如果您在单独的机器上使用其他调度程序和工作人员,那么您可能可以获得加速,但这取决于您在做什么。这里有一个示例http://www.mathworks.com/products/parallel-computing/examples.html?file=/products/demos/shipping/distcomp/paralleldemo_backslash_bench.html显示了 MATLAB\运算符的一些基准。

最后,值得注意的是,索引分布式数组很不幸,特别是与 MATLAB 的内置索引相比。如果您可以在 spmd 块内提取您的共同分布式数组的“本地部分”并专门使用这些数组,那也可能会有所帮助。

于 2012-10-26T09:24:33.153 回答