返回介绍

反卷积层实现

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

为了了解卷积操作,我们需要首先了解中间层的特征激活值。我们使用了一种新的方式将这些激活值映射回输入像素空间,表明了什么样的输入模式将会导致 feature map 中一个给定的激活值。我们使用反卷积网络来完成映射。一个反卷积网络可以被看成是一个卷积模型,这个模型使用和卷积同样的组件(过滤和池化),但是却是相反的过程,因此是将特征映射到像素。在中,反卷积网络被提出作为一种进行非监督学习的方法,但是在这里,它没有学习能力,仅仅用来探测一个已经训练好的卷积神经网络。

  1. 获取对应卷积层的参数(卷积核)shape 为(NCHW),并且将卷积核转置(NCHW-->NCWH),也就是高和宽互换,原理请参考神经网络的反向传播
  2. 使用 fluid.dygraph.Conv2DTranspose() 动态图 API 创建反卷积层,并且用获得参数初始
  3. 进行反卷积

特征图的可视化

一般的 RGB 图像像素取值范围为 0-255,但在网络中的数据不一定会在这个范围内,它可能更接近(-1, 1)、(-10, 10)…

所以我们需要编写一个函数,使其可以拉伸图像像素取值范围,尽可能接近 0-255 取值范围。 我们要处理一个取值在未知范围的数组,其 shape 为 C, H, W(一般 2D 卷积后的特征图像格式为 NCHW,N 代表 Batch Size,C 为通道数/卷积的 num_filters,H 和 W 则为长宽,这里我们取单批数据) 获取这个数组的取值范围并设计算法进行拉伸 假定取值范围在(-1, 4),我们要将其等比例变成(0, 255) 取值范围 算法部分可以用一张图来解释

这是单通道的像素拉伸,在“猫十二分类”中,这里的单通道特征图像可能会是一只猫耳朵、一个猫爪…

  • 将 single_featuremap_display 设置为 True,则可以显示指定数目的单通道特征图
  • 将 single_featuremap_display 设置为 False,则会将指定数目的特征图进行通道合并,显示的是一张融合特征图

实现代码如下:

#猫十二分类(动态图)
#导入需要的包
import os,sys,time
import paddle.fluid as fluid
import numpy as np
import cv2
import matplotlib.pylab as plt
from PIL import Image
#本次训练的参数
train_paramters={
    'train_image_list':'train_list.txt',      #训练数据的标注文件
    'test_image_dir':'cat_12_test',           #测试数据集
    'batch_size':32,                          #批大小
    'epoch_num':40,
    'save_model_name':'Cat_2_classes12'       #训练的轮数
}

#反卷积实现
class Reverse_Conv:
    def __init__(self,layername,display_featuremaps_num,\
    layer,num_channels,num_filters,filter_size,\
    single_featuremap_display=False,stride=1,padding=1,act='relu'):
        '''
        layername:显示特征图时自定义的名称
        display_featuremaps_num:要可视化的 featuremap 的数量
        layer:卷积层对应的反卷积层
        param:反卷积网络的参数
        num_channels:通道数,比数据格式是 NCHW,那么 num_channels=C
        filter_size,num_filters:反卷积 API 的参数
        featuremaps:shape 为(featuremaps_num,H,W)
        single_featuremap_display:是否显示每个 featuremap
        '''
        self.param = (np.transpose(layer.parameters()[0].numpy(),(0,1,3,2)))   #获得对应层卷积参数,并且转置(NCHW-->NCWH)作为新参数
        self.num_channels = num_channels
        self.num_filters = num_filters
        self.filter_size = filter_size
        self.stride = stride
        self.padding = padding
        self.act = act

        self.title = layername
        self.featuremaps_num = display_featuremaps_num
        self.single_featuremap_display = single_featuremap_display

    def reverse_conv(self,rx):
        '''
        创建反卷积层
        输入数据进行反卷积
        rx:NCHW 格式的 featuremap
        '''
        reverse_conv = fluid.dygraph.Conv2DTranspose(num_channels=self.num_channels,num_filters=self.num_filters,\
        filter_size=self.filter_size,stride=self.stride,padding=self.padding,act=self.act,\
        param_attr=fluid.initializer.NumpyArrayInitializer(self.param))
        rx=reverse_conv(rx)
        if(self.featuremaps_num>0):
            self.featuremaps = rx[0].numpy()
            self.concat_featuremaps()
        return rx

    def fix_value(self,img_pixs):#像素拉伸
        '''
        img_pixs:featuremap 的像素矩阵
        '''
        pix_max=np.max(img_pixs)#取最大像素
        pix_min=np.min(img_pixs)#取最小像素
        pix_range=np.abs(pix_max)+np.abs(pix_min)#获取像素距离
        if(pix_range==0): #如果所有值都是零则直接返回(下面不能除以零)
            return img_pixs
        pix_rate = 255/pix_range#获取像素缩放倍率
        pix_left = pix_min*pix_rate#获取最小还原像素值
        img_pixs = img_pixs*pix_rate-pix_left#整体像素值平移
        img_pixs[np.where(img_pixs<0)]=0. #增加鲁棒性,检查超出区间的像素值,np.where(a<x) 与 a<x 等同
        img_pixs[np.where(img_pixs>255)]=255.
        return img_pixs

    def concat_featuremaps(self):
        '''
        featuremaps 可视化
        输入(CHW) 的特征图,使其显示
        '''
        count=0
        for featuremap in self.featuremaps:
            if count>self.featuremaps_num:#超过指定数量就结束
                break
            if count==0:
                featuremap = self.fix_value(featuremap)#像素拉伸
                total_featuremaps = featuremap
            else:
                featuremap = self.fix_value(featuremap)
                total_featuremaps += featuremap #通道合并
            count+=1
            if(self.single_featuremap_display):#单独显示一张 featuremap
                single_featuremap = Image.fromarray(np.asarray(featuremap).astype('uint8')).convert('RGB')
                plt.imshow(single_featuremap)
                plt.title('featuremap'+str(count)+' of '+self.title)
                plt.show()
                time.sleep(0.2)
        total_featuremaps = self.fix_value(total_featuremaps) #再次矫正像素取值范围
        total_featuremaps = Image.fromarray(np.asarray(total_featuremaps).astype('uint8')).convert('RGB')
        plt.imshow(total_featuremaps)
        plt.title('total_featuremap of '+self.title)
        plt.show()
2020-07-28 11:12:35,653-INFO: font search path ['/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/ttf', '/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/afm', '/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/matplotlib/mpl-data/fonts/pdfcorefonts']
2020-07-28 11:12:35,993-INFO: generated new fontManager

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

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

发布评论

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