深度学习笔记35_函数式API之Inception/Resnet网络构建

Posted 瓦力人工智能

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习笔记35_函数式API之Inception/Resnet网络构建相关的知识,希望对你有一定的参考价值。

层组成的有向无环图

前面我们介绍了关于多输入和多输出模型的构建,里面的注意点就数据的输入和模型目标输出。构建模型的过程还是比较像sequencial.现在我们要实现具有复杂的内部拓扑结构的网络。
有向无环图(directed acyclic graph)

  • acyclic(无环),就是这个图不能循环

  • 图自己输出不能称为自己输入????

  • 这里我们相对来说的允许循环的是:循环连接

Inception 模块

模型的介绍

Inception 是一种流行的卷积神经网络的架构类型,其基本的思路就是:

  • 模块堆叠,模块本身看起来就是像是小型的独立网络

  • 模块有好几个分支网络并行构成:3-4个分支网络

  • 基本的模式:1x1卷积 -> 3x3卷积 -> 将各个分支的结果连接在一起

为什么要这样的设计:

  • 多个分支,有助于网络分别学习不同的空间特征

  • 有助于学习逐个通道的特征,

  • 比联合学习这两种特征更加有效

Inception V3 网络的架构如下图:

  • 含池化运算、不同尺寸的空间卷积

  • 不包含空间卷积的分支

Inception V3

下面就用函数API来实现Inception模块。

from keras import layers

# 分支1 Conv2D 1x1卷积 步幅=2
# 这里输出的卷积滤波器的数量:128,filter size:1
branch_a = layres.Conv2D(128,1,
                         activation='relu',
                        strides=2)(x)
# 分支2: Conv2D 1x1 + Conv2D 3x3
branch_b = layers.Conv2D(128,1,
                        activation='relu')(x)
branch_b = layers.Conv2D(128,3,
                        activation='relu',
                        strides=2)(branch_b)
# 分支3:avegPool 3 + Conv2D 3
branch_c = layers.AveragePooling2D(3,
                              strides=2)(x)
branch_c = layers.Conv2D(128,3
                activation='relu')(branch_c)

#分支4:Conv2D 1+Conv2D 3 + Conv2D 3
branch_d = layers.Conv2D(128,1,
                activation='relu')(x)
branch_d = layers.Conv2D(128,3,
                activation='relu')(branch_d)
branch_d = layers.Conv2D(128,3,
                activation='relu'
                stride=2)(branch_d)

# 将上面的四个分支连接到一起
output = layers.concatenate(
[branch_a,branch_b,branch_c,branch_d],axis=1)

以上仅仅只是Inception V3 架构中的一个模块。其实在keras中已经包含了整架构的模型,具体函数如下:

keras.applications.inception_v3.InceptionV3(include_top=True, weights='imagenet', input_tensor=None, input_shape=None, pooling=None, classes=1000)

包括在 ImageNet 数据集上预训练得到的权重

  • include_top: 是否包括顶层的全连接层。

  • weights: None 代表随机初始化, 'imagenet' 代表加载在 ImageNet 上预训练的权值。

  • input_tensor: 可选,Keras tensor 作为模型的输入(即 layers.Input() 输出的 tensor)。

  • input_shape: 可选,输入尺寸元组,仅当 include_top=False 时有效,否则输入形状必须是 (299, 299, 3)(对于 channels_last 数据格式),或者 (3, 299, 299)(对于 channels_first 数据格式)。它必须拥有 3 个输入通道,且宽高必须不小于 139。例如 (150, 150, 3) 是一个合法的输入尺寸。

  • pooling: 可选,当 include_top 为 False 时,该参数指定了特征提取时的池化方式。

  • None 代表不池化,直接输出最后一层卷积层的输出,该输出是一个四维张量。
    'avg' 代表全局平均池化(GlobalAveragePooling2D),相当于在最后一层卷积层后面再加一层全局平均池化层,输出是一个二维张量。'max' 代表全局最大池化
    -classes: 可选,图片分类的类别数,仅当 include_top 为 True 并且不加载预训练权值时可用。

Resnet 模块

模型的介绍

残差连接(residual connection)是一种常见的类图网络组件.

残差连接的作用:

  • 解决梯度消失

  • 解决表示瓶颈

  • 向任何多于 10 层的模型中添加残差连接,都可能会有所帮助

残差连接的基本结构:

  • 让前面某层的输出作为后面某层的输入

  • 有效地创造了一条捷径:前面层的输出没有与后面层的激活连接在一起

  • 如果它们的形状不同:用一个线性变换将前面层的激活改变成目标形状

    • 不带激活的Dense层

    • 不带激活的1x1卷积

两个解释

表示瓶颈

