轻松体验TensorFlow 第一个神经网络:基本分类(Part 1)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了轻松体验TensorFlow 第一个神经网络:基本分类(Part 1)相关的知识,希望对你有一定的参考价值。

参考技术A

关于 Jupyter Notebook 的使用,可以参考如下链接,有详细的步骤和截图:

Jupyter Notebook神器-免费体验来自微软的Azure Notebook

基于Jupyter Notebook 快速体验Python和plot()绘图方法

基于Jupyter Notebook 快速体验matplotlib.pyplot模块中绘图方法

TensorFlow 基本分类(basic classification)演示的完整代码,可以访问:

上述命令运行时间较长,请耐心等待。

pip list 命令用来查看当前环境下的Python 包,grep 命令用来查找和筛选。中间的竖线表示 pipe(管道),将pip list 命令的输出作为 grep 命令的输入。

pip 前面的感叹号是cell 中运行 Linux 命令的方式,在命令行中运行则不需要加感叹号。

上述命令的输出,表示当前环境已经安装好了 TensorFlow 包。如果没有安装,可以通过如下命令安装:

安装TensorFlow命令,说明如下:

本地安装TensorFlow,截图如下。

TensorFlow 安装完成:

下面训练了一个神经网络模型,来对服装图像进行分类,例如运动鞋和衬衫。需要使用tf.keras,这是一个用于在TensorFlow 中构建和训练模型的高级API。

下面使用Fashion MNIST 数据集,其中包含了10个类别中共70,000张灰度图像。图像包含了低分辨率(28 x 28像素)的单个服装物品,图片链接如下所示:

Fashion-MNIST是一个替代MNIST手写数字集的图像数据集。 它是由Zalando(一家德国的 时尚 科技 公司)旗下的研究部门提供。其涵盖了来自10种类别的共7万个不同商品的正面图片。Fashion-MNIST的大小、格式和训练集/测试集划分与原始的MNIST完全一致。60000/10000的训练测试数据划分,28x28的灰度图片。可以直接用它来测试你的机器学习和深度学习算法性能,且不需要改动任何的代码。

MNIST是 Mixed National Institute of Standards and Technology database 的简写。

下面使用60,000张图像来训练网络和10,000张图像来评估网络模型学习图像分类任务的准确程度。

可以直接从TensorFlow 使用Fashion MNIST,只需导入并加载数据。

加载数据集并返回四个NumPy数组:

图像是28x28 NumPy数组,像素值介于0到255之间。labels是一个整数数组,数值介于0到9之间。

下面是图像类别和标签的对应关系:

每个图像都映射到一个标签。由于类别名称不包含在数据集中,因此把他们存储在这里以便在绘制图像时使用:

以下显示训练集中有60,000个图像,每个图像表示为28 x 28像素:

训练集中有 60000个标签,并且每个标签都是0-9 之间的整数。

测试集和训练集类似,有10000个图像和对应的10000个图像标签。

在训练网络之前必须对数据进行预处理。 如果检查训练集中的第一个图像,将看到像素值落在0到255的范围内:

代码说明:

plt.figure() 创建一个新的figure。

plt.colorbar() 方法用来显示当前image 的颜色方案。

在发送到神经网络模型之前,我们将这些值缩放到0到1的范围(归一化处理)。为此,我们将像素值值除以255。重要的是,对训练集和测试集要以相同的方式进行预处理:

显示训练集中的前25个图像,并在每个图像下方显示类别名。验证数据格式是否正确,我们是否已准备好构建和训练网络。

代码说明:

plt.xticks([])和plt.yticks([]) - 以空list 作为xticks() 方法的参数,查看数据集中图像隐藏坐标轴。

plt.xlabel() 方法可以在 x 轴的下方显示指定文本。

plt.subplot(5,5,1) 方法 - 表示5行5列共25个位置,最后一个参数1 表示Axes的位置,第一行的位置编号为:1-5,第二行的位置编号为:6-10,依此类推。

上述代码遍历了25 个位置(for i in range(25)),批量显示多张图。针对每一个位置,设置隐藏x和y轴,不显示网关线(grid),在对应的位置显示图像以及类别(label)。

需要注意的地方:Axes 位置的起始值是1,不是常见的0。

对TensorFlow 深度学习有兴趣的同学,可以访问如下链接。

深度学习三人行(第2期)---- TensorFlow爱之再体验

上一期,我们一起学习了TensorFlow的基础知识,以及其在线性回归上的初体验,该期我们继续学习TensorFlow方面的相关知识。学习的路上,我们多多交流,共同进步。本期主要内容如下:

  • 梯度下降TF实战

  • 模型保存和恢复

  • TensorBoard可视化

  • 模块与共享变量

文末附本期代码关键字,回复关键字即可下载。


一. 梯度下降TF实战

11 TensorFlow直接计算

下面代码基本上函数都有接触过,其中tf.random_uniform()函数在图中创建一个包含随机值的节点,类似于NumPy中的random()函数。

