摘要

卷积神经网络依赖于称为卷积的计算机视觉/图像处理技术。 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(过滤器)

图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

图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 模块中可以看到一个很好的例子:

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

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

图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

图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

图 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

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

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

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

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

activation

图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

图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

图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(子集)数据集

图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 示例

图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 Kclass StridedNet:@staticmethoddef 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 itselfmodel = Sequential()inputShape = (height, width, depth)chanDim = -1# if we are using "channels first", update the input shape# and channels dimensionif 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 volumemodel.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) filtersmodel.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 volumemodel.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) filtersmodel.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 layermodel.add(Flatten())model.add(Dense(512, kernel_initializer=init))model.add(Activation("relu"))model.add(BatchNormalization())model.add(Dropout(0.5))# softmax classifiermodel.add(Dense(classes))model.add(Activation("softmax"))# return the constructed network architecturereturn 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 filenamelabel = 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 imageif label not in LABELS:continue# load the image and resize it to be a fixed 96x96 pixels,# ignoring aspect ratioimage = cv2.imread(imagePath)image = cv2.resize(image, (96, 96))# update the data and labels lists, respectivelydata.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   supportFaces       0.97      0.99      0.98       109Leopards       1.00      0.76      0.86        50Motorbikes       0.91      1.00      0.95       200airplanes       0.98      0.93      0.95       200accuracy                           0.95       559macro avg       0.97      0.92      0.94       559
weighted avg       0.95      0.95      0.95       559

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

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

总结

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

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

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

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

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

深度学习入门,Keras Conv2D类参数详解相关推荐

  1. Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解

    Keras深度学习实战(4)--深度学习中常用激活函数和损失函数详解 常用激活函数 Sigmoid 激活函数 Tanh 激活函数 ReLU 激活函数 线性激活函数 Softmax 激活函数 损失函数 ...

  2. pythonsvc_sklearn-SVC实现与类参数详解

    sklearn-SVC实现与类参数 它是基于libsvm实现的.随着样本数量的增加,拟合时间的复杂度要高于二次,这就使得当样板数量超过一万个时,很难扩展到数据集中. 在多类处理时,是按照1对1的方案进 ...

  3. 【20210922】【机器/深度学习】KNN (K近邻) 算法详解

    一.算法概念 KNN, K-near neighbor,即最近邻算法.它是一种分类算法,算法思想是:一个样本与数据集中的 k 个样本最相似,如果这 k 个样本中的大多数属于某一个类别,则该样本也属于这 ...

  4. 深度学习——感知机(perceptron)图文详解

    感知机 一,什么是感知机 二,用感知机搭建简单逻辑电路 2.1 与门 2.2 与非门,或门 三,感知机的实现 3.1 简单感知机的实现 3.2 导入权重和偏置 3.3 使用权重和偏置的实现 四,感知机 ...

  5. 汽车知识入门篇之汽车参数详解

    许多消费者在购车之前都会先关注车型的口碑,这是很实用的方法.不过读懂参数可能更方便找到满足自身需求的车型. 一.汽车的主要结构参数和性能参数 汽车的主要特征和技术特性随所装用的发动机类型和特性的不同, ...

  6. 【深度学习】ResNet——CNN经典网络模型详解(pytorch实现)

    建议大家可以实践下,代码都很详细,有不清楚的地方评论区见~ 1.前言 ResNet(Residual Neural Network)由微软研究院的Kaiming He等四名华人提出,通过使用ResNe ...

  7. 深度学习(十四)——Softmax详解, 目标检测, RCNN

    https://antkillerfarm.github.io/ Softmax详解 首先给出Softmax function的定义: yc=ζ(z)c=ezc∑Cd=1ezd for c=1,-,C ...

  8. st-link v2怎么连接_深度学习之 YOLO v1,v2,v3详解 - 一杯清酒邀明月

    (写在前面:如果你想 run 起来,立马想看看效果,那就直接跳转到最后一张,动手实践,看了结果再来往前看吧,开始吧······) 一.YOLOv1 简介 这里不再赘述,之前的我的一个 GitChat ...

  9. 深度学习-目标检测YOLOV3 YOLOv4原理详解

    2.YoloV3核心基础内容 2.1 网络结构可视化 Yolov3是目标检测Yolo系列非常非常经典的算法,不过很多同学拿到Yolov3或者Yolov4的cfg文件时,并不知道如何直观的可视化查看网络 ...

  10. 机器学习、深度学习中常用的优化算法详解——梯度下降法、牛顿法、共轭梯度法

    一.梯度下降法 1.总述: 在机器学习中,基于基本的梯度下降法发展了三种梯度下降方法,分别为随机梯度下降法,批量梯度下降法以及小批量梯度下降法. (1)批量梯度下降法(Batch Gradient D ...

最新文章

  1. 笔记。------数组
  2. 产品经理和UX设计师,变革已可期
  3. Maven 连接私服资源库配置
  4. 35/100. Permutations
  5. BZOJ 3527: [ZJOI2014]力(FFT)
  6. 百度开源 FAQ 问答系统(AnyQ)安装---Linux(无docker)+小白编译AnyQ-dockerlinux[CentOs]
  7. LinkedList理解(1)结构
  8. Leetcode 刷题笔记(三十) ——动态规划篇之子序列问题:回文
  9. Oracle 动态视图3 V$SESSION
  10. 同样是百度输入法,定制远没有原版好用
  11. Tomcat下载安装配置详细过程
  12. SQLserver 获取当前时间戳
  13. windows修改注册表,替换按键映射
  14. BIGEMAP GIS Office
  15. ubuntu本地安装中文
  16. php添加删除div,前端JavaScript-动态添加和删除div元素
  17. 记一次src挖洞实战——逻辑漏洞
  18. 在C/C++中常用的符号
  19. 麻省理工学院计算机科学,麻省理工学院素以世界顶尖的工程学和计算机科学而享誉世界[1-2] ,位列2015-16年世...
  20. 计算机通讯技术的专业有哪些,通信类包括哪些专业

热门文章

  1. html图片点击加边框颜色代码,用HTML代码给图片添加边框方法
  2. 积分上限函数求导总结
  3. mongo分片集群部署
  4. 文本挖掘系列之文本信息抽取
  5. 达梦8基础对象操作管理
  6. 寻梦港家政上门服务小程序微擎
  7. 白菜萝卜的做法 - 凉拌菜
  8. 外卖CPS小程序源码分享
  9. 一名爱折腾人士的Apps for iPhone分享
  10. 使用手册 煤矿风险管控系统_煤矿风险分级管控手册.doc