从机器学习到无人驾驶
上QQ阅读APP看书,第一时间看更新

2.3 Hello TensorFlow—一个简单的例子

我们已经安装了TensorFlow的开发环境,接下来通过简单的例子来说明如何利用TensorFlow来进行机器学习应用开发。首先使用TensorFlow中的高级API—Keras开发一个简单的例子,在这个例子中将训练一个简单的单层神经网络来识别手写数字,使用的训练数据库是大名鼎鼎的MNIST。闲话少叙,我们先来整体看一下实例的实现代码。

代码虽然非常简洁,但是完全包含了整个机器学习的数据准备、模型构建、模型训练和模型应用(评估)的过程。首先import tensorflow as tf引入了TensorFlow机器学习框架,如果要使用TensorFlow进行机器学习,那么这显而易见是必不可少的。接下来就是数据准备的过程,为了更好地说明数据准备过程,我们先来简单介绍数据集合MNIST。MNIST是深度学习的经典入门Demo,它是由60000张训练图片和10000张测试图片构成的,每张图片都是28×28像素大小(见图2.6),而且都是由黑白色构成的(这里的黑色是一个0~1的浮点数,黑色越深,表示数值越靠近1),这些图片是采集的不同的人手写的0~9的数字。TensorFlow将这个数据集和相关操作封装到了库中。

图2.6 MNIST图片

图2.6是4张MNIST图片。这些图片并不是传统意义上的PNG或者JPG格式的,因为PNG或者JPG格式的图片会带有很多干扰信息(如数据块、图片头、图片尾、长度等),这些图片会被处理成很简易的二维数组,如图2.7所示。

图2.7 MNIST图片与二维数组的关系

   mnist = tf.keras.datasets.mnist
   (x_train, y_train),(x_test, y_test) = mnist.load_data()

上述代码是数据读取的过程。tf.Keras将机器学习常用的测试标定数据集合的下载和简单数据处理过程内联设置到Datasets的API中,包括MNIST、Cifar10等。利用数据集合的load_data()方法可以直接下载对应的数据,并且框架为了能够让人工智能的初学者更快上手,在返回值中直接将训练数据和测试数据区分开,通过x_train、y_train、x_test、y_test四个变量一次性保存对应的训练和测试数据的输入和输出值。由于输入值是28×28的灰度像素值矩阵,因此利用

   x_train, x_test = x_train/255.0, x_test/255.0

将这些值缩小到0到1之间,这种手法是在图像识别中经常使用的。

接下来就是模型构建的过程。在进行模型构建之前,我们需要简单介绍Keras和TensorFlow的关系。Keras是一个用Python编写的高级神经网络API,它能够以TensorFlow、CNTK或者Theano作为后端运行。Keras的开发重点是支持快速的实验,能够以最小的时延把你的想法转换为实验结果。最初的TensorFlow是没有直接内嵌Keras的API的,但是由于使用Keras后可以在很大程度上提高开发速度,增加代码的可读性,在应用算法定义阶段受到了很多数据科学家和开发者的欢迎,因此TensorFlow在1.4版本正式增加了tf.keras模块,是TensorFlow对Keras API规范的实现。这是一个用于构建和训练模型的高阶API,包含对TensorFlow特定功能(例如Eager Execution、tf.data管道和Estimator)的顶级支持。tf.keras使TensorFlow更易于使用,并且不会牺牲灵活性和性能。

   model = tf.keras.models.Sequential([
     tf.keras.layers.Flatten(input_shape=(28, 28)),
     tf.keras.layers.Dense(512, activation=tf.nn.relu),
     tf.keras.layers.Dropout(0.2),
     tf.keras.layers.Dense(10, activation=tf.nn.softmax)
   ])

Sequential是Keras的线性模型框架,使用这个框架无论是在函数构造的时候填充函数层(Layers)还是使用add方法进行填充,结果都是函数层保持线性排列,如图2.8所示,而且顺序保持与填充顺序一致。

图2.8 机器学习线性网络示意图

在Sequential传入数组中包含四层,第一层tf.keras.layers.Flatten(input_shape=(28, 28))的功能是将输入的数据拍平,换句话说,就是将二维数据矩阵转换为一维数据矩阵;第二层tf.keras.layers.Dense(512, activation=tf.nn.relu)通过ReLU函数进行数据激活;第三层tf.keras.layers.Dropout(0.2)通过Dropout减少网络活性,防止过拟合;第四层tf.keras.layers.Dense(10, activation=tf.nn.softmax)利用Softmax函数输出最终判定。因为本章主要展示TensorFlow进行机器学习的基础用法,给大家一个比较直观的认知过程,所以具体函数的实现和推导过程会在后续章节中详细分析。

接下来,使用梯度下降的方法进行训练:model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']),compile函数的3个输入值分别设定了梯度下降使用的优化算法、梯度下降的损失函数以及训练过程的监控指标。在本节展示的例子中,我们使用标准ADAM优化算法,使用交叉熵作为损失函数,在例子中会看到网络的预测精确度随着训练而逐步提升,如图2.9所示。

图2.9 HelloTF实例训练结果

model.fit(x_train, y_train, epochs=5)是启动训练的过程,通过这样一个简单的函数调用,利用准备好的数据进行模型训练,找到模型的近似最优解。

model.evaluate(x_test, y_test)最后利用测试数据评估模型的预测精确度,通过测试,模型的预测精确度达到了98%。在Hello TensorFlow代码说明的最后需要补充两点:第一,MNIST模型相对比较简单,其他许多机器学习算法(例如支持向量机)在这个模型上都可以取得不错的预测结果;第二,如果需要将手写数字识别投入实际业务场景中,由于实际业务场景往往和金融、政府服务相关,因此98%的预测精确度可能还不够,但是不用担心,这只是开端,在后续章节中会介绍能力更加强劲的算法,读者可利用后续知识技能改造Hello TensorFlow。