Python复现Xception模型:深度可分离卷积与网络结构详解

晚来风
晚来风
发布时间:2026-10-15| 5人浏览过
原创

本文详细解析Xception模型,该模型通过深度可分离卷积替换Inception v3中的多尺寸卷积核,有效减少参数量。文章梳理了Entry、Middle、Exit三个Flow的结构差异,对比了普通卷积与深度可分离卷积的参数计算,并提供基于Keras的完整Python复现代码及图像预测示例,帮助开发者快速掌握该经典深度学习架构。

Xception是在Inception之后提出的对Inception v3的另一种改进方案,学习这一架构具有重要的参考价值。

什么是Xception模型

Xception由谷歌公司提出,作为Inception v3的改进版本,其核心改进在于采用深度可分离卷积(depthwise separable convolution)替代了原Inception v3中的多尺寸卷积核特征响应操作。

在深入讲解Xception模型之前,首先需要明确深度可分离卷积块(depthwise separable convolution block)的基本概念。

深度可分离卷积块包含两个主要部分:深度可分离卷积和1x1普通卷积。其中,深度可分离卷积通常使用3x3大小的卷积核,主要作用是进行特征提取;而1x1普通卷积则用于调整通道数。

下图展示了深度可分离卷积块的结构示意图:

引入深度可分离卷积块的主要目的是以更少的参数替代传统的3x3普通卷积。

我们可以通过对比普通卷积与深度可分离卷积块来直观理解其差异:

假设存在一个3×3大小的卷积层,输入通道数为16,输出通道数为32。具体而言,32个3×3大小的卷积核会遍历16个通道中的每个数据,最终生成所需的32个输出通道。该过程所需的参数数量为16×32×3×3=4608个。

若应用深度可分离卷积,首先使用16个3×3大小的卷积核分别遍历16个通道的数据,得到16个特征图谱。随后,在融合操作前,使用32个1×1大小的卷积核遍历这16个特征图谱。此过程所需的参数数量为16×3×3+16×32×1×1=656个。

由此可见,depthwise separable convolution能够显著减少模型的参数量。

通俗地理解,深度可分离卷积结构块中,3x3卷积核的厚度仅为一层,它在输入张量上逐层滑动,每次卷积生成一个输出通道;卷积完成后,再利用1x1卷积调整通道厚度。

(注:视频中存在些许错误,感谢zl960929的提醒。Xception使用的深度可分离卷积块SeparableConv2D,其实际顺序为先进行深度可分离卷积,再进行1x1卷积。)

对于Xception模型而言,其整体结构可分为三个Flow,分别是Entry flow、Middle flow和Exit flow。

模型共包含14个Block,其中Entry flow包含4个,Middle flow包含8个,Exit flow包含2个。

具体结构如下所示:

其内部主要结构由残差卷积网络搭配SeparableConv2D层实现各个Block。在Xception模型中,Entry flow和Exit flow中常见的两种Block结构如下:

而Middle flow中主要使用的Block结构如下:

Xception网络部分的Python实现代码

