机器学习中构建第一个图像分类器的所有步骤(带代码)

如果您想创建一个图像分类器但不知道从哪里开始,请按照此快速指南了解这些概念,并能够训练卷积神经网络以识别您想要的任何图像!

为了实现这一点,我们提供的代码是用Python(3.x)编写的,我们将主要使用Keras库。

现在,我们将重点介绍卷积神经网络,它对列和神经元,输入和输出保持相同的想法,同时简单地添加一种方法来提取图像中的信息。

什么是卷积神经网络?

这种类型的神经网络由一些深度神经网络组成,在此基础上进行一些运算。

总的来说,请记住,图像只是一个数字矩阵,如果图像只是灰度级,则维度为2;如果包含颜色,则维度为3(第三维度用于所有RGB级别)。

首先,当一个图像被赋予算法时,它首先在初始图像上应用一个小的过滤器并将其带到它的任何地方。此步骤称为卷积。

机器学习中构建第一个图像分类器的所有步骤(带代码)

图1 - 5x5图像与3x3过滤器的卷积

在图1中,初始图像为绿色,过滤器为黄色,并将每个初始图像的数乘以相应的过滤器得出另一个数。

在该操作之后,获得新的矩阵(红色)。通过将红色矩阵的像素与模型进行比较,程序可以确定是否存在与第一图像上的模型相对应的对象。

例如,仅在一行像素上获得较大的数字意味着初始图像在那里包含一行。

下一步称为Pooling。它是关于获取每个区域的最高值并仅使用这些值形成新矩阵。它减少了矩阵的空间维度,因此有助于神经网络更快地运行。

机器学习中构建第一个图像分类器的所有步骤(带代码)

图2 - pooling操作示例

在图2中,您可以看到图像的维度分为4个部分,每个部分都表示其最高值。新形成的图像更小。

此外,在此过程中使用激活函数来标准化所有获得的值。在下面的示例中,我们将使用ReLU。

最后,最后一步可用于提高精度,称为Dropout。它迫使神经网络在学习阶段随机禁用某些神经元。我们也将在我们的示例中实现此函数。

既然您已经了解了卷积的基础知识,我们就可以开始构建一个卷积!

准备数据

只有当您想要使用自己的数据或无法在网上轻松找到的数据时,此部分才有用,构建一个卷积神经网络也许更适合你的需要。否则,直接使用Keras数据集的代码:

from keras.datasets import mnist #replace mnist with any dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data()

机器学习中构建第一个图像分类器的所有步骤(带代码)

在这里,我们只需调用函数load_data来设置训练和测试阶段的数据集。您可以将任何要使用的数据集替换为“mnist”(在两行中都更改它)。

如果要创建自己的数据集,请执行以下步骤:

首先,您需要收集大量图像。越多越好。请记住为每个类保留大致相同数量的图像。例如,对于我的二维国际象棋分类器,我为每个可能的块(和空案例)准备了160个图像,所以总共约2,000个图像,但是数据集的大小取决于项目。

还有一个强大的工具可以帮助您创建更多数据,称为数据扩充。它只是修改一个图像并通过翻转,旋转或裁剪来回放大量新的和唯一的图像,所有这些都基于第一个图像。

最后确保所有数据都归入一个专门用于此目的的文件夹中,其中每个类都有自己的子文件夹。现在在主文件夹中,我们将创建一个python程序来设置所有数据。

import numpy as np
import os
from matplotlib import pyplot as plt
import cv2
import random
import pickle
file_list = []
class_list = []
DATADIR = "data"
# All the categories you want your neural network to detect
CATEGORIES = ["bishopB", "bishopW", "empty", "kingB", "kingW",
	 "knightB", "knightW", "pawnB", "pawnW", "queenB",
	 "queenW", "rookB", "rookW"]
# The size of the images that your neural network will use
IMG_SIZE = 50
# Checking or all images in the data folder
for category in CATEGORIES :
	path = os.path.join(DATADIR, category)
	for img in os.listdir(path):
		img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE)
training_data = []
def create_training_data():
	for category in CATEGORIES :
		path = os.path.join(DATADIR, category)
		class_num = CATEGORIES.index(category)
		for img in os.listdir(path):
			try :
				img_array = cv2.imread(os.path.join(path, img), cv2.IMREAD_GRAYSCALE)
				new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
				training_data.append([new_array, class_num])
			except Exception as e:
				pass
create_training_data()
random.shuffle(training_data)
X = [] #features
y = [] #labels
for features, label in training_data:
	X.append(features)
	y.append(label)
X = np.array(X).reshape(-1, IMG_SIZE, IMG_SIZE, 1)
# Creating the files containing all the information about your model
pickle_out = open("X.pickle", "wb")
pickle.dump(X, pickle_out)
pickle_out.close()
pickle_out = open("y.pickle", "wb")
pickle.dump(y, pickle_out)
pickle_out.close()
pickle_in = open("X.pickle", "rb")
X = pickle.load(pickle_in)