在之前Sequential模型中,任何表示层都是基于上一层的信息,如果在某一层信息突然丢失很多,那么下一层接收的信息也是非常有限,这样一层的传递,导致激活中能够塞入的信息也变少。所以无法表示更多的信息。这里有一个形象的例子:

假设你有一条包含一系列操作的音频处理流水线,每个操作的输入都是前一个操作的输出,如果某个操作将信号裁剪到低频范围(比如0~15 kHz),那么下游操作将永远无法恢复那些被丢弃的频段。任何信息的丢失都是永久性的。

残差连接可以将较早的信息重新注入到下游数据中,从而部分解决了深度学习模型的这一问题。

梯度消失

问题都出现是将来自输出损失的反馈信号向下传播到更底部的层。如果这个反馈信号的传播需要经过很多层,那么信号可能会变得非常微弱,甚至完全丢失,导致网络无法训练。

在上一个章节中,我们提到了长序列的循环网络就存在梯度消失的问题,我们的解决方案是:

  • 引入了一个携带轨道(carry track)

  • 与主处理轨道平行的轨道上传播信息

残差连接在前向反馈中也类似该解决方案:

  • 引入了一个纯线性的信息携带轨道

  • 与主要的层堆叠方向平行

这样就有助于于跨越任意深度的层来传播梯度。

# 如果特征图的尺寸相同
# 用的是恒等残差连接(identity 
# residual connection)
from keras import layers

x=...
y = layers.Conv2D(128,3,
            activation='relu',
            padding='same')(x)
y = layers.Conv2D(128,3,
            activation='relu',
            padding='same')(y)
y = layers.Conv2D(128,3,
            activation='relu',
            padding='same')(y)
# 将原始 x 与输出特征相加
y = layers.add([y,x])
# 如果特征图的尺寸不同
from keras import layers

x=...
y = layers.Conv2D(128,3,
            activation='relu',
            padding='same')(x)
y = layers.Conv2D(128,3,
            activation='relu',
            padding='same')(y)
y = layers.MaxPooling2D(2,
            stride=2)(y)

# 使用 1×1 卷积,将原始 x 张量线性下采
# 样为与 y 具有相同的形状
residual = layers.Conv2D(128,1,
            stride=2,
            padding='same')(x)
# residual 与输出特征相加
y = layers.add([y,residual])

1x1卷积的作用

本内容参考吴恩达老师的深度学习课程中内容来解释。

1x1 是什么

说的简单点就是利用一个只用一个(1x1)数的filter进行卷积计算,如下图:

深度学习笔记35_函数式API之Inception/Resnet网络构建
1×1卷积

如果仅有只有则仅仅只有一个通道,就如同图上半部所示,
如通道数是32维,就如同图下半部所示。

1×1卷积所实现的功能是遍历这36个单元格,计算左图中32个数字和过滤器中32个数字的元素积之和,然后应用ReLU非线性函数

深度学习笔记35_函数式API之Inception/Resnet网络构建
1×1卷积

1x1 卷积的作用

降维/升维
1x1卷积一般只改变输出通道数(channels),而不改变输出的宽度和高度,改变通道数就可以实现对特征的拉升和压缩。专业点说法就是降维/升维。如下图

深度学习笔记35_函数式API之Inception/Resnet网络构建
降维
降维/升维

降维的作用:减少参数
升维的作用:用最少的参数拓宽网络channal

跨通道信息交互(channal 的变换)

使用1x1卷积核,实现降维和升维的操作其实就是channel间信息的线性组合变化,3x3,64channels的卷积核后面添加一个1x1,28channels的卷积核,就变成了3x3,28channels的卷积核,原来的64个channels就可以理解为跨通道线性组合变成了28channels,这就是通道间的信息交互。

增加非线性特性  
1x1卷积核,可以在保持feature map尺度不变的(即不损失分辨率)的前提下大幅增加非线性特性(利用后接的非线性激活函数),把网络做的很deep。


分享关于人工智能,机器学习,深度学习以及计算机视觉的好文章,同时自己对于这个领域学习心得笔记。想要一起深入学习人工智能的小伙伴一起结伴学习吧!扫码上车!

瓦力人工智能 - 扫码上车


以上是关于深度学习笔记35_函数式API之Inception/Resnet网络构建的主要内容,如果未能解决你的问题,请参考以下文章

深度学习笔记33_函数式API及多输入模型的建立

深度学习笔记34_函数式API之多输出模型构建

GoogLeNet(Inception V1)

「深度学习一遍过」必修13:使用pytorch对Inception结构模型进行设计

如何使用Keras函数式API进行深度学习?

Keras深度学习实战——基于Inception v3实现性别分类