AI 技术讲座精选:​通过学习Keras从零开始实现VGG网络

2018-04-26 16:34:08 浏览数 (1)

Keras代码示例多达数百个。通常我们只需复制粘贴代码,而无需真正理解这些代码。通过学习本教程,您将搭建非常简单的构架,但是此过程会带给您些许好处:您将通过阅读 VGG*的论文原著学习使用 Keras 从零开始实现 VGG 网络。

我使用的术语是指由牛津大学计算机视觉组 (Visual Geometry Group, VGG)为ILSVRC-2014构建的网络构架。

那么,实现别人构建出来的结构有什么意义呢?

关键在于学习,通过完成本教程的学习,您将:

  • 进一步了解 VGG 构架;
  • 进一步了解卷积神经网络;
  • 进一步学习如何在 Keras 中搭建网络;
  • 通过阅读科学论文进一步学习科学方法并实践部分方法。

为什么以 VGG 作为起步?

  • 它的搭建较为简单;
  • 它在 ILSVRC-2014 (ImageNet 竞赛)中取得了优异的成绩;
  • 它在当下应用广泛;
  • 它的论文很有阅读价值;
  • 可以使用 Keras 搭建该网络,这样您就可以对比您的代码。

目标受众

刚开始学习深度学习并且从未使用 Keras 搭建过任何网络的人员。

预备知识

