机器学习中构建第一个图像分类器的所有步骤(带代码)
如果您想创建一个图像分类器但不知道从哪里开始,请按照此快速指南了解这些概念,并能够训练卷积神经网络以识别您想要的任何图像!
为了实现这一点,我们提供的代码是用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”的可以帮助您改善训练周期的长度,主要是避免过度拟合。