深度学习入门,Keras Conv2D类参数详解

举报
AI浩 发表于 2022/01/15 05:26:14 2022/01/15
【摘要】 摘要卷积神经网络依赖于称为卷积的计算机视觉/图像处理技术。 CNN 会自动学习在训练过程中应用于输入图像的内核。在今天的教程中,我们将讨论 Keras Conv2D 类,包括训练自己的 卷积 神经网络 (CNN) 时需要调整的最重要参数。我们将使用Keras Conv2D类实现一个简单的CNN。然后,我们将在 CALTECH-101 数据集上培训和评估此 CNN。学完本文您能够:快速确定您...

摘要

convolutions_kernel_sliding

卷积神经网络依赖于称为卷积的计算机视觉/图像处理技术。 CNN 会自动学习在训练过程中应用于输入图像的内核。

在今天的教程中,我们将讨论 Keras Conv2D 类,包括训练自己的 卷积 神经网络 (CNN) 时需要调整的最重要参数。我们将使用Keras Conv2D类实现一个简单的CNN。然后,我们将在 CALTECH-101 数据集上培训和评估此 CNN。

学完本文您能够:

  1. 快速确定您是否需要使用Keras Conv2D 类的特定参数
  2. 决定该特定参数的适当值
  3. 有效训练自己的卷积神经网络

总的来说,我的目标是帮助减少使用Keras的Conv2D课程时的任何困惑、焦虑或挫折感。通过此教程后,您将对 Keras Conv2D 参数有很强的了解。

在本教程的第一部分,我们将讨论 Keras Conv2D 类的参数。

从那里,我们将利用Conv2D类实现一个简单的凸起神经网络。

然后,我们将接受 CNN 实施,然后在 CALTECH-101 数据集上进行培训。

最后,我们将评估网络并检查其性能。

让我们继续前进,开始吧!

Keras Conv2D 类

Keras Conv2D 类具有以下参数:

tensorflow.keras.layers.Conv2D(filters, kernel_size, strides=(1, 1),
  padding='valid', data_format=None, dilation_rate=(1, 1),
  activation=None, use_bias=True, kernel_initializer='glorot_uniform',
  bias_initializer='zeros', kernel_regularizer=None,
  bias_regularizer=None, activity_regularizer=None,
  kernel_constraint=None, bias_constraint=None)

L看起来有点让人不知所措, 对吧?

你打算如何正确设置这些值?

不用担心 - 让我们单独检查每个参数,让您不仅对每个参数控制有很强的了解,而且能够正确设置每个参数

filters(过滤器)

image-20211029211343725

图1: The Keras Conv2D parameter, filters determines 第一个需要的 Conv2D 参数是“过滤 器”卷积层将学习。

网络架构早期的层(即更接近实际输入图像)学习纵向过滤器更少,而网络中较深的层(即更接近输出预测)将学习更多的滤镜。

与早期的 Conv2D 层相比,中间的 Conv2D 层将学习更多的滤镜,但过滤器比接近输出的层更少。让我们继续举一个例子:

