如何在Keras中从头开始开发VGG、Inception和ResNet模块

里程碑模型中有一些离散的体系结构元素,你可以在设计自己的卷积神经网络时使用它们。

具体地说,在图像分类等任务中实现最先进结果的模型使用重复多次的离散体系结构元素,例如VGG模型中的VGG块、GoogLeNet中的初始模块和ResNet中的残差模块。

一旦你能够实现这些架构元素的参数化版本,你就可以在为计算机视觉和其他应用程序设计你自己的模型时使用它们。

在本教程中,你将了解如何从头开始从里程碑卷积神经网络模型实现关键架构元素。

完成本教程后,你将了解:

  • 如何实现用于VGG-16和VGG-19卷积神经网络模型的VGG模块。
  • 如何实现GoogLeNet模型中使用的朴素和优化的初始模块。
  • 如何实现ResNet模型中的身份残差模块。

教程概述

本教程分为三个部分;它们是:

  • 如何实现VGG块。
  • 如何实现先启模块。
  • 如何实现残差模块。

如何实现VGG块

以牛津大学视觉几何小组命名的VGG卷积神经网络结构是计算机视觉深度学习方法使用的一个重要里程碑。

Karen Simonyan和Andrew Zisserman在2014年发表的题为《用于大规模图像识别的甚深卷积网络》的论文中描述了该架构,并在LSVRC-2014计算机视觉竞赛中取得了顶尖成绩。

该体系结构中的关键创新是定义和重复我们将称为VGG块的内容。这些是使用小滤光片(例如,3×3像素)的卷积层组,后跟最大汇聚层。

图像通过一堆卷积(卷积)。层,其中我们使用具有非常小的接收字段的过滤器:3×3(这是捕捉左/右、上/下、中心的概念的最小尺寸)。[…]。最大合用是在2×2像素窗口上执行的,步长为2。

具有VGG块的卷积神经网络在从头开始开发新模型时是一个明智的起点,因为它易于理解、易于实现,并且在从图像中提取特征方面非常有效。

我们可以将VGG块的规格概括为一个或多个卷积层,具有相同数目的滤波器,滤波器大小为3×3,跨度为1×1,填充相同,使得输出大小与每个滤波器的输入大小相同,并且使用校正的线性激活函数。然后,在这些层之后是大小为2×2、跨度相同的最大汇聚层。

我们可以使用KERAS函数API定义一个函数来创建VGG块,该函数具有给定数目的卷积层和给定数目的每层滤波器。

# function for creating a vgg block
def vgg_block(layer_in, n_filters, n_conv):
	# add convolutional layers
	for _ in range(n_conv):
		layer_in = Conv2D(n_filters, (3,3), padding='same', activation='relu')(layer_in)
	# add max pooling layer
	layer_in = MaxPooling2D((2,2), strides=(2,2))(layer_in)
	return layer_in

要使用该函数,需要传入块之前的层,并接收可用于集成到模型中的块末尾的层。

例如,第一层可能是一个输入层,它可以作为参数传递到函数中。然后,该函数返回对块中的最后一层(池层)的引用,该层可以连接到展平层和后续的密集层以进行分类预测。

我们可以通过定义一个期望正方形彩色图像作为输入的小模型来演示如何使用该函数,并将单个VGG块添加到具有两个卷积层的模型中,每个卷积层具有64个滤镜。

# Example of creating a CNN model with a VGG block
from keras.models import Model
from keras.layers import Input
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.utils import plot_model

# function for creating a vgg block
def vgg_block(layer_in, n_filters, n_conv):
	# add convolutional layers
	for _ in range(n_conv):
		layer_in = Conv2D(n_filters, (3,3), padding='same', activation='relu')(layer_in)
	# add max pooling layer
	layer_in = MaxPooling2D((2,2), strides=(2,2))(layer_in)
	return layer_in

# define model input
visible = Input(shape=(256, 256, 3))
# add vgg module
layer = vgg_block(visible, 64, 2)
# create model
model = Model(inputs=visible, outputs=layer)
# summarize model
model.summary()
# plot model architecture
plot_model(model, show_shapes=True, to_file='vgg_block.png')

运行该示例将创建模型并汇总结构。

我们可以看到,正如预期的那样,该模型添加了具有两个卷积层的单个VGG块,每个卷积层具有64个滤波器,随后是最大池层。

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         (None, 256, 256, 3)       0
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 256, 256, 64)      1792
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 256, 256, 64)      36928
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 128, 128, 64)      0
=================================================================
Total params: 38,720
Trainable params: 38,720
Non-trainable params: 0
_________________________________________________________________

