• Xception --tensorflow2.x


    简介

    Xception和SqueezeNet一样,是一种降低参数量的轻量级神经网络,它主要使用了

    1. 深度分离卷积(Depthwise separable convolution)结构,该结构替换了原来的Inception中的多尺寸卷积结构。这里需要弄清深度分离卷积(Depthwise separable convolution)、深度卷积(depthwise convolution)、逐点卷积( pointwise convolution)、逐点分组卷积(pointwise group convolutions)的概念。深度可分离卷积分为两步,第一步为深度卷积,它是分组卷积的极限操作,即每组只有一个单通道卷积核;第二步为逐点卷积,也就是使用1x1的卷积核。

    对比一下深度可分离卷积和普通卷积的区别:
    下图为普通的卷积操作,每个卷积核对应通道与输入对应通道进行卷积操作后求和,输出通道数为卷积核数。
    Figure1
    下图为深度分离卷积操作的第一步-深度卷积,我是这样理解的,使用了一个卷积核通道数与输入通道数相等的卷积核,每个卷积核的通道与输入对应通道卷积操作后不进行求和(也可以这样理解,使用了多个(与输入通道数相等)单通道卷积核,每个卷积核负责输入的一个通道,卷积操作后不进行求和,而是Conact(深度方向堆叠),这样会得到与输入通道数(channels)相等的输出。
    关于深度卷积和普通卷积的区别,这篇文章讲的也很清楚:
    DepthwiseConv2D和Conv2D详解
    在这里插入图片描述
    下图为深度分离卷积操作的第二步-逐点卷积(pointwise convolution):就是使用1x1的普通卷积,输出通道数等与卷积核数(output channels ==filters)。
    在这里插入图片描述

    1. 类似于ResNet,Xception引入了Residual module

    Xception 网络结构

    Xception引入了Entry flow、Middle flow、Exit flow三个flow,Entry flow主要用来不断下采样,减小空间维度;Middle flow用来学习关联关系,优化特征;Exit flow是汇总,整理特征,传递给全连接层表达信息。

    在这里插入图片描述
    上表中的Conv和SeparableConV由下面的Layer表示
    在这里插入图片描述

    代码

    import tensorflow as tf
    from tensorflow.keras.layers import *
    from tensorflow.keras import Model
    class Conv(Model):#普通卷积块
        def __init__(self,filters=32,kernel_size=(3,3),strides=2):
            super().__init__()
            self.filters=filters
            self.kernel_size=kernel_size
            self.strides=strides
            self.layers1=[]
            self.layers1.append(Conv2D(filters=self.filters,kernel_size=self.kernel_size,strides=self.strides,padding='same'))
            self.layers1.append(BatchNormalization())
            self.layers1.append(Activation('relu'))                     
        def call(self,x):
            for layer in self.layers1.layers:
                x=layer(x)
            return x
    class Separable_residual(Model):#深度可分卷积+残差块,用于Entry_flow和Exit_flow
        def __init__(self,mode=2,filters1=128,filters2=128):
            super().__init__()
            if mode==2:
                self.a1=Activation('relu')
            else:
                self.a1=Activation(None)
            self.c1=SeparableConv2D(filters=filters1,kernel_size=3,strides=1,padding='same')
            self.b1=BatchNormalization()
            
            self.a2=Activation('relu')
            self.c2=SeparableConv2D(filters=filters2,kernel_size=3,strides=1,padding='same')
            self.b2=BatchNormalization()
            
            self.p2=MaxPooling2D(pool_size=(3,3),strides=2,padding='same')
            self.residual=Conv(filters=filters2,kernel_size=1,strides=2)
        def call(self,x):
            residual=self.residual(x)
            x=self.a1(x)
            x=self.c1(x)
            x=self.b1(x)
            x=self.a2(x)
            x=self.c2(x)
            x=self.b2(x)
            x=self.p2(x)
            y=x+residual
            return y
    class Middle_Separable_residual(Model):#middle_flow module
        def __init__(self):
            super().__init__()
            self.layers1=[]
            for i in range(3):
                self.layers1.append(Activation('relu'))
                self.layers1.append(SeparableConv2D(filters=728,kernel_size=3,padding='same'))
        def call(self,x):
            residual=x
            for layer in self.layers1.layers:
                x=layer(x)
            y=x+residual
            return y
    def Entry_flow(x,filters_list):
        x=Conv()(x)
        x=Conv(filters=64,strides=1)(x)
        for filters in filters_list:
            if filters==128:
                x=Separable_residual(mode=1)(x)
            else:
                x=Separable_residual(2,filters,filters)(x)
        return x
    def Middle_flow(x):
        x=Middle_Separable_residual()(x)
        return x
    def Exit_flow(x):
        x=Separable_residual(mode=2,filters1=728,filters2=1024)(x)
        x=SeparableConv2D(filters=1536,kernel_size=3,padding='same')(x)
        x=Activation('relu')(x)
        x=SeparableConv2D(filters=2048,kernel_size=3,padding='same')(x)
        x=Activation('relu')(x)    
        x=GlobalAveragePooling2D()(x)
        x =Dense(1000, activation='softmax')(x)
        return x
    
    def Xception(input,arg_list):
        x=Entry_flow(input,arg_list)
        x=Middle_flow(x)
        x=Exit_flow(x)
        return x
    ##用下面代码简单运行一下模型,验证其正确性
    import numpy as np
    inputs = np.zeros((1, 299, 299, 3), dtype=np.float32)
    outputs = Xception(inputs,[128,256,728])
    outputs.shape
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    这里的Xception没有用父类tensorflow.keras.Model封装起来,封装也挺简单,参考我之前写的其他模型就能封装,这里直接 def 函数建立模型。

    参考

    keras深度可分离卷积SeparableConv2D与DepthwiseConv2D
    Xception 网络结构的原理与 Tensorflow2.0 实现

  • 相关阅读:
    基于Nuxtjs的同构渲染实践
    『现学现忘』Docker基础 — 25、Docker镜像讲解
    Docker应用下滑、近七成开发者有安全疑虑,中国云原生用户调查报告来了
    垃圾分类查询管理系统
    深圳铨顺宏圆满落幕IOTE 2022第十八届国际物联网展
    Spring笔记
    获取 Android 手机屏幕的实际大小(英寸)
    图像处理01 小波变换
    C++--简单实现定长内存池
    Java学习Go(入门)
  • 原文地址:https://blog.csdn.net/Big_SHOe/article/details/127985188