【问题标题】:Extract diagonal element from each frontal slice of tensor从张量的每个正面切片中提取对角线元素
【发布时间】:2015-02-09 03:05:24
【问题描述】:

我有一个 p×p×n 张量。我想为每个 p-by-p 切片提取对角线元素。有没有人知道如何在不循环的情况下做到这一点?

谢谢。

【问题讨论】:

  • 为什么要不循环执行? pn 会有多大?

标签: matlab matrix vectorization


【解决方案1】:

Behold 强大而强大的bsxfunvectorizing MATLAB problems 使用MATLAB's linear indexing 非常有效地完成这项任务 -

diags = A(bsxfun(@plus,[1:p+1:p*p]',[0:n-1]*p*p))

使用4 x 4 x 3 大小的输入数组运行示例 -

A(:,:,1) =
    0.7094    0.6551    0.9597    0.7513
    0.7547    0.1626    0.3404    0.2551
    0.2760    0.1190    0.5853    0.5060
    0.6797    0.4984    0.2238    0.6991
A(:,:,2) =
    0.8909    0.1493    0.8143    0.1966
    0.9593    0.2575    0.2435    0.2511
    0.5472    0.8407    0.9293    0.6160
    0.1386    0.2543    0.3500    0.4733
A(:,:,3) =
    0.3517    0.9172    0.3804    0.5308
    0.8308    0.2858    0.5678    0.7792
    0.5853    0.7572    0.0759    0.9340
    0.5497    0.7537    0.0540    0.1299
diags =
    0.7094    0.8909    0.3517
    0.1626    0.2575    0.2858
    0.5853    0.9293    0.0759
    0.6991    0.4733    0.1299

基准测试

这里有几个运行时测试比较这种基于 bsxfun 的方法和 repmat + eye based approach 的大数据大小 -

***** Datasize: 500 x 500 x 500 *****
----------------------- With BSXFUN
Elapsed time is 0.008383 seconds.
----------------------- With REPMAT + EYE
Elapsed time is 0.163341 seconds.

***** Datasize: 800 x 800 x 500 *****
----------------------- With BSXFUN
Elapsed time is 0.012977 seconds.
----------------------- With REPMAT + EYE
Elapsed time is 0.402111 seconds.

***** Datasize: 1000 x 1000 x 500 *****
----------------------- With BSXFUN
Elapsed time is 0.017058 seconds.
----------------------- With REPMAT + EYE
Elapsed time is 0.690199 seconds.

【讨论】:

  • 好宠物!非常乖巧听话。 +1。
  • 直接indexing 而不是masking。可爱的:)
  • @SanthanSalai 是的!更少的内存需求并且仍然是矢量化的,这只是其中一种特殊情况。
  • 任何看到这种问题的人显然会想到masking,但你选择了不同的路线;)
  • @SanthanSalai 我没有采取不同的路线,我本能地采取了默认路线,bsxfun 路线! ;)
【解决方案2】:

我的一个建议是创建一个p x p 逻辑单位矩阵,在第三维中复制这个n 次,然后使用这个矩阵来访问你的张量。像这样,假设你的张量存储在A

ind = repmat(logical(eye(p)), [1 1 n]);
out = A(ind);

使用示例:

>> p = 5; n = 3;
>> A = reshape(1:75, p, p, n)

A(:,:,1) =

     1     6    11    16    21
     2     7    12    17    22
     3     8    13    18    23
     4     9    14    19    24
     5    10    15    20    25


A(:,:,2) =

    26    31    36    41    46
    27    32    37    42    47
    28    33    38    43    48
    29    34    39    44    49
    30    35    40    45    50


A(:,:,3) =

    51    56    61    66    71
    52    57    62    67    72
    53    58    63    68    73
    54    59    64    69    74
    55    60    65    70    75

>> ind = repmat(logical(eye(p)), [1 1 n]);
>> out = A(ind)

out =

     1
     7
    13
    19
    25
    26
    32
    38
    44
    50
    51
    57
    63
    69
    75

您会注意到我们抓取了第一个切片的对角线,然后是第二个切片的对角线,依此类推,直到最后一个切片。这些值都连接到一个向量中。

【讨论】:

  • 我也在这里使用了我的"pet"! ;)
【解决方案3】:

只是阅读Divakar's 的答案并试图理解为什么他再次比my idea 快大约 10 倍,我将代码混合在一起,最终得到更快的代码:

A=reshape(A,[],n);
diags2 = A(1:p+1:p*p,:);

对于 500x500x500 张量,Divakar 的解决方案为 0.008 秒,我使用 Matlab 2013a 的解决方案为 0.005 秒。可能纯索引是击败bsxfun 的唯一方法。

【讨论】:

  • 啊涉及到重塑索引,很好。 reshape 会不会有点昂贵的事情?
  • reshape 不是基本零成本吗?我从未见过它增加了任何实质性的运行时间。
  • 好吧,与permute 之类的东西相比,reshape 的成本并不高,但肯定不是免费的。您是否在时间安排中包括了重塑?
  • 是的,它已包含在我的计时中。 reshape 根本不会触及内存中的数据。
  • @Divakar:昨天在聊天中与 Ander Biguri 进行了类似的讨论。现在意识到即使你不知道重塑的速度,我想我应该share that knowledge
猜你喜欢
  • 2016-07-04
  • 1970-01-01
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 2020-02-05
  • 2013-02-08
相关资源
最近更新 更多