还创建了模型体系结构的地块,这可能有助于使模型布局更加具体。

注意,创建绘图的前提是你安装了pydot和pyraphviz。如果不是这样,你可以注释掉import语句并调用示例中的plot_model()函数。

带VGG块的卷积神经网络结构图

在你自己的模型中使用VGG块应该是很常见的,因为它们是如此简单和有效。

我们可以扩展该示例并演示具有三个VGG块的单个模型,前两个块具有两个卷积层,分别具有64个和128个滤波器,第三个块具有四个卷积层,具有256个滤波器。这是VGG块的常见用法,其中过滤器的数量随着模型深度的增加而增加。

下面提供了完整的代码清单。

# Example of creating a CNN model with many VGG blocks
from keras.models import Model
from keras.layers import Input
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.utils import plot_model

# function for creating a vgg block
def vgg_block(layer_in, n_filters, n_conv):
	# add convolutional layers
	for _ in range(n_conv):
		layer_in = Conv2D(n_filters, (3,3), padding='same', activation='relu')(layer_in)
	# add max pooling layer
	layer_in = MaxPooling2D((2,2), strides=(2,2))(layer_in)
	return layer_in

# define model input
visible = Input(shape=(256, 256, 3))
# add vgg module
layer = vgg_block(visible, 64, 2)
# add vgg module
layer = vgg_block(layer, 128, 2)
# add vgg module
layer = vgg_block(layer, 256, 4)
# create model
model = Model(inputs=visible, outputs=layer)
# summarize model
model.summary()
# plot model architecture
plot_model(model, show_shapes=True, to_file='multiple_vgg_blocks.png')

同样,运行示例总结了模型体系结构,我们可以清楚地看到VGG块的模式。

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         (None, 256, 256, 3)       0
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 256, 256, 64)      1792
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 256, 256, 64)      36928
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 128, 128, 64)      0
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 128, 128, 128)     73856
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 128, 128, 128)     147584
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 64, 64, 128)       0
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 64, 64, 256)       295168
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 64, 64, 256)       590080
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 64, 64, 256)       590080
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 64, 64, 256)       590080
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 32, 32, 256)       0
=================================================================
Total params: 2,325,568
Trainable params: 2,325,568
Non-trainable params: 0
_________________________________________________________________

创建了模型体系结构的图,提供了层的相同线性级数的不同视角。

具有多个VGG块的卷积神经网络结构的绘制

如何实现Inestation模块

Christian Szegedy等人在2015年的论文中描述了Inestation模块,并在GoogLeNet模型中使用了该模块。书名叫“带着卷曲走得更深”

与VGG模式一样,GoogLeNet模式在2014年版ILSVRC挑战赛中取得了顶尖成绩。

初始模型的关键创新被称为初始模块。这是具有不同大小滤波器(例如,1×1、3×3、5×5)的并行卷积层的块,以及一个和3×3最大合并层,然后将其结果级联。

为了避免补丁对齐问题,Inception体系结构的当前版本被限制为筛选器大小为1×1、3×3和5×5;这一决定更多地是基于便利性而不是必要性。[…]。此外,由于合并操作对于当前卷积网络的成功是必不可少的,因此建议在每个这样的阶段中添加可选的并行合并路径也应该具有额外的有益效果。

这是一个非常简单而强大的体系结构单元,它不仅允许模型学习相同大小的并行过滤器,还允许学习不同大小的并行过滤器,从而允许在多个尺度上学习。

我们可以直接使用Kera函数API实现初始模块。下面的函数将为每个并行卷积层创建具有固定数量的滤波器的单个初始模块。从本文描述的GoogLeNet体系结构来看,似乎没有对并行卷积层使用系统的滤波器大小,因为模型是高度优化的。因此,我们可以参数化模块定义,以便指定要在每个1×1、3×3和5×5筛选器中使用的筛选器数量。

# function for creating a naive inception block
def inception_module(layer_in, f1, f2, f3):
	# 1x1 conv
	conv1 = Conv2D(f1, (1,1), padding='same', activation='relu')(layer_in)
	# 3x3 conv
	conv3 = Conv2D(f2, (3,3), padding='same', activation='relu')(layer_in)
	# 5x5 conv
	conv5 = Conv2D(f3, (5,5), padding='same', activation='relu')(layer_in)
	# 3x3 max pooling
	pool = MaxPooling2D((3,3), strides=(1,1), padding='same')(layer_in)
	# concatenate filters, assumes filters/channels last
	layer_out = concatenate([conv1, conv3, conv5, pool], axis=-1)
	return layer_out

