Вот один из способов использования нарезки, укладки и изменения формы на основе вида:
In [239]: half_way = b.shape[0]//2
In [240]: upper_half = torch.stack((b[:half_way, :][:, 0], b[:half_way, :][:, 1]), dim=0).view(-1, 3, 3)
In [241]: lower_half = torch.stack((b[half_way:, :][:, 0], b[half_way:, :][:, 1]), dim=0).view(-1, 3, 3)
In [242]: torch.stack((upper_half, lower_half))
Out[242]:
tensor([[[[11, 17, 9],
[ 6, 5, 4],
[ 2, 10, 3]],
[[11, 8, 4],
[14, 13, 12],
[16, 1, 5]]],
[[[13, 14, 12],
[ 7, 1, 15],
[16, 8, 0]],
[[17, 0, 10],
[ 7, 15, 9],
[ 6, 2, 3]]]])
Некоторые предостережения в том, что это будет работать только для n=2
. Однако это в 1,7 раза быстрее, чем ваш подход, основанный на циклах, но требует больше кода.
Вот более обобщенный подход , который масштабируется до любого положительного целого числа n
:
In [327]: %%timeit
...: block_size = b.shape[0]//a.shape[0]
...: seq_of_tensors = [b[block_size*idx:block_size*(idx+1), :].permute(1, 0).flatten().reshape(2, 3, 3).unsqueeze(0) for idx in range(a.shape[0])]
...: torch.cat(seq_of_tensors)
...:
23.5 µs ± 460 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Вы также можете использовать view
вместо изменения формы:
block_size = b.shape[0]//a.shape[0]
seq_of_tensors = [b[block_size*idx:block_size*(idx+1), :].permute(1, 0).flatten().view(2, 3, 3).unsqueeze(0) for idx in range(a.shape[0])]
torch.cat(seq_of_tensors)
# outputs
tensor([[[[11, 17, 9],
[ 6, 5, 4],
[ 2, 10, 3]],
[[11, 8, 4],
[14, 13, 12],
[16, 1, 5]]],
[[[13, 14, 12],
[ 7, 1, 15],
[16, 8, 0]],
[[17, 0, 10],
[ 7, 15, 9],
[ 6, 2, 3]]]])
Примечание : обратите внимание, что я все еще использую понимание списка, поскольку мы должны равномерно разделить наш тензор b
, чтобы переставить, сгладить, изменить форму, отжать, а затем объединить / сложить вдоль измерения 0. Это все еще немного быстрее, чем мое решение выше.