为什么tensorflow使用channel-last排序而不是row-major?

Eli*_*igo 14 python memory numpy tensorflow

在大多数tensorflow教程中,作者使用通道最后维度排序,例如

input_layer = tf.reshape(features, [-1, 28, 28, 1])
Run Code Online (Sandbox Code Playgroud)

最后一位代表通道数(https://www.tensorflow.org/tutorials/layers).习惯了Theano和Numpy(都使用C-ordering,即row-major),我发现这很尴尬.此外,在已经读取文档上在tensorflow内存布局方案,我估计信道最后一个布局会造成更多的高速缓存未命中,因为卷积是在各个信道进行的,而在后沟道排序这些信道的线性存储器混合,有效地将缓存缩小N(其中N是通道数),这在3D和4D卷积中效率特别低.我弄错了吗?

PS

我发现了一个密切相关的线程(Tensorflow 3通道颜色输入顺序).接受回答的作者声明TF默认使用row-major,但鉴于我到目前为止发现的所有教程都显示了频道最后的排序,我发现这种说法具有误导性.

nes*_*uno 18

这是解释:

https://www.tensorflow.org/performance/performance_guide#use_nchw_image_data_format

图像数据格式是指批量图像的表示.TensorFlow支持NHWC(默认为TensorFlow)和NCHW(默认为cuDNN).N表示批量中的图像数量,H表示垂直维度中的像素数量,W表示水平维度中的像素数量,C表示通道(例如1表示黑色和白色,3对于RGB等.)尽管cuDNN可以在两种格式上运行,但以默认格式运行会更快.

最佳实践是构建适用于NCHW和NHWC的模型,因为在GPU上使用NCHW进行训练是常见的,然后在CPU上使用NHWC进行推理.

这两种格式的简短历史是TensorFlow使用NHWC开始,因为它在CPU上的速度要快一些.然后TensorFlow团队发现NCHW在使用NVIDIA cuDNN库时表现更好.目前的建议是用户在其模型中支持这两种格式.从长远来看,我们计划重写图形以使格式之间的切换透明.

此外,我们可以在这里看到代码,当输入的格式为NHWC时,tensorflow会将它转换为NCHW.

  if (data_format == FORMAT_NHWC) {
    // Convert the input tensor from NHWC to NCHW.
    TensorShape nchw_shape =
        ShapeFromFormat(FORMAT_NCHW, in_batch, in_rows, in_cols, in_depths);
    if (in_depths > 1) {
      Tensor transformed_input;
      OP_REQUIRES_OK(ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                             nchw_shape, &transformed_input));
      functor::NHWCToNCHW<GPUDevice, T, 4>()(
          ctx->eigen_device<GPUDevice>(),
          const_cast<const Tensor&>(input).tensor<T, 4>(),
          transformed_input.tensor<T, 4>());
      input = transformed_input;
    } else {
      // If depth <= 1, then just reshape.
      CHECK(input.CopyFrom(input, nchw_shape));
    }
  }
Run Code Online (Sandbox Code Playgroud)

您可以指定要用于每个操作的数据格式,但默认的张量流不使用NCHW而是使用NHWC,这就是为什么即使TF defelopers仍然使用NHWC来避免在每个操作中指定格式

  • “performance_guide”的引用链接现在是 404。 (3认同)
  • 很好的澄清!但是 OP 有一个很好的观点,NHWC 似乎对缓存未命中不友好,但是 TF 如何实现它以在 CPU 设备上获得良好的性能? (2认同)

eta*_*ion 7

你的问题是基于一种误解。

row-major 和 NHWC 之间没有矛盾。Row-major 意味着最右边的索引是在它改变时引起内存中最小跳跃的索引,而最左边的索引的变化引起最大的跳跃。在行优先中,最后一个维度是连续的,在列优先中,第一个维度是连续的。请参阅https://en.wikipedia.org/wiki/Row-_and_column-major_order#Address_calculation_in_general了解如何计算任意维数的内存偏移。

所以,TF 的内存是按行优先布局的。索引顺序的差异是微妙的(有些人甚至更喜欢 CHWN - 请参阅https://github.com/soumith/convnet-benchmarks/issues/66#issuecomment-155944875)。NCHW 很受欢迎,因为它是 cudnn 最擅长的。但基本上深度学习中的每个常见内存布局都是行优先的。