要使用该函数,请提供对前一层的引用作为输入、过滤器的数量,它将返回对串联过滤器层的引用,然后你可以连接到更多初始模块或子模型以进行预测。

我们可以通过创建具有单个初始模块的模型来演示如何使用此功能。在这种情况下,过滤器的数量基于本文表1中的“初始(3a)”。

下面列出了完整的示例。

# example of creating a CNN with an inception module
from keras.models import Model
from keras.layers import Input
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers.merge import concatenate
from keras.utils import plot_model

# function for creating a naive inception block
def naive_inception_module(layer_in, f1, f2, f3):
	# 1x1 conv
	conv1 = Conv2D(f1, (1,1), padding='same', activation='relu')(layer_in)
	# 3x3 conv
	conv3 = Conv2D(f2, (3,3), padding='same', activation='relu')(layer_in)
	# 5x5 conv
	conv5 = Conv2D(f3, (5,5), padding='same', activation='relu')(layer_in)
	# 3x3 max pooling
	pool = MaxPooling2D((3,3), strides=(1,1), padding='same')(layer_in)
	# concatenate filters, assumes filters/channels last
	layer_out = concatenate([conv1, conv3, conv5, pool], axis=-1)
	return layer_out

# define model input
visible = Input(shape=(256, 256, 3))
# add inception module
layer = naive_inception_module(visible, 64, 128, 32)
# create model
model = Model(inputs=visible, outputs=layer)
# summarize model
model.summary()
# plot model architecture
plot_model(model, show_shapes=True, to_file='naive_inception_module.png')

运行该示例将创建模型并汇总各层。

我们知道卷积层和池层是平行的,但这个总结并不容易捕捉到结构。

