nd
到nd
转换的一般思路
这种nd
到nd
转换的想法只使用两个东西 -
重新排列轴:以使扁平化版本对应于输出的扁平化版本的顺序。因此,如果您不知何故使用它两次,请再次查看,因为您不应该这样做。
重塑:将轴分割或将最终输出带到所需的形状。当输入较低维度且我们需要将其分成块时,大多数情况下需要拆分轴。同样,您不应该需要这超过两次。
因此,通常我们会有三个步骤:
[ Reshape ] ---> [ Permute axes ] ---> [ Reshape ]
Create more axes Bring axes Merge axes
into correct order
回溯法
在给定输入和输出的情况下,最安全的解决方法是使用回溯法,即将输入的轴(从较小的nd
到较大的nd
)或输出的轴(从较大的nd
到较小的nd
)进行分割。拆分的想法是将较小的nd
的维数与较大的nd
的维数相同。然后,研究输出的步幅,并将其与输入匹配以获得所需的排列顺序。最后,如果最终的nd
是较小的,则可能需要进行重塑(默认方式或C顺序)以合并轴。
如果输入和输出的维数相同,则需要拆分两者并分成块,并将它们的步幅相互比较。在这种情况下,我们应该有块大小的额外输入参数,但这可能是离题。
示例
让我们使用这个特定案例来演示如何应用这些策略。在这里,输入是4D
,而输出是2D
。因此,我们很可能不需要重塑来拆分。因此,我们需要从排列轴开始。由于最终输出不是4D
,而是2D
,因此我们需要在最后进行重塑。
现在,这里的输入是:
In [270]: a
Out[270]:
array([[[[ 0, 0],
[ 0, 0]],
[[ 5, 10],
[15, 20]]],
[[[ 6, 12],
[18, 24]],
[[ 7, 14],
[21, 28]]]])
预期输出为:
In [271]: out
Out[271]:
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
此外,这是从较大的
nd
到较小的
nd
的转换,因此回溯方法涉及将输出分割并研究其
strides,并与输入中相应的值进行匹配。
axis = 3
--- -->
axis = 1
------>
axis=2| axis=0| [ 0, 5, 0, 10],
| [ 6, 7, 12, 14],
v
| [ 0, 15, 0, 20],
v
[18, 21, 24, 28]])
因此,所需的排列顺序为
(2,0,3,1)
:
In [275]: a.transpose((2, 0, 3, 1))
Out[275]:
array([[[[ 0, 5],
[ 0, 10]],
[[ 6, 7],
[12, 14]]],
[[[ 0, 15],
[ 0, 20]],
[[18, 21],
[24, 28]]]])
然后,只需将其重新塑造为预期的形状:
In [276]: a.transpose((2, 0, 3, 1)).reshape(4,4)
Out[276]:
array([[ 0, 5, 0, 10],
[ 6, 7, 12, 14],
[ 0, 15, 0, 20],
[18, 21, 24, 28]])
更多例子
我挖掘了我的历史记录,找到了一些基于nd
到nd
转换的Q&A
。虽然这些例子的解释较少,但它们可以作为其他案例。正如之前提到的那样,在每个地方最多只需要两个reshapes
和至多一个swapaxes
/transpose
即可完成任务。它们列在下面:
.transpose(2, 0, 3, 1)
比使用.transpose(0,2,1,3)
并采用Fortran顺序进行重塑更加优雅。 - juanpa.arrivillaga