在图像卷积和池化操作中有固定的kernel_size和stride,当stride > 1时,边界上会有可能发生越界的问题。
Caffe中的卷积、池化后输出图像尺寸计算
(1)卷积
计算定义在conv_layer.cpp
中的compute_output_shape()
函数中
const int output_h = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
const int output_w = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
height、width :卷积操作输入的图像h、w,conv_input_shape_.cpu_data()[1], conv_input_shape_.cpu_data()[2]
kernel_h、kernel_w:卷积核的h、w,kernel_shape_.cpu_data()[0], kernel_shape_.cpu_data()[1]
stride_h、stride_w:步长的h、w,stride_.cpu_data()[0], stride_.cpu_data()[1]
pad_h、pad_w:zero padding的h、w,pad_.cpu_data()[0], pad_.cpu_data()[1]
caffe的卷积操作:将kernel转为channel*kernel_h*kernel_w
大小的一维行向量,例如CIFAR10 接data层的conv1,对于3*32*32
的输入,那在conv1中卷积核就是3*5*5
的一维行向量。然后将3*32*32
的输入图像按3*5*5
的长度转换为多个列向量。最后通过求向量的点积完成卷积运算。
注:channel不是指输入图像的通道数,其指的是输入到卷积层的通道数,比如接pooling1的conv2,输入为32*16*16
的特征图,那么kernel则转换为32*5*5
的一维行向量,特征图对应转为32*5*5
长度的多个列向量。
im2col.cpp
中im2col_cpu()
函数实现了转换输入为列向量的操作:
(2)池化
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;
定义在pooling_layer.cpp
中
CIFAR10中的pooling1,kernel为33,stride为2,pad未定义,输入为conv1得到的3232*32的特征图,
pooled_height_=static_cast<int>(ceil(static_cast<float>(32+2*0-3)/2))+1=static_cast<int>(ceil(14.5))+1=16
ceil为向上取整
所以,pooling1的输出为32*16*16
Caffe中对于越界问题的处理如图所示: