深度学习之路=====8=====>>Xception(tensorflow2)

简介

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

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

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

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

Xception 网络结构

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

深度学习之路=====8=====>>Xception(tensorflow2)_第4张图片
上表中的Conv和SeparableConV由下面的Layer表示
深度学习之路=====8=====>>Xception(tensorflow2)_第5张图片

代码

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
        

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

参考

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

你可能感兴趣的:(深度学习之路,tensorflow,深度学习,人工智能)