大家好,我技术人Howzit,这是深度学习入门系列第十六篇,欢迎大家一起交流!
文章目录
- 16.1 图像中的目标检测数据集
- 16.2 Keras中加载CIFAR-10数据集
- 16.3 CIFAR10的简单CNN
- 16.4 CIFAR-10的更大CNN
- 16.5 改善模型扩展
- 16.6 总结
- 16.6.6 接下来
传统神经网络解决不了的一个难题就是对象识别。在这里,模型可以识别图片中的对象。本节课,你将学习在Keras中如何开发和评估深度学习模型用于对象识别。一步步完成之后,你将知道:
- 关于CIFAR-10对象识别数据集以及如何在Keras中加载和使用。
- 如何创建一个用于对象识别的卷积神经网络。
- 如何通过创建更深的卷积神经网络提高性能。
让我们开始吧。
注意: 对于这节课,你可能想使用GPU而不是CPU来加速计算,比如第五章描述的过程。这是个建议,不是必须的。这节课在CPU上工作将正常运行。
16.1 图像中的目标检测数据集
自动识别图像中对象是一个难题,因为对象,位置,照明等的排列几乎无限。这真是个很难得问题。这是一个在计算机视觉中值得研究的问题,也是最近深度学习能力一次重要的展示。CIFAR开发出了标准计算机视觉和深度学习模型。
CIFAR-10数据集由6000张图片组成,被分成10类(因此命名我CIFAR-10)。类中包括一般对象,如飞机,汽车,鸟类,猫等等。数据集用标准的方法进行切分,5000个用于训练模型,剩余1000用于评估其性能。这些照片具有红色,绿色和蓝色通道的彩色,但尺寸小到仅为32×32像素。
使用非常大卷积神经网络能够获得显著的结果。你能够从Rodrigo Benenson网页上了解在CIFAR-10数据集上的这些显著结果。模型性能用分类精度表示,在写本文时,这个问题表现好的在90%以上,人类在表现为94%,最好的为96%。
16.2 Keras中加载CIFAR-10数据集
CIFAR-10能轻松在Keras中加载。Keras具有自动下载数据的功能,如何CIFAR-10并使用 cifar10.load_data() 函数,数据存在 ~/.keras/datasets目录下。这个数据集有163M,因此需要花费几分钟下载。一旦下载成功,接着就调用函数加载数据以备使用。
数据集被存放在Keras 数据集和测试集,以备Keras使用。每张图片采用一个三维矩阵表示,每个维度分别为红,绿,蓝,宽和高。我们采用Matplotlib Python绘制库直接绘制图片。
# Plot ad hoc CIFAR10 instances
from tensorflow.keras.datasets import cifar10
from matplotlib import pyplot
from PIL import Image
# load data
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
# create a grid of 3x3 images
for i in range(0, 9):
pyplot.subplot(330 + 1 + i)
pyplot.imshow(Image.fromarray(X_train[i]))
# show the plot
pyplot.show()
运行上面代码创建一个3×3的图片。这些图片从较小的32×32放大的,但是你仍然能够清楚看到,卡车,马和汽车。这些图像已被强制设为纵横比,您还可以在失真的图像上看到有些对象的。
16.3 CIFAR10的简单CNN
使用CNN能够很好的解决了CIFAR-10的问题。我们能通过导入这个例子需要的类和函数快速开始。
# Simple CNN model for CIFAR-10
import numpy
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.layers import Convolution2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.python.keras.utils import np_utils
from tensorflow.keras import backend as KK.set_image_dim_ordering("th")
作为一个好的实践,我们接下来初始化随机数种子为常数来确保结果的可复制性。
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
接下来,我们加载CIFAR-10数据集
# load data
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
对于每个红绿蓝通道其像素值范围在0-255。这是一个很好实践来进行标准化数据。因为输入值能够很好理解,所以我们能轻松通过除以其最大观察值255来标准化每个像素值到0-1之间。注意,数据是以整型加载的,所以我们必须转换成浮点型进行做除法。
# normalize inputs from 0-255 to 0.0-1.0
X_train = X_train.astype("float32")
X_test = X_test.astype("float32")
X_train = X_train / 255.0
X_test = X_test / 255.0
输出变量把每个类定义为从0到1的整型向量。我们能使用one-hot编码将他们转换成二维矩阵目的更好的建立分类问题模型。我们知道对于这个问题有10类别,因此我们期望二维矩阵的宽度为10。
# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
让我把从定义简单CNN模型为基准模型并评估在这个问题上表现如何上开始。我们将使用具有两个卷积层的结构,紧跟着最大池化并和网络扁平化到完全连接的层再到进行预测。我们基准模型结果如下:
- 卷积层,32个3×3大小的特征图,整流器激活函数权重约束最大范式设为3。
- Dropout 设置为20%。
- 卷积层,32个3×3大小的特征图,整流器激活函数权重约束最大范式设为3。
- 最大池化从大小为2×2。
- 扁平层
- 有512个单元和整流器激活函数的全连接层。
- Dropout设置为50%。
- 拥有10个单元和softmax激活函数的全连接层。
对数损失函数与配置有大动量和权重衰减的随机梯度下降优化算法一起使用,开始学习速率为0.01。 下面提供了网络结构的可视化
# Create the model
model = Sequential()
model.add(Convolution2D(32, 3, 3, input_shape=(3, 32, 32), border_mode="same",
activation="relu", W_constraint=max_norm(3)))
model.add(Dropout(0.2))
model.add(Convolution2D(32, 3, 3, activation="relu", border_mode="same",
W_constraint=max_norm(3)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(512, activation="relu", W_constraint=max_norm(3)))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation="softmax"))
# Compile mode
epochs = 25
lrate = 0.01
decay = lrate / epochs
sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False)
model.compile(loss="categorical_crossentropy", optimizer=sgd, metrics=["accuracy"])
print(model.summary())
我用25个迭代周期和32个批处理拟合这个模型。选择一个小点迭代周期有助于这个教程持续进行。正常来说,迭代周期数量是大于整个问题一个或者二个数量级。一旦模型拟合了,我们在测试集上评估它并打印出分类结果。
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test),epochs=epochs,batch_size=32, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1] * 100))
为了完整性,下面提供的完整代码。
# Simple CNN model for CIFAR-10
import numpy
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.layers import Convolution2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.python.keras.utils import np_utils
from tensorflow.keras import backend as K
K.set_image_dim_ordering("th")
# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load data
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
# normalize inputs from 0-255 to 0.0-1.0
X_train = X_train.astype("float32")
X_test = X_test.astype("float32")
X_train = X_train / 255.0
X_test = X_test / 255.0
# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
# Create the model
model = Sequential()
model.add(Convolution2D(32, 3, 3, input_shape=(3, 32, 32), border_mode="same",
activation="relu", W_constraint=max_norm(3)))
model.add(Dropout(0.2))
model.add(Convolution2D(32, 3, 3, activation="relu",border_mode="same",W_constraint=max_norm(3)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(512, activation="relu", W_constraint=max_norm(3)))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation="softmax"))
# Compile mode
epochs = 25
lrate = 0.01
decay = lrate / epochs
sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False)
model.compile(loss="categorical_crossentropy", optimizer=sgd, metrics=["accuracy"])
print(model.summary())
# Fit the model
model.fit(X_train,
y_train,
validation_data=(X_test, y_test),
epochs=epochs,
batch_size=32,
verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1] * 100))
在每次训练集和测试集上,每次迭代会打印出分类精度和损失。模型在测试集上评估并获得69.9%精度,它已经不错了,但是不算优秀。
...
Epoch 20/25
50000/50000 [==============================] - 143s - loss: 0.2858 - acc: 0.9011 -val_loss: 1.0091 - val_acc: 0.7063
Epoch 21/25
50000/50000 [==============================] - 143s - loss: 0.2693 - acc: 0.9067 - val_loss: 1.0122 - val_acc: 0.7069
Epoch 22/25
50000/50000 [==============================] - 143s - loss: 0.2544 - acc: 0.9119 -val_loss: 1.0240 - val_acc: 0.7097
Epoch 23/25
50000/50000 [==============================] - 143s - loss: 0.2399 - acc: 0.9168 - val_loss: 1.0680 - val_acc: 0.7077
Epoch 24/25
50000/50000 [==============================] - 143s - loss: 0.2285 - acc: 0.9197 -val_loss: 1.0702 - val_acc: 0.7119
Epoch 25/25
50000/50000 [==============================] - 143s - loss: 0.2177 - acc: 0.9238 - val_loss: 1.0686 - val_acc: 0.7085
Accuracy: 70.85%
我们能通过创建更深网络来显著提高精度。这个是下一节要学习的。
16.4 CIFAR-10的更大CNN
我们已经看到,简单CNN在复杂问题上差的表现。在本节中,我们将研究扩大模型的规模和复杂性。我们针对上面简单CNN设计一个更深的版本。我们通过更多特征图引入新的卷积层。我们将使用卷积层,池化层,卷积层和最大化采样层的相同模式。
这个模式将使用32,64,128个特征图重复3次。这是越来越小的特征图不断增加的结果。最后,一个新的且更大的Dense层在网络输出端使用,以尝试把更多特征图更好转成类值。
我们总结了新网络结果如下:
- 卷积输入层,有32×32大小的特征图和整流器激活函数。
- dropout为20%。
- 卷积层,有32×32大小的特征图和整流器激活函数。
- 大小为2×2的最大池化层。
- 卷积层,有64×64大小的特征图和整流器激活函数。
- dropout为20%。
- 卷积层,有64×64大小的特征图和整流器激活函数。
- 大小为2×2的最大池化层。
- 卷积层,有128×128大小的特征图和整流器激活函数。
- dropout为20%。
- 卷积层,有128×128大小的特征图和整流器激活函数。
- 大小为2×2的最大池化层。
- 扁平化层
- dropout为20%。
- 有1024单元和整流器激活函数的全连接层
- dropout为20%。
- 有512单元和整流器激活函数的全连接层
- dropout为20%
- 有10单元和softmax激活函数的全连接层
这是一个大点的网络,展示起来有点笨重。我们使用上面同样流程和同样的迭代周期但更大点批处理大小64-通过更小的实验发现-进行拟合和评估这个模型。
# Large CNN model for the CIFAR-10 Dataset
import numpy
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.constraints import max_norm
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import MaxPool2D
from tensorflow.python.keras.utils import np_utils
from tensorflow.keras import backend as K
K.set_image_data_format("th")
#fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)
# load data
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
# normalize inputs from 0-255 to 0.0-1.0
X_train = X_train.astype("float32")
X_test = X_test.astype("float32")
X_train = X_train / 255.0
X_test = X_test / 255.0
# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
num_classes = y_test.shape[1]
# Create the model
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), input_shape=(32, 32, 3), activation="relu",padding="same"))
model.add(Dropout(0.2))
model.add(Conv2D(32, kernel_size=(3, 3), activation="relu", padding="same"))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Conv2D(64, kernel_size=(3, 3), activation="relu", padding="same"))
model.add(Dropout(0.2))
model.add(Conv2D(64, kernel_size=(3, 3), activation="relu", padding="same"))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Conv2D(128, kernel_size=(3, 3), activation="relu", padding="same"))
model.add(Dropout(0.2))
model.add(Conv2D(128, kernel_size=(3, 3), activation="relu", padding="same"))
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dropout(0.2))
model.add(Dense(1024, activation="relu", kernel_constraint=max_norm(3)))
model.add(Dropout(0.2))
model.add(Dense(512, activation="relu", kernel_constraint=max_norm(3)))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation="softmax"))
# Compile model
epochs = 25
lrate = 0.01
decay = lrate / epochs
sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False)
model.compile(loss="categorical_crossentropy", optimizer=sgd, metrics=["accuracy"])
print(model.summary())
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs,batch_size=64)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1] * 100))
在训练集和测试集上运行这个例子每次迭代会打印出分类精度和损失。对于最终的模型分类精度估计是78.77%,要比简单模型要好接近10个点。
# 50000/50000 val_loss: [==============================] - 34s - loss: 0.4993 - acc: 0.8230 - 0.5994 - val_acc: 0.7932
# Epoch 20/25
# 50000/50000 val_loss: [==============================] - 34s - loss: 0.4877 - acc: 0.8271 - 0.5986 - val_acc: 0.7932
# Epoch 21/25
# 50000/50000 val_loss: [==============================] - 34s - loss: 0.4714 - acc: 0.8327 - 0.5916 - val_acc: 0.7959
# Epoch 22/25
# 50000/50000 val_loss: [==============================] - 34s - loss: 0.4603 - acc: 0.8376 - 0.5954 - val_acc: 0.8003
# Epoch 23/25
# 50000/50000 val_loss: [==============================] - 34s - loss: 0.4454 - acc: 0.8410 - 0.5742 - val_acc: 0.8024
# Epoch 24/25
# 50000/50000 val_loss: [==============================] - 34s - loss: 0.4332 - acc: 0.8468 - 0.5829 - val_acc: 0.8027
# Epoch 25/25
# 50000/50000 val_loss:[==============================] - 34s - loss: 0.4217 - acc: 0.8498 - 0.5785 - val_acc: 0.8018
# Accuracy: 80.18%
16.5 改善模型扩展
我们在这个非常困难的问题上获得不错的结果,但是仍然有一些好方法获得世界级分类结果。下面一些想法你可以在你的模型上扩展并提高你模型性能。
- 更多的训练周期 每个模型都训练一个较小的迭代周期25。训练大规模卷积神经网络一般需要上百或者上千迭代周期。我期望随着迭代周期数量增加性能也有显著的提高。
- 图片数据增强 图片中对象位置变化的。另外一个改善模型性能可能是使用数据增强技术。如变化,随机移位,水平翻转方法可能有用。
- 更深的网络拓扑结构 已提出的更大网络是深度学习网络,但是它是针对这个问题而设计的。这涉及到更多贴近输入端的特征图,而且可能进行更少的池化
另外,已经证明有用的标准卷积神经网络可能在这个问题进行被采用和评估。
在这个问题上你获得什么精度呢?
16.6 总结
在这节课,你已经学习如何创建一个深度学习模型用于图像对象检测。完成这个课程学习之后,你已经学到:
- 关于CIFAR-10数据集和如何在Keras中加载它并从数据集中绘制示例。
- 如何在这个问题上训练和评估一个简单的神经网络模型。
- 如何把一个简单卷积神经网络模型扩展为深度卷积神经网络模型,是为了在难题上提升性能。
- 如何在棘手的对象识别问题上使用数据增强技术来获得进一步性能提升。
16.6.6 接下来
CIFAR-10提出了一个困难的挑战并且你现在知道如何开发一个更大的卷积神经网络模型。这种类型网络的一个聪明之处在于,它们可以用于学习其他领域(例如单词序列)中的空间结构。在下一章中,您将研究将一维卷积神经网络应用于情感分类的自然语言处理问题。