TensorFlow入门案例分析

来源:互联网 发布:php图书管理系统 编辑:程序博客网 时间:2024/05/31 06:24

本文通过对TensorFlow的一个入门案例进行整理和分析,介绍了使用TensorFlow模型的一些基本概念和一般性的规律

在进入案例之前首先介绍一下使用TensorFlow编程模型会涉及到的基本概念。

一、TensorFlow编程模型

基本概念

  1. TensorFlow编程模型将计算表示为一个有向图(computation graph)
  2. 图的每一个节点(node)代表一个运算操作(operation)
  3. 图的边有两种含义:
    • 一种表示数据流(flow)
    • 一种表示依赖控制(contrial dependencies)。这类边约束节点执行的顺序,可以用来进行条件控制
  4. 在计算图的边中流动(flow)的数据被称为张量(tensor)——tensorflow命名的由来
  5. 用户与tensorflow交互的接口:Session
    • 可通过Seesion的Extend方法向计算图添加新的节点和边
    • 可通过Session的Run方法来执行计算图
  6. Variable:一种特殊运算符,将一些需要保留的tensor储存在内存或者显存中,并在计算时更新

实现原理

涉及到的几个重要概念:

  1. client:客户端
  2. session:提供client与master和worker相连的接口
  3. master:负责指导所有worker按流程执行计算图
  4. worker:与计算设备(CPU或者GPU)相连,负责管理这些计算设备。每一个worker可以管理多个设备。

这几个概念的关系为:
client通过session的接口与master及多个worker相连,其中每一个worker可以与多个硬件设备(device)相连,比如CPU或者GPU。

TensorFlow的执行模式有两种:

  1. 单机模式:client, master, worker全部在一台机器上的同一个进程中
  2. 分布式模式:允许client, master, worker在不同机器的不同进程中。同时由集群调度系统同意管理各项任务

在本文中,我们只涉及到单机模式,可以暂且不去关注分布式模式。

二、案例

该案例是通过一个单层的softmax神经元对MNIST手写数字进行识别。先上代码,该代码可以直接运行,后续我们对代码进行分析。

本文目标是总结TensorFlow的使用,对于softmax神经元的模型、MNIST手写数字以及一些机器学习的先验知识,在此不去详细介绍。

# -*- coding: utf-8 -*-import tensorflow as tffrom tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets('MNIST_data/', one_hot = True)print(mnist.train.images.shape, mnist.train.labels.shape)print(mnist.test.images.shape, mnist.test.labels.shape)#加载MNIST数据集,并输出数据集的信息sess = tf.InteractiveSession() #创建一个sessionx = tf.placeholder(tf.float32,[None, 784]) #用于输入训练数据W = tf.Variable(tf.zeros([784,10])) #softmax神经元的权值矩阵b = tf.Variable(tf.zeros([10])) #softmax神经元的偏置矩阵y = tf.nn.softmax(tf.matmul(x,W )+b) #通过softmax计算出来的labely_ = tf.placeholder(tf.float32, [None, 10]) #用于输入真实的labelcross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y), reduction_indices=[1]))#实现的交叉熵函数,其中:#y_*tf.log(y)是计算交叉熵的基本求和项#tf.reduce_sum是求和函数#reduction_indices=[1]用于对每个batch数据求均值train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)#梯度下降算法的优化器,设置学习速率为0.5,优化目标是最小化代价函数cross_entropytf.global_variables_initializer().run()#TensorFlow的全局优化器for i in range(1000):#执行训练操作    batch_xs, batch_ys = mnist.train.next_batch(100)    train_step.run({x:batch_xs, y_:batch_ys})correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))#tf.argmax是从tensor中寻找最大值的序号accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))#tf.cast用于强制类型转换,此处是将correct_prediction(bool值)转化为floatprint(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels}))

该程序的输出为:

Extracting MNIST_data/train-images-idx3-ubyte.gzExtracting MNIST_data/train-labels-idx1-ubyte.gzExtracting MNIST_data/t10k-images-idx3-ubyte.gzExtracting MNIST_data/t10k-labels-idx1-ubyte.gz((55000, 784), (55000, 10))((10000, 784), (10000, 10))0.9219

代码要点:

1. MNIST数据的加载

对于MNIST数据集,tensorflow提供了一个自动加载的脚本,对应代码如下:

mnist = input_data.read_data_sets('MNIST_data/', one_hot = True)print(mnist.train.images.shape, mnist.train.labels.shape)print(mnist.test.images.shape, mnist.test.labels.shape)

该代码在第一次执行的时候,会自动从网上下载MNIST数据集,并保存到指定文件夹(例子中为MNIST_data/)中。后面再运行的时候,则不需要联网,脚本会直接从文件夹中读取数据。
这段代码的输出为:

Extracting MNIST_data/train-images-idx3-ubyte.gzExtracting MNIST_data/train-labels-idx1-ubyte.gzExtracting MNIST_data/t10k-images-idx3-ubyte.gzExtracting MNIST_data/t10k-labels-idx1-ubyte.gz((55000, 784), (55000, 10))((10000, 784), (10000, 10))

前四行是读取数据的输出,后两行是我们print出来的。上述代码将MNIST数据集读取到mnist对象中。后续会用到MNIST数据的两个部分:

  1. 第一部分是用于训练数据的图像。这些图像扫描自数百人的手写样本, 他们中一半人是美国人口普查局的员工,一半人是高校学生。这些图像是28 × 28 大小的灰度图像。这部分图像可以通过mnist.train访问。
  2. 第二部分是用于测试数据的图像,同样是 28 × 28 的灰度图像。这部分图像可以通过mnist.test访问。