深度学习三人行(第2期)---- TensorFlow爱之再体验

tf.assign()函数的作用是创建一个将新值赋给变量的一个节点,这里相当于执行如下迭代:

深度学习三人行(第2期)---- TensorFlow爱之再体验

接下来就是不断迭代更新θ值,来我们看下迭代的最终结果:

深度学习三人行(第2期)---- TensorFlow爱之再体验

我们可以看到,每次迭代损失函数都在下降。

1.2 autodiff方法计算

上面的方法并没有什么问题,但是唯一不足的是需要数学推导梯度的损失函数公式。在线性回归中,这个是没问题的,但是如果在深度神经网络中,我们就死翘翘了,即使我们使用其他方法推出数学公式来运行,也不会得到高效的运行代码。外面只需要将下面的代码替换成上面的梯度公式即可:

深度学习三人行(第2期)---- TensorFlow爱之再体验

自动计算梯度一般有以下四种方法,TensorFlow用了reverse-mode autodiff方法,该方法特别适用于大量输入,少量输出的神经网络系统中。

深度学习三人行(第2期)---- TensorFlow爱之再体验

1.3 优化器来计算

对于梯度下降法,TensorFlow还可以更简单一些,直接用优化器来做,如下代码:

深度学习三人行(第2期)---- TensorFlow爱之再体验

而且,当我们想选择不同类型的优化器的时候,直接修改其中一行代码即可,比方说,我们想用一种收敛更快的方法矩优化(后面系列会有介绍)的话,那么我们只需要修改具体查看代码如下即可:

深度学习三人行(第2期)---- TensorFlow爱之再体验

1.4 训练过程中传输数据

我们之前学习学习梯度下降的时候,学过一种叫做小批量数据梯度下降的方法,其基本思想就是不断输入小批量的数据进行梯度下降寻优(详情可见机器学习第五期 )。这里就牵涉到一个如何在训练过程中传输数据的问题,我们一起学习下。

要想在训练的过程中进行更新输入参数,最简单的方法是用placeholder节点,从字面意思我们也可以看出来,这种节点不参与计算,这种节点一般用在运行过程中进行传输训练数据,当然,如果在运行时没有对placeholder节点进行赋值的话,将会出现异常。既然我们知道了原理,那么我们看一下如何实现:

深度学习三人行(第2期)---- TensorFlow爱之再体验

正如上面代码所示,我们创建placeholder节点是通过调用placeholder函数完成的,函数中我们需要说明tensor的数据类型,如上图,我们在图中并未对节点A进行数据传入,而是在计算B的时候通过feed_dict将数据A进行传入。为了实现我们的MBGD梯度下降算法,我们需要对之前代码进行稍微修改,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

首先就是在创建图的阶段,我们通过placeholder来修改X和y。然后再执行阶段通过feed_dict将X和y逐个的传入,如下图:

深度学习三人行(第2期)---- TensorFlow爱之再体验


二. 模型保存和恢复

2.1 保存模型

当我们训练好一个模型之后,一般情况下都会保存下来,以备后面调用,或者在训练的过程中,我们有时候也希望将训练的中间结果保存下来,防止训练过程中断电等异常出现,避免重新训练,那么如何保存下来呢?

TensorFlow中保存模型还是比较简单的,我们只需要在创建图阶段创建一个Saver的节点,然后在执行阶段需要保存模型的地方调用Save()函数即可,如下代码:

深度学习三人行(第2期)---- TensorFlow爱之再体验

从上面我们也可以看出,在构建图的结尾我们创建了saver节点(with语句前面),而在执行阶段中,if语句下面和最后一行代码的地方,我们调用了save函数来保存模型。保存在save函数的输入路径中。那么如何恢复呢?

2.2 模型恢复

恢复模型也很简单和保存一样在构建图的结尾创建一个saver节点,不同的是在执行阶段的开始,用restore()函数进行模型恢复,如下图:

深度学习三人行(第2期)---- TensorFlow爱之再体验

默认情况下,保存和恢复模型是按照变量自有的名字来进行的,但是如果我们想更高级些的话,我们可以指定保存和恢复哪些变量,以及用什么名字来保存变量,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

我们将theta变量保存为weights名称。

其实在上面的保存过程中,saver默认将计算图也以.meta为后缀的文件保存起来了,当我们需要恢复计算图的时候,我们可以调用tf.train.import_meta_graph()函数来进行恢复,该函数自动将meta计算图加载到默认图中,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

到目前为止,我们学习了构建计算图,以及利用MBGD的方法来进行线性回归。学习了如何保存和恢复模型。但是到目前为止,我们的输出信息还是依赖于print函数,有木有一种更好的可视化的方法呢?


三. TensorBoard可视化

我们可以通过TensorBoard来进行可视化训练过程,比如学习曲线等信息。对于诊断错误和发现模型瓶颈很有帮助,下面我们一起学习下如何玩转TensorBoard吧。