model.add(Conv2D(32, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
...
model.add(Conv2D(64, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
...
model.add(Conv2D(128, (3, 3), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
...
model.add(Activation("softmax"))

在第一行,我们总共使用了32过滤器。然后,最大拼接用于减少输出体积的空间尺寸。

然后,我们使用64的过滤器。同样,最大池化用于减少空间尺寸。

最后的 Conv2D 层使用128过滤器。

请注意,随着我们的输出空间体积正在减少,我们学到的过滤器数量正在增加- 这是设计 CNN 架构的常见做法,我建议您也这样做。至于选择适当的数量过滤 器,我几乎总是建议使用2的次方作为值。

您可能需要根据数据集的复杂性和 (2) 神经网络的深度来调整确切值,但我建议从前面的 [32,64, 128]范围内的过滤器开始,在更深的层中增加到[256,512,1024]。

同样,值的确切范围可能不同,但从较少的过滤器开始,仅在必要时增加。

kernel_size

image-20211029211410837

图2: 深度学习 Conv2D 参数,决定了内核的维度。常见的尺寸包括 1×1、3×3、5×5 和 *7×7,*这些尺寸可以以"或"tuples"的身份传递。 filter_size:(1, 1)、(3, 3)、(5, 5)、(7, 7)

您需要提供给 Keras Conv2D 类的第二个必需参数是 kernel_size ,它是一个 2 元组,指定了 2D 卷积窗口的宽度和高度。 kernel_size 也必须是奇数。 kernel_size 的典型值包括: (1, 1) , (3, 3) , (5, 5) , (7, 7) 。 很少看到大于 7×7 的内核大小。

那么,你什么时候使用每个?

如果您的输入图像大于 128×128,您可以选择使用大于 3 的内核大小来这样做的好处:

(1) 学习更大的空间过滤器

(2)帮助减小体积大小。

其他网络,例如 VGGNet,在整个网络中专门使用 (3, 3) 过滤器。 更高级的架构如 Inception、ResNet 和 SqueezeNet 设计了整个微架构,它们是网络内部的“模块”,可以学习不同尺度(即 1×1、3×3 和 5×5)的局部特征,然后结合输出。 在下面的 Inception 模块中可以看到一个很好的例子:

image-20211029211427494

图3: Inception/GoogLeNet CNN 架构在网络内部使用“微架构”模块,学习不同尺度(filter_size)的局部特征,然后组合输出。

ResNet 架构中的 Residual 模块使用 1×13×3 过滤器作为一种降维形式,这有助于保持网络中的参数数量较少(或在给定网络深度的情况下尽可能少) ):

image-20211029211449671

图4: ResNet“残差模块”使用 1×1 和 3×3 过滤器进行降维。 这有助于用更少的参数使整个网络更小。

那么,您应该如何选择 filter_size ? 首先,检查你的输入图像——它是否大于 128×128? 如果是这样,请考虑使用 5×5 或 7×7 内核来学习更大的特征,然后快速减少空间维度——然后开始使用 3×3 内核:

model.add(Conv2D(32, (7, 7), activation="relu"))
...
model.add(Conv2D(32, (3, 3), activation="relu"))

如果您的图像小于 128×128,您可能需要考虑坚持使用小点的 1×1 和 3×3 过滤器。

strides

strides 参数是一个 2 元组整数,指定沿输入体积的 x 和 y 轴的卷积“步长”。

strides 值默认为 (1, 1) ,这意味着:

  • 给定的卷积滤波器应用于输入体积的当前位置
  • 过滤器向右移动 1 个像素,然后过滤器再次应用于输入体积
  • 这个过程一直执行,直到我们到达体积的最右侧边界,我们将过滤器向下移动一个像素,然后从最左侧重新开始

通常,您会将 strides 参数保留为默认 (1, 1) 值; 但是,您可以偶尔将其增加到 (2, 2) 以帮助减小输出体积的大小(因为滤波器的步长较大)。 通常,您会看到 2×2 步幅作为最大池化的替代:

model.add(Conv2D(128, (3, 3), strides=(1, 1), activation="relu"))
model.add(Conv2D(128, (3, 3), strides=(1, 1), activation="relu"))
model.add(Conv2D(128, (3, 3), strides=(2, 2), activation="relu"))

在这里我们可以看到前两个 Conv2D 层的步幅为 1×1。 最终的 Conv2D 层; 然而,它代替了最大池化层,而是通过跨步卷积减少了输出体积的空间维度。

2014 年,Springenber 等人。 发表了一篇题为 Striving for Simplicity: The All Convolutional Net 的论文,该论文证明在某些情况下用跨步卷积替换池化层可以提高准确性。

ResNet 是一种流行的 CNN,已经接受了这一发现——如果您查看 ResNet 实现的源代码(或自己实现它),您会看到 ResNet 响应跨步卷积而不是最大池化以减少两者之间的空间维度 残余模块。

padding

img

图5: 应用于带有填充的图像的 3×3 内核。 Keras Conv2D 填充参数接受“valid”(无填充)或“same”(填充 + 保留空间维度)。 此动画贡献给 StackOverflow。

Keras Conv2D 类的填充参数可以采用以下两个值之一: valid 或 same 。 使用有效参数,输入体积不会被零填充,并且空间维度可以通过卷积的自然应用减少。 下面的例子自然会减少我们体积的空间维度:

model.add(Conv2D(32, (3, 3), padding="valid"))

如果您想要保留体积的空间尺寸,以便输出体积大小与输入体积大小匹配,那么您需要为 padding 提供“same”的值:

model.add(Conv2D(32, (3, 3), padding="same"))

虽然默认的 Keras Conv2D 值是有效的,但我通常会将其设置为网络中大多数层的相同值,

然后通过以下任一方式减少我的体积的空间维度:

​ 最大池化

​ - 跨步卷积

我建议您也使用类似的方法来填充 Keras Conv2D 类。

data_format

image-20211029211617490

图 6: Keras 作为高级框架,支持多个深度学习后端。 因此,它包括对“channels last”和“channels last”通道排序的支持。

Conv2D 类中的数据格式值可以是 channels_last 或 channels_first : Keras 的 TensorFlow 后端使用最后排序的通道。 Theano 后端使用通道优先排序。

由于以下两个原因,您通常不必像 Keras 那样触及此值:

​ - 您很有可能使用 TensorFlow 后端到 Keras

​ - 如果没有,你可能已经更新了你的 ~/.keras/keras.json 配置文件来设置你的后端和相关的频道排序

我的建议是永远不要在你的 Conv2D 类中明确设置 data_format ,除非你有很好的理由这样做。

dilation_rate

image-20211029211658301

Figure 7: Keras 深度学习 Conv2D 参数 dilation_rate 接受一个 2 元组整数来控制膨胀卷积。

Conv2D 类的 dilation_rate 参数是一个二元组整数,控制膨胀卷积的膨胀率。 扩张卷积是一种基本卷积,仅应用于具有定义间隙的输入体积,如上图 7 所示。 您可以在以下情况下使用扩张卷积:

​ 1、您正在处理更高分辨率的图像,但细粒度的细节仍然很重要

​ 2、 您正在构建一个参数较少的网络

activation

image-20211029211807347

图8: Keras 提供了许多常见的激活函数。 Conv2D 的激活参数是一个方便的问题,它允许指定卷积后使用的激活函数。

Conv2D 类的激活参数只是一个方便的参数,允许您提供一个字符串,指定执行卷积后要应用的激活函数的名称。 在以下示例中,我们执行卷积,然后应用 ReLU 激活函数:

model.add(Conv2D(32, (3, 3), activation="relu"))

等效于:

model.add(Conv2D(32, (3, 3)))
model.add(Activation("relu"))

我的建议? 如果您可以使用激活参数,并且它有助于保持您的代码更清晰——这完全取决于您,并且不会影响您的卷积神经网络的性能。

use_bias

Conv2D 类的 use_bias 参数控制是否向卷积层添加偏置向量。 通常,您希望将此值保留为 True ,尽管 ResNet 的某些实现会忽略偏差参数。 我建议保持偏见,除非你有充分的理由不这样做。

kernel_initializer 和bias_initializer

image-20211029211855079

图9: Keras 为 Conv2D 类提供了许多初始化器。 初始化器可用于帮助更有效地训练更深的神经网络。

kernel_initializer 控制用于在实际训练网络之前初始化 Conv2D 类中的所有值的初始化方法。 类似地,bias_initializer 控制在训练开始之前如何初始化偏置向量。 完整的初始化器列表可以在 Keras 文档中找到; 但是,这是我的建议:

1、不理会bias_initialization——默认情况下它会用零填充(你很少,如果有的话,必须改变bias初始化方法)。

2、kernel_initializer 默认为 glorot_uniform ,这是 Xavier Glorot 统一初始化方法,对于大多数任务来说是完美的; 然而,对于更深层的神经网络,您可能希望使用 he_normal(MSRA/He 等人的初始化),当您的网络具有大量参数(即 VGGNet)时,该方法特别有效。

在我实现的绝大多数 CNN 中,我要么使用 glorot_uniform 要么使用 he_normal——我建议你也这样做,除非你有特定的理由使用不同的初始化程序。

kernel_regularizer、bias_regularizer 和 activity_regularizer

image-20211029211911166

图10: 应该调整正则化超参数,尤其是在处理大型数据集和非常深的网络时。 我经常调整 kernel_regularizer 参数以减少过度拟合并增加模型泛化到不熟悉的图像的能力。

kernel_regularizer 、bias_regularizer 和 activity_regularizer 控制应用于 Conv2D 层的正则化方法的类型和数量。 应用正则化可以帮助您: 减少过拟合的影响 提高模型的泛化能力 在处理大型数据集和深度神经网络时,应用正则化通常是必须的。 通常你会遇到应用 L1 或 L2 正则化的情况——如果我检测到过度拟合的迹象,我将在我的网络上使用 L2 正则化:

from tensorflow.keras.regularizers import l2
...
model.add(Conv2D(32, (3, 3), activation="relu"),
	kernel_regularizer=l2(0.0005))

您应用的正则化量是您需要针对自己的数据集进行调整的超参数,但我发现 0.0001-0.001 的值是一个很好的开始范围。

我建议不要管你的偏差正则化器——正则化偏差通常对减少过度拟合的影响很小。

我还建议将 activity_regularizer 保留为其默认值(即,没有活动正则化)。

虽然权重正则化方法对权重本身进行操作,f(W),其中 f 是激活函数,W 是权重,但活动正则化器对输出 f(O) 进行操作,其中 O 是层的输出。

除非有非常具体的原因,您希望对输出进行正则化,否则最好不要理会这个参数。

kernel_constraint 和bias_constraint

Keras Conv2D 类的最后两个参数是 kernel_constraint 和 bias_constraint 。

这些参数允许您对 Conv2D 层施加约束,包括非负性、单位归一化和最小-最大归一化。

您可以在 Keras 文档中查看受支持约束的完整列表。

同样,除非您有特定原因对 Conv2D 层施加约束,否则我建议您单独保留内核约束和偏差约束。

CALTECH-101(子集)数据集

image-20211029211938358

图11: CALTECH-101 数据集包含 101 个对象类别,每个类别有 40-80 张图像。 今天博客文章示例的数据集仅包含其中 4 个类:人脸、豹子、摩托车和飞机(来源)。

CALTECH-101 数据集是一个包含 101 个对象类别的数据集,每个类别有 40 到 800 张图像。

大多数图像每类大约有 50 张图像。

数据集的目标是训练一个能够预测目标类别的模型。 在神经网络和深度学习重新兴起之前,最先进的准确率仅为约 65%。

然而,通过使用卷积神经网络,可以达到 90% 以上的准确率(正如 He 等人在他们 2014 年的论文《用于视觉识别的深度卷积网络中的空间金字塔池化》中所证明的那样)。

今天,我们将在数据集的 4 类子集上实现一个简单而有效的 CNN,它能够达到 96% 以上的准确率:

  • Faces: 436 images
  • Leopards: 201 images
  • Motorbikes: 799 images
  • Airplanes: 801 images

我们使用数据集的子集的原因是,即使您没有 GPU,您也可以轻松地按照此示例从头开始训练网络。

同样,本教程的目的并不是要在 CALTECH-101 上提供最先进的结果——而是要教您如何使用 Keras 的 Conv2D 类来实现和训练自定义卷积神经网络的基础知识 .

项目结构

数据集地址:

http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz

linux下载指令:

$ wget http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz
$ tar -zxvf 101_ObjectCategories.tar.gz

项目的树结构

$ tree --dirsfirst -L 2 -v
.
├── 101_ObjectCategories
...
│   ├── Faces [436 entries]
...
│   ├── Leopards [201 entries]
│   ├── Motorbikes [799 entries]
...
│   ├── airplanes [801 entries]
...
├── pyimagesearch
│   ├── __init__.py
│   └── stridednet.py
├── 101_ObjectCategories.tar.gz
├── train.py
└── plot.png

第一个目录 101_ObjectCategories/ 是我们在上一节中提取的数据集。 它包含 102 个文件夹,因此我删除了今天的博客文章我们不关心的行。 剩下的是前面讨论过的四个对象类别的子集。

pyimagesearch/ 模块不可通过 pip 安装。 您必须使用“下载”来获取文件。 在该模块中,您将找到包含 StrdedNet 类的 stridendet.py

除了 stridednet.py 之外,我们还将查看根文件夹中的 train.py。 我们的训练脚本将使用 StridedNet 和我们的小数据集来训练模型以用于示例目的。

训练脚本将生成训练历史图 plot.png 。

Keras Conv2D 示例

image-20211029212011620

图12: 一个名为“StridedNet”的深度学习 CNN 作为今天关于 Keras Conv2D 参数的博客文章的示例。 点击 展开。

现在我们已经回顾了 (1) Keras Conv2D 类的工作原理和 (2) 我们将训练网络的数据集,让我们继续实施我们将训练的卷积神经网络。 我们今天将使用的 CNN,“StridedNet”,是我为本教程的目的而编写的。 StridedNet 具有三个重要的特性:

它使用跨步卷积而不是池化操作来减小体积大小

第一个 CONV 层使用 7×7 过滤器,但网络中的所有其他层使用 3×3 过滤器(类似于 VGG)

MSRA/He 等人。 正态分布算法用于初始化网络中的所有权重

现在让我们继续并实施 StridedNet。

打开一个新文件,将其命名为 stridednet.py ,并插入以下代码:

# import the necessary packages
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Dense
from tensorflow.keras import backend as K

class StridedNet:
	@staticmethod
	def build(width, height, depth, classes, reg, init="he_normal"):
		# initialize the model along with the input shape to be
		# "channels last" and the channels dimension itself
		model = Sequential()
		inputShape = (height, width, depth)
		chanDim = -1

		# if we are using "channels first", update the input shape
		# and channels dimension
		if K.image_data_format() == "channels_first":
			inputShape = (depth, height, width)
			chanDim = 1

我们所有的 Keras 模块都在第 2-9 行导入,即 Conv2D。

我们的 StrdedNet 类在第 11 行定义,在第 13 行使用单个构建方法。

build 方法接受六个参数:

​ width :图像宽度(以像素为单位)。

​ height :以像素为单位的图像高度。

​ depth :图像的通道数。

​ classes :模型需要预测的类数。

​ reg : 正则化方法。

​ init :内核初始化程序。

​ width 、 height 和 depth 参数影响输入体积形状。

对于“channels_last”排序,输入形状在第 17 行指定,其中深度是最后一个。 我们可以使用 Keras 后端检查 image_data_format 以查看我们是否需要适应“channels_first”排序(第 22-24 行)。 让我们看看如何构建前三个 CONV 层:

# our first CONV layer will learn a total of 16 filters, each
		# Of which are 7x7 -- we'll then apply 2x2 strides to reduce
		# the spatial dimensions of the volume
		model.add(Conv2D(16, (7, 7), strides=(2, 2), padding="valid",
			kernel_initializer=init, kernel_regularizer=reg,
			input_shape=inputShape))
		# here we stack two CONV layers on top of each other where
		# each layerswill learn a total of 32 (3x3) filters
		model.add(Conv2D(32, (3, 3), padding="same",
			kernel_initializer=init, kernel_regularizer=reg))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(Conv2D(32, (3, 3), strides=(2, 2), padding="same",
			kernel_initializer=init, kernel_regularizer=reg))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(Dropout(0.25))

每个 Conv2D 都使用 model.add 堆叠在网络上。

请注意,对于第一个 Conv2D 层,我们已经明确指定了 inputShape,以便 CNN 架构可以在某个地方开始和构建。然后,从这里开始,每次调用 model.add 时,前一层都充当下一层的输入。

考虑到前面讨论的 Conv2D 参数,您会注意到我们使用跨步卷积来减少空间维度而不是池化操作。

应用 ReLU 激活(参见图 8)以及批量归一化和 dropout。

我几乎总是推荐批量归一化,因为它倾向于稳定训练并使调整超参数更容易。也就是说,它可以使您的训练时间增加一倍或三倍。明智地使用它。

Dropout 的目的是帮助你的网络泛化而不是过拟合。当前层的神经元以概率 p 与下一层的神经元随机断开连接,因此网络必须依赖现有的连接。我强烈建议使用 dropout。

我们来看看更多层的StridedNet:

# our first CONV layer will learn a total of 16 filters, each
		# Of which are 7x7 -- we'll then apply 2x2 strides to reduce
		# the spatial dimensions of the volume
		model.add(Conv2D(16, (7, 7), strides=(2, 2), padding="valid",
			kernel_initializer=init, kernel_regularizer=reg,
			input_shape=inputShape))
		# here we stack two CONV layers on top of each other where
		# each layerswill learn a total of 32 (3x3) filters
		model.add(Conv2D(32, (3, 3), padding="same",
			kernel_initializer=init, kernel_regularizer=reg))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(Conv2D(32, (3, 3), strides=(2, 2), padding="same",
			kernel_initializer=init, kernel_regularizer=reg))
		model.add(Activation("relu"))
		model.add(BatchNormalization(axis=chanDim))
		model.add(Dropout(0.25))

网络越深,我们学习的过滤器就越多。 在大多数网络的末尾,我们添加了一个全连接层:

# fully-connected layer
		model.add(Flatten())
		model.add(Dense(512, kernel_initializer=init))
		model.add(Activation("relu"))
		model.add(BatchNormalization())
		model.add(Dropout(0.5))
		# softmax classifier
		model.add(Dense(classes))
		model.add(Activation("softmax"))
		# return the constructed network architecture
		return model

具有 512 个节点的单个全连接层被附加到 CNN。

最后,一个“softmax”分类器被添加到网络中——这一层的输出是预测值本身。

这是一个包装。 如您所见,一旦您知道参数的含义(Conv2D 具有很多参数的潜力),Keras 语法就非常简单。

让我们学习如何编写脚本来使用一些数据训练 StridedNet!

实现训练脚本

现在我们已经实现了我们的 CNN 架构,让我们创建用于训练网络的驱动程序脚本。 打开 train.py 文件并插入以下代码:

# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")
# import the necessary packages
from pyimagesearch.stridednet import StridedNet
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.regularizers import l2
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import cv2
import os

我们在第 2-18 行导入我们的模块和包。 请注意,我们没有在任何地方导入 Conv2D。 我们的 CNN 实现包含在 stridednet.py 中,我们的 StridedNet 导入处理它(第 6 行)。

我们的 matplotlib 后端设置在第 3 行——这是必要的,这样我们可以将我们的绘图保存为图像文件,而不是在 GUI 中查看它。 我们在第 7-9 行从 sklearn 导入功能:

LabelBinarizer :用于“one-hot”编码我们的类标签。 	

​ train_test_split :用于拆分我们的数据,以便我们拥有训练和评估集。

category_report :我们将使用它来打印评估的统计信息。 

在 keras 中,我们将使用:

​ ImageDataGenerator :用于数据增强。 有关 Keras 数据生成器的更多信息,请参阅上周的博客文章。

​ Adam:SGD 的优化器替代方案。

​ l2 :我们将使用的正则化器。 向上滚动以阅读有关正则化器的信息。 应用正则化可减少过拟合并有助于泛化。

我们将在运行时使用 argparse 来处理命令行参数,而 OpenCV (cv2) 将用于从数据集中加载和预处理图像。

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
	help="path to input dataset")
ap.add_argument("-e", "--epochs", type=int, default=50,
	help="# of epochs to train our network for")
ap.add_argument("-p", "--plot", type=str, default="plot.png",
	help="path to output loss/accuracy plot")
args = vars(ap.parse_args())

我们的脚本可以接受三个命令行参数:

​ --dataset :输入数据集的路径。

​ --epochs :要训练的时期数。 默认情况下,我们将训练 50 个 epoch。

​ --plot :我们的损失/准确度图将输出到磁盘。 此参数包含文件路径。

默认情况下,它只是 “plot.png” 。 让我们准备加载我们的数据集:

# initialize the set of labels from the CALTECH-101 dataset we are
# going to train our network on
LABELS = set(["Faces", "Leopards", "Motorbikes", "airplanes"])
# grab the list of images in our dataset directory, then initialize
# the list of data (i.e., images) and class images
print("[INFO] loading images...")
imagePaths = list(paths.list_images(args["dataset"]))
data = []
labels = []

在我们实际加载数据集之前,我们将继续进行初始化:

​ LABELS :我们将用于训练的标签。

imagePaths :数据集目录的图像路径列表。 我们将很快根据文件路径中解析的类标签过滤这些。 

​ data :一个列表,用于保存我们的网络将在其上训练的图像。

​ 标签:一个列表,用于保存与数据对应的类标签。

让我们填充我们的数据和标签列表:

# loop over the image paths
for imagePath in imagePaths:
	# extract the class label from the filename
	label = imagePath.split(os.path.sep)[-2]
	# if the label of the current image is not part of of the labels
	# are interested in, then ignore the image
	if label not in LABELS:
		continue
	# load the image and resize it to be a fixed 96x96 pixels,
	# ignoring aspect ratio
	image = cv2.imread(imagePath)
	image = cv2.resize(image, (96, 96))
	# update the data and labels lists, respectively
	data.append(image)
	labels.append(label)

遍历所有 imagePaths 。

在循环内,我们:

从路径中提取标签。

仅过滤 LABELS 集中的类。 这两行使我们分别跳过不属于 Faces、Leopards、Motorbikes 或 Airplanes 类的任何标签。

加载并调整我们的图像。

最后,将图像和标签添加到各自的列表中。

在下一个块中有四个动作发生:

# convert the data into a NumPy array, then preprocess it by scaling
# all pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
# perform one-hot encoding on the labels
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data, labels,
	test_size=0.25, stratify=labels, random_state=42)
# construct the training image generator for data augmentation
aug = ImageDataGenerator(rotation_range=20, zoom_range=0.15,
	width_shift_range=0.2, height_shift_range=0.2, shear_range=0.15,
	horizontal_flip=True, fill_mode="nearest")

这些行动包括:

  • ​ 将数据转换为 NumPy 数组,每个图像缩放到范围 [0, 1]。
  • 使用我们的 LabelBinarizer将我们的标签二值化为“one-hot encoding”。 这意味着我们的标签现在用数字表示,其中“one-hot”示例可能是: [0, 0, 0, 1] 表示“飞机” [0, 1, 0, 0] 代表“豹” 等等。
  • 将我们的数据拆分为训练和测试。
  • 初始化我们的 ImageDataGenerator 以进行数据增强。 你可以在这里读更多关于它的内容。
# initialize the optimizer and model
print("[INFO] compiling model...")
opt = Adam(lr=1e-4, decay=1e-4 / args["epochs"])
model = StridedNet.build(width=96, height=96, depth=3,
	classes=len(lb.classes_), reg=l2(0.0005))
model.compile(loss="categorical_crossentropy", optimizer=opt,
	metrics=["accuracy"])
# train the network
print("[INFO] training network for {} epochs...".format(
	args["epochs"]))
H = model.fit(x=aug.flow(trainX, trainY, batch_size=32),
	validation_data=(testX, testY), steps_per_epoch=len(trainX) // 32,
	epochs=args["epochs"])

为了评估我们的模型,我们将使用 testX 数据并打印一个分类报告:

# evaluate the network
print("[INFO] evaluating network...")
predictions = model.predict(x=testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
	predictions.argmax(axis=1), target_names=lb.classes_))

对于 TensorFlow 2.0+,我们不再使用 .predict_generator 方法; 它被替换为 .predict 并具有相同的函数签名(即,第一个参数可以是 Python 生成器对象)。

最后,我们将绘制我们的准确率/损失训练历史并将其保存到磁盘:

# plot the training loss and accuracy
N = args["epochs"]
plt.style.use("ggplot")
plt.figure()
plt.plot(np.arange(0, N), H.history["loss"], label="train_loss")
plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss")
plt.plot(np.arange(0, N), H.history["accuracy"], label="train_acc")
plt.plot(np.arange(0, N), H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy on Dataset")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="lower left")
plt.savefig(args["plot"])

训练和评估

此时,我们已准备好训练我们的网络! 打开一个终端,将目录更改为您下载代码和 CALTECH-101 数据集的位置,然后执行以下命令:

$ python train.py --dataset 101_ObjectCategories
[INFO] loading images...
[INFO] compiling model...
[INFO] training network for 50 epochs...
Epoch 1/50
52/52 [==============================] - 2s 45ms/step - loss: 2.0399 - accuracy: 0.4963 - val_loss: 1.4532 - val_accuracy: 0.5671
Epoch 2/50
52/52 [==============================] - 2s 38ms/step - loss: 1.5679 - accuracy: 0.6748 - val_loss: 1.9899 - val_accuracy: 0.4651
Epoch 3/50
52/52 [==============================] - 2s 39ms/step - loss: 1.3503 - accuracy: 0.7284 - val_loss: 2.0150 - val_accuracy: 0.5510
...
Epoch 48/50
52/52 [==============================] - 2s 38ms/step - loss: 0.5473 - accuracy: 0.9689 - val_loss: 0.5118 - val_accuracy: 0.9857
Epoch 49/50
52/52 [==============================] - 2s 38ms/step - loss: 0.5734 - accuracy: 0.9555 - val_loss: 0.7230 - val_accuracy: 0.9410
Epoch 50/50
52/52 [==============================] - 2s 38ms/step - loss: 0.5697 - accuracy: 0.9653 - val_loss: 0.6236 - val_accuracy: 0.9517
[INFO] evaluating network...
              precision    recall  f1-score   support
       Faces       0.97      0.99      0.98       109
    Leopards       1.00      0.76      0.86        50
  Motorbikes       0.91      1.00      0.95       200
   airplanes       0.98      0.93      0.95       200
    accuracy                           0.95       559
   macro avg       0.97      0.92      0.94       559
weighted avg       0.95      0.95      0.95       559

image-20211029212045192

图13: 我使用 Keras 和 matplotlib 生成的准确率/损失图用于训练 StridedNet,这是一个展示 Keras Conv2D 参数的示例 CNN。

如您所见,我们的网络在测试集上获得了约 95% 的准确率,并且过拟合最小!

总结

在今天的教程中,我们讨论了卷积层和 Keras Conv2D 类。 你现在知道:

  • Keras Conv2D 类最重要的参数是什么(过滤器、内核大小、步幅、填充)

  • 这些参数的正确值是什么

  • 如何使用 Keras Conv2D 类创建自己的卷积神经网络

  • 如何训练您的 CNN 并在示例数据集上对其进行评估

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。