神经网络中“滑动窗口”(卷积、池化等)的分数输出维度

机器算法验证 神经网络 深度学习 卷积神经网络
2022-04-12 12:33:49

据我所见,ResNet-152(论文可视化Caffe 模型)期望输入尺寸为 224x224x3,其第一层进行 64 次卷积,每层针对 7x7 内核,填充为 3,步幅 = 2。

由于,它的输出尺寸应该是 112.5x112.5x64 (对吧?)。这必须转换为整数,它看起来像 Caffe“向零截断”,输出的尺寸实际上是 112x112x64(这里是代码),我用 Caffe 加载了模型并验证了它)。input+2×paddingfilterstride=112.5

这似乎与 Caffe 的池化层策略(代码)不同,后者会限制结果,而不是截断结果。

我的问题:

  1. 处理内核/填充/步幅设置的传统方法是什么,导致“分数”维度(例如上面的 112.5)。
  2. 通用框架(Caffe、TensorFlow、Torch...)是否一致?
  3. Caffe 的卷积层和池化层的行为之间的不一致是“设计使然”吗?如果是这样,为什么?
1个回答

小数部分来自步幅操作。没有步幅,输出大小应该是output_no_stride = input + 2*pad - filter + 1 = 224. 跨步,使用的常规公式是output_with_stride = floor((input + 2*pad - filter) / stride) + 1 = 112

在许多编程语言中,整数除法的默认行为是“向零舍入”,因此当分子和分母为正整数时,可以省略下限运算。(参考:Caffe 的卷积实现Cudnn 文档

比较有步幅和没有步幅的输出维度

output_with_stride = floor((input + 2*pad - filter) / stride) + 1
                   = floor((output_no_stride - 1) / stride) + 1
                   = ceil(output_no_stride / stride)

Caffe 的池化有点复杂,它首先用天花板代替地板,然后如果最后一个池不是严格在图像内部开始,则将大小减小一,如代码所示。

  pooled_height_ = static_cast<int>(ceil(static_cast<float>(
      height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1;
  pooled_width_ = static_cast<int>(ceil(static_cast<float>(
      width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1;
  if (pad_h_ || pad_w_) {
    // If we have padding, ensure that the last pooling starts strictly
    // inside the image (instead of at the padding); otherwise clip the last.
    if ((pooled_height_ - 1) * stride_h_ >= height_ + pad_h_) {
      --pooled_height_;
    }
    if ((pooled_width_ - 1) * stride_w_ >= width_ + pad_w_) {
      --pooled_width_;
    }
    CHECK_LT((pooled_height_ - 1) * stride_h_, height_ + pad_h_);
    CHECK_LT((pooled_width_ - 1) * stride_w_, width_ + pad_w_);
  }

我认为结果大部分与传统公式一致,除非最后一个池完全在原始输入之外。