__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            (None, 256, 256, 3)  0
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 256, 256, 64) 256         input_1[0][0]
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 256, 256, 128 3584        input_1[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 256, 256, 32) 2432        input_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)  (None, 256, 256, 3)  0           input_1[0][0]
__________________________________________________________________________________________________
concatenate_1 (Concatenate)     (None, 256, 256, 227 0           conv2d_1[0][0]
                                                                 conv2d_2[0][0]
                                                                 conv2d_3[0][0]
                                                                 max_pooling2d_1[0][0]
==================================================================================================
Total params: 6,272
Trainable params: 6,272
Non-trainable params: 0
__________________________________________________________________________________________________

还创建了模型体系结构的图,该图有助于清楚地看到模块的并行结构以及模块的每个元素的输出的匹配形状,该匹配形状允许通过第三维(滤波器或通道)直接连接它们。

具有朴素初始模块的卷积神经网络结构图

我们实现的初始模块的版本称为朴素初始模块。

为了减少所需的计算量,对该模块进行了修改。具体地说,在3×3和5×5卷积层之前增加1×1卷积层,以减少3×3和5×5卷积层之前的滤光片数量,并在合并层之后增加滤光片的数量。

这导致了Inception体系结构的第二个想法:明智地降低维度,否则计算需求会增加太多。[…]。也就是说,在昂贵的3×3和5×5卷积之前,使用1×1卷积来计算约简。除了用作还原剂外,它们还包括使用整流线性激活,使它们具有双重用途。

如果你打算在模型中使用许多初始模块,则可能需要这种基于计算性能的修改。

下面的函数通过参数化实现此优化改进,以便你可以控制3×3和5×5卷积层之前滤波器数量的减少量,以及在最大池化之后增加的滤波器数量。

# function for creating a projected inception module
def inception_module(layer_in, f1, f2_in, f2_out, f3_in, f3_out, f4_out):
	# 1x1 conv
	conv1 = Conv2D(f1, (1,1), padding='same', activation='relu')(layer_in)
	# 3x3 conv
	conv3 = Conv2D(f2_in, (1,1), padding='same', activation='relu')(layer_in)
	conv3 = Conv2D(f2_out, (3,3), padding='same', activation='relu')(conv3)
	# 5x5 conv
	conv5 = Conv2D(f3_in, (1,1), padding='same', activation='relu')(layer_in)
	conv5 = Conv2D(f3_out, (5,5), padding='same', activation='relu')(conv5)
	# 3x3 max pooling
	pool = MaxPooling2D((3,3), strides=(1,1), padding='same')(layer_in)
	pool = Conv2D(f4_out, (1,1), padding='same', activation='relu')(pool)
	# concatenate filters, assumes filters/channels last
	layer_out = concatenate([conv1, conv3, conv5, pool], axis=-1)
	return layer_out

我们可以使用这些优化的初始模块中的两个创建模型,以获得架构在实践中看起来如何的具体想法。

在这种情况下,滤波器配置的数量基于本文表1中的“inception(3a)”和“inception(3b)”。

下面列出了完整的示例。

# example of creating a CNN with an efficient inception module
from keras.models import Model
from keras.layers import Input
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers.merge import concatenate
from keras.utils import plot_model

# function for creating a projected inception module
def inception_module(layer_in, f1, f2_in, f2_out, f3_in, f3_out, f4_out):
	# 1x1 conv
	conv1 = Conv2D(f1, (1,1), padding='same', activation='relu')(layer_in)
	# 3x3 conv
	conv3 = Conv2D(f2_in, (1,1), padding='same', activation='relu')(layer_in)
	conv3 = Conv2D(f2_out, (3,3), padding='same', activation='relu')(conv3)
	# 5x5 conv
	conv5 = Conv2D(f3_in, (1,1), padding='same', activation='relu')(layer_in)
	conv5 = Conv2D(f3_out, (5,5), padding='same', activation='relu')(conv5)
	# 3x3 max pooling
	pool = MaxPooling2D((3,3), strides=(1,1), padding='same')(layer_in)
	pool = Conv2D(f4_out, (1,1), padding='same', activation='relu')(pool)
	# concatenate filters, assumes filters/channels last
	layer_out = concatenate([conv1, conv3, conv5, pool], axis=-1)
	return layer_out

# define model input
visible = Input(shape=(256, 256, 3))
# add inception block 1
layer = inception_module(visible, 64, 96, 128, 16, 32, 32)
# add inception block 1
layer = inception_module(layer, 128, 128, 192, 32, 96, 64)
# create model
model = Model(inputs=visible, outputs=layer)
# summarize model
model.summary()
# plot model architecture
plot_model(model, show_shapes=True, to_file='inception_module.png')

运行该示例将创建图层的线性摘要,这并不能真正帮助你了解正在发生的情况。

__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            (None, 256, 256, 3)  0
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 256, 256, 96) 384         input_1[0][0]
__________________________________________________________________________________________________
conv2d_4 (Conv2D)               (None, 256, 256, 16) 64          input_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)  (None, 256, 256, 3)  0           input_1[0][0]
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 256, 256, 64) 256         input_1[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 256, 256, 128 110720      conv2d_2[0][0]
__________________________________________________________________________________________________
conv2d_5 (Conv2D)               (None, 256, 256, 32) 12832       conv2d_4[0][0]
__________________________________________________________________________________________________
conv2d_6 (Conv2D)               (None, 256, 256, 32) 128         max_pooling2d_1[0][0]
__________________________________________________________________________________________________
concatenate_1 (Concatenate)     (None, 256, 256, 256 0           conv2d_1[0][0]
                                                                 conv2d_3[0][0]
                                                                 conv2d_5[0][0]
                                                                 conv2d_6[0][0]
__________________________________________________________________________________________________
conv2d_8 (Conv2D)               (None, 256, 256, 128 32896       concatenate_1[0][0]
__________________________________________________________________________________________________
conv2d_10 (Conv2D)              (None, 256, 256, 32) 8224        concatenate_1[0][0]
__________________________________________________________________________________________________
max_pooling2d_2 (MaxPooling2D)  (None, 256, 256, 256 0           concatenate_1[0][0]
__________________________________________________________________________________________________
conv2d_7 (Conv2D)               (None, 256, 256, 128 32896       concatenate_1[0][0]
__________________________________________________________________________________________________
conv2d_9 (Conv2D)               (None, 256, 256, 192 221376      conv2d_8[0][0]
__________________________________________________________________________________________________
conv2d_11 (Conv2D)              (None, 256, 256, 96) 76896       conv2d_10[0][0]
__________________________________________________________________________________________________
conv2d_12 (Conv2D)              (None, 256, 256, 64) 16448       max_pooling2d_2[0][0]
__________________________________________________________________________________________________
concatenate_2 (Concatenate)     (None, 256, 256, 480 0           conv2d_7[0][0]
                                                                 conv2d_9[0][0]
                                                                 conv2d_11[0][0]
                                                                 conv2d_12[0][0]
==================================================================================================
Total params: 513,120
Trainable params: 513,120
Non-trainable params: 0
__________________________________________________________________________________________________

创建了一个模型体系结构图,该图清楚地显示了每个模块的布局,以及第一个模型如何供给第二个模块。

请注意,由于空间原因,每个初始模块中的第一个1×1卷积在最右边,但除此之外,其他层在每个模块中从左到右组织。

具有高效初始模块的卷积神经网络结构图

如何实现残差模块

卷积神经网络的残差网络结构(ResNet)是由Kming He等人提出的。在他们2016年题为“图像识别的深度残差学习”的论文中,这篇论文在2015年版的ILSVRC挑战中取得了成功。

ResNet中的一个关键创新是剩余模块。残差模块,特别是恒等残差模型,是具有相同数目的滤波器和较小滤波器大小的两个卷积层的块,其中第二层的输出与第一卷积层的输入相加。绘制为图形时,模块的输入将添加到模块的输出中,并称为快捷连接。

我们可以使用函数API和add()合并函数在KERAS中直接实现这一点。

# function for creating an identity residual module
def residual_module(layer_in, n_filters):
	# conv1
	conv1 = Conv2D(n_filters, (3,3), padding='same', activation='relu', kernel_initializer='he_normal')(layer_in)
	# conv2
	conv2 = Conv2D(n_filters, (3,3), padding='same', activation='linear', kernel_initializer='he_normal')(conv1)
	# add filters, assumes filters/channels last
	layer_out = add([conv2, layer_in])
	# activation function
	layer_out = Activation('relu')(layer_out)
	return layer_out

这种直接实现的一个限制是,如果输入层中的过滤器数量与模块的最后一个卷积层中的过滤器数量(由n_filter定义)不匹配,那么我们将得到一个错误。

一种解决方案是使用通常称为投影层的1×1卷积层,以增加用于输入层的滤波器的数目或减少用于模块中最后卷积层的滤波器的数目。前一种解决方案更有意义,并且是本文提出的方法,称为投影快捷方式。

当尺寸增加时[…],我们考虑两个选项:(A)快捷方式仍然执行身份映射,并填充额外的零个条目以增加维度。此选项不引入任何额外参数;(B)投影快捷方式[…] 用于匹配尺寸(通过1×1卷积完成)。

下面是函数的更新版本,如果可能,它将使用标识,否则输入中的筛选器数量的投影与n_filter参数不匹配。

# function for creating an identity or projection residual module
def residual_module(layer_in, n_filters):
	merge_input = layer_in
	# check if the number of filters needs to be increase, assumes channels last format
	if layer_in.shape[-1] != n_filters:
		merge_input = Conv2D(n_filters, (1,1), padding='same', activation='relu', kernel_initializer='he_normal')(layer_in)
	# conv1
	conv1 = Conv2D(n_filters, (3,3), padding='same', activation='relu', kernel_initializer='he_normal')(layer_in)
	# conv2
	conv2 = Conv2D(n_filters, (3,3), padding='same', activation='linear', kernel_initializer='he_normal')(conv1)
	# add filters, assumes filters/channels last
	layer_out = add([conv2, merge_input])
	# activation function
	layer_out = Activation('relu')(layer_out)
	return layer_out

我们可以在一个简单的模型中演示此模块的用法。

下面列出了完整的示例。

# example of a CNN model with an identity or projection residual module
from keras.models import Model
from keras.layers import Input
from keras.layers import Activation
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import add
from keras.utils import plot_model

# function for creating an identity or projection residual module
def residual_module(layer_in, n_filters):
	merge_input = layer_in
	# check if the number of filters needs to be increase, assumes channels last format
	if layer_in.shape[-1] != n_filters:
		merge_input = Conv2D(n_filters, (1,1), padding='same', activation='relu', kernel_initializer='he_normal')(layer_in)
	# conv1
	conv1 = Conv2D(n_filters, (3,3), padding='same', activation='relu', kernel_initializer='he_normal')(layer_in)
	# conv2
	conv2 = Conv2D(n_filters, (3,3), padding='same', activation='linear', kernel_initializer='he_normal')(conv1)
	# add filters, assumes filters/channels last
	layer_out = add([conv2, merge_input])
	# activation function
	layer_out = Activation('relu')(layer_out)
	return layer_out

# define model input
visible = Input(shape=(256, 256, 3))
# add vgg module
layer = residual_module(visible, 64)
# create model
model = Model(inputs=visible, outputs=layer)
# summarize model
model.summary()
# plot model architecture
plot_model(model, show_shapes=True, to_file='residual_module.png')

运行该示例首先创建模型,然后打印层的摘要。

因为模块是线性的,所以此摘要有助于了解正在发生的情况。

__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            (None, 256, 256, 3)  0
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 256, 256, 64) 1792        input_1[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 256, 256, 64) 36928       conv2d_2[0][0]
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 256, 256, 64) 256         input_1[0][0]
__________________________________________________________________________________________________
add_1 (Add)                     (None, 256, 256, 64) 0           conv2d_3[0][0]
                                                                 conv2d_1[0][0]
__________________________________________________________________________________________________
activation_1 (Activation)       (None, 256, 256, 64) 0           add_1[0][0]
==================================================================================================
Total params: 38,976
Trainable params: 38,976
Non-trainable params: 0
__________________________________________________________________________________________________

还创建了模型体系结构的图。

我们可以看到模块的输入中带有过滤器数量的膨胀,并且在模块的末尾添加了两个元素。

带残差模块的卷积神经网络结构图

本文描述了其他类型的剩余连接,如瓶颈。这些都留给读者作为练习,可以通过更新RESERVE_MODULE()函数轻松实现。

进一步阅读

如果你想深入了解,本节提供了更多关于该主题的资源。

文章

论文

API接口

摘要

在本教程中,你了解了如何从头开始从里程碑卷积神经网络模型实现关键架构元素。

具体地说,你了解到:

  • 如何实现用于VGG-16和VGG-19卷积神经网络模型的VGG模块。
  • 如何实现GoogLeNet模型中使用的朴素和优化的初始模块。
  • 如何实现ResNet模型中的身份残差模块。

00

Python

发表评论

电子邮件地址不会被公开。 必填项已用*标注

什么阻碍了你实现迈入机器学习领域的目标?

什么阻碍了你实现迈入机器学习领域的目标?

2020-04-22 机器学习

如果你在为进入机器学习领域而挣扎,感觉到有什么东西阻止了自己的开始,那么你应该看看这篇文章。 在这篇文章中,我们会讨论阻止进入机器学习领域的自我限制的信念,让你明白面临的问题。 几乎总是一种自我限制的信念阻碍了你们的进步。 也许你会在一个或多个这样的信念中看到自己。如果是这样的话, [......]

了解详情

R语言机器学习迷你课程

R语言机器学习迷你课程

2020-08-12 机器学习

在这个迷你课程中,你将发现如何开始,构建精确的模型,并自信地完成在14天内使用R预测建模机器学习项目。 这是一个重要而重要的文章。你可能想把它书签。 了解如何准备数据,拟合机器学习模型,并用我的新书评估他们在r上的预测,包括14步教程、3个项目和完整源代码。 我们开始吧。 [......]

了解详情

关于机器学习的几点思考

关于机器学习的几点思考

2020-04-26 机器学习

机器学习是一个大的、跨学科的研究领域。 你可以通过机器学习获得令人印象深刻的结果,并找到非常具有挑战性的问题的解决方案。但这只是更广泛的机器学习领域的一小部分,通常被称为预测建模或预测分析。 在这篇文章中,你将发现如何改变你对机器学习的思考方式,以便更好地为你提供机器学习实践者的服务。 [......]

了解详情

找到你的机器学习部落

找到你的机器学习部落

2020-04-26 机器学习

机器学习是一个充满算法和数据的迷人而强大的研究领域。 问题是,有这么多不同类型的人对机器学习感兴趣,每个人都有不同的需求。重要的是要了解你想要从机器学习中得到什么,并根据这些需求调整你的自学。 如果你不这样做,你很容易就会陷入困境,迷失方向,失去兴趣,得不到你想要的东西。 找到 [......]

了解详情

应用机器学习过程

应用机器学习过程

2020-04-26 机器学习

随着时间的推移,在处理应用机器学习问题时,你会开发出一种模式或流程,以快速获得良好的正常结果。 一旦开发完成,你就可以在一个又一个项目上反复使用此过程。你的流程越健壮、越发达,你就能越快地获得可靠的结果。 在这篇文章中,我想与你分享我解决机器学习问题的过程框架。 你可以将其用作下一 [......]

了解详情