本文来源于EliteDataScience网站,原文地址在这儿。
在这个循序渐进的Keras教程中,您将学习如何使用Python构建卷积神经网络。
我们将训练一个手写数字识别分类器,其在著名的MNIST数据集上将具有超过99%的准确率。
指南适用于对应用深度学习感兴趣的初学者。
我们的目标是向您介绍Python中构建神经网络的最流行、最强大的库之一。 本教程中我们将忽略大部分理论和数学知识,当然我们也会指出学习获取这些知识所需的资源。
开始之前
为什么是Keras
Keras是我们建议使用Python语言来学习深度学习使用的库,对初学者来说尤其适用。其简约的模块化方法使得深度神经网络的启动和运行变得轻而易举。你可以在下面的网址了解更多:
- The Keras library for deep learning in Python
什么是深度学习
深度学习是指具有多个隐藏层的神经网络,其可以在输入数据学习抽象知识。 这个概念虽然过于简化,但它现在对我们来说是一个实用的定义。
例如,深度学习已经使计算机视觉的重大进步。 我们现在可以对图像分类,在其中查找对象,甚至标记它们。 为了做到这些,具有许多隐藏层的深度神经网络可以从原始输入图像中渐进地学习更复杂的特征:
- 第一个隐藏层可能只学习局部边缘模式。
- 然后,每个后续层(或过滤器)学习更复杂的表示。
- 最后,最后一层可以将图像分类为猫或袋鼠。
这些类型的深度神经网络称为卷积神经网络。
什么是卷积神经网络
简而言之,卷积神经网络(CNN)是多层神经网络(有时多达17层或更多层),它们将输入数据假设为图像。
典型CNN框架
通过以上需求,CNN可以大幅减少需要调整的参数数量。 因此,CNN可以有效地处理原始图像的高维度。
它们的运行机制超出了本教程的范围,但您可以在此处阅读更多相关内容。
本教程不是
这不是深度学习的完整课程。 相反,本教程旨在帮助您从零开始完成第一个卷积神经网络项目。
如果您对掌握深度学习背后的理论感兴趣,我们建议您从Stanfor学习这门课程:
- CS231n: 用于视觉识别的卷积神经网络
小提示
我们试图尽可能简化本教程,这意味着我们不会对任何一个主题进行太多细节处理。 如果您想了解有关功能或模块的更多信息,请在您旁边打开Keras文档。
Keras 教程内容
以下是完成您的第一个CNN项目所需的步骤:
- 设置环境并安装所需包
- 导入模块和库
- 从MNIST加载图像数据
- 预处理数据
- 预处理分类
- 定义模型
- 编译模型
- 训练模型
- 评估模型
步骤一:设置环境并安装所需包
我们假设您使用ubuntu系统,本教程需要以下安装:
- Python3
- Numpy
- Matplotlib
- TensorFlow (Keras依赖)
- Keras
首先设置虚拟环境:
代码语言:javascript复制python3 -m venv .env
source .env/bin/activate
安装所需包:
代码语言:javascript复制pip3 install numpy matplotlib tensorflow keras
如果你像我一样喜欢用jupyter:
代码语言:javascript复制pip3 install jupyter
最后启动jupyter,进入浏览器:
代码语言:javascript复制jupyter notebook
步骤二: 导入模块和库
让我们首先导入numpy并为计算机的伪随机数生成器设置种子。 这允许我们从我们的脚本中重现结果:
代码语言:javascript复制import numpy as np
np.random.seed(123)
接下来,我们将从Keras导入Sequential模型。 这只是神经网络层的一个线性堆栈,它非常适合我们在本教程中构建的前馈CNN类型。
代码语言:javascript复制from keras.models import Sequential # Keras model module
接下来,让我们从Keras导入“核心”层。 这些是几乎在任何神经网络中使用的层:
代码语言:javascript复制from keras.layers import Dense, Dropout, Activation, Flatten
然后,我们将从Keras导入CNN层。 这些卷积层,可以帮助我们有效地训练图像数据:
代码语言:javascript复制from keras.layers import Convolution2D, MaxPooling2D
最后,我们将导入一些实用程序。 这有助于我们转换数据:
代码语言:javascript复制from keras.utils import np_utils
现在我们有了构建神经网络架构所需的一切。
第三步:从MNIST加载图像数据
MNIST是深度学习和计算机视觉入门的理想数据集。它的数据集足可以训练神经网络,但它可以在一台计算机上进行管理。 我们在帖子中更多地讨论它:8个有趣的初学者机器学习项目。
Keras库中已经体贴地包含了这些数据,我们可以这样加载:
代码语言:javascript复制from keras.datasets import mnist
# load pre-shuffled MNIST data into train and test sets
(X_train, y_train), (X_test, y_test) = mnist.load_data()
如果以上操作加载速度很慢,你也可以首先下载这个文件到本地,然后:
代码语言:javascript复制import gzip
import pickle
import sys
f = gzip.open('mnist.pkl.gz','rb')
if sys.version_info < (3,):
data = pickle.load(f)
else:
data = pickle.load(f, encoding='bytes')
f.close()
(X_train, y_train), (X_test, y_test) = data
看看训练集的维度:
代码语言:javascript复制print(X_train.shape)
# (60000, 28, 28)
太棒了,我们的训练集中有60,000个样本,图像分别为28像素×28像素。 我们可以通过在matplotlib中绘制第一个样本来确认这一点:
代码语言:javascript复制from matplotlib import pyplot as plt
plt.imshow(X_train[0])
# <matplotlib.image.AxesImage at 0x7fcc6ee9fd3
输出:
通常,使用计算机视觉时,在进行任何算法工作之前,以可视方式绘制数据是非常有帮助。这是个快速的健全性检查,可以防止容易避免的错误(例如误解数据维度)。
第四步:预处理数据
使用Theano后端时,必须显式声明输入图像深度的尺寸。 例如,具有所有3个RGB通道的全色图像的深度为3。
我们的MNIST图像的深度为1,但我们必须明确声明。
换句话说,我们希望将数据集从形状(n,width,height)转换为(n,depth,width,height)。
通过以下代码来实现:
代码语言:javascript复制X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
print(X_train.shape)
# (60000, 1, 28, 28)
输入数据的最终预处理步骤是将我们的数据类型转换为float32,并将我们的数据值标准化为范围[0,1]。
代码语言:javascript复制# 转换数据类型,规范化数据
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
现在,我们的输入数据已准备好了。
第五步:预处理分类
接下来,我们看看我们的类标签数据的形状:
代码语言:javascript复制print(y_train.shape)
# (60000,)
有点问题。我们应该有10个不同的类,每个数字一个,但看起来我们只有一维数组。 我们来看看前10个训练样本的标签:
代码语言:javascript复制print(y_train[:10])
# [5 0 4 1 9 2 1 3 1 4]
这正是问题所在。 y_train和y_test数据不会拆分为10个不同的类标签,而是表示为具有类值的单个数组。
我们可以轻松解决这个问题:
代码语言:javascript复制# 将一维的分类据站转换为十维分类矩阵
Y_train = np_utils.to_categorical(y_train, 10)
Y_test = np_utils.to_categorical(y_test,10)
print(Y_train.shape)
# (60000, 10)
第六步:定义模型
现在我们已经准备好定义我们的模型架构了。 在实际的研发工作中,研究人员将花费大量时间研究模型架构。
为了使本教程继续进行,我们不打算在这里讨论理论或数学。 仅这一点就是一个内容复杂的领域,我们推荐前面提到的CS231n课程,供那些想要了解更多知识的人使用。
此外,当您刚刚开始时,您可以从学术论文中复制经过验证的架构或使用现有示例。 这里是Keras中的示例实现列表。
让我们首先声明一个顺序模型:
代码语言:javascript复制model = Sequential()
接下来,我们声明输入层:
代码语言:javascript复制model.add(Convolution2D(32, (3, 3), activation='relu', input_shape=(1,28,28), data_format='channels_first'))
输入形状参数应为1个样本的形状。 在这种情况下,它与每个数字图像的(深度,宽度,高度)相对应(1,28,28)。
但前3个参数代表什么? 它们分别对应于要使用的卷积滤波器的数量,每个卷积内核中的行数以及每个卷积内核中的列数。
*注意:默认情况下,步长为(1,1),可以使用'subsample'参数进行调整。
我们可以通过打印当前模型输出的形状来确认:
代码语言:javascript复制print(model.output_shape)
# (None, 32, 26, 26)
接下来,我们为我们的模型添加更多层,就像我们正在构建legos:
代码语言:javascript复制model.add(Convolution2D(32,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
同样,我们不会过多地讨论理论,但有必要对我们刚刚添加的Dropout层稍作说明。这是一种使我们的模型正规化以防止过度拟合的方法。 你可以在这里读到更多关于它的内容。
MaxPooling2D是一种通过在前一层上滑动2x2池滤波器并在2x2滤波器中取4个值中的最大值来减少模型中参数数量的方法。
到目前为止,对于模型参数,我们添加了两个Convolution层。 要完成我们的模型架构,让我们添加一个完全连接的层,然后添加输出层:
代码语言:javascript复制# add full connected layer and then the output layer
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
对于Dense图层,第一个参数是图层的输出大小。 Keras自动处理层之间的连接。
请注意,最后一层的输出大小为10,对应于10个数字类。
另请注意,卷积层的权重必须在将它们传递到完全连接的Dense层之前展平(制作为1维)。
现在我们需要做的就是定义损失函数和优化器,然后我们就可以开始训练它了。
第七步:编译模型
最困难的部分已经结束了。
我们只需要编译模型,就可以开始训练了。 当我们编译模型时,我们声明了损失函数和优化器(SGD,Adam等)。
代码语言:javascript复制# compile model
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
Keras具有各种损失函数和开箱即用的优化器可供选择。
第八步:训练模型
为了适应模型,我们所要做的就是声明要训练的批量大小和时期数,然后传入我们的训练数据。
代码语言:javascript复制# fit model on training data
model.fit(X_train, Y_train,
batch_size=32, nb_epoch=10, verbose=1)
# Epoch 1/10
# 60000/60000 [==============================] - 187s 3ms/step - loss: 0.3342 - acc: 0.8960
# Epoch 2/10
# 60000/60000 [==============================] - 195s 3ms/step - loss: 0.1292 - acc: 0.9623
# Epoch 3/10
# 60000/60000 [==============================] - 205s 3ms/step - loss: 0.0934 - acc: 0.9721
# Epoch 4/10
# 60000/60000 [==============================] - 182s 3ms/step - loss: 0.0790 - acc: 0.9768
# Epoch 5/10
# 60000/60000 [==============================] - 193s 3ms/step - loss: 0.0713 - acc: 0.9790
# Epoch 6/10
# 60000/60000 [==============================] - 186s 3ms/step - loss: 0.0642 - acc: 0.9807
# Epoch 7/10
# 60000/60000 [==============================] - 179s 3ms/step - loss: 0.0579 - acc: 0.9829
# Epoch 8/10
# 60000/60000 [==============================] - 178s 3ms/step - loss: 0.0530 - acc: 0.9844
# Epoch 9/10
# 60000/60000 [==============================] - 169s 3ms/step - loss: 0.0508 - acc: 0.9849
# Epoch 10/10
# 60000/60000 [==============================] - 169s 3ms/step - loss: 0.0476 - acc: 0.9854
# <keras.callbacks.History at 0x7fcc6c3834a8>
容易,对吧?
您还可以使用各种回调来设置早期停止规则,保存模型权重,或记录每个训练时期的历史记录。
第九步:评估模型
最后,我们可以在测试数据上评估我们的模型:
代码语言:javascript复制score = model.evaluate(X_test, Y_test, verbose=0)
恭喜......你已经完成了这个Keras教程!
你刚刚完成了Keras核心功能的旋风之旅,但我们只是触及了表面。 希望您已经得到进一步探索Keras所提供的所有知识的兴趣。
我们建议您在Keras的其他示例模型和斯坦福大学的计算机视觉课程中继续学习。