首页天道酬勤,

,

张世龙 05-05 23:22 104次浏览

池化层的导出池化层的输入一般来源于前一个卷积层,主要作用是提供较强的鲁棒性。 例如,最大轮询取小区域中的最大值,即使该区域中的其他值稍微改变,或者图像稍微移动,轮询后的结果也不变。 (减少参数数量,防止过拟合现象的发生。 池层一般没有参数,因此对于反向传播,只需推导输入参数,不需要更新权重。

池化层的向前计算

在前向计算中,对卷积层的输出map不重叠的n*n区域(在本例中为2*2,其他大小的轮询过程相似)进行下采样,并在每个区域中使用重叠区域

在上图中,池化层1的输入端是卷积层1的输出端,其大小为24*24,在每个不重叠的2*2区域中执行下采样。 对于最大轮询,选择每个区域的最大值作为输出。 对于均轮询,必须计算每个区域的平均值作为输出。 最终,该层输出(24/2 ) * (24/2 )的map。 池化层2的计算过程也是同样的。

让我们用图标来看看两种不同的轮询过程。

最大轮询:

均轮询:

池化层的逆计算

池化层反向传播时,最大轮询和均轮询方式也采用不同的方式。

对于最大轮询,前向计算是每个选定2*2区域的最大值。 在此,需要记录各小区域中最大值的位置。 在反向传播时,只有其最大值对下一层有贡献,所以把残差传递到该最大值的位置,使区域内其他2*2-1=3个位置为零。 具体流程如下图所示。 其中,4*4矩阵中的非零位置是前面计算的每个小区域的最大值的位置。

对于均轮询,必须将残差平均划分为2*2=4,并传递给当前小区域的四个单元。 具体流程如下。

Caffe中池化层的实现

在caffe中,池化层的配置信息如下:

层{ name : ' pool1' type : ' pooling ' bottom 3360 ' con v1 ' top : ' pool1' pooling _ param { pool 3360 maxkernax

与卷积层一样,也包括该层的名称、类别、下层、上层等信息。 看看和卷积层不同的地方。

Pool是池方式,默认值为MAX,可以选择的参数为MAX、AVE、STOCHASTIC。

kernel_size :表示池化区域的大小,也可以通过kernel_h和kernel_w分别设定长度和宽度。

Stride :步长,即每个池化区域左右或上下移动的距离一般与kernel_size相同,池化不重叠。 可以小于kernel_size。 也就是说,是重叠池化。 在Alexnet中使用了重叠池化的方法。

在Caffe中,与池化层相关的文件有两个,一个是cudnn_pooling_layer.cu,一个是使用cudnn的函数,只要传递数据就可以得到该层的输出结果,所以在此不太介绍

另一个是pooling_layer.cu,是作者自己编写的核函数,包含MaxPool、AvePool和StoPool的相关函数。 以MaxPool为例。

前向计算的前向过程代码如下。 在应该注意的地方添加了评论。

templatetypenamedtype//_ _ global _ _是该函数需要发送到gpu的内核函数_ _ global _ voidmaxpoolforward (constinthreads ) const int channels,const int height,const int width,const int pooled_height,const int pooled_width,const ing const int kereret const int stride_w,const int pad_h,const int pad_w,Dtype* const top_data

e* top_mask) {//nthreads为线程总数,为该池化层输出神经元总数,即一个线程对应输出的一个神经元结点//index为线程索引 CUDA_KERNEL_LOOP(index, nthreads) { //n、c、pw、ph分别为每个batch中样本数、该层的channel数目(即输出几个map),每个map的长和宽 const int pw = index % pooled_width; const int ph = (index / pooled_width) % pooled_height; const int c = (index / pooled_width / pooled_height) % channels; const int n = index / pooled_width / pooled_height / channels;//hstart,wstart,hend,wend为bottom blob(即上一层)中的点的坐标范围//需要使用这些点来计算输出神经元的值 int hstart = ph * stride_h - pad_h; int wstart = pw * stride_w - pad_w; const int hend = min(hstart + kernel_h, height); const int wend = min(wstart + kernel_w, width); hstart = max(hstart, 0); wstart = max(wstart, 0); Dtype maxval = -FLT_MAX; int maxidx = -1; const Dtype* const bottom_slice = bottom_data + (n * channels + c) * height * width; for (int h = hstart; h < hend; ++h) { for (int w = wstart; w < wend; ++w) { if (bottom_slice[h * width + w] > maxval) { maxidx = h * width + w; maxval = bottom_slice[maxidx]; } } }//将结果保存到index对应点 top_data[index] = maxval; if (mask) { mask[index] = maxidx; } else { top_mask[index] = maxidx; } }}

反向传播

代码如下

template <typename Dtype>__global__ void MaxPoolBackward(const int nthreads, const Dtype* const top_diff, const int* const mask, const Dtype* const top_mask, const int num, const int channels, const int height, const int width, const int pooled_height, const int pooled_width, const int kernel_h, const int kernel_w, const int stride_h, const int stride_w, const int pad_h, const int pad_w, Dtype* const bottom_diff) { CUDA_KERNEL_LOOP(index, nthreads) { // find out the local index // find out the local offset const int w = index % width; const int h = (index / width) % height; const int c = (index / width / height) % channels; const int n = index / width / height / channels; const int phstart = (h + pad_h < kernel_h) ? 0 : (h + pad_h - kernel_h) / stride_h + 1; const int phend = min((h + pad_h) / stride_h + 1, pooled_height); const int pwstart = (w + pad_w < kernel_w) ? 0 : (w + pad_w - kernel_w) / stride_w + 1; const int pwend = min((w + pad_w) / stride_w + 1, pooled_width); Dtype gradient = 0; const int offset = (n * channels + c) * pooled_height * pooled_width; const Dtype* const top_diff_slice = top_diff + offset;//mask为前向过程中与每个top_data中的点对应的bottom_data中的点在每个小区域中的坐标 if (mask) { const int* const mask_slice = mask + offset; for (int ph = phstart; ph < phend; ++ph) { for (int pw = pwstart; pw < pwend; ++pw) { if (mask_slice[ph * pooled_width + pw] == h * width + w) { gradient += top_diff_slice[ph * pooled_width + pw]; } } } } else { const Dtype* const top_mask_slice = top_mask + offset; for (int ph = phstart; ph < phend; ++ph) { for (int pw = pwstart; pw < pwend; ++pw) { if (top_mask_slice[ph * pooled_width + pw] == h * width + w) { gradient += top_diff_slice[ph * pooled_width + pw]; } } } } bottom_diff[index] = gradient; }}

全局最大池化代替FC,全局平均池化英文