创建 array/tensor 个循环移位数组

Create array/tensor of cycle shifted arrays

我想创建 2d 张量(或 numpy 数组,并不重要),其中每一行都将循环移位到第一行。我使用 for 循环:

import torch
import numpy as np

a = np.random.rand(33, 11)
miss_size = 64
lp_order = a.shape[1] - 1
inv_a = -np.flip(a, axis=1)
mtx_size = miss_size+lp_order   # some constant
mtx_row = torch.cat((torch.from_numpy(inv_a), torch.zeros((a.shape[0], miss_size - 1 + a.shape[1]))), dim=1)
mtx_full = mtx_row.unsqueeze(1)
for i in range(mtx_size):
        mtx_row = torch.roll(mtx_row, 1, 1)
        mtx_full = torch.cat((mtx_full, mtx_row.unsqueeze(1)), dim=1)

需要解压缩,因为我将 2d 张量堆叠到 3d 张量中

有没有更有效的方法?也许是线性代数技巧或更多 pythonic 方法。

您可以使用 scipy.linalg.circulant():

scipy.linalg.circulant([1, 2, 3])
# array([[1, 3, 2],
#        [2, 1, 3],
#        [3, 2, 1]])

我相信您可以使用 torch.gather 通过构造适当的索引张量来实现此目的。这种方法也适用于批处理。

如果我们采用这种方法,objective 就是构建一个索引张量,其中每个值都引用 mtx_row 中的一个索引(这里是最后一个维度 dim=1)。在这种情况下,它的形状为 (3, 3):

tensor([[0, 1, 2],
        [2, 0, 1],
        [1, 2, 0]])

您可以通过使用自己的转置广播 torch.arange 并对结果矩阵应用模来实现此目的:

>>> idx = (n-torch.arange(n)[None].T + torch.arange(n)[None]) % n
tensor([[0, 1, 2],
        [2, 0, 1],
        [1, 2, 0]])

mtx_row整形(2, 3):

>>> mtx_row
tensor([[0.3523, 0.0170, 0.1875],
        [0.2156, 0.7773, 0.4563]])

从那里你需要 idxmtx_row 所以它们有相同的形状:

>>> idx_ = idx[None].expand(len(mtx_row), -1, -1)
>>> val_ = mtx_row[:, None].expand(-1, n, -1)

然后我们可以在最后一个维度上应用torch.gather dim=2:

>>> val_.gather(-1, idx_)
tensor([[[0.3523, 0.0170, 0.1875],
         [0.1875, 0.3523, 0.0170],
         [0.0170, 0.1875, 0.3523]],

        [[0.2156, 0.7773, 0.4563],
         [0.4563, 0.2156, 0.7773],
         [0.7773, 0.4563, 0.2156]]])