使用Keras的流程如图7-8所示。
图7-8 Keras使用的过程
(1)选择模型
Keras提供序贯式模型和函数式模型两种模型,在以下的例子中将使用序贯式模型。
(2)构建网络层
在以下的例子中使用了卷积网络层和丢弃层(Dropout)。
(3)编译
编译相当于进行搭建,可以使用model.compile( )函数体验其作用。
(4)训练
这是耗费时间的步骤,通过训练计算出所有的网络参数,对应的函数是model.fit( )。
(5)预测
这是使用模型解决问题的步骤。例如,一个用来识别花朵类型的网络,输入花朵图片之后,预测出该花朵的类别。
几乎所有智能手机都支持手写识别,即通过手指或手写笔在屏幕上进行书写,然后识别出所写的字符(图7-9)。下面以手写数字识别为例讲解上述流程并具体实现这个识别任务。
传统计算机视觉方法中,识别手写字体是通过定义特征完成的。例如,某个手写数字带有两个封闭区域,就很可能是8。这样的方法经过不断地特征总结,准确率可以超过90%,这已经达到了可以实际应用的水平。但是当需要识别的类别变得更多的时候,例如,从10个数字增加到3 900个汉字,如果依然通过总结特征进行识别,那么识别率的提升就需要巨大的工作量,也很难提高到可用的程度。
然而通过深度学习,手写识别变成了一项简单的工作。这里的简单是指构建过程简单,但完成这个识别任务的整个工作并不容易,因为深度学习需要做大量的标注训练数据的工作。对手写数字来说,所谓的标注数据,就是通过人工标注各个手写图片到底是什么数字,从而建立图片和数字之间的映射关系(表7-1)。
图7-9 手写数字图片
表7-1 图片标注
在这个案例中,使用的数据集是深度学习经常使用的数据集MINST。这是一个手写数字数据库,包含60 000个训练样本和10 000个测试样本,每个样本图像的宽高为28×28。需要注意的是,此数据集中的图片是以二进制存储的,不能直接以图像格式查看,不过很容易找到将其转换成图像格式的工具。
接下来的代码将引导读者下载数据、构建网络、训练网络。使用的网络是在处理图片数据时非常有效的卷积神经网络。尽管这个案例搭建网络的过程很简单,但是读者可以据此进行更深入地探索。这一节编写代码的方式与前几章稍有不同,可以把它们保存成.py文件后直接运行,其中每一部分的含义已经在相应位置做了详细注释。读者在掌握了基本方法后,还可以尝试对参数进行调整,并观察调整后的识别效果,从而进一步理解这种方法。
from __future__ import print_function
#导入这个模块是增加Python不同版本之间兼容性的一种做法
import keras
#导入keras模块
from keras.datasets import mnist
#导入数据库函数,因为国内访问亚马逊云速度较慢,也可以不用这种方式下
#载数据,而是从教材资源平台下载并读取数据
from keras.models import Sequential
#使用keras的序贯模型
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D
#导入需要使用的网络层,包括稠密层、Dropout层、压平层、二维卷积层、
#池化层
from keras import backend as K
#导入后端
batch_size=128
#控制每个训练批次的数据大小的参数,读者可以调整并观察会产生什么变化
num_classes=10
#分类器类别数量。因为要识别0到9共10个手写数字,所以类别是10
#如果识别手写小写字母,则分类就是26
epochs=12
#训练周期,读者可以调整并观察效果,训练周期越大,训练时间越长
img_rows,img_cols=28,28
#图片的长和宽的像素数
(x_train,y_train),(x_test,y_test)=mnist.load_data(path="D:\\mnist.npz")
#如果方便访问亚马逊云,可以用(x_train,y_train),(x_test,y_test)=
#mnist.load_data( )来自动下载数据。如果已经从教材资源平台将数据下载
#到本地,#假设保存在D盘根目录下,就使用上述命令形式。需要注意的是,
#为了和linux兼容,windows下的路径反斜杠"\"都要写成"\\"另外,
#上述命令将数据分为训练数据和验证数据。无论是训练集还是验证集,都令x
#是输入数据,y是输出数据
if K.image_data_format()=='channels_first':
x_train=x_train.reshape(x_train.shape[0],1,img_rows,img_cols)
x_test=x_test.reshape(x_test.shape[0],1,img_rows,img_cols)
input_shape=(1,img_rows,img_cols)
else:
x_train=x_train.reshape(x_train.shape[0],img_rows,img_cols,1)
x_test=x_test.reshape(x_test.shape[0],img_rows,img_cols,1)
input_shape=(img_rows,img_cols,1)
#因为Theano和TensorFlow定义的图片格式不同,这里针对不同的后台对
#数据进行处理,读者暂且可以不用深究
x_train=x_train.astype('float32')
x_test=x_test.astype('float32')
x_train/=255
x_test/=255
print('x_train shape:',x_train.shape)
print(x_train.shape[0],'train samples')
print(x_test.shape[0],'test samples')
#上述命令给出训练集和测试集的维度,输出如下:
#x_train shape:(60000,28,28,1)
#60000 train samples
#10000 test samples
y_train=keras.utils.to_categorical(y_train,num_classes)
y_test=keras.utils.to_categorical(y_test,num_classes)
#上述命令将训练数据和验证数据的类别转化成keras支持的格式
#通过以下代码构建深度网络,使用2D卷积层,池化层、Dropout层、压平
#层等
model=Sequential()
model.add(Conv2D(32,kernel_size=(3,3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64,(3,3),activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes,activation='softmax'))
#上述深度网络包括两个卷积层,输出如下:
#WARNING:TensorFlow:From C:\Python\WinPython-64bit-3.6.1.0Q
#t5\Python-3.6.1.amd64\lib\site-packages\keras\backend\
#TensorFlow_backend.py:1062:calling reduce_prod(from
#TensorFlow.Python.ops.math_ops)with keep_dims is
#deprecated and will #be removed in a future version.
#Instructions for updating:
#keep_dims is deprecated,use keepdims instead
#这是一条警告命令,版本不同,警告信息可能也不同,提示内容是一些命令可
#能在后续版本中将不予支持
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=['accuracy'])
#使用以上代码进行网络具体搭建
#一般也会输出类似的警告信息
model.fit(x_train,y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test,y_test))
#使用上述代码进行模型训练,训练时长根据配置不同而不同
#训练过程中会给出每次更新网络参数所需的时间、损失、精度等
#因为训练过程有随机因素,所以读者训练的结果也许会有差别,不必纠结
Train on 60000 samples,validate on 10000 samples
Epoch 1/12
60000/60000[==============================]-131s-loss:0.3303-acc:0.8998-val_loss:0.0758-val_acc:0.9766
Epoch 2/12
60000/60000[==============================]-9s-loss:
0.1106-acc:0.9676-val_loss:0.0522-val_acc:0.9825
Epoch 3/12
60000/60000[==============================]-9s-loss:
0.0831-acc:0.9746-val_loss:0.0405-val_acc:0.9870
Epoch 4/12
60000/60000[==============================]-9s-loss:0.0677-acc:0.9798-val_loss:0.0360-val_acc:0.9873
Epoch 5/12
60000/60000[==============================]-9s-loss:0.0595-acc:0.9821-val_loss:0.0353-val_acc:0.9875
Epoch 6/12
60000/60000[==============================]-10s-loss:0.0556-acc:0.9837-val_loss:0.0327-val_acc:0.9891
Epoch 7/12
60000/60000[==============================]-12s-loss:0.0481-acc:0.9855-val_loss:0.0292-val_acc:0.9896
Epoch 8/12
60000/60000[==============================]-14s-loss:0.0453-acc:0.9860-val_loss:0.0299-val_acc:0.9897
Epoch 9/12
60000/60000[==============================]-17s-loss:0.0420-acc:0.9868-val_loss:0.0297-val_acc:0.9899
Epoch 10/12
60000/60000[==============================]-17s-loss:0.0395-acc:0.9878-val_loss:0.0289-val_acc:0.9904
Epoch 11/12
60000/60000[==============================]-17s-loss:0.0376-acc:0.9885-val_loss:0.0278-val_acc:0.9914
Epoch 12/12
60000/60000[==============================]-15s-loss:0.0357-acc:0.9885-val_loss:0.0268-val_acc:0.9909
#训练结果如下。同样,不同的配置和训练过程会导致总损失不同
#读者实践过程中获得的数值一般不会与教材的示例完全一致
score=model.evaluate(x_test,y_test,verbose=0)
print('Test loss:',score[0])
#使用总损失对模型进行评估,即评估该模型的效果,通过总损失表示
在本教材使用的计算机上,该训练样本的损失如下。
Test loss:0.0268492490485