基础Python和基本卷积神经网络知识。我建议您阅读斯坦福大学的 CS231n:视觉认知卷积神经网络课程笔记(CS231n: Convolutional Neural Networks for Visual Recognition notes,http://cs231n.stanford.edu/)。

练习 0

浏览“VGG 网络论文:大型图像识别的深度卷积网络(Very Deep Convolutional Networks for Large-ScaleImage Recognition,https://arxiv.org/abs/1409.1556)。对结果和该网络的构架形成更好的理解。根据结果选择您要搭建的构架。

练习 1

学习网络结构。考虑以下超参数:卷积过滤器(感受野)的大小、步幅(stride)和补零(padding)的数量。另外,检查使用的是哪种激活函数。如果您不确定这些术语的含义,查看CS231n课程笔记。记得查看输入数据的大小。

计算各层网络须学习的参数数量。将每层网络学习的参数数量求和得出须学习的参数总数。CS231n 卷积神经网络课程笔记有很大帮助。记得将所有偏差求和。另外,计算每层网络输出的形状(宽度、高度、深度)。使用纸和铅笔!在此练习中画图有很大帮助。

您可以在此论文中找到关于参数数量和参数计算方法的信息。

练习 2

阅读 Keras 文件的第一页(https://keras.io/)并开始构建Keras的 Sequential模型(https://keras.io/getting-started/sequential-model-guide)。在您首次试验之前略过示例部分。回到论文,更加仔细地进行阅读。着重阅读结构配置部分。开始编码网络结构。您将需要认真阅读 Keras 文件的网络层部分。

注意:我仅仅建议您略过示例部分,以免您看到构建 VGG 网络的具体代码。始终建议您阅读示例,因为您可能从这些示例中学到该文件其他部分不涵括的知识。

提示:

  • 阅读该论文的第 2 部分(卷积神经网络配置)。
  • 记住 Keras 包括: 例如,如果您想使用keras.layers.pooling.MaxPooling2D,输入from keras.layers.pooling import MaxPooling2D。这样做会使代码的可读性更好。
  • 如果您遇到困难,可以查看一下 Keras 文件中的示例。

练习 3

将您的结果与与 Keras 构建的 VGG 做对比。检查您网络的参数数量是否与 Keras 的参数数量相同。您可以使用model.summary()显示参数数量和您网络中各层的输出形状。

获得解决方法

在此部分中,我关注更多的将是获得解决方法的过程而不是解决方法本身。

练习 0

如果是首次练习,我每次开始阅读论文时做的第一件事是:先阅读摘要,再读总结,然后再通览全文寻找感兴趣的结果(通常为表格和图表)。

表 3 和表 4 中显示的结果表明最佳的网络配置为 D 和 E。这些配置的结构显示在表 1 中。注意,您不需要阅读整篇论文寻找这个信息,因为您可以通过快速浏览图片和表格轻易找到需要的信息(暂时)。

我决定使用配置 D,因为它的性能几乎和配置 E 相同,但是它的结构更简单(16 个卷积神经网络而不是 19 个)。

表 1:卷积神经网络配置(如每列所示)。配置的深度从左侧(A )栏至右侧(E)栏递增(添加的层用粗体显示)。卷积层参数表示为“conv<感受野大小>-<通道数>”。为简洁起见,本表未显示 ReLU 激活函数。

练习 1

我们想要理解该网络配置。从我们的第一个练习中,我们在表 1 中列出了不同的配置。我们从该表的描述得知,conv3–64是一个感受野大小为 3x3,通道数为 64(过滤器)的卷积层:

卷积层参数表示为“conv感受野大小—通道数”。

但是,该表并未给出有关卷积补零(用零元素填充)和步幅的信息。为了找到这些信息,我们再次浏览该论文。

2.1 配置

在训练中,输入卷积神经网的是一张固定大小(224 × 224 RDB)的图像。我们进行的预处理只是用每个像素的 RGB 值减去训练集中算得的 RGB 平均值。该图像经一堆卷积层处理,在处理时我们使用非常小的感受野: 3 × 3(这是捕捉左/右、上/下和中心概念的最小大小)。在其中一个配置中,我们还使用 1 × 1 的卷积层,它可以看作是输入通道的一个线性转化(在非线性转化之后)。卷积步幅设定为 1 像素;卷积层输入的空间补零为:3 × 3 卷积层补零数为 1 像素,这样在卷积后空间分辨率可以保持不变。空间池化由五个 max-pooling 层进行,这些层紧跟在卷积层之后(不是所有 max-pooling 层都跟在卷积层后)。Max-pooling 在步幅为 2 ,大小为 2 × 2 像素的窗口上进行。

一堆卷积层(不同的配置有不同的深度)之后是三个全连接层:前两个连接层每个拥有 4096 个通道,第三个进行 1000 类 ILSVRC 分类,因此有 1000 个通道(每个类别一个通道)。最后一层为 soft-max 层。所有网络中的全连接层的配置都是一样的。

所有隐蔽层装有 rectification(ReLU(Krizhevsky 等人,2012)) non-linearity(RELU)。注意,我们全部的网络(除了一个)都不包含局部响应归一化( Local ResponseNormalization,LRN))(Krizhevsky等人,2012):如第 4 节所示,这样的归一化并不会提升在ILSVRC上的性能,而且还会增加内存消耗和计算时间。如果适用的话,LRN 层的参数为(Krizhevsky 等人,2012)。

在论文上作笔记能帮您更好地组织思路。无论你是打印论文并用笔作笔记还是在电子文档上作笔记,始终要作笔记。

现在我们知道了关于网络配置的全部信息:

  • 输入大小: 224 x 224;
  • 感受野大小: 3 x 3;
  • 卷积步幅为 1 像素;
  • 补零数为 1(3 x 3感受野),保持相同的空间分辨率;
  • 步幅2 像素的2 x 2 max pooling;
  • 有两个全连接层,每层有 4096 个单位;
  • 最后一层为 softmax 分类层,共有 1000 个单位(代表 1000 个ImageNet类别);
  • 激活函数为ReLU。

我们现在可以计算需学习的参数的数目了。

你可以在第 2.3 节(讨论)找到此信息。

对于第一个卷积层而言,网络必须学习 64 个大小为3x3的过滤器,输入深度(3)。另外,每个过滤器还有个偏差参数,因此参数的总数目为 64x64x3x3 64 = 1792。你可以使用相同的算法计算其他卷积层。

卷积层的输出的深度将为其卷积过滤器的数量。补零数选为 1 像素,这样就可以保持。整个卷积层的空间分辨率。这样,空间分辨率将只有在池化层(Pooling Layers)才会发生改变。因此,第一个卷积层的输出将为224 x 224 x 64。

池化层并不学习任何参数,因此可学习参数的数量为 0。为了计算池化层的输出形状,我们必须考虑窗口的大小和步幅。由于窗口为2 x 2,步幅为 2,该卷积层对每个 2 x 2 像素输出一个像素,并且跳 2 个像素进行下一计算(不发生重叠),因此每个池化层的空间分辨率都除以 2.深度维持不变。

为了计算全连接层的参数数量,我们必须用前一层的单位数量乘以当前层的单位数量。按照上一段描述的逻辑,你可以得出最后一个卷积层的单位数为 7x7x512。因此,配置 D 第一个全连接层的参数数量将为 7x7x512x4096 4096 = 102764544。

如果可以将参数的总数量与论文中的结果作对比(表 2):

练习 2

在 Keras 文件的第一页,你会发现您将需要搭建一个 Sequential 模型:

from keras.models import Sequential

model = Sequential()

使用 model.add() 添加卷积层。另一种替代方法是将卷积层列表传递给 Sequential 模型构建器(我使用过这种方法)。

最难的部分是为每一卷积层确定准确的参数。可以通过查看文档完成此步:卷积、池化、核心层。

我们先确定我们将使用哪几层。由于 VGG 网络适用于图像,我们将使用 Conv2D 和 MaxPooling2D。阅读关于这些卷积层类型的整个文件很重要。

对于 Conv2D 层,我们要注意的第一件事情是:

当在模型中将该层最为首层时,需给出关键词语句 input_shape(整数元组,不包括样本轴),例如128x128 RGB的图像编码为:input_shape=(128, 128, 3),data_format="channels_last"。

因此,我们必须确定图像的 input_shape。从练习 2 中,我们已知输入大小为 224x224。我们处理的是彩色图像,因此输入深度为 3。

通过阅读 Conv2D 语句,我们可以学习如何定义内核大小、步幅、补零数和激活函数。

其中须注意的一个重要语句为 data_format:它用于定义 Keras 内数据流的顺序。由于我不想为 Keras 中的每个程序设置此语句,我通过编辑 ~/keras/keras.json 将此语句设置为默认:

{

"image_data_format": "channels_last"

# (...) other configs

}

我们需要使用的语句为 filters、kernel_size、strides、padding 和 activation。如果你想在之后训练此模型,其他一些语句可能很有用,例如 kernel_initializer。

过滤器、内核大小和步幅的设置不是很重要。激活函数的设置需要你阅读激活文件(https://keras.io/activations/)。

Padding 有两个选项:valid 或 same。这两个选项的含义都不明确,因此我不得不用谷歌进行检索。我找到了解释1https://github.com/fchollet/keras/issues/1984和解释2http://datascience.stackexchange.com/questions/11840/border-mode-for-convolutional-layers-in-keras。另一种方法是直接查看 Keras 实现(https://github.com/fchollet/keras/blob/5cef75219abc339b64e35f221775692d3cf04b84/keras/utils/conv_utils.py#L89-L115)。

如果边界模式为“valid”,您得到的输出就会小于输入,因为只有在输入和过滤器完全重叠下才会计算卷积。 如果边界模式为“same”,您得到的输出大小将与输入大小一样。这意味着过滤器不得不越出输入的界限“过滤器大小 / 2”——输入外的区域通常都填充零元素。

因此,我们要将 padding 设置为 same。

由于我们要将补零数设置为零,我们就使用语句 padding="valid"。由于 padding 的默认值为 vaid,我们可以省略这个语句(但是注意 Keras API 会发生很大的改变,进而这将导致未来版本的 Keras 的结构发生变化)。

在我们调用全连接层(稠密层)之前,我们需要flatten最后一个卷积网络的输出。这将把卷积神经网络的三维输出转化为一维。

最后是稠密层,我们仅需设置单元数量和激活函数。

最终的代码十分精简:

注意,我并未包括 Dropout 层,也没设置权重初始化器,因为我们仍未涉及训练步骤。

你可以在此处找到 VGG 的 Keras 实现:

https://github.com/fchollet/keras/blob/master/keras/applications/vgg16.py

练习 3

您可以通过运行以下代码检查 VGG16 或 VGG19:

from keras.applications import VGG16, VGG19

VGG16.summary()

VGG19.summary()

延 伸

接下来的一个有趣的步骤是训练 VGG16。但是,训练ImageNet是个更为复杂的任务。VGG 论文声明:

使用装配四个NVIDIATitanBlack图形处理器(GPU)的系统训练一个简单的网络需要 2—3 周的时间(根据结构类型)。

即使你的设备价值数千美元,也要花费很多时间。

尽管如此,尝试创新出一些关于训练和测试设置的有趣想法,例如:加入 Dropout 层,设置优化器、编译模型和研究预处理等。

你还可以尝试使用预训练权重在 VGG 上进行微调。

本文由 AI100 编译,转载需得到本公众号同意。


编译:AI100

原文链接:https://hackernoon.com/learning-keras-by-implementing-vgg16-from-scratch-d036733f2d5


0 人点赞