keras教程:卷积神经网络(CNNs)终极入门指南

2018-06-21 12:09:57 浏览数 (1)

本篇教程将会手把手教你使用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时代生存下去的资本。

长按上方二维码,关注我们

0 人点赞