计算机视觉是当今的热门话题之一。它为涉及图像的不同问题提供了稳健的解决方案。在本文中,我们将使用Tensorflow从头开始创建一个卷积神经网络(CNN)。然后,我们将使用它对猫和狗的图像进行分类,这是最流行的图像分类数据集之一。
本文旨在帮助该领域的新手,尤其是Tensorflow,学习获取数据、处理数据、建立模型、训练数据并最终使用数据进行预测的基本原理。

什么是分类?
我们必须回答的第一个问题是什么是分类。我会尽可能简短地介绍这些原则,并提供其他有价值的文章,更深入地介绍它们。
分类是为给定的输入数据分配标签的过程。例如,我们可以对电子邮件是否为垃圾邮件进行分类。在这种情况下,对于给定的图像,我们将预测图像是猫还是狗。
为了更详细地解释什么是分类以及最流行的算法,我建议通过中培IT学院机器学习、深度学习、计算机图像处理及知识图谱应用与核心技术实战课程进行系统学习。
卷积神经网络(CNN)
以下关键概念是CNN(或ConvNet)。CNN是一类神经网络,它将图像作为输入,对其应用一系列操作并返回输出。该输出可以是概率、图像类别的预测或另一个新图像。这取决于网络架构和我们试图解决的问题。
在这种情况下,我们将使用一个简单的CNN来对狗或猫类中的输入图像进行分类。它将返回给定图像是狗或猫的概率。
为了更好地理解这种神经网络在图像中执行的操作,亦可参考中培IT学院机器学习、深度学习、计算机图像处理及知识图谱应用与核心技术实战课程。
建立我们的网络
是时候开始工作并构建我们的分类器了。正如我们之前所说,我们将使用Tensorflow和Keras,使用简单的CNN架构来制作猫/狗分类器。
加载数据集
我们将使用牛津IIIT宠物数据集,其中包含7000多张猫和狗的图像。该数据集具有CC-BY-SA 4.0许可证,这意味着我们可以将数据共享和调整用于任何目的。
首先,我们将需要以下库。
import pandas as pd
import glob
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras
from keras.preprocessing.image import ImageDataGenerator
接下来,我们将加载数据集。你可以从Kaggle下载它,并将文件夹复制到你的工作目录中。此外,您可以直接从数据集的网站获取数据。
一旦我们有了数据集,它将包含一个名为“images”的文件夹,里面有所有宠物图像。
每个图像都将在文件名中包含其标签。正如我们在数据集的信息中看到的,数据被划分为不同的品种。
有12种猫和25种狗。我们将遵循的策略是使用所有的狗品种作为狗的图像,并使用所有的猫品种作为猫的图像。我们不会考虑品种,因为我们想建立一个二进制分类器。
让我们看看我们有多少数据。、
print('There are {} images in the dataset'.format(len(glob.glob('images/*.jpg'))))
正如我们所看到的,总共有7390张图片。现在是时候摆脱这些品种了。我们将创建两个列表,一个包含所有狗的照片,另一个包含猫的所有图像。
CATS = ['Abyssinian', 'Bengal', 'Birman', 'Bombay', 'British_Shorthair', 'Egyptian_Mau', 'Maine_Coon', 'Persian', 'Ragdoll', 'Russian_Blue', 'Siamese', 'Sphynx']
cats_images = []
dogs_images = []
for img in glob.glob('images/*.jpg'):
if any(cat in img for cat in CATS):
cats_images.append(img)
else:
dogs_images.append(img)
现在我们可以看看我们有多少动物的图像。
print('There are {} images of cats'.format(len(cats_images)))
print('There are {} images of dogs'.format(len(dogs_images)))
该数据集有2400只猫和4990只狗。
数据分区
对于我们的网络,我们希望使用三个不同的集合:
训练:用于训练模型的图像。
验证:在训练过程中测试模型的图像。
测试:在模型完成训练后,对其进行测试的图像。
我们将使用70%的图像进行训练,10%用于验证,剩下的20%用于测试。
由于我们只有两个图像列表(狗和猫),我们需要将这些列表划分为不同的集合。我们将用熊猫来做到这一点。
首先,我们对数据进行混洗,并将其分为三组,其对应的数据分布为70/10/20。
#shuffle the lists
np.random.shuffle(cats_images)
np.random.shuffle(dogs_images)
#split the data into train, validation and test sets
train_d, val_d, test_d = np.split(dogs_images, [int(len(dogs_images)*0.7), int(len(dogs_images)*0.8)])
train_c, val_c, test_c = np.split(cats_images, [int(len(cats_images)*0.7), int(len(cats_images)*0.8)])
接下来,我们必须使用panda创建数据帧。
train_dog_df = pd.DataFrame({'image':train_d, 'label':'dog'})
val_dog_df = pd.DataFrame({'image':val_d, 'label':'dog'})
test_dog_df = pd.DataFrame({'image':test_d, 'label':'dog'})
train_cat_df = pd.DataFrame({'image':train_c, 'label':'cat'})
val_cat_df = pd.DataFrame({'image':val_c, 'label':'cat'})
test_cat_df = pd.DataFrame({'image':test_c, 'label':'cat'})
它们将只有两列,一列带有图像名称,另一列带有标签“cat”或“dog”。
最后,我们可以连接数据帧。
train_df = pd.concat([train_dog_df, train_cat_df])
val_df = pd.concat([val_dog_df, val_cat_df])
test_df = pd.concat([test_dog_df, test_cat_df])
print('There are {} images for training'.format(len(train_df)))
print('There are {} images for validation'.format(len(val_df)))
print('There are {} images for testing'.format(len(test_df)))
我们已经从数据集中完美的创建了三个分区。
数据预处理
以下步骤是对所有图像进行预处理。我们希望它们具有相同的维度(因为CNN需要具有相同维度的所有输入数据),并且它们的像素被归一化。这样做的原因是为了更快地训练我们的神经网络模型。
我们将使用Keras中的ImageDataGenerator类。
BATCH_SIZE = 32
IMG_HEIGHT = 224
IMG_WIDTH = 224
#create the ImageDataGenerator object and rescale the images
trainGenerator = ImageDataGenerator(rescale=1./255.)
valGenerator = ImageDataGenerator(rescale=1./255.)
testGenerator = ImageDataGenerator(rescale=1./255.)
#convert them into a dataset
trainDataset = trainGenerator.flow_from_dataframe(
dataframe=train_df,
class_mode="binary",
x_col="image",
y_col="label",
batch_size=BATCH_SIZE,
seed=42,
shuffle=True,
target_size=(IMG_HEIGHT,IMG_WIDTH) #set the height and width of the images
)
valDataset = valGenerator.flow_from_dataframe(
dataframe=val_df,
class_mode='binary',
x_col="image",
y_col="label",
batch_size=BATCH_SIZE,
seed=42,
shuffle=True,
target_size=(IMG_HEIGHT,IMG_WIDTH)
)
testDataset = testGenerator.flow_from_dataframe(
dataframe=test_df,
class_mode='binary',
x_col="image",
y_col="label",
batch_size=BATCH_SIZE,
seed=42,
shuffle=True,
target_size=(IMG_HEIGHT,IMG_WIDTH)
)
我们刚刚创建了3个新的数据集,每个数据集都有经过预处理的图像。此外,我们应用shuffle属性来随机重组图像的顺序,并使用batch_size将图像连接到32个元素的组中。这意味着我们将一次向CNN提供32张图片。每一步中的图像越少,模型学习得越好,但完成训练过程需要更长的时间。这是一个我们可以用来检查性能如何随它而变化的参数。
可视化
如果我们想检查数据集的结果,我们可以进行以下编译。
images, labels = next(iter(testDataset))
print('Batch shape: ', images.shape)
print('Label shape: ', labels.shape)
我们有32张带有相关标签的图片。此外,我们可以绘制这些图像(例如,第四个图像)。
plt.imshow(images[3])
print('Label: ', labels[3])
标签为1表示狗,0表示猫。
模型
既然我们已经准备好了所有的数据,现在是时候构建模型了。
model = keras.Sequential([
keras.layers.InputLayer(input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
keras.layers.Conv2D(64, (3, 3), activation='relu'),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(128, (3, 3), activation='relu'),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(256, (3, 3), activation='relu'),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Conv2D(512, (3, 3), activation='relu'),
keras.layers.GlobalAveragePooling2D(),
keras.layers.Dense(1, activation='sigmoid')
])
这是一个简单的CNN模型,具有四个卷积层和一个由具有1个输出神经元的密集层组成的输出层。
让我们进入训练阶段。我们需要编译并拟合模型。我们将使用二进制交叉熵作为损失函数,因为我们使用的是带有整数标签的类(0表示cat,1表示dog)。优化器将是adam算法,我们将使用准确性作为过程的度量。
我们将对网络进行15代的培训。
epochs=15
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history = model.fit(trainDataset, epochs=epochs, validation_data=(valDataset))
现在我们已经训练了我们的第一个CNN!我们可以在训练过程中查看网络的准确性和损失值。
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend(['Training', 'Validation'])
plt.show()
最后一步是评估这个模型。为此,我们将使用测试数据集。
loss, acc = model.evaluate(testDataset)
print('Loss:', loss)
print('Accuracy:', acc)
该模型的准确率为80%。
你已经训练出了你的第一个卷积神经网络,祝贺你!现在我们已经训练了我们的新模型,我们可以用它来预测猫和狗的真实图像。这是我们可以使用我们的模型进行预测的部分。这些图像以前在任何过程阶段都不应该被看到。
预测
预测阶段是与现实世界问题最相似的场景,一旦模型经过训练,它就必须对看不见的数据进行分类。
在我们的例子中,我们将为下面的图像预测类。
对于人类来说,这显然是一只可爱的猫的形象,但让我们看看我们的模型对此有什么看法。
def preprocess(image):
img_resize = tf.image.resize(image, [IMG_HEIGHT, IMG_WIDTH])
img_norm = img_resize / 255
return img_norm
img = plt.imread('pexels-cat-predict.jpg')
img = tf.reshape(img, (-1, IMG_HEIGHT, IMG_HEIGHT, 3))
img = preprocess(img)
model.predict(img)
在这种情况下,我们必须将图像重塑为网络的输入格式,并将其标准化,就像我们对所有数据集的图像所做的那样。
然后我们把它交给模型,输出为0.08。该输出可以在0到1之间变化,因为网络的输出层具有s形激活函数。由于我们的类对于猫是0,对于狗是1,所以我们的模型同意这个图像是猫的。
本文介绍了一个简单的方法,从零开始CNN。它的表现不错,但仍有很大的改进空间。在这里,我向大家推荐中培IT学院机器学习、深度学习、计算机图像处理及知识图谱应用与核心技术实战课程,课程涉及了深度学习、机器学习、神经网络、图像识别、知识图谱等人工智能领域的核心技术知识,将会给学员带来较大收获。