其实TensorBoard可视化训练过程是读取log信息的过程,那我们就需要将需要可视化的内容写成log存下来,然后调用TensorBoard进行读取显示。

比方说我们想看一下我们创建的图到底长什么样子,那么我们可以把这个图FileWriter把图存下来,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

其中logdir是保存路径。那么保存下来之后,如何用TensorBoard打开呢?

windws下,我们重新打开cmd,输入如下指令:

tensorboard --logdir =E://PyProjects//tf_logs//run-20180306133922

后面的路径是你log保存的路径,然后在浏览器中打开http://localhost:6006/#graphs,就可以看到我们代码中创建的图了,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

其中每个节点点开都会有关于该节点的输入输出等说明,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

好了,至此我们学会了如何打开TensorBoard查看log,那我们看下基于MBGD的线性回归的学习曲线如何,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

从学习曲线上可以看出来我们的MSE是成下降趋势的。关于TensorBoard的更多有趣的玩法,我们边学边探索。


四. 模块化与共享变量

4.1 节点分组

当我们处理比较复杂的模型的时候,比如神经网络的时候,计算图可能会有N多节点,为了避免节点混乱,我们可以对节点分组。比方说,我们要对前面代码中的error和mse进行分组为loss,那么我们可以code如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

用with语句对ops进行分组,该op的名字前面会有一个组名的前缀如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

而在TensorBoard中mse和error也将会以loss的形式出现:

深度学习三人行(第2期)---- TensorFlow爱之再体验

4.2 模块化

假如我们想创建一个图,并增加两个修正线性单元(ReLU),ReLU计算输入的线性加和,并且输出0和计算结果中的最大值,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

用代码实现,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

可以看出上面的代码是具有很大的重复性,这种代码很难维持,且容易出错,比方说上面代码中就有一个复制粘贴的错误,看出来了么?而且,如果我们想再增加一些ReLU的话,会显得很繁琐易错等,所以说我们需要避免这种类型的代码,我们可以对代码进行模块化封装,如下我们可以将ReLU封装如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

这样,我们可以很easy的创建一堆ReLU,比方说5个,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

当然,我们也可以给这一堆relu进行前面介绍的命名分组,这样会显得更为简洁,尝试下吧。

4.3 共享变量

  • 如果我们想在计算图的不同组件用同一个变量的话,一个简单的方法就是先创建这个变量,然后通过函数传到需要的地方,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

这样我们就做到了将threshold共享给所有的ReLU。也就是说,我们可以通过threshold来控制所有的ReLU了。这样做是没问题的,也实现了我们想要的功能。但是如果有很多的变量需要共享,按照这样的方式进行逐个传入的话,我们就会比较痛苦。有些人为了减轻这种痛苦,将众多共享变量封装成字典或者一个类传入函数中,这样是可以的。但是还有一种值得推荐的方法就是,将共享变量设置为函数的一个属性:

深度学习三人行(第2期)---- TensorFlow爱之再体验

  • TensorFlow还提供了更为简洁和模块化的方法,那就是通过get_variable()进行创建一个共享变量(如果已经存在的话,就重新利用)。如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

如果该变量之前已经通过get_variable()创建过了,那么此时就会出错。如果已经存在的话,我们可以通过设置变量范围的属性reuse为true来避免异常,如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

或者在with语句块中,通过调用reuse_variables()函数。如下:

深度学习三人行(第2期)---- TensorFlow爱之再体验

下面我们来看一下上述共享变量方法的完整代码,

深度学习三人行(第2期)---- TensorFlow爱之再体验

上面的代码定义了relu函数,然后创建了共享变量threshold,最后通过函数内重新利用threshold创建了5个ReLUs。然而上面的代码中,我们在函数relu外面定义和初始化共享变量,那么能不能在函数里面进行定义共享变量呢?上代码如下:

上面创建5个ReLU的代码中保证了在创建第一个的时候resue=false,而后4个的时候resule=true保证了变量的共享。


五. 本期小结

至此,我们从TensorFlow直接计算梯度下降法入手,分别学习了autodiff方法,优化器的方法以及MBGD。接着为了利用训练好的模型,我们学习了模型的保存和恢复,之后我们又一起学习了TensorBoard来可视化我们的计算图和学习曲线等,最后,从节点分组下手,学习了代码的模块化和几种共享变量的实现。当然还有很多功能,我们边学边聊。


本文代码回复关键字:runtf2


以上是关于轻松体验TensorFlow 第一个神经网络:基本分类(Part 1)的主要内容,如果未能解决你的问题,请参考以下文章

MNIST实例-Tensorflow 初体验

小白学数据神经网络第二弹:Google可视化体验平台Tensorflow Playground

深度学习三人行(第2期)---- TensorFlow爱之再体验

深度学习之TensorFlow安装与初体验

亲测有效,保姆级tensorflow安装教程手把手教你安装tensorflow,轻松入门BP神经网络入门!

亲测有效,保姆级tensorflow安装教程手把手教你安装tensorflow,轻松入门BP神经网络入门!