深度学习和 Python 开始
摘要
使用 Keras 训练您的第一个简单神经网络不需要很多代码,但我们将开始缓慢,一步一步地进行,确保您了解如何在自己的自定义数据集中培训网络的过程。
我们今天将涵盖的步骤包括:
安装 Keras 和其他对系统的依赖
从磁盘中加载数据
创建您的训练和测试拆分
定义您的 Keras 模型架构
编译您的 Keras 模型
根据培训数据培训模型
根据测试数据评估您的模型
使用训练有素的 Keras 模型进行预测
我还包括一个额外的部分,培训你的第一个凸起神经网络。
这似乎是很多步骤,但我向你保证,一旦我们开始进入示例,你会看到,示例是线性的,使直观的意义,并会帮助您了解与Keras训练神经网络的基本原理。
数据集
数据集选用了猫狗大战的部分数据集,猫狗个选2000张,Pandas类别是我从网上搜索的,一百多张。如下图:
此数据集的目的是将图像正确分类为包含:
猫
狗
熊猫
项目结构
.
├── data
│ ├── cats
│ ├── dogs
│ └── panda
├── images
│ ├── cat.jpg
│ ├── dog.jpg
│ └── panda.jpg
├── output
│ ├── simple_nn.model
│ ├── simple_nn_lb.pickle
│ ├── simple_nn_plot.png
│ ├── smallvggnet.model
│ ├── smallvggnet_lb.pickle
│ └── smallvggnet_plot.png
├── models
│ ├── __init__.py
│ └── smallvggnet.py
├── predict.py
├── train_simple_nn.py
└── train_vgg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
从磁盘中加载数据
**图4:**将图像从磁盘加载到内存中。
现在,Keras 安装在我们的系统上,我们可以开始使用 Keras 实施我们的第一个简单的神经网络训练脚本。我们稍后将实施一个成熟的共周神经网络,但让我们从轻松开始,并努力向上。
train_simple_nn.py
# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")
# import the necessary packages
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import SGD
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2-19行导入我们所需的包裹。
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,
help="path to output trained model")
ap.add_argument("-l", "--label-bin", required=True,
help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,
help="path to output accuracy/loss plot")
args = vars(ap.parse_args())
1
2
3
4
5
6
7
8
9
10
11
当我们执行我们的脚本时,我们的脚本将动态处理通过命令行提供的附加信息。 附加信息采用命令行参数的形式。 该模块内置于 Python 中,将处理解析您在命令字符串中提供的信息。
我们有四个命令线参数要解析:
–dataset:通往磁盘上图像数据集的路径。
-model: 我们的模型将序列化,输出到磁盘。此参数包含输出模型文件的路径。
–label-bin: 数据集标签被序列化为磁盘,以便于在其他脚本中回忆。这是通往输出标签二元化器文件的路径。
–plot:输出训练图图像文件的路径。我们将审查此图,以检查我们的数据是否过度/不足。
# initialize the data and labels
print("[INFO] loading images...")
data = []
labels = []
# grab the image paths and randomly shuffle them
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)
# loop over the input images
for imagePath in imagePaths:
# load the image, resize the image to be 32x32 pixels (ignoring
# aspect ratio), flatten the image into 32x32x3=3072 pixel image
# into a list, and store the image in the data list
image = cv2.imread(imagePath)
image = cv2.resize(image, (32, 32)).flatten()
data.append(image)
# extract the class label from the image path and update the
# labels list
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
将数据排序,然后打乱这些序列。
循环读读取图片,将图片resize为(32×32)的图片,然后展平成一列数据。然后将数据放到data里面,将label放到labels里面。
# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
1
2
3
对数据做归一化。
切分训练集和测试集
**Figure 5:**在训练深度学习或机器学习模型之前,您必须将数据拆分为训练集和测试集。 这篇博文中使用了 Scikit-learn 来分割我们的数据。
现在我们已经从磁盘加载了我们的图像数据,接下来我们需要构建我们的训练和测试分割:
# 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, random_state=42)
1
2
3
4
按照4:1的比例将数据切分为训练集和测试集。
# convert the labels from integers to vectors (for 2-class, binary
# classification you should use Keras' to_categorical function
# instead as the scikit-learn's LabelBinarizer will not return a
# vector)
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
1
2
3
4
5
6
7
将标签做二值化操作
1, 0, 0# 对应猫
0, 1, 0# 对应狗
0, 0, 1# 对应熊猫
请注意,只有一个阵列元素是"hot"的,这就是为什么我们称之为"one-hot"编码。
定义您的 Keras 模型架构
**图6:**我们简单的神经网络是使用Keras在这个深度学习教程创建的。
下一步是使用 Keras 定义我们的神经网络架构。在这里,我们将使用一个网络,其中一个输入层、两个隐藏层和一个输出层:
# define the 3072-1024-512-3 architecture using Keras
model = Sequential()
model.add(Dense(1024, input_shape=(3072,), activation="sigmoid"))
model.add(Dense(512, activation="sigmoid"))
model.add(Dense(len(lb.classes_), activation="softmax"))
1
2
3
4
5
由于我们的模型非常简单,我们继续在此脚本中定义它(通常我喜欢在单独的文件中为模型架构创建一个单独的类)。
第一个隐藏层将有节点。input_shape是3072(32x32x3=3072)输出:1024。
第二个隐藏层将有节点输入就是上一个节点的输出所以是1024,输出是512
最后,最终输出层(第 78 行)中的节点数将是可能的类标签的数量——在这种情况下,输出层将有三个节点,一个用于我们的每个类标签(“猫”、“狗” ”和“熊猫”)。
编译你的 Keras 模型
上一步我们定义了我们的神经网络架构,下一步是"compile"它:
# initialize our initial learning rate and # of epochs to train for
INIT_LR = 0.01
EPOCHS = 80
# compile the model using SGD as our optimizer and categorical
# cross-entropy loss (you'll want to use binary_crossentropy
# for 2-class classification)
print("[INFO] training network...")
opt = SGD(lr=INIT_LR)
model.compile(loss="categorical_crossentropy", optimizer=opt,
metrics=["accuracy"])
1
2
3
4
5
6
7
8
9
10
学习率在优化器中设置,优化器使用SGD。
分类交叉熵被用作几乎所有训练进行分类的网络的损失。唯一的例外是2类分类,其中只有两个可能的类标签。在这种情况下,你会想交换"categorical_crossentropy"为"binary_crossentropy"。
训练
**图8:**训练数据和汇编模型培训深度学习模型。
现在,我们的 Keras 模型已编译,我们可以在我们的培训数据上"拟合"(即训练)它:
# train the neural network
H = model.fit(x=trainX, y=trainY, validation_data=(testX, testY),
epochs=EPOCHS, batch_size=32)
1
2
3
batch_size:控制通过网络传递的每组数据的大小。较大的 GPU 将能够容纳更大的批次大小。我建议从32或64(实际大小需要考虑显存的大小)
评估您的Keras模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jOd6McZD-1635420207841)(https://pyimagesearch.com/wp-content/uploads/2018/09/keras_tutorial_step7.png)]
**图9:**在符合我们的模型后,我们可以使用我们的测试数据进行预测并生成分类报告。
我们已经培训了我们的实际模型,但现在我们需要根据我们的测试数据来评估它。
重要的是,我们评估我们的测试数据,以便我们可以获得一个公正的(或尽可能接近公正)的表示,我们的模型如何表现良好的数据,它从来没有受过培训。
# 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_))
# plot the training loss and accuracy
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["accuracy"], label="train_acc")
plt.plot(N, H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy (Simple NN)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig(args["plot"])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
运行此脚本时,您会注意到我们的 Keras 神经网络将开始训练,一旦培训完成,我们将评估测试集上的网络:
$ python train_simple_nn.py --dataset animals --model output/simple_nn.model \
--label-bin output/simple_nn_lb.pickle --plot output/simple_nn_plot.png
Using TensorFlow backend.
[INFO] loading images...
[INFO] training network...
Train on 2250 samples, validate on 750 samples
Epoch 1/80
2250/2250 [==============================] - 1s 311us/sample - loss: 1.1041 - accuracy: 0.3516 - val_loss: 1.1578 - val_accuracy: 0.3707
Epoch 2/80
2250/2250 [==============================] - 0s 183us/sample - loss: 1.0877 - accuracy: 0.3738 - val_loss: 1.0766 - val_accuracy: 0.3813
Epoch 3/80
2250/2250 [==============================] - 0s 181us/sample - loss: 1.0707 - accuracy: 0.4240 - val_loss: 1.0693 - val_accuracy: 0.3533
...
Epoch 78/80
2250/2250 [==============================] - 0s 184us/sample - loss: 0.7688 - accuracy: 0.6160 - val_loss: 0.8696 - val_accuracy: 0.5880
Epoch 79/80
2250/2250 [==============================] - 0s 181us/sample - loss: 0.7675 - accuracy: 0.6200 - val_loss: 1.0294 - val_accuracy: 0.5107
Epoch 80/80
2250/2250 [==============================] - 0s 181us/sample - loss: 0.7687 - accuracy: 0.6164 - val_loss: 0.8361 - val_accuracy: 0.6120
[INFO] evaluating network...
precision recall f1-score support
cats 0.57 0.59 0.58 236
dogs 0.55 0.31 0.39 236
panda 0.66 0.89 0.76 278
accuracy 0.61 750
macro avg 0.59 0.60 0.58 750
weighted avg 0.60 0.61 0.59 750
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
此网络很小,当与小数据集结合时,我的 CPU 上每个epoch只需 2 秒。
在这里你可以看到,我们的网络正在获得60%的准确性。
由于我们随机挑选给定图像的正确标签的几率为 1/3,我们知道我们的网络实际上已经学会了可用于区分三个类别的模式。
我们还保存了我们的情节:
训练损失
验证损失
训练精度
验证精度
…确保我们能够轻松地发现我们的结果中过度拟合或不合适。
**图10:**我们简单的神经网络训练脚本(与Keras一起创建)生成精确/丢失情节,以帮助我们发现不足/过度拟合。
看看我们的情节,我们看到少量的过度适合开始发生超过epoch+45,我们的训练和验证损失开始分歧,并出现了明显的差距。
最后,我们可以将模型保存到磁盘中,以便以后可以重复使用,而无需重新训练它:
# save the model and label binarizer to disk
print("[INFO] serializing network and label binarizer...")
model.save(args["model"], save_format="h5")
f = open(args["label_bin"], "wb")
f.write(pickle.dumps(lb))
f.close()
1
2
3
4
5
6
使用 Keras 模型对新数据进行预测
在这一点上, 我们的模型是训练有素的, 但如果我们想在我们的网络已经培训后对图像做出预测呢?
那我们该怎么办?
我们如何从磁盘中加载模型?
我们如何加载图像,然后对图像进行预处理以进行分类?
在predict.py 脚本中,我将向您展示如何操作,因此打开它并插入以下代码:
# import the necessary packages
from tensorflow.keras.models import load_model
import argparse
import pickle
import cv2
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to input image we are going to classify")
ap.add_argument("-m", "--model", required=True,
help="path to trained Keras model")
ap.add_argument("-l", "--label-bin", required=True,
help="path to label binarizer")
ap.add_argument("-w", "--width", type=int, default=28,
help="target spatial dimension width")
ap.add_argument("-e", "--height", type=int, default=28,
help="target spatial dimension height")
ap.add_argument("-f", "--flatten", type=int, default=-1,
help="whether or not we should flatten the image")
args = vars(ap.parse_args())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
首先,我们将导入所需的包和模块。 每当您编写脚本以从磁盘加载 Keras 模型时,您都需要显式导入 from。 OpenCV 将用于注释和显示。该模块将用于加载我们的标签 binarizer.load_modeltensorflow.keras.modelspickle 接下来,让我们解析我们的命令行参数:
–image :我们输入图像的路径。
–model :我们经过训练和序列化的 Keras 模型路径。
–label-bin :序列化标签二值化器的路径。
–width :我们的 CNN 输入形状的宽度。本次设置为32。
–height :输入到 CNN 的图像的高度。本次设置为32。
–flatten :我们是否应该展平图像。默认情况下,我们不会展平图像。如果您需要展平图像,将其设置为1。
接下来,让我们根据命令行参数加载图像并调整其大小:
# load the input image and resize it to the target spatial dimensions
image = cv2.imread(args["image"])
output = image.copy()
image = cv2.resize(image, (args["width"], args["height"]))
# scale the pixel values to [0, 1]
image = image.astype("float") / 255.0
1
2
3
4
5
6
# check to see if we should flatten the image and add a batch
# dimension
if args["flatten"] > 0:
image = image.flatten()
image = image.reshape((1, image.shape[0]))
# otherwise, we must be working with a CNN -- don't flatten the
# image, simply add the batch dimension
else:
image = image.reshape((1, image.shape[0], image.shape[1],
image.shape[2]))
1
2
3
4
5
6
7
8
9
10
将图像展平。
# load the model and label binarizer
print("[INFO] loading network and label binarizer...")
model = load_model(args["model"])
lb = pickle.loads(open(args["label_bin"], "rb").read())
# make a prediction on the image
preds = model.predict(image)
# find the class label index with the largest corresponding
# probability
i = preds.argmax(axis=1)[0]
label = lb.classes_[i]
1
2
3
4
5
6
7
8
9
10
加载模型然后预测模型
猫: 54.6%
狗: 45.4%
熊猫: +0%
换句话说,我们的网络"认为"它看到*“猫”,它肯定"知道"它没有看到"熊猫"。*
找到最大值的索引(第 0 个"猫"指数)。
标签二进制器中提取‘“猫”字符串标签。
很简单, 对吧?
现在,让我们显示结果:
# draw the class label + probability on the output image
text = "{}: {:.2f}%".format(label, preds[0][i] * 100)
cv2.putText(output, text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
(0, 0, 255), 2)
# show the output image
cv2.imshow("Image", output)
cv2.waitKey(0)
1
2
3
4
5
6
7
**图11:**在我们的 Keras 教程中,猫被正确地分类为一个简单的神经网络。
在这里你可以看到,我们简单的Keras神经网络已经分类输入图像为"猫"55.87%的概率,尽管猫的脸被一块面包部分遮盖。
搭建CNN网络
无可否认,使用标准的馈入神经网络对图像进行分类并不是一个明智的选择。
相反,我们应该利用卷积神经网络 (CNN),该网络旨在对图像的原始像素强度进行操作,并学习可用于高精度对图像进行分类的歧视性滤镜。
我们今天在这里讨论的模型是Vggnet的较小变体, 我称之为 “小 Vggnet” 。
VGGNet 样型号具有两个共同特征:
只使用 3×3 卷积核
在应用池操作之前,在网络架构中,相互叠加在一起
现在,让我们继续实施小型VGGNet。
打开
smallvggnet.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 MaxPooling2D
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 K
1
2
3
4
5
6
7
8
9
10
导入需要的包。
class SmallVGGNet:
@staticmethod
def build(width, height, depth, classes):
# initialize the model along with the input shape to be
# "channels last" and the channels dimension itself
model = Sequential()
inputShape = (height, width, depth)
chanDim = -1
# if we are using "channels first", update the input shape
# and channels dimension
if K.image_data_format() == "channels_first":
inputShape = (depth, height, width)
chanDim = 1
1
2
3
4
5
6
7
8
9
10
11
12
13
创建SmallVGGNet类,在类中增加build方法。
build需要四个参数,分别是宽,高,深度和类别。
# CONV => RELU => POOL layer set
model.add(Conv2D(32, (3, 3), padding="same",
input_shape=inputShape))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
1
2
3
4
5
6
7
第一个卷积层,经过池化后,尺寸减少一半。
# (CONV => RELU) * 2 => POOL layer set
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(64, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
1
2
3
4
5
6
7
8
9
第二个卷积层,经过池化后,尺寸减少一半。
# (CONV => RELU) * 3 => POOL layer set
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(Conv2D(128, (3, 3), padding="same"))
model.add(Activation("relu"))
model.add(BatchNormalization(axis=chanDim))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
1
2
3
4
5
6
7
8
9
10
11
12
第三个卷积层,经过池化后,尺寸减少一半。
# first (and only) set of FC => RELU layers
model.add(Flatten())
model.add(Dense(512))
model.add(Activation("relu"))
model.add(BatchNormalization())
model.add(Dropout(0.5))
# softmax classifier
model.add(Dense(classes))
model.add(Activation("softmax"))
# return the constructed network architecture
return model
1
2
3
4
5
6
7
8
9
10
11
展平,然后输入全连接层。到这里模型就完成了。下面开始编写train代码:
train_vgg.py
# set the matplotlib backend so figures can be saved in the background
import matplotlib
matplotlib.use("Agg")
# import the necessary packages
from pyimagesearch.smallvggnet import SmallVGGNet
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 SGD
from imutils import paths
import matplotlib.pyplot as plt
import numpy as np
import argparse
import random
import pickle
import cv2
import os
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
导入需要的包。
# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to input dataset of images")
ap.add_argument("-m", "--model", required=True,
help="path to output trained model")
ap.add_argument("-l", "--label-bin", required=True,
help="path to output label binarizer")
ap.add_argument("-p", "--plot", required=True,
help="path to output accuracy/loss plot")
args = vars(ap.parse_args())
1
2
3
4
5
6
7
8
9
10
11
我们有四个命令线参数要解析:
–dataset集
:通往磁盘上图像数据集的路径。
–model: 我们的模型将序列化,输出到磁盘。此参数包含输出模型文件的路径。请务必相应地命名您的模型,以便您不会覆盖任何以前训练过的模型(如简单的神经网络模型)。
–label-bin: 数据集标签被序列化为磁盘,以便于在其他脚本中回忆。这是通往输出标签二元化器文件的路径。
-plot:输出训练图图像文件的路径。我们将审查此图,以检查我们的数据是否过度/不足。
每次训练模型时,应更改参数,应在命令行中指定不同的图段文件名,以便您拥有与笔记本或笔记文件中的训练笔记对应的图集历史记录。这个教程使深度学习看起来很容易,但请记住,我经历了几次迭代的训练之前,我确定了所有参数与您分享这个脚本。
让我们加载并预处理我们的数据:
# initialize the data and labels
print("[INFO] loading images...")
data = []
labels = []
# grab the image paths and randomly shuffle them
imagePaths = sorted(list(paths.list_images(args["dataset"])))
random.seed(42)
random.shuffle(imagePaths)
# loop over the input images
for imagePath in imagePaths:
# load the image, resize it to 64x64 pixels (the required input
# spatial dimensions of SmallVGGNet), and store the image in the
# data list
image = cv2.imread(imagePath)
image = cv2.resize(image, (64, 64))
data.append(image)
# extract the class label from the image path and update the
# labels list
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
和前面的类似,这里resize大小是64×64。下一步是切分数据集。
# 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, random_state=42)
# convert the labels from integers to vectors (for 2-class, binary
# classification you should use Keras' to_categorical function
# instead as the scikit-learn's LabelBinarizer will not return a
# vector)
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
1
2
3
4
5
6
7
8
9
10
11
按照4:1拆分训练集和测试集,然后二值化。
# construct the image generator for data augmentation
aug = ImageDataGenerator(rotation_range=30, width_shift_range=0.1,
height_shift_range=0.1, shear_range=0.2, zoom_range=0.2,
horizontal_flip=True, fill_mode="nearest")
# initialize our VGG-like Convolutional Neural Network
model = SmallVGGNet.build(width=64, height=64, depth=3,
classes=len(lb.classes_))
1
2
3
4
5
6
7
初始化图像数据生成器以执行图像增强。
图像增强允许我们通过随机旋转、移动、剪切、缩放和翻转,从现有培训数据中构建"附加"培训数据。
数据增强通常是关键步骤,作用:
避免过度拟合
确保您的模型概括良好
我建议您始终执行数据增强,除非您有明确的理由不执行。
# initialize our initial learning rate, # of epochs to train for,
# and batch size
INIT_LR = 0.01
EPOCHS = 75
BS = 32
# initialize the model and optimizer (you'll want to use
# binary_crossentropy for 2-class classification)
print("[INFO] training network...")
opt = SGD(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="categorical_crossentropy", optimizer=opt,
metrics=["accuracy"])
# train the network
H = model.fit(x=aug.flow(trainX, trainY, batch_size=BS),
validation_data=(testX, testY), steps_per_epoch=len(trainX) // BS,
epochs=EPOCHS)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
首先,我们确定我们的学习率、EPOCHS和批次大小。
然后,我们初始化我们的随机梯度下降 (SGD) 优化器 。
最后,我们将评估我们的模型,绘制损失/精度曲线,并保存模型:
# 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_))
# plot the training loss and accuracy
N = np.arange(0, EPOCHS)
plt.style.use("ggplot")
plt.figure()
plt.plot(N, H.history["loss"], label="train_loss")
plt.plot(N, H.history["val_loss"], label="val_loss")
plt.plot(N, H.history["accuracy"], label="train_acc")
plt.plot(N, H.history["val_accuracy"], label="val_acc")
plt.title("Training Loss and Accuracy (SmallVGGNet)")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend()
plt.savefig(args["plot"])
# save the model and label binarizer to disk
print("[INFO] serializing network and label binarizer...")
model.save(args["model"], save_format="h5")
f = open(args["label_bin"], "wb")
f.write(pickle.dumps(lb))
f.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
我们对测试集进行预测,然后使用科学学习来计算和打印我们的
$ python train_vgg.py --dataset animals --model output/smallvggnet.model \
--label-bin output/smallvggnet_lb.pickle \
--plot output/smallvggnet_plot.png
Using TensorFlow backend.
[INFO] loading images...
[INFO] training network...
Train for 70 steps, validate on 750 samples
Epoch 1/75
70/70 [==============================] - 13s 179ms/step - loss: 1.4178 - accuracy: 0.5081 - val_loss: 1.7470 - val_accuracy: 0.3147
Epoch 2/75
70/70 [==============================] - 12s 166ms/step - loss: 0.9799 - accuracy: 0.6001 - val_loss: 1.6043 - val_accuracy: 0.3253
Epoch 3/75
70/70 [==============================] - 12s 166ms/step - loss: 0.9156 - accuracy: 0.5920 - val_loss: 1.7941 - val_accuracy: 0.3320
...
Epoch 73/75
70/70 [==============================] - 12s 166ms/step - loss: 0.3791 - accuracy: 0.8318 - val_loss: 0.6827 - val_accuracy: 0.7453
Epoch 74/75
70/70 [==============================] - 12s 167ms/step - loss: 0.3823 - accuracy: 0.8255 - val_loss: 0.8157 - val_accuracy: 0.7320
Epoch 75/75
70/70 [==============================] - 12s 166ms/step - loss: 0.3693 - accuracy: 0.8408 - val_loss: 0.5902 - val_accuracy: 0.7547
[INFO] evaluating network...
precision recall f1-score support
cats 0.66 0.73 0.69 236
dogs 0.66 0.62 0.64 236
panda 0.93 0.89 0.91 278
accuracy 0.75 750
macro avg 0.75 0.75 0.75 750
weighted avg 0.76 0.75 0.76 750
[INFO] serializing network and label binarizer...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
CPU 的训练需要一些时间 - 75 个时代都需要超过一分钟的时间。训练需要一个多小时。
GPU 将在几分钟内完成整个过程,因为每个时代只需要 2 秒,如所示!
**图12:**我们对 Keras 准确/损失图的深入学习表明,我们通过 SmallVGGNet 模型获得了 76% 的动物数据准确性。
正如我们的结果表明的,你可以看到,我们使用 卷积 神经网络在动物数据集上实现了76% 的准确性,明显高于之前使用标准全连接网络的 60% 的准确性。
$ python predict.py --image images/panda.jpg --model output/smallvggnet.model \
--label-bin output/smallvggnet_lb.pickle --width 64 --height 64
Using TensorFlow backend.
[INFO] loading network and label binarizer...
1
2
3
4
**图13:**我们通过Keras教程的深入学习,展示了我们如何自信地识别图像中的熊猫。
我们的CNN很有信心,这是一只"熊猫"。我也是, 但我只是希望他不要盯着我看!
让我们试试一只可爱的小猎犬:
$ python predict.py --image images/dog.jpg --model output/smallvggnet.model \
--label-bin output/smallvggnet_lb.pickle --width 64 --height 64
Using TensorFlow backend.
[INFO] loading network and label binarizer...
1
2
3
4
**图14:**一只小猎犬被确认为使用Keras、TensorFlow和Python的狗。我们的 Keras 教程介绍了深度学习的基础知识,但刚刚触及了该领域的表面。
总结
在今天的教程中,您学习了如何从 Keras、深度学习和 Python 开始。
具体来说,您学习了与 Keras 和您自己的自定义数据集合作的七个关键步骤:
如何从磁盘中加载数据
如何创建您的培训和测试拆分
如何定义您的 Keras 模型架构
如何编译和准备您的Keras模型
如何根据您的培训数据对模型进行培训
如何在测试数据上评估模型
如何使用您训练有素的 Keras 模型进行预测
从那里,您还学会了如何实现卷积神经网络,使您能够获得比标准全连接网络更高的精度。