我看到在卷积网络的世界里有两种类型的数据:通道第一和通道最后。
根据许多网站,&;渠道优先&;为NCHW
格式,channel-last"相当于NHWC
格式。这很清楚,因为在通道第一格式中,C
位于H
和W
之前。然而,ARM似乎已经定义了"通道优先"&;作为NHWC
,你可以在这篇论文中看到。
P6两种最常见的图像数据格式是通道宽度-高度(CHW),即通道最后,和高度-宽度-通道(HWC),即通道第一。维度排序与数据步的排序相同。在在HWC格式中,沿通道的数据以1的步长存储,沿宽度存储数据以通道数为步长,沿高度的数据以(通道数×图像宽度)的步长存储。
这也是合理的,因为"渠道第一"听起来MAC操作是按通道进行的,如下所示:
for (N){
for (H){
for (W){
for (C){
}
}
}
}
所以没有固定的通道优先或通道最后的定义,不是吗?
另外,我不确定当你说NHWC
或NCHW
时,你的具体意思是什么?我想重要的是算法和内存中的数据排列的结合。如果数据以NHWC
格式输入,则需要这样设计算法。
而且,由于没有固定的NHWC
和NCHW
的定义,我认为如果你只是说PyTorch是NCHW
,通道优先或其他没有提及数据如何在内存中排列的东西是没有任何意义的。
或者当你听到NCHW
时,你可以意识到内存中的数据排列就像ch0[0,0]
,ch1[0, 0]
,ch2[0, 0]
,ch0[1, 0]
,ch1[1, 0]
,ch2[1, 0]
,ch0[2, 0]
,…?
谁能帮助澄清我对数据格式的理解?
我最初忽略了您所链接的论文,其中他们清楚地定义了两个对立的术语通常如何在文档和其他地方使用。确实有两种不同的方式来看待CHW
和HWC
…
TLDR;对于终端用户,CHW
是通道优先,而HWC
是通道最后。在这种情况下,我们指的是通道维度相对于其他维度(H
和W
)的位置。它是在CHW
之前还是在HWC
之后,是由所使用的库定义的约定问题(例如。PyTorchvs。Tensorflow)。在内存分配方面,调用CHW
通道是有意义的,这意味着通道轴的stride将是最后一个:它将在张量的其他轴上最后展开。
如果你只是说PyTorch是NCHW,通道优先或其他没有提及数据如何在内存中排列的东西,我认为这没有任何意义。
对于终端用户(如终端开发人员),如何分配或安排内存并不重要。重要的是要知道如何使用PyTorch提供的API来操作torch.Tensor
。当我们说NCHW
时,我们指的是"通道优先",即形状为(batch_size, channel, height, width)
的张量。在所有PyTorch文档页面中,您将找到张量需要具有的确切形状,输入和输出。它只是碰巧他们选择了坚持NCHW约定的二维通道张量。
坚持使用一种格式是有意义的,让它用于底层实现-内存安排确实重要-或最终用户本身-习惯于使用单一格式。
以TensorFlow为例,channel是最后一个,所以使用的格式是NHWC
。
回到HWC
(resp。CHW
)被命名为通道优先。channel-last)。这与张量步幅有关:即。数据在内存中的布局。直观地,您可以认为格式HWC
是通道优先,因为通道维度是第一个展开的轴。
如果你看这个例子:
>>> x = torch.rand(2,3,4) # last dimension is the channel axis
tensor([[[0.5567, 0.0276, 0.6491, 0.7933],
[0.2876, 0.0361, 0.3883, 0.3201],
[0.6742, 0.0305, 0.5719, 0.4683]],
[[0.3385, 0.2082, 0.1675, 0.3429],
[0.6146, 0.0533, 0.6147, 0.2216],
[0.1855, 0.6107, 0.1716, 0.0071]]])
底层的内存安排实际上是在平坦化数据时显示的(假设初始张量的数据在内存中是连续的):
>>> x.flatten()
tensor([0.5567, 0.0276, 0.6491, 0.7933, 0.2876, 0.0361, 0.3883, 0.3201, 0.6742,
0.0305, 0.5719, 0.4683, 0.3385, 0.2082, 0.1675, 0.3429, 0.6146, 0.0533,
0.6147, 0.2216, 0.1855, 0.6107, 0.1716, 0.0071])
注意上面的数据是如何布局的:通过通道0.5567, 0.0276, 0.6491, 0.7933
,然后0.2876, 0.0361, 0.3883, 0.3201
,等等…
在另一种格式(即。CHW
),它将被布局为0.5567, 0.2876, 0.6742
,然后0.3385, 0.6146, 0.1855
,等等…
因此,当涉及到如何在内存中分配数据时,调用CHW
channel-last(HWC
aschannel-first)确实是有意义的。