返回介绍

反池化层的实现

发布于 2025-02-17 22:41:42 字数 4673 浏览 0 评论 0 收藏 0

我们可以通过正向传播时记录池化时最大值位置。 在反池化的时候,只把池化过程中最大激活值所在的位置坐标的值激活,其它的值置为 0 过程如下图所示:

maxpool 需要记录池化之前最大值的位置

im2col

im2col 函数 会考虑滤波器大小、步幅、填充,将输入数据展开为 2 维数组。池化的情况下,在通道方向上是独立的。具体地讲,如下图所示,池化的应用区域按通道单独展开。 像这样展开之后,只需对展开的矩阵求各行的最大值,并转换为合适的形状即可

  • 将特征图按池化的大小展开成(-1,pool_h*pool_w ) 的形状(这里只论单张特征图),每行就是一池化的应用区域
  • 记录每行最大值的位置 argmax
  • 反池化时把特征图的值赋值到 0 矩阵 argmax 位置

具体思路如下图

实现代码如下:

class Reverse_Pooling:
    def __init__(self,temp_data,pool_h,pool_w,stride=1,pad=0):
        '''
        temp_data:用于获取最大值索引,池化之前的数据
        '''
        self.pool_h = pool_h
        self.pool_w = pool_w
        self.stride = stride
        self.pad = pad
        self.temp_data = temp_data.numpy()

    def im2col(self,input_data):
        """
        input_data : 由(数据量,通道,高,长) 的 4 维数组构成的输入数据
        -------
        col : 2 维数组
        """
        filter_h = self.pool_h
        filter_w = self.pool_w
        stride = self.stride
        pad = self.pad

        N, C, H, W = input_data.shape 
        out_h = (H + 2*pad - filter_h)//stride + 1  #计算池化之后的 H,W
        out_w = (W + 2*pad - filter_w)//stride + 1

        img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant') #进行边填充,padding
        col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))    #创建池化输出

        for y in range(filter_h):
            y_max = y + stride*out_h
            for x in range(filter_w):
                x_max = x + stride*out_w
                col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

        col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1) 
        return col

    def col2im(self,col):
        """
        col :col : 2 维数组(展开的池化层)
        input_shape : 输入数据的形状(例:(10, 1, 28, 28))
        """

        filter_h = self.pool_h
        filter_w = self.pool_w
        stride = self.stride
        pad = self.pad
        input_shape=self.x.shape
        N,C,H,W = input_shape
        out_h=(H+2*pad-filter_h)//stride+1
        out_w=(W+2*pad-filter_w)//stride+1
        col=col.reshape(N,out_h,out_w,C,filter_h,filter_w).transpose(0,3,4,5,1,2)

        img=np.zeros((N,C,H+2*pad+stride-1,W+2*pad+stride-1))
        for y in range(filter_h):

            y_max = y+stride*out_h
            for x in range(filter_w):
                x_max = x +stride*out_w
                img[:, :, y:y_max:stride, x:x_max:stride] += col[:, :, y, x, :, :]

        return img[:, :, pad:H + pad, pad:W + pad]

    def forward(self):
        x=self.temp_data
        N,C,H,W = x.shape
        out_h = int(1+(H-self.pool_h)/self.stride)  #计算池化后的 H,W
        out_w = int(1+(W-self.pool_w)/self.stride)
        #展开(1)
        col = self.im2col(x)  #所有特征图展开展开成(N,C,H*W)
        col = col.reshape(-1,self.pool_h*self.pool_w)  #(N,C,H*W)-->(N*C,H*W)
        #最大值(2)
        out = np.max(col,axis=1)
        #取最大值坐标反向池化用
        arg_max = np.argmax(col,axis=1)  
        self.x = x
        self.arg_max = arg_max

    def backward(self,dout):
        self.forward()
        dout = dout.numpy()       
        dout = dout.transpose(0,2,3,1)
        pool_size = self.pool_h * self.pool_w
        dmax = np.zeros((dout.size,pool_size)) #创建反池化输出
        dmax[np.arange(self.arg_max.size),self.arg_max.flatten()] = dout.flatten()  #对输出按索引赋值
        dmax = dmax.reshape(dout.shape + (pool_size,))
        dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
        dx = self.col2im(dcol)
        dx=fluid.dygraph.to_variable(dx.astype('float32'))

        return dx

通过猫十二分类来了解卷积神经网络的特征学习

这里我们使用百度飞桨深度学习框架的猫十二分类数据集,看看卷积神经网络是如何学习到猫的特征的

解压数据集文件

fork 本项目后在终端粘贴下面命令(建议用 GPU 环境,CPU 很慢哦)

终端输入命令:

unzip data/data10954/cat_12_test.zip 
unzip data/data10954/cat_12_train.zip

训练集一共 2161 张猫脸图片,总共分为 12 类猫脸,并且训练集已经把标注放在 train_list.txt 文件中

如图所示,前面是图片 PATH,后面是标签(有些图片不可读,我已经删除)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文