机器学习中构建第一个图像分类器的所有步骤(带代码)

在第14行中,您可以将列表更改为您需要的任何类,但保留与之前用于子文件夹的名称相同的名称。

最后,在运行程序之后,数据将在文件中设置并准备好使用。

构建卷积神经网络

import tensorflow as tf 
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D
import pickle
from keras.models import model_from_json
from keras.models import load_model
import matplotlib.pyplot as plt
# Opening the files about data
X = pickle.load(open("X.pickle", "rb"))
y = pickle.load(open("y.pickle", "rb"))
# normalizing data (a pixel goes from 0 to 255)
X = X/255.0
# Building the model
model = Sequential()
# 3 convolutional layers
model.add(Conv2D(32, (3, 3), input_shape = X.shape[1:]))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(64, (3, 3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
# 2 hidden layers
model.add(Flatten())
model.add(Dense(128))
model.add(Activation("relu"))
model.add(Dense(128))
model.add(Activation("relu"))
# The output layer with 13 neurons, for 13 classes
model.add(Dense(13))
model.add(Activation("softmax"))
# Compiling the model using some basic parameters
model.compile(loss="sparse_categorical_crossentropy",
				optimizer="adam",
				metrics=["accuracy"])
# Training the model, with 40 iterations
# validation_split corresponds to the percentage of images used for the validation phase compared to all the images
history = model.fit(X, y, batch_size=32, epochs=40, validation_split=0.1)
# Saving the model
model_json = model.to_json()
with open("model.json", "w") as json_file :
	json_file.write(model_json)
model.save_weights("model.h5")
print("Saved model to disk")
model.save('CNN.model')
# Printing a graph showing the accuracy changes during the training phase
print(history.history.keys())
plt.figure(1)
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'validation'], loc='upper left')

机器学习中构建第一个图像分类器的所有步骤(带代码)

如果您决定使用导入的数据集,请按照我们之前看到的行替换第9行和第10行,将第44行替换为:

model.fit(x_train, y_train, batch_size=32, epochs=40, verbose=1, validation_data=(x_test, y_test))

机器学习中构建第一个图像分类器的所有步骤(带代码)

在第37行中,将Dense()的参数修改为您拥有的类的数量。这是神经网络可能输出的数量。

对于每个卷积层,您可以看到我们总是首先添加它的神经元数量和过滤器大小。然后,我们涉及到激活函数,最后使用Pooling方法。我们还在第30行添加了Dropout以了解如何执行此操作。

此外,在第一个“普通”隐藏层之前,我们添加了函数Flatten(),它将以前卷积中的所有信息转换为神经元的输入。在这一点上,剩下的仅仅包含来自基本神经网络的层和神经元。

在这里,你构建了自己的分类器!

预测图像类

现在,您可以使用神经网络预测您想要的任何图像。只需制作一个涉及以下几行的小脚本:

import cv2
import tensorflow as tf
CATEGORIES = ["bishopB", "bishopW", "empty", "kingB", "kingW",
			"knightB", "knightW", "pawnB", "pawnW",
			"queenB", "queenW", "rookB", "rookW"]
def prepare(file):
 IMG_SIZE = 50
 img_array = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
 new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
 return new_array.reshape(-1, IMG_SIZE, IMG_SIZE, 1)
model = tf.keras.models.load_model("CNN.model")
image = "test.jpg" #your image path
prediction = model.predict([image])
prediction = list(prediction[0])
print(CATEGORIES[prediction.index(max(prediction))])

机器学习中构建第一个图像分类器的所有步骤(带代码)

函数prepare(file)允许我们使用任意大小的图像,因为它会自动将其调整为我们在第一个程序中定义的图像大小。

如果您在数据程序中修改了图像大小,也可以在此处进行修改。

您刚刚构建了适合自己图像的图像分类器。当然,请不要犹豫修改您看到的任何代码行,因为根据这些参数,您的神经网络精度可能会有很大差异。以下是关于这些问题的简要说明:

  • 模型:您可以轻松添加或删除神经网络中的某些层,更改神经元的数量,甚至激活函数。
  • 数据:获得的准确度不符合您的预期?也许您可以添加更多数据,并主要验证您的所有图像都存储在其文件夹中。
  • IMG_SIZE:在数据集的程序中定义,它表示网络将处理的图像的大小。不要尝试太大的数字,因为高质量的图像会导致更长的训练周期。此外,即使是众所周知的数据库(如MNIST)也只包含非常少的图像(MNIST为28x28)。不要忘记在最后一个程序中修改整形函数的IMG_SIZE。
  • 使用Keras的新参数。名为“EarlyStopping”的可以帮助您改善训练周期的长度,主要是避免过度拟合。