本篇教程将会手把手教你使用keras搭建卷积神经网络(CNNs)。为了使你能够更快地搭建属于自己的模型,这里并不涉及有关CNNs的原理及数学公式,感兴趣的同学可以查阅《吊炸天的CNNs,这是我见过最详尽的图解!》
写在程序之前:
为了学习得更快,一些背景知识需要你了解
• 最常见的CNNs架构
上述模式,是一个最为常见的卷积网络架构模式。
如果上述链条理解起来比较吃力,你可以到这里恶补下基础知识。我们后面的代码,都是遵循上述模式来编写的。
• MNIST 数据集
在MNIST数据集中,包含着70,000个从0~9的手写体数字。每个图像的大小都是28*28,这里列举几张灰度图:
在本教程中,我们的训练样本,就来自于MNIST数据集,它是初学者入门图像识别时,最好用、最便捷的数据集。
数据的加载方法,我会在下文中详细讲解,此处你只需要了解,我们的数据源自MNIST就可以了。
• 本教程使用的是
Python 3.5.2, Theano 0.8.2
下面,我们就开始正式的课程。
使用Keras建立你的第一个CNNs模型的具体步骤:
1. 导入库和模块
2. 从MNIST加载图像数据
3. 预处理图像数据
4. 预处理分类标签
5. 定义模型架构
6. 编译模型
7. 训练模型
8. 评估模型
第一步:导入库和模块
导入numpy。numpy可用于进行数组运算。
接下来,我们从Keras中导入Sequential,它是多个网络层的线性堆叠。
简单来说,假设Sequential像一个书柜,每本书都是一个“网络层”,只要有了“书柜”,你就可以把“书”一本本的堆叠上去。
之后,依次导入
卷积层 Convolution2D
池化层 MaxPooling2D
激活层 Activation
展开层 Flatten
全连接层 Dense
Dropout层
这些“网络层”,相当于上面书架中的“图书”。将这些“网络层”堆叠起来,就构成了文章开篇所提到的“最常见的CNNs架构”模式。
最后,我们从Keras导入np_utils,它能帮助我们将数据形态转换为我们想要的样子。
第二步:从MNIST加载图像数据
通过print,我们能够看到数据集的形态:
X_train是一个含有60,000个训练样本的数据集,并且,每一个样本图像的尺寸都是28*28,例如,第1个训练样本为:
看样子,上面的数字有可能是3,有可能是5。但是不管怎样,我们已经清楚地看到,X_train中的每一个样本,都是一张28*28的手写数字图。
接下来,我们再来看看y_train:
y_train是60,000个训练样本的标签,例如,第1个训练样本的标签为“5”:
好吧,原来上面那张歪歪扭扭的数字,不是3……
使用同样的方法,我们还可以查看测试集的数据形态,在这里,我们有10,000个测试样本:
温馨提示:
无论是训练集,还是测试集,这里y的形态,都与X的不太一样
例如,
X_train.shape=(60000, 28, 28)
而 y_train.shape=(60000, )
后面我们会将它们的形态进行调整,使它们保持一致,并符合图像识别的格式要求。
第三步:预处理图像数据
在CNNs中,图像不仅有“宽度”和“高度”,而且还有深度。
对于彩色图片,图像的深度为3,即有“红R,绿G,蓝B”3个通道;
对于像MNIST这样的灰度图片,其图像深度仅为1:
(点击图片,查看大图)
所以,我们数据集的形态,应该从
(样本数量, 图片宽度, 图片高度)
转换为
(样本数量, 图片深度, 图片宽度, 图片高度)
实现这一转换的方式很简单:
为了确保我们的确已经将格式转换过来了,再次打印X_train.shape查看:
OK,(样本数量, 图片深度, 图片宽度, 图片高度)我们已全都具备。
预处理的最后一步,是将我们输入的数据,转换为float32类型,并且,将数值范围从[0, 255]标准化到[0, 1]范围内:
第四步:预处理分类标签
在第二步的时候,我们已经提到了,分类标签y的数据形态,似乎与图像X的有些不同。
实际上,我们有“0~9”一共十个不同的类标签。
我们期待看到这样的格式:
如果分类标签为“5”,那么,
如果分类标签为“9”,那么,
以此类推……
但是,我们现在的y值,一上来就是
0,1,2, …… , 9
因此,我们需要对其进行转换:
转换后的结果,我们来看一下:
还记得我们将X_train形态转换后,得到的样子吗?
X_train.shape=(60000, 1, 28, 28)
表示“有60,000个样本,每个样本的维度为(1*28*28)”
这里,经过转换后的Y_train的形态为
Y_train.shape=(60000, 10)
表示“有60,000个样本,每个样本的维度为10”
请记住上面的数据形态,只有当我们输入数据(X,Y)符合上述形态时,代码才会正常运行。
第五步:定义模型架构
经过前四步,我们已经把所有的准备工作都做好了。现在,我们开始定义模型。
回忆我们在开篇提到的“CNNs架构”
再次祭上这张神图……
“定义模型架构”,意味着我们要确定图中“若干次”的具体次数。
在本例中,我们将使用这样的架构:
当然,“若干次”的具体次数该如何来设定,并没有硬性的规定。
你可以尝试构建不同的模式,并从中选择一个预测准确度最高的模型来使用。
我们在这里使用了“2次 - 1次 - 2次”的结构。
好啦,废话不多说,直接上代码。
先搭一个“书架”:
再往“model”中,添加各层。
添加第1个“卷积 → ReLU”:
过滤器的作用是提取图片的特征,通常情况下,过滤器的个数由你自己来决定,这里设置了32个过滤器。
过滤器的大小,你可以设置为3*3,也可以设置为5*5,都是较为常用的尺寸。
经过第1个“卷积 → ReLU”的处理,我们来看看得到了什么:
输出的结果是,大小为26*26,一共32张图片。
为什么是32张图片?
这32张图片长得什么样子?
为什么图片大小比输入时变小了?
想要了解具体原理的同学,可以参考这里。
接下来,我们再添加第2个“卷积 → ReLU”:
然后是“池化层”:
池化层的作用是将图片缩小。
举个例子:
经过上面第2个“卷积 → ReLU”的处理后,输出结果的形态为
(None, 32, 24, 24)
表示“有32张24*24大小的图片”。
经过“最大池化”的处理后,得到的是
(None, 32, 12, 12)
表示“有32张12*12大小的图片”,
可以看到,图片的宽、高都缩小了一半。
最后,我们来添加2个全连接层:
(点击图片,查看大图)
第六步:编译模型
刚刚的第五步,我们只是搭起了一个模型的架子,而现在我们需要做的工作是,让模型能够跑起来。
第七步:训练模型
好啦,构建CNNs,所有最难的部分都已经过去了。
下面,我们就要把数据“喂给”模型,让它开始为我们干活儿了!
你的屏幕会显示这么一大堆东西:
(点击图片,查看大图)
第八步:评估模型
还记得我们在最初加载MNIST数据时,其中含有10,000个测试样本吗?
在代码的最后,我们可以充分利用这10,000个测试样本,来评估我们构建的模型其预测效果:
输出结果为:
预测准确度高达0.989。
恭喜你!现在,你已经会用keras做图像分类了~~
如果在本文中,有任何疑问,可以关注微信公众号:AI传送门,留言给我们,我们会定期为同学进行答疑。
长按上方二维码,关注我们
下面附上全部代码:
(可左右滑动此代码)
代码语言:javascript复制
import numpy as np
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Flatten, Dense, Dropout
from keras.utils import np_utils
from keras.datasets import mnist
# 加载MNIST数据集,其中包含60,000个训练样本、10,000个测试样本
(X_train, y_train), (X_test, y_test) = mnist.load_data()
# 调整加载数据的形态
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train /= 255
X_test /= 255
Y_train = np_utils.to_categorical(y_train, 10)
Y_test = np_utils.to_categorical(y_test, 10)
model = Sequential()
# 添加第一个卷积层,其中,超参数32,3,3分别表示“过滤器的个数、过滤器的宽、过滤器的高”
# input_shape = (1, 28, 28)表示“输入图片的深度为1,宽度为28,高度为28”
model.add(Convolution2D(32, 3, 3, input_shape=(1, 28, 28)))
# 添加激活层(ReLU)
model.add(Activation('relu'))
# 添加第二个卷积层
# 除第1层卷积外,其余各层卷积均不再需要输入input_shape,算法会自动识别其形态
model.add(Convolution2D(32, 3, 3))
# 添加激活层(ReLU)
model.add(Activation('relu'))
# 添加池化层
model.add(MaxPooling2D(pool_size=(2, 2)))
# 添加展开层,因为,在“全连接层”之前,需要先将图片的像素值展开
model.add(Flatten())
# 添加第1个全连接层
# “128”表示神经元的个数,可以设置为任意数值
model.add(Dense(128, activation='relu'))
# 添加dropout层,防止过拟合
model.add(Dropout(0.5))
# 添加第2个全连接层
# “10”表示神经元的个数,但是由于本层为CNNs架构的最后一层(即“输出层”),
# 所以,此处的数值只能为“10”,对应“0-9”个数字分类
# “softmax”是非线性函数,输出的结果为“最初输入的图片,属于每种类别的概率”
model.add(Dense(10, activation='softmax'))
# 编译模型
# 告诉模型,我们的目标是要使得“误差损失:categorical_crossentropy”尽可能小
# 为了实现这一“目标”,所使用的优化方法是:adam
# 使用“准确率:accuracy”来评估模型的预测效果
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# 训练模型
# batch_size=32 表示一批处理32个样本
# nb_epoch=10 表示10个周期,每个周期都把全部60,000个样本遍历一遍
# validation_split=0.3 表示从训练样本中拿出30%作为交叉验证集
model.fit(X_train, Y_train,
batch_size=32, nb_epoch=10, validation_split=0.3)
# 评估模型
score = model.evaluate(X_test, Y_test)
print(score)
关于AI传送门
AI传送门是国内一家最易学习的AI平台。在这里:
● 国外课程一点即播——省去访问外国网站找资料的时间;
● 英语资料全中文呈现——降低学习门槛;
● 数学公式直观化展示——以鲜明的色彩加以标注,将天书般的公式,拆解成更易理解的小运算,只要你的语文理解没有问题,那么数学的理解,也将不是问题。
你需要做的:
每周拿出1-2天时间,学习平台上的新内容,记住,能学多少学多少,不要勉强自己;
放下对英语的顾虑、对数学的恐惧——这些,都交给我们。
慢慢地积累,你会发现:
在这个平台上,你能看懂的东西越来越多,不明白的内容越来越少;直到有一天,你已不再需要我们,届时,你将拥有在AI时代生存下去的资本。
长按上方二维码,关注我们