【问题标题】:Contracting tensor in MatlabMatlab中的收缩张量
【发布时间】:2019-04-28 16:39:47
【问题描述】:

我正在寻找一种在 Matlab 中收缩张量的两个索引的方法。

假设我有一个维度为 [17,10,17,12] 的张量,我正在寻找一个函数,它对具有相同索引的第一维和第三维求和,并留下一个维度为 [10,12] 的矩阵(类似到二维的轨迹)。

我目前正在研究张量网络,主要使用“置换”和“重塑”功能。如果一个人在收缩多个张量并且从一开始就没有小心,那么最终可能会得到一个想要在 [i,j,i,k] 形式的张量中收缩的索引。

当然,人们可以返回并以一种不会发生这种情况的方式收缩张量,但我仍然对更强大的解决方案感兴趣。

编辑:

大意是:

A = rand(17,10,17,12);
A_contracted = zeros(10,12);
for i = [1:10]
    for j = [1:12]
        for k = [1:17]
            A_contracted(i,j) = A_contracted(i,j) + A(k,i,k,j);
        end
    end

end

【问题讨论】:

    标签: matlab tensor


    【解决方案1】:

    这是一种方法:

    A_contracted = permute(sum( ...
       A.*((1:size(A,1)).'==reshape(1:size(A,3), 1, 1, [])), [1 3]), [2 4 1 3]);
    

    以上使用implicit expansion 以及在sum 中一次沿多个维度进行操作的可能性,这是最近的Matlab 功能。对于较旧的 Matlab 版本,

    A_contracted = permute(sum(sum( ...
       A.*bsxfun(@eq, (1:size(A,1)).', reshape(1:size(A,3), 1, 1, [])),1),3), [2 4 1 3]);
    

    【讨论】:

      【解决方案2】:

      [我觉得我开始听起来像是一张破唱片...]

      您应该始终首先将代码实现为循环,然后尝试使用permutereshape 进行优化。但请注意,permute 需要复制数据,因此往往会增加工作量,而不是减少工作量。最新版本的 MATLAB 在循环方面不再缓慢,因此复制数据不再是加快速度的有用技巧。

      例如,问题中的循环可以简化为:

      A_contracted = zeros(size(A,2),size(A,4));
      for k = 1:size(A,1)
          A_contracted = A_contracted + squeeze(A(k,:,k,:));
      end
      

      (我也推广到任意大小)。

      Luis' answer 相比,我看到矢量化方法在小型阵列(例如 OP (17x10x17x12) 中的阵列)中以 0.09 毫秒对 0.19 毫秒获胜。但是,周围的时间非常短,可能不值得付出努力。但是,对于较大的数组(我尝试了 17x100x17x120),我看到循环方法赢得了 1.3 毫秒和 2.6 毫秒。

      数据越多,使用简单的旧循环的优势就越大。对于 170x100x170x120,它是 0.04 秒对 0.45 秒。


      测试代码:

      A = rand(17,100,17,120);
      assert(all(method2(A)==method1(A),'all'))
      timeit(@()method1(A))
      timeit(@()method2(A))
      
      function A_contracted = method1(A)
      A_contracted = permute(sum( ...
         A.*((1:size(A,1)).'==reshape(1:size(A,3), 1, 1, [])), [1 3]), [2 4 1 3]);
      end
      
      function A_contracted = method2(A)
      A_contracted = zeros(size(A,2),size(A,4));
      for k = 1:size(A,1)
          A_contracted = A_contracted + squeeze(A(k,:,k,:));
      end
      end
      

      【讨论】:

        【解决方案3】:

        我的教授提出了另一种解决方案(以下用方法 3 表示),涉及重塑和矩阵乘法。

        1. 采用收缩索引大小的单位矩阵
        2. 将其重塑为矢量
        3. 相应地重塑您想要收缩的张量
        4. 将向量和张量相乘
        5. 重塑收缩张量

        Luis's(方法1)和Cris's答案(方法2)比较的示例代码:

        A = rand(17,10,17,10);
        
        timeit(@()method1(A))
        timeit(@()method2(A))
        timeit(@()method3(A))
        
        function A_contracted = method1(A)
        A_contracted = permute(sum( ...
           A.*((1:size(A,1)).'==reshape(1:size(A,3), 1, 1, [])), [1 3]), [2 4 1 3]);
        end
        
        
        function A_contracted = method2(A)
        A_contracted = zeros(size(A,2),size(A,4));
        for k = 1:size(A,1)
            A_contracted = A_contracted + squeeze(A(k,:,k,:));
        end
        end
        
        
        function A_contracted = method3(A)
        sa_1 = size(A,1);
        Unity = eye(size(A, 1));
        Unity = reshape(Unity, [1,sa_1*sa_1]);
        A1 = permute(A, [1,3,2,4]);
        A2 = reshape(A1, [sa_1*sa_1, size(A1, 3)* size(A1,4)]);
        UnA = Unity*A2;
        A_contracted = reshape(UnA, [size(A1,3), size(A1,4)]);
        end
        

        method3 在小维度上的优势超过 method1 和 method2 一个数量级,并且在较大维度上也优于 method1,但在较大维度上被 for 循环击败一个数量级。

        method3 具有(有点个人的)优势,即在我的物理课程中的应用程序更直观,因为收缩实际上并不是在张量本身中,而是在度量方面。 method3 可以很容易地适应这个特性。

        【讨论】:

          【解决方案4】:

          很简单

          squeeze(sum(sum(a,3),1))
          

          sum(a,n) 对数组的第 n 维求和,squeeze 删除任何单维数

          【讨论】:

          • 我已经编辑了这个问题。我相信您建议的内容独立地对索引进行求和,但不是在同一步骤中。我刚刚尝试过,它没有给出想要的结果。
          • @Phteven 您应该添加一个小示例和所需的输出。建议的答案对您最初的问题是正确的:我正在寻找一个函数,它对第一个和第三个索引求和并留下一个维度为 [5,3] 的矩阵。 不幸的是,您的编辑不正确MATLAB 代码,目前还不清楚,你真正想要实现什么。此外,您的编辑使给定的(正确)答案无效,因此后来的读者可能会认为,这个答案从一开始就是(或曾经)错误的。
          • @user1543042 对此我很抱歉。我添加的代码现在适用于我的示例。对于提出不当的问题,答案当然是正确的,但不是我的问题。
          猜你喜欢
          • 2011-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-25
          • 2012-01-03
          • 1970-01-01
          相关资源
          最近更新 更多