NCHW与TensorFlow / cuDNN中的NHWC相比要快多少?

时间:2017-05-31 09:05:33

标签: tensorflow gpu cudnn

The official TensorFlow performance guide州:

  

CNN使用的大多数TensorFlow操作都支持NHWC和NCHW数据格式。在GPU上,NCHW更快。但在CPU上,NHWC有时会更快。

对于卷积,NCHW与TensorFlow / cuDNN中的NHWC相比要快多少?对此有任何参考或基准吗?

另外,为什么它更快?据我所知(参见here),TensorFlow for GPU上的NHWC将在内部始终转置为NCHW,然后调用cuDNN conv内核为NCHW,然后将其转置回来。但为什么会这样呢? cuDNN conv内核也适用于NHWC。也许在某些时候他们进行了比较,而NHDNC的cuDNN conv内核非常慢。但这是最新的吗?差异有多大? NHWC如此慢得多的技术原因是什么?或者这个案例的cuDNN内核是不是很好地优化了?

4 个答案:

答案 0 :(得分:4)

原因是大多数简单卷积的实现(此处不讨论winograd或fft)最终都进行了某种简单的矩阵乘法,这意味着它们在其内部循环中将两个张量的值相乘并求和。

在采用SSE或AVX优化的CPU实现中,沿着C维执行此操作更快,因为您只需将4乘以4或8乘以8,然后进行减少(将4或添加完所有C维后,最后添加8次。

但是,在GPU上,减少线程的开销是一项成本更高的操作(至少直到开普勒引入包装级原子操作之前),因此从历史上来说,它已经过优化,因此包装中的每个线程都可以连续读取(在内存)HW值,并通过循环在C的各个部分进行累加。

请注意,尽管最新的nvidia卡(RTX)现在具有张量乘法核心,可以在一个操作中处理小块,包括减少一小部分C,因此在这些卡上,使用NHWC实际上更快(或NCHWC混合格式)。

答案 1 :(得分:3)

从TF1.1开始,你甚至无法直接致电NHWC。 TF进行NCHW的转换。因此,无论在cuDNN中实施NHWC的效率如何,从TF用户的角度来看,NCHW更快:

https://github.com/tensorflow/tensorflow/issues/8286

性能比当然取决于问题,但我的感觉是它很大,你不想使用NHWC(在GPU上),如果你可以避免它(看起来很可能你' d也浪费记忆力。)

答案 2 :(得分:0)

我认为手动优化布局没有太大意义,尤其是因为data_format="channels_first"看起来比在TensorFlow中坚持默认设置更为冗长,并且内部应该照顾好它。

我希望使用NCHW的培训时间最多快几个百分点,而且随着时间的推移,随着XLA JIT编译的成熟,这种性能差异将会消失。

使用Keras,您可以使用K.set_image_data_format轻松地尝试这两种方法,因此请尝试两者,并查看它们对您的特定模型有何影响。

这是使用VGG模型https://gist.github.com/carlthome/51d62cbf5fc23098418eef93b11a5d78

的小型基准

答案 3 :(得分:0)

CPU端:

让我们假设它们的输入和过滤器都转置成GEMM:对于NCHW,im2col之后的输入形状为W[out_channels, in_channels * filter_height * filter_width]X[in_channels * filter_height * filter_width, out_height * out_width],对于NHWC,im2col之后的输入形状为X[out_height * out_width, filter_height * filter_width * in_channels]W[filter_height * filter_width * in_channels, out_channels],前者会做W*X,而后者会做X*W,因为您会看到区别仅在于out_channels首先或out_height * out_width首先,您几乎可以分辨出任何性能差异,因为对GEMM进行了高度优化,它将使用某种打包和切片技术来进行小的补丁矩阵乘法。

NCHW的最大麻烦来自im2col,因为对于NHWC,您可以存储内部moset in_channels数据,而NCHW需要从一行到另一行,从一个通道跳到另一个通道以获得完整的数据补丁(这也是XNNPACK所做的事情)以提高性能)。

GPU端:

对此一无所知。