在MATLAB中进行高效的3D元素操作

时间:2015-10-22 01:54:45

标签: matlab matrix multidimensional-array bsxfun elementwise-operations

说我有两个可能性:

A=50;
B=50;
C=1000;
X = rand(A,B);
Y = rand(A,B,C);

我想从X的每个切片C中减去Y。这是一个相当普遍的问题,我找到了三种替代解决方案:

% Approach 1: for-loop
tic
Z1 = zeros(size(Y));
for i=1:C
    Z1(:,:,i) = Y(:,:,i) - X;
end
toc

% Approach 2: repmat
tic
Z2 = Y - repmat(X,[1 1 C]);
toc

% Approach 3: bsxfun
tic
Z3=bsxfun(@minus,Y,X);
toc

我正在建立一个经常(即数千次)解决这类问题的程序,所以我正在寻找最有效的解决方案。以下是一种常见的结果模式:

Elapsed time is 0.013527 seconds.
Elapsed time is 0.004080 seconds.
Elapsed time is 0.006310 seconds.

循环显然较慢,而bsxfun比repmat慢一点。当我对X的切片进行逐元素乘法(而不是减去)Y时,我发现相同的模式,尽管repmat和bsxfun在乘法中稍微靠近。

增加数据的大小...

A=500;
B=500;
C=1000;
Elapsed time is 2.049753 seconds.
Elapsed time is 0.570809 seconds.
Elapsed time is 1.016121 seconds.

在这里,repmat是明显的赢家。我想知道SO社区中是否有人有一个很酷的伎俩来加速这项操作。

1 个答案:

答案 0 :(得分:2)

根据您的实际情况,bsxfunrepmat有时会比另一个更具优势,就像@rayryeng建议的那样。您还可以考虑另外一个选项:mex。我硬编码了一些参数以获得更好的性能。

#include "mex.h"
#include "matrix.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

    double *A, *B, *C;
    int ind_1, ind_2, ind_3, ind_21, ind_32, ind_321, Dims[3] = {500,500,5000};

    plhs[0] = mxCreateNumericArray(3, Dims, mxDOUBLE_CLASS, mxREAL);
    A = mxGetPr(prhs[0]);
    B = mxGetPr(prhs[1]);
    C = mxGetPr(plhs[0]);

    for ( int ind_3 = 0; ind_3 < 5000; ind_3++)
    {
        ind_32 = ind_3*250000;
        for ( int ind_2 = 0; ind_2 < 500; ind_2++)
        {
            ind_21 = ind_2*500;         // taken out of the innermost loop to save some calculation
            ind_321 = ind_32 + ind_21;
            for ( int ind_1 = 0 ; ind_1 < 500; ind_1++)
            {
                C[ind_1 + ind_321] = A[ind_1 + ind_321] - B[ind_1 + ind_21];
            }
        }
    }
} 

要使用它,请将其输入命令窗口(假设您将上述c文件命名为mexsubtract.c)

mex -WIN64 mexsubtract.c

然后你可以像这样使用它:

Z4 = mexsubtract(Y,X);

以下是我的计算机上使用A = 500,B = 500,C = 5000:

的一些测试结果
(repmat) Elapsed time is 3.441695 seconds.
(bsxfun) Elapsed time is 3.357830 seconds.
(cmex)   Elapsed time is 3.391378 seconds.

这是一个很有竞争力的竞争者,在一些更极端的情况下,它会有优势。例如,这是我得到的A = 10,B = 500,C = 200000:

(repmat) Elapsed time is 2.769177 seconds.
(bsxfun) Elapsed time is 3.178385 seconds.
(cmex)   Elapsed time is 2.552115 seconds.