如何在不循环的情况下在MATLAB中乘法张量?

时间:2015-07-19 01:35:53

标签: performance matlab multidimensional-array vectorization multiplication

假设我有:

A = rand(1,10,3);
B = rand(10,16);

我想得到:

C(:,1) = A(:,:,1)*B;
C(:,2) = A(:,:,2)*B;
C(:,3) = A(:,:,3)*B;

我能以某种方式将它乘以一行以便它更快吗?

如果我像这样创建新的张量b

,该怎么办?
for i = 1:3
    b(:,:,i) = B;
end

我可以将A和B相乘得到相同的C但速度更快吗?通过上面的循环创建b所花费的时间并不重要,因为我将需要C用于许多不同的A-s而B保持不变。

4 个答案:

答案 0 :(得分:7)

置换AB的尺寸,然后应用矩阵乘法:

C = B.'*permute(A, [2 3 1]);

答案 1 :(得分:5)

如果A true 3D数组,如A = rand(4,10,3)并假设B保持为2D数组,那么每个A(:,:,1)*B会产生一个2D数组。

因此,假设您希望将这些2D数组作为切片存储在输出数组的第三维中,C就像这样 -

C(:,:,1) = A(:,:,1)*B;
C(:,:,2) = A(:,:,2)*B;
C(:,:,3) = A(:,:,3)*B; and so on.

为了以矢量化的方式解决这个问题,其中一种方法是将整形A用于合并第一维和第三维的二维数组,然后执行矩阵多重复制。最后,为了使输出大小与前面列出的C相同,我们需要重新整形的最后一步。

实现看起来像这样 -

%// Get size and then the final output C
[m,n,r] = size(A);
out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]);

示例运行 -

>> A = rand(4,10,3);
B = rand(10,16);

C(:,:,1) = A(:,:,1)*B;
C(:,:,2) = A(:,:,2)*B;
C(:,:,3) = A(:,:,3)*B;
>> [m,n,r] = size(A);
out = permute(reshape(reshape(permute(A,[1 3 2]),[],n)*B,m,r,[]),[1 3 2]);
>> all(C(:)==out(:)) %// Verify results
ans =
     1

根据comments,如果A是一个在开始时始终为单个维度的3D数组,则可以使用squeeze然后使用矩阵乘法 -

C = B.'*squeeze(A)

答案 2 :(得分:1)

编辑: @LuisMendo指出这确实可能适用于此特定用例。但是,如果A的第一个维度不是1,则(通常)不可能。

我已经解决了一段时间了,我从来没有能够提出解决方案。 bsxfun使得逐个元素的计算变得很好,但是张量乘法是一个非常不受支持的东西。对不起,祝你好运!

你可以查看this mathworks file exchange file,这将使你更容易并支持你正在寻找的行为,但我相信它也依赖于循环。 编辑:它依赖于MEX / C ++,因此如果您正在寻找它,那么它不是纯粹的MATLAB解决方案。

答案 3 :(得分:0)

我必须同意@GJSein,for循环非常快

time
    0.7050    0.3145

这里是计时器功能

function time

    n = 1E7;
    A = rand(1,n,3);
    B = rand(n,16);
    t = [];
    C = {};

    tic
        C{length(C)+1} = squeeze(cell2mat(cellfun(@(x) x*B,num2cell(A,[1 2]),'UniformOutput',false)));
    t(length(t)+1) = toc;

    tic
        for i = 1:size(A,3)
            C{length(C)+1}(:,i) = A(:,:,i)*B;
        end
    t(length(t)+1) = toc;

    disp(t)
end