AIRX · 2020年05月08日

使用Keras和TensorFlow 2.0建立深度学习模型对图像进行分类

在本文中,我们将构建一个深度学习模型来对图像中的对象进行分类。为了构建卷积神经网络,我们将使用Kaggle提供的这个数据集。(https://www.kaggle.com/c/dogs...)CNN是一种主要用于视觉任务的神经网络。该网络将检测动物的特征,然后使用这些特征将给定的输入图像分类为猫或狗。

以下内容由公众号:AIRX社区(国内领先的AI、AR、VR技术学习与交流平台) 整理

首发平台:AIRX社区

导入必要的包文件

先激活虚拟环境
`conda activate my_env
`
运行以下命令安装keras和tensorflow:

`conda install tensorflow keras pillow
`
在这里,我们还安装了pillow以便于以后加载图像。

现在导入以下包:

  • 连续初始化人工神经网络
  • 用于实现处理图像的卷积网络
  • MaxPooling2D用于添加池化层
  • Flatten转换池的功能映射成一个列,将被馈送到全连接层
  • 这将为神经网络增加一个完全连接的层

from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense

初始化神经网络

接下来,我们将使用该Sequential包来初始化线性的图层堆栈。对于像这样的分类问题,我们通常创建一个分类变量。
`
classifier = Sequential()`
我们现在有了一个神经网络的实例,但它本身并不能做任何事情。我们需要对数据集应用一个函数,这意味着网络需要一个卷积层。我们将在下一步中添加这一层。

添加卷积层

通过调用分类器上的add函数并传递所需的参数来添加层。传递参数是使用Convolution2D完成的。第一个参数(滤波器)是卷积中输出滤波器的数量。它们也被称为特征检测器。

第二和第三参数代表2D卷积窗口的高度和宽度。input_shape是输入图像的形状。黑白图像转换为2D阵列,而彩色图像转换为3D阵列。

卷积是涉及两个函数的数学计算,旨在找出这两个函数如何相互影响。

该过程涉及三个关键项目:输入图像,特征检测器和特征图。通过将输入图像逐个元素的矩阵表示与特征检测器相乘,可以获得特征图。此过程旨在减小图像的大小,并保留了对分类输入图像很重要的功能,并丢弃了不分类的功能。每个特征图都会检测图像独特特征的位置。

在这种情况下,我们正在处理彩色图像。因此,我们将三个通道传递给该input_shape参数。我们还需要为每个通道传递2D数组的尺寸。我们将传递的最后一个参数是激活函数。由于图像分类是非线性任务,因此我们将使用整流器功能。这样可以确保我们在操作过程中不会得到负值。
`classifier.add(Conv2D(32, (3, 3), input_shape = (256, 256, 3), activation='relu'))
`
我们现在有一个CNN,它将检测图像数据集中的特征。在下一步中,我们将使用池来减小这些特性的大小。这将有助于减少深度学习模型的计算时间

合并以减少要素图的大小

现在,我们将向网络中添加一个池层,以减少功能映射的大小。我们使用2x2池大小的最大池。这减少了图像的大小,同时保留了重要的信息。

物体在图像中的位置不会影响神经网络感知其独特特征的能力。由于图像在光照和拍摄角度方面有很大的不同,所以汇集确保了神经网络能够检测出独特的特征,尽管存在这些差异。

Max pooling将一个2x2矩阵放入feature map中,并从中选择最大的值。2x2矩阵在整个feature map中移动,并在每个移动中选择最大的值。获得的值形成一个矩阵,称为池功能映射。

最大池是重要的,因为它保持了图像的独特功能,同时减少了图像的大小。这个过程也减少了过度拟合,因为CNN只接收对分类任务很重要的特征。
`classifier.add(MaxPooling2D(pool_size=(2,2)))
`
在下一步中,我们将把这些特征映射转换为一种可被深度学习模型接受的格式。

扁平化特征映射

是时候将所有的特征映射平铺成一个单独的向量了。然后将这个向量传递给CNN进行处理。这是通过调用分类器上的Flatten()函数实现的。

`classifier.add(Flatten())
`
在这一点上,特征是在一个结构中,可以输入到神经网络。但是,我们必须添加一个层,在将特征输入到神经网络后,它将为我们提供输出。这将是下一步的主题。

向神经网络添加层

我们将使用上面得到的向量作为神经网络的输入,使用Keras中的稠密函数。

它采用的第一个参数是units,units是隐藏层中的节点数。通过实验可以确定最佳的单units。第二个参数是激活函数。这一层通常使用ReLu激活函数。

扁平的特征图被传递给CNN。这个过程涉及到输入层、全连接层和输出层。全连通层和人工神经网络中的隐层是一样的,只是现在它是全连通的。从输出层获得预测的图像类。

该网络计算预测和预测过程中的误差。网络通过误差的反向传播来改进预测。最后的结果是一个介于0和1之间的数字。这个数字表示每个类的概率。
`classifier.add(Dense(units = 128, activation='relu'))
`
现在,我们准备添加输出层。在这一层,我们将使用sigmoid激活函数,因为我们期望一个二进制结果。如果我们期望有两个以上的可能结果,我们就会使用softmax函数。这里的单位是1,因为我们只期望类的预测概率。

`classifier.add(Dense(units=1, activation='sigmoid'))
`
我们现在已经有了深度学习模型的所有层。然而,在开始训练模型之前,我们必须确保减少了训练过程中出现的错误。这最大化了从模型中获得良好结果的机会。因此,在下一个步骤中,我们将实现一个策略来减少训练中的错误。

编译CNN

用该compile函数完成CNN的编译。该函数需要三个参数:

  • 优化器
  • 损失函数
  • 绩效指标

我们将应用梯度下降作为模型的优化器。在这种情况下,binary_crossentropy损失函数最合适,因为这是二进制分类问题。梯度下降是一种优化策略,用于减少训练过程中的误差,以使误差最小。这是通过找到成本函数最小的点来实现的。这被称为局部最小值,是通过对特定点的斜率求微分并降到成本函数的最小值而发现的。在这里,我们将使用流行的Adam优化器。
`classifier.compile(optimizer='adam', loss='binary_crossentropy',metrics=['accuracy'])
`
现在,我们确定在训练过程中可以正确处理错误,我们已经准备好将分类器适合训练图像。

拟合CNN

在拟合CNN之前,我们将使用Keras对图像进行预处理,以减少过度拟合。这个过程称为图像增强。为此,我们将使用ImageDataGenerator函数。
from keras.preprocessing.image import ImageDataGenerator
该功能将缩放、缩放、剪切和翻转图像。rescale参数对图像像素值进行重新排序,取值范围为0到1。horizontal_flip=真水平翻转图像。
`train_datagen = ImageDataGenerator(rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)
`
之后,我们还需要使用ImageDataGenerator重新调整测试数据图像。

`test_datagen = ImageDataGenerator(rescale=1./255)
`
接下来,我们将使用train_datagen创建一个训练集。使用flow_from_directory从当前工作目录获取图像。传入路径作为第一个参数,target_size作为第二个参数。

target_size是图像的大小。我们将使用256x256,因为我们已经在上面指定了它。batch_size是必须通过网络的图像数量,以便更新权重。我们将class_mode指定为二进制,因为这确实是一个二进制分类问题。

运行以下命令来加载训练图像。因为我们的笔记本和training_set在同一个文件夹中,所以加载图像不会有任何错误。

`training_set = train_datagen.flow_from_directory('training_set', target_size=(256, 256), batch_size=32, class_mode='binary')
`
现在我们将创建一个具有与上面类似参数的测试集。同样,因为我们的Jupyter笔记本和test_set在同一个文件夹中,所以测试集的图像将被加载,没有任何错误。

`test_set = test_datagen.flow_from_directory('test_set', target_size=(256, 256), batch_size=32, class_mode='binary')
`
steps_per_epoch是在完成一个epoch之前从生成器获得的步骤数。epochs是用来训练CNN的迭代次数。validation_steps是在停止之前要验证的步骤总数。

classifier.fit_generator(training_set, steps_per_epoch=40, epochs=25, validation_data=test_set, validation_steps=1000)
Output
Epoch 1/25
40/40 [==============================] - 7341s 1s/step - loss: 8.0578 - acc: 0.5000 - val_loss: 8.0575 - val_acc: 0.5001
<keras.callbacks.History at 0x7f87a8efb7f0>

回顾一下,在这一步中,我们加载了训练和测试图像,对它们进行预处理,并将训练集安装到我们创建的模型中。接下来就是测试的时候了~

预测

首先,我们必须对图像进行预处理。这可以在numpy和image的帮助下实现。image将用于加载新图像,而numpy将用于将它们转换为numpy数组。
`
import numpy as np
from keras.preprocessing import image`

我们现在可以加载我们想要预测的图像。这是使用图像模块中的load_img函数完成的。将图像的位置作为第一个参数传递,并将图像的大小作为第二个参数传递。使用与模型训练时相同的图像大小。

test_image = image.load_img('dog.jpg', target_size=(256, 256))
由于我们使用彩色图像,我们必须将测试图像转换为3D数组。我们可以使用图像模块中的img_to_array函数来实现这一点。

test_image = image.img_to_array(test_image)
在这一点上,我们应该有三维的图像。然而,在进行预测之前,我们需要传入第四个参数。此参数对应于批大小。

图像现在是三维的。你可能已经注意到了,我们是分批传递图像的。在本例中,我们将有一批一个输入图像。NumPy中的expand_dims方法将使我们能够添加第四个维度。

我们传递给它的第一个参数是测试图像,第二个参数是我们想要添加的维度的位置,将它添加到第一个位置,因为这是神经网络期望的位置。第一个位置对应轴0:

test_image = np.expand_dims(test_image, axis=0)
现在使用predict方法预测图像属于哪一类:

prediction = classifier.predict(test_image)
来自训练集的class_indices属性将帮助我们获得类标签。

training_set.class_indices
我们得到的输出将是这样的:

Output
{'cats': 0, 'dogs': 1}

总结

在这篇文章中,我们使用Keras构建了一个可以对图像进行分类的深度学习模型。我们结合之前的人工神经网络知识来实现这个目标。为了进一步改进模型,可以尝试使用keras中的不同激活函数或优化器函数。如果想了解更多关于CNNs的信息,可以查看Keras文档:

https://keras.io/layers/convo...
关于更多机器学习、CV、AR、VR资源和技术干货,可以关注公众号:AIRX社区,共同学习,一起进步!
二维码.jpg

推荐阅读
关注数
4
内容数
7
AIRX是一个专注AI、AR、VR技术学习与交流的平台
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息