N代表数量,C代表channel,H代表高度,w代表宽度。NCHW其实代表的是[W H C N]第一个元素,第二个元素是沿着w方向即001,这样下去002 003,再接着就是沿着H方向,即004 005 006 007...这样到09后,沿C方向,轮到020,之后021 022...一直到319,然后沿着N方向。
NHWC的话以此类推,代表的是[C W H N ],第一个元素是000,第二个沿C方向,即020,040,060...一直到300,之后沿W方向,001 021 041 061 301...到了303后,沿着H方向,即004 024 ...304。最后到了319,变成了N方向,320,340...
例如data_format默认值NHWC,其中N表示这张图片有几张,H表示图像在垂直方向有多少像素,W表示水平方向像素数,C表示通道数(例如黑白图像的通道树C = 1 ,RGB彩色图像的通道数C = 3 )。为了便于演示,我们后面作图均使用RGB三通道图像。
NCHW中,C排列在外层,每个通道内像素紧紧挨在一起,即“RRRRRGGGGGBBBBB”
NHWC格式中,C排列在最内层,多个通道对应空间位置紧挨在一起,即“RGBRGBRGBRGBRGBRGB”这种形式。
如果我们需要对图像做彩色转灰度计算,NCHW计算过程如下:
即R通道所有像素值乘以0.299,G通道所有像素值乘以0.587,B通道所有像素值乘以0.114,最后将三个通道结果相加得到灰度值。
相应地,NHWC数据格式的彩色转灰度计算过程如下:
输入数据分成多个(R,G,B)像素值,每个像素组中R通道像素值乘以0.299,G通道像素值乘以0.587,B通道像素值乘以0.114后相加得到一个灰度输出像素。将多组结果拼接在一起得到所有灰度输出像素。
以上使用的两种数据格式进行RGB->灰度计算的复杂度是相同的,区别与访存特性。通过两张图对比可以发现,NHWC的访存局部性更好(每三个像素值即可得到一个输出像素),NCHW则必须等所有通道输入准备号才能的到最终输出结果,需要占用较大的临时空间。
在CNN中常常见到1x1卷积,也是每个输入channel乘一个权重,然后将所有channel结果累加得到一个输出channel。如果使用NHWC数据格式,可以将卷即计算简化为矩阵乘计算,即1×1卷积核实现了每个输入像素组到每个输出像素组的线性变换。
那为什么TensorFlow悬在NHWC作为默认格式,因为早期开发都散基于CPU,使用NHWC会比NCHW稍微快一些。(不难理解,NHWC局部性更好,cache(缓存)利用率高)。
NCHW则是Nvidia cuDNN默认格式,使用GPU加速时用NCHW格式会更快(也有个别情况例外)。
最佳实践:设计网络时充分考虑两种格式,最好能灵活切换,在GPU上训练使用NCHW格式,在CPU上做预测时使用NHWC格式。
在不同的硬件加速的情况下,选用的类型不同,在intelGPU加速的情况下,因为GPU对于图像的处理比较多,希望在访问同一个channel的像素是连续的,一般存储选用NCHW,这样在做CNN的时候,在访问内存的时候就是连续的了,比较方便。