从输出可以看出,训练数据集的规模为55000,测试数据集规模为10000。另外,输出中的784是每幅图像的大小,即28×28 =784,10是数字图像的分类数,即分为0~9十个类别。

2. TensorFlow计算图的构建

sess = tf.InteractiveSession() #创建一个sessionx = tf.placeholder(tf.float32,[None, 784]) #用于输入训练数据W = tf.Variable(tf.zeros([784,10])) #softmax神经元的权值矩阵b = tf.Variable(tf.zeros([10])) #softmax神经元的偏置矩阵y = tf.nn.softmax(tf.matmul(x,W )+b) #通过softmax计算出来的labely_ = tf.placeholder(tf.float32, [None, 10]) #用于输入真实的labelcross_entropy = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y),reduction_indices=[1]))#实现的交叉熵函数,其中:#y_*tf.log(y)是计算交叉熵的基本求和项#tf.reduce_sum是求和函数#reduction_indices=[1]用于对每个batch数据求均值

这部分分为三个子部分,要点如下:

(1)通过tf.InteractiveSession()创建session

一个Seesion包含了操作对象执行的环境,我们通过session实现图和计算内核的交互。使用InteractiveSession命令会将该Session注册为默认的session,之后的运算默认跑在这个session,不同session之间的数据和运算是相互独立的。

(2)构建计算图

这部分主要根据设计的网络结构,构建tensorflow的计算图。具体代码怎么实现,需要结合网络结构进行,具有很大的灵活性。关于神经网络结构的设计问题在本文中暂不涉及。
代码流程的要点如下:

  1. 通过placeholder()函数创建用于输入数据的对象,该函数第一个参数是数据类型,第二个参数的带输入的tensor的shape,例子中[None,748]表示不限输入的条数,每条输入是一个784维向量
  2. 通过Variable函数存储模型参数。不同于存储数据的tensor一旦使用就会消失,Variable在模型训练迭代中是一直存放在内存中,并在每轮迭代中更新
  3. 调用nn.softmax、matmul计算等函数,构建计算图。TensorFlow提供了一系列计算函数,使得我们构建计算图就像写公式一样方便
  4. 构建代价函数。代价函数需要将计算图的计算结果与训练集自带的label进行对比,因此还需要placeholder()函数创建一个用于输入label数据的对象

3. 训练网络

在第二步中,我们完成了计算图的构建,以及代价函数的定义。此时,需要一个优化算法对网络进行训练(反向传播、梯度下降)。TensorFlow提供了封装好的优化器完成这件事情,我们只需要每轮迭代时feed数据给优化器。

代码如下:

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)#梯度下降算法的优化器,设置学习速率为0.5,优化目标是最小化代价函数cross_entropytf.global_variables_initializer().run()#TensorFlow的全局参数优化器for i in range(1000):#执行训练操作    batch_xs, batch_ys = mnist.train.next_batch(100)    train_step.run({x:batch_xs, y_:batch_ys})

代码要点:

  1. 调用了封装好的优化器train_step,传入学习速率,以及绑定代价函数
  2. 调用并执行了一个全局参数优化器
  3. 通过for循环进行训练,训练的每一步调用优化器train_step的run方法。该方法传入一个字典参数,参数中的x和y分别对应了上面计算图中的placeholder,是字典的键,对应的值分别是训练集中取到的图像和label,通过调用mnist.train.next_batch()获得。
  4. 从这里,可以看出上面通过placeholder()定义的对象,是在每个学习周期内都变化的,需要在每一轮学习时传入新的数据。

4. 测试与结果处理

完成训练后,需要对训练好的网络的识别准确率进行测试。代码如下:

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))#tf.argmax是从tensor中寻找最大值的序号accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))#tf.cast用于强制类型转换,此处是将correct_prediction(bool值)转化为floatprint(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels}))

代码要点:

  1. 定义对比计算结果与期望结果的函数correct_prediction
  2. 定义计算识别精度的函数accuracy
  3. accuracy.eval计算识别精度,此时传入字典型参数{x: mnist.test.images, y_: mnist.test.labels},指明计算所用的数据集

这部分代码的输出为0.9219,即训练好的神经网络对MNIST手写数据的识别准确率达到92.19%. 由于算法在执行过程中具有一定的随机性,因此这个值并不是每次执行都是一样的,但基本上在92%左右。

三、要点回顾

我们通过TensorFlow实现一个单层的神经网络,回顾整个流程,我们要做的事情有一下几个要点:

(1)加载训练数据与测试数据

(2)构建TensorFlow计算图。这部分要点如下:

1.  创建一个session2. 通过placeholder()定义需要在每一轮学习中都改变的对象,一般为训练数据以及训练数据对应的label3.  通过Variable定义网络参数,这些参数常驻在内存中,在学习过程中被不断改进4.  定义代价函数

到目前为止,只是定义计算图,还没有涉及到数据的输入与计算。

(3)选定优化器,并迭代对网络进行训练。在每一轮训练中,通过字典类型传入训练数据,字典的键是计算图中通过placeholder()定义的对象,值是测试数据。

(4)通过测试数据对训练好的网络进行进行效果测试。此时,也是通过字典类型传入测试数据,与上述过程一样。

(5)回顾上面的步骤,代码中只有两个地方进行了数据的输入,一是在训练的时候,调用优化器对象的run函数;二是在效果测试的时候,调用评估对象的eval函数。输入参数的方式都是通过字典,字典的键是在计算图中通过placeholder()定义的对象。

原创粉丝点击