#-------------------------------------------------------------#
#   Xception的网络部分
#-------------------------------------------------------------#
from keras.preprocessing import image
from keras.models import Model
from keras import layers
from keras.layers import Dense,Input,BatchNormalization,Activation,Conv2D,SeparableConv2D,MaxPooling2D
from keras.layers import GlobalAveragePooling2D,GlobalMaxPooling2D
from keras import backend as K
from keras.applications.imagenet_utils import decode_predictions
def Xception(input_shape = [299,299,3],classes=1000):
    img_input = Input(shape=input_shape)
    #--------------------------#
    # Entry flow
    #--------------------------#
    #--------------------#
    # block1
    #--------------------#
    # 299,299,3 -> 149,149,64
    x = Conv2D(32, (3, 3), strides=(2, 2), use_bias=False, name='block1_conv1')(img_input)
    x = BatchNormalization(name='block1_conv1_bn')(x)
    x = Activation('relu', name='block1_conv1_act')(x)
    x = Conv2D(64, (3, 3), use_bias=False, name='block1_conv2')(x)
    x = BatchNormalization(name='block1_conv2_bn')(x)
    x = Activation('relu', name='block1_conv2_act')(x)
    #--------------------#
    # block2
    #--------------------#
    # 149,149,64 -> 75,75,128
    residual = Conv2D(128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
    residual = BatchNormalization()(residual)
    x = SeparableConv2D(128, (3, 3), padding='same', use_bias=False, name='block2_sepconv1')(x)
    x = BatchNormalization(name='block2_sepconv1_bn')(x)
    x = Activation('relu', name='block2_sepconv2_act')(x)
    x = SeparableConv2D(128, (3, 3), padding='same', use_bias=False, name='block2_sepconv2')(x)
    x = BatchNormalization(name='block2_sepconv2_bn')(x)
    x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block2_pool')(x)
    x = layers.add([x, residual])
    #--------------------#
    # block3
    #--------------------#
    # 75,75,128 -> 38,38,256
    residual = Conv2D(256, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)
    residual = BatchNormalization()(residual)
    x = Activation('relu', name='block3_sepconv1_act')(x)
    x = SeparableConv2D(256, (3, 3), padding='same', use_bias=False, name='block3_sepconv1')(x)
    x = BatchNormalization(name='block3_sepconv1_bn')(x)
    x = Activation('relu', name='block3_sepconv2_act')(x)
    x = SeparableConv2D(256, (3, 3), padding='same', use_bias=False, name='block3_sepconv2')(x)
    x = BatchNormalization(name='block3_sepconv2_bn')(x)
    x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block3_pool')(x)
    x = layers.add([x, residual])
    #--------------------#
    # block4
    #--------------------#
    # 38,38,256 -> 19,19,728
    residual = Conv2D(728, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)
    residual = BatchNormalization()(residual)
    x = Activation('relu', name='block4_sepconv1_act')(x)
    x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name='block4_sepconv1')(x)
    x = BatchNormalization(name='block4_sepconv1_bn')(x)
    x = Activation('relu', name='block4_sepconv2_act')(x)
    x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name='block4_sepconv2')(x)
    x = BatchNormalization(name='block4_sepconv2_bn')(x)
    x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block4_pool')(x)
    x = layers.add([x, residual])
    #--------------------------#
    # Middle flow
    #--------------------------#
    #--------------------#
    # block5--block12
    #--------------------#
    # 19,19,728 -> 19,19,728
    for i in range(8):
        residual = x
        prefix = 'block' + str(i + 5)
        x = Activation('relu', name=prefix + '_sepconv1_act')(x)
        x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv1')(x)
        x = BatchNormalization(name=prefix + '_sepconv1_bn')(x)
        x = Activation('relu', name=prefix + '_sepconv2_act')(x)
        x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv2')(x)
        x = BatchNormalization(name=prefix + '_sepconv2_bn')(x)
        x = Activation('relu', name=prefix + '_sepconv3_act')(x)
        x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv3')(x)
        x = BatchNormalization(name=prefix + '_sepconv3_bn')(x)
        x = layers.add([x, residual])
    #--------------------------#
    # Exit flow
    #--------------------------#
    #--------------------#
    # block13
    #--------------------#
    # 19,19,728 -> 10,10,1024
    residual = Conv2D(1024, (1, 1), strides=(2, 2),
                      padding='same', use_bias=False)(x)
    residual = BatchNormalization()(residual)
    x = Activation('relu', name='block13_sepconv1_act')(x)
    x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name='block13_sepconv1')(x)
    x = BatchNormalization(name='block13_sepconv1_bn')(x)
    x = Activation('relu', name='block13_sepconv2_act')(x)
    x = SeparableConv2D(1024, (3, 3), padding='same', use_bias=False, name='block13_sepconv2')(x)
    x = BatchNormalization(name='block13_sepconv2_bn')(x)
    x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block13_pool')(x)
    x = layers.add([x, residual])
    #--------------------#
    # block14
    #--------------------#
    # 10,10,1024 -> 10,10,2048
    x = SeparableConv2D(1536, (3, 3), padding='same', use_bias=False, name='block14_sepconv1')(x)
    x = BatchNormalization(name='block14_sepconv1_bn')(x)
    x = Activation('relu', name='block14_sepconv1_act')(x)
    x = SeparableConv2D(2048, (3, 3), padding='same', use_bias=False, name='block14_sepconv2')(x)
    x = BatchNormalization(name='block14_sepconv2_bn')(x)
    x = Activation('relu', name='block14_sepconv2_act')(x)
    x = GlobalAveragePooling2D(name='avg_pool')(x)
    x = Dense(classes, activation='softmax', name='predictions')(x)
    inputs = img_input
    model = Model(inputs, x, name='xception')
    model.load_weights("xception_weights_tf_dim_ordering_tf_kernels.h5")
    return model

图片预测

建立网络后,可以使用以下代码进行图像预测。

def preprocess_input(x):
    x /= 255.
    x -= 0.5
    x *= 2.
    return x
if __name__ == '__main__':
    model = Xception()
    img_path = 'elephant.jpg'
    img = image.load_img(img_path, target_size=(299, 299))
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    print('Input image shape:', x.shape)
    preds = model.predict(x)
    print(np.argmax(preds))
    print('Predicted:', decode_predictions(preds))

预测所需的已训练好的Xception模型权重文件可在https://github.com/fchollet/deep-learning-models/releases下载,获取方式非常便捷。

预测结果示例如下:

Predicted: [[('n02504458', 'African_elephant', 0.47570863), ('n01871265', 'tusker', 0.3173351), ('n02504013', 'Indian_elephant', 0.030323735), ('n02963159', 'cardigan', 0.0007877756), ('n02410509', 'bison', 0.00075616257)]]

以上就是Python神经网络Xception模型复现的详细内容,更多关于Xception模型复现的资料请关注本站其他相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。