Xception和SqueezeNet一样,是一种降低参数量的轻量级神经网络,它主要使用了
对比一下深度可分离卷积和普通卷积的区别:
下图为普通的卷积操作,每个卷积核对应通道与输入对应通道进行卷积操作后求和,输出通道数为卷积核数。
下图为深度分离卷积操作的第一步-深度卷积,我是这样理解的,使用了一个卷积核通道数与输入通道数相等的卷积核,每个卷积核的通道与输入对应通道卷积操作后不进行求和(也可以这样理解,使用了多个(与输入通道数相等)单通道卷积核,每个卷积核负责输入的一个通道,卷积操作后不进行求和,而是Conact(深度方向堆叠),这样会得到与输入通道数(channels)相等的输出。
关于深度卷积和普通卷积的区别,这篇文章讲的也很清楚:
DepthwiseConv2D和Conv2D详解
下图为深度分离卷积操作的第二步-逐点卷积(pointwise convolution):就是使用1x1的普通卷积,输出通道数等与卷积核数(output channels ==filters)。
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=filtersself.kernel_size=kernel_sizeself.strides=stridesself.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_flowdef __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+residualreturn y
class Middle_Separable_residual(Model):#middle_flow moduledef __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=xfor layer in self.layers1.layers:x=layer(x)y=x+residualreturn 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 xdef 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 实现
上一篇:演讲结束语怎么说