【问题标题】:How to multiply tensors in MATLAB without looping?如何在不循环的情况下在 MATLAB 中将张量相乘?
【发布时间】:2015-10-08 10:26:45
【问题描述】:

假设我有:

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 保持不变。

【问题讨论】:

  • 如果A = rand(4,10,3) 是一个没有单一维度的3D 数组怎么办?那么输出必须是什么?
  • @Divakar 我的问题总是单例。
  • 在这种情况下,只需 squeeze A 并使用矩阵乘法 - C = B.'*squeeze(A)
  • @Divakar 这就是 LuisMendo 的回答,它确实加快了程序的运行速度,无论如何谢谢!

标签: performance matlab multidimensional-array vectorization multiplication


【解决方案1】:

置换AB 的维度,然后应用矩阵乘法:

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

【讨论】:

  • 你是绝对正确的。但是,OP 应该记住,此解决方案仅适用于 A 的第一个维度是单例的。
  • 10% 的执行时间减少!非常感谢!
  • 非常好,但我想知道为什么 OP 使用具有单维的 3 维数组
【解决方案2】:

如果A 是一个 3D 数组,类似于A = rand(4,10,3) 并假设B 保持为2D 数组,那么每个A(:,:,1)*B 都会产生一个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)

【讨论】:

    【解决方案3】:

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

    我已经为此苦苦挣扎了一段时间,但我一直无法提出解决方案。 bsxfun 可以很好地执行逐元素计算,但是张量乘法是非常不支持的。对不起,祝你好运!

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

    【讨论】:

    • 你是对的,我已经更新了我的答案。我将把它留在这里指出,一般来说,您的解决方案不成立。但是,它确实解决了这里提出的问题。
    • 在您编辑后,我已删除我的反对票。不过,我不清楚张量乘法是 OP 所追求的。如果A 的第一个维度不是1,则问题中的赋值C(:,1) = A(:,:,1)*B 没有意义,因为A(:,:,1)*B 将是一个矩阵,而不是一个向量
    【解决方案4】:

    我不得不同意@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
    

    【讨论】:

      猜你喜欢
      • 2022-11-15
      • 2017-06-14
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 2021-11-27
      • 2023-03-24
      相关资源
      最近更新 更多