• 好好学习第5天:Xception动物识别



    ​>- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/k-vYaC8l7uxX51WoypLkTw) 中的学习记录博客**

    活动地址:CSDN21天学习挑战赛

    一、Xception介绍

    Xception作为Inception v3的改进,主要是在Inception v3的基础上引入了depthwise separable convolution,在基本不增加网络复杂度的前提下提高了模型的效果。

    简化 的Inception模块

     简化 的Inception模块的严格重构

      Inception 模块的“极端”版本,1x1 卷积的每个输出通道都有一个空间卷积。

     

    参考论文:Xception: Deep Learning with Depthwise Separable Convolutions

     将卷积神经网络中的 Inception 模块解释为介于常规卷积和深度可分离卷积操作(深度卷积后跟点卷积)之间的中间步骤。从这个角度来看,深度可分离卷积可以理解为具有最大数量的塔的 Inception 模块。这一观察使我们提出了一种受 Inception 启发的新型深度卷积神经网络架构,其中 Inception 模块已被深度可分离卷积取代。我们表明,这种被称为 Xception 的架构在 ImageNet 数据集(Inception V3 的设计目标)上略微优于 Inception V3,并且在包含 3.5 亿张图像和 17,000 个类别的更大图像分类数据集上显着优于 Inception V3。由于 Xception 架构与 Inception V3 具有相同数量的参数,因此性能提升不是由于容量增加,而是更有效地使用模型参数。

    深度可分离卷积,由深度卷积组成,即在输入的每个通道上独立执行的空间卷积,然后是逐点卷积,即 1x1 卷积,将深度卷积输出的通道投影到新的通道空间上。不要将其与空间可分离卷积混淆,后者在图像处理社区中通常也称为“可分离卷积”。
     

    Xception网络结构:

     Xception 架构有 36 个卷积层,构成网络的特征提取基础。在论文的实验评估中,专门研究图像分类,因此卷积基础之后将是逻辑回归层。可以选择在逻辑回归层之前插入全连接层。36 个卷积层被构造成 14 个模块,除了第一个和最后一个模块外,所有这些模块周围都有线性残差连接。

    二、实验过程

    1.导入库

    1. # 查看当前kernel下已安装的包 list packages
    2. !pip list --format=columns
    pip install tensorflow==2.4.1

    刚开始使用的tensorflow版本是1.4.0,后面会报错。

    1. import matplotlib.pyplot as plt
    2. # 支持中文
    3. plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
    4. plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
    5. import os,PIL
    6. # 设置随机种子尽可能使结果可以重现
    7. import numpy as np
    8. np.random.seed(1)
    9. # 设置随机种子尽可能使结果可以重现
    10. import tensorflow as tf
    11. tf.random.set_seed(1)
    12. import pathlib

    2.导入数据集

    1. data_dir = "data-xception"
    2. data_dir = pathlib.Path(data_dir)
    1. image_count = len(list(data_dir.glob('*/*')))
    2. print("图片总数为:",image_count)

     应该是4000,不知道为啥只有3998。

    1. batch_size = 2
    2. img_height = 299
    3. img_width = 299

    就下面这一段代码需要tensorflow版本2.2.0以上

    1. """
    2. 关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
    3. """
    4. train_ds = tf.keras.preprocessing.image_dataset_from_directory(
    5. data_dir,
    6. validation_split=0.2,
    7. subset="training",
    8. seed=12,
    9. image_size=(img_height, img_width),
    10. batch_size=batch_size)

    1. """
    2. 关于image_dataset_from_directory()的详细介绍可以参考文章:https://mtyjkh.blog.csdn.net/article/details/117018789
    3. """
    4. val_ds = tf.keras.preprocessing.image_dataset_from_directory(
    5. data_dir,
    6. validation_split=0.2,
    7. subset="validation",
    8. seed=12,
    9. image_size=(img_height, img_width),
    10. batch_size=batch_size)

     

    1. class_names = train_ds.class_names
    2. print(class_names)

     

    为什么会出现“.ipynb_checkpoints”?
    1. for image_batch, labels_batch in train_ds:
    2. print(image_batch.shape)
    3. print(labels_batch.shape)
    4. break

     

    1. AUTOTUNE = tf.data.AUTOTUNE
    2. train_ds = (
    3. train_ds.cache()
    4. .shuffle(1000)
    5. # .map(train_preprocessing) # 这里可以设置预处理函数
    6. # .batch(batch_size) # 在image_dataset_from_directory处已经设置了batch_size
    7. .prefetch(buffer_size=AUTOTUNE)
    8. )
    9. val_ds = (
    10. val_ds.cache()
    11. .shuffle(1000)
    12. # .map(val_preprocessing) # 这里可以设置预处理函数
    13. # .batch(batch_size) # 在image_dataset_from_directory处已经设置了batch_size
    14. .prefetch(buffer_size=AUTOTUNE)
    15. )

     3.网络结构

    1. #====================================#
    2. # Xception的网络部分
    3. #====================================#
    4. from tensorflow.keras.preprocessing import image
    5. from tensorflow.keras.models import Model
    6. from tensorflow.keras import layers
    7. from tensorflow.keras.layers import Dense,Input,BatchNormalization,Activation,Conv2D,SeparableConv2D,MaxPooling2D
    8. from tensorflow.keras.layers import GlobalAveragePooling2D,GlobalMaxPooling2D
    9. from tensorflow.keras import backend as K
    10. from tensorflow.keras.applications.imagenet_utils import decode_predictions
    11. def Xception(input_shape = [299,299,3],classes=1000):
    12. img_input = Input(shape=input_shape)
    13. #=================#
    14. # Entry flow
    15. #=================#
    16. # block1
    17. # 299,299,3 -> 149,149,64
    18. x = Conv2D(32, (3, 3), strides=(2, 2), use_bias=False, name='block1_conv1')(img_input)
    19. x = BatchNormalization(name='block1_conv1_bn')(x)
    20. x = Activation('relu', name='block1_conv1_act')(x)
    21. x = Conv2D(64, (3, 3), use_bias=False, name='block1_conv2')(x)
    22. x = BatchNormalization(name='block1_conv2_bn')(x)
    23. x = Activation('relu', name='block1_conv2_act')(x)
    24. # block2
    25. # 149,149,64 -> 75,75,128
    26. residual = Conv2D(128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
    27. residual = BatchNormalization()(residual)
    28. x = SeparableConv2D(128, (3, 3), padding='same', use_bias=False, name='block2_sepconv1')(x)
    29. x = BatchNormalization(name='block2_sepconv1_bn')(x)
    30. x = Activation('relu', name='block2_sepconv2_act')(x)
    31. x = SeparableConv2D(128, (3, 3), padding='same', use_bias=False, name='block2_sepconv2')(x)
    32. x = BatchNormalization(name='block2_sepconv2_bn')(x)
    33. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block2_pool')(x)
    34. x = layers.add([x, residual])
    35. # block3
    36. # 75,75,128 -> 38,38,256
    37. residual = Conv2D(256, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)
    38. residual = BatchNormalization()(residual)
    39. x = Activation('relu', name='block3_sepconv1_act')(x)
    40. x = SeparableConv2D(256, (3, 3), padding='same', use_bias=False, name='block3_sepconv1')(x)
    41. x = BatchNormalization(name='block3_sepconv1_bn')(x)
    42. x = Activation('relu', name='block3_sepconv2_act')(x)
    43. x = SeparableConv2D(256, (3, 3), padding='same', use_bias=False, name='block3_sepconv2')(x)
    44. x = BatchNormalization(name='block3_sepconv2_bn')(x)
    45. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block3_pool')(x)
    46. x = layers.add([x, residual])
    47. # block4
    48. # 38,38,256 -> 19,19,728
    49. residual = Conv2D(728, (1, 1), strides=(2, 2),padding='same', use_bias=False)(x)
    50. residual = BatchNormalization()(residual)
    51. x = Activation('relu', name='block4_sepconv1_act')(x)
    52. x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name='block4_sepconv1')(x)
    53. x = BatchNormalization(name='block4_sepconv1_bn')(x)
    54. x = Activation('relu', name='block4_sepconv2_act')(x)
    55. x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name='block4_sepconv2')(x)
    56. x = BatchNormalization(name='block4_sepconv2_bn')(x)
    57. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block4_pool')(x)
    58. x = layers.add([x, residual])
    59. #=================#
    60. # Middle flow
    61. #=================#
    62. # block5--block12
    63. # 19,19,728 -> 19,19,728
    64. for i in range(8):
    65. residual = x
    66. prefix = 'block' + str(i + 5)
    67. x = Activation('relu', name=prefix + '_sepconv1_act')(x)
    68. x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv1')(x)
    69. x = BatchNormalization(name=prefix + '_sepconv1_bn')(x)
    70. x = Activation('relu', name=prefix + '_sepconv2_act')(x)
    71. x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv2')(x)
    72. x = BatchNormalization(name=prefix + '_sepconv2_bn')(x)
    73. x = Activation('relu', name=prefix + '_sepconv3_act')(x)
    74. x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv3')(x)
    75. x = BatchNormalization(name=prefix + '_sepconv3_bn')(x)
    76. x = layers.add([x, residual])
    77. #=================#
    78. # Exit flow
    79. #=================#
    80. # block13
    81. # 19,19,728 -> 10,10,1024
    82. residual = Conv2D(1024, (1, 1), strides=(2, 2),
    83. padding='same', use_bias=False)(x)
    84. residual = BatchNormalization()(residual)
    85. x = Activation('relu', name='block13_sepconv1_act')(x)
    86. x = SeparableConv2D(728, (3, 3), padding='same', use_bias=False, name='block13_sepconv1')(x)
    87. x = BatchNormalization(name='block13_sepconv1_bn')(x)
    88. x = Activation('relu', name='block13_sepconv2_act')(x)
    89. x = SeparableConv2D(1024, (3, 3), padding='same', use_bias=False, name='block13_sepconv2')(x)
    90. x = BatchNormalization(name='block13_sepconv2_bn')(x)
    91. x = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='block13_pool')(x)
    92. x = layers.add([x, residual])
    93. # block14
    94. # 10,10,1024 -> 10,10,2048
    95. x = SeparableConv2D(1536, (3, 3), padding='same', use_bias=False, name='block14_sepconv1')(x)
    96. x = BatchNormalization(name='block14_sepconv1_bn')(x)
    97. x = Activation('relu', name='block14_sepconv1_act')(x)
    98. x = SeparableConv2D(2048, (3, 3), padding='same', use_bias=False, name='block14_sepconv2')(x)
    99. x = BatchNormalization(name='block14_sepconv2_bn')(x)
    100. x = Activation('relu', name='block14_sepconv2_act')(x)
    101. x = GlobalAveragePooling2D(name='avg_pool')(x)
    102. x = Dense(classes, activation='softmax', name='predictions')(x)
    103. inputs = img_input
    104. model = Model(inputs, x, name='xception')
    105. return model
    1. model = Xception()
    2. # 打印模型信息
    3. model.summary()

    4.训练过程

    1. # 设置初始学习率
    2. initial_learning_rate = 1e-4
    3. lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    4. initial_learning_rate,
    5. decay_steps=300, # 敲黑板!!!这里是指 steps,不是指epochs
    6. decay_rate=0.96, # lr经过一次衰减就会变成 decay_rate*lr
    7. staircase=True)
    8. # 将指数衰减学习率送入优化器
    9. optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)

     

    1. model.compile(optimizer=optimizer,
    2. loss ='sparse_categorical_crossentropy',
    3. metrics =['accuracy'])
    1. epochs = 3
    2. history = model.fit(
    3. train_ds,
    4. validation_data=val_ds,
    5. epochs=epochs
    6. )

     才训练两下就搞不动了,CPU不给力啊,我真的会谢!

    5.评估

    1. # 模型评估
    2. acc = history.history['accuracy']
    3. val_acc = history.history['val_accuracy']
    4. loss = history.history['loss']
    5. val_loss = history.history['val_loss']
    6. epochs_range = range(epochs)
    7. plt.figure(figsize=(12, 4))
    8. plt.subplot(1, 2, 1)
    9. plt.plot(epochs_range, acc, label='Training Accuracy')
    10. plt.plot(epochs_range, val_acc, label='Validation Accuracy')
    11. plt.legend(loc='lower right')
    12. plt.title('Training and Validation Accuracy')
    13. plt.subplot(1, 2, 2)
    14. plt.plot(epochs_range, loss, label='Training Loss')
    15. plt.plot(epochs_range, val_loss, label='Validation Loss')
    16. plt.legend(loc='upper right')
    17. plt.title('Training and Validation Loss')
    18. plt.show()

    等我搞出来上一步!

  • 相关阅读:
    vue的v-for中循环修改变量(this.xxx)的给子组件传值覆盖重复的问题
    Docker技术全景:推动云原生架构的关键力量
    机器学习——异常检测
    连接虚拟机工具推荐
    UE4 C++:TArray容器
    【SDS】简单动态字符串
    [论文-ing]Weakly Supervised Universal Fracture Detectionin Pelvic X-rays
    基于内容相似度的房源推荐系统(Python+Weapp+SpringBoot+MySQL)
    计算机网络-局域网和城域网(二)
    Go中原生http服务的实现方式
  • 原文地址:https://blog.csdn.net/liuyingshudian/article/details/126453070