TensorFlow基础

TensorFlow基础

  TensorFlow是由Google公司开源的机器学习计算框架。本文将对TensorFlow的基本概念和模型架构进行介绍。

1 - 数据流图

  数据流图是TensorFlow的核心概念。在所有机器学习算法执行之前,TensorFlow可将其抽象表示成数据流图(dataflow graph)。TensorFlow中的数据流图是有向图,由顶点组成。其中,顶点表示一个局部的计算单元,通常是指操作(operation);边表示顶点的输入或输出,通常是指张量(tensor)。

  在TensorFlow中,张量是n-维的数组。将张量的维度定义为(rank),张量的大小定义为形状(shape)。从数学角度来说,张量是对标量(0-阶张量)、向量(1-阶张量)、矩阵(2-阶张量)的扩展。在数据流图中,张量本质上是符号句柄(symbolic handle),本身并不存储任何数据,仅仅是数据的引用(reference)。

  在TensorFlow中,可以将操作理解为函数,具体可指数学公式变量(variable)、占位符(placeholder)、常量(constant)、队列(queue)等。操作允许有零个或多个张量作为输入,完成指定的计算后,产生零个或多个张量作为输出。在一些特定情况下,例如执行随机梯度下降算法时,整个数据流图可能会被迭代地执行多次。但是,所有张量无法在两次迭代过程中进行传递。因此,通常会将诸如神经网络中的权重、偏置值等定义为变量。变量可持久化到内存中,并不会在迭代过程中被销毁。有些变量的值只有当数据流图执行时,由用户来给定。此时,可以将其定义为占位符。通过使用队列,可使得数据流图异步执行。

  与操作密切相关的一个概念是(kernel)。核是操作在某种特定设备(device)上的实现。设备是TensorFlow的计算核心。所有数据流图中的顶点都必须对应到一个可用的设备上来执行。除了常见的CPU或GPU,TensorFlow还允许用户注册新的设备。例如,Google在2016年5月新添加了Tensor Processing Unit(TPU),一种专门为快速完成张量计算的物理执行单元。

  数据流图中所有操作和张量都需要在一个特殊的环境中执行,TensorFlow将其称之为会话(session)。会话提供了run()方法,可将输入数据“喂”(feed)给数据流图中的操作,并将最终的计算结果“带”(fetch)回来。

1.1

图1 - 数据流图

  图1是一张构建完成后的数据流图。其中,圆形表示变量,圆角矩形表示机器学习中常见的数学计算,带箭头的边表示张量。

2 - 集群架构

  TensorFlow集群由客户端(client)、主节点(master),以及多个工作节点(worker)组成。

  • 客户端

  用户通过客户端构建数据流图,并通过会话接口向主节点发送执行请求。客户端一般由Python或C++实现。一个客户端往往可以与多个TensorFlow集群通信。同时,一个TensorFlow集群也可以与多个客户端通信。

  • 主节点

  主节点提供RPC服务,接收来自客户端的执行请求。同时,作为代理,将任务分配给工作节点,并负责协调工作节点的执行。

  • 工作节点

  工作节点一般包含一个或多个设备,并负责监督这些设备执行数据流图的一部分。

  TensorFlow将所要执行的计算按照cluster、job、task三个粒度进行划分。cluster包含一系列的job,job由一系列的task组成。其中,cluster一般指完成相对高层次的目标,比如,训练一个神经网络。job的目标则相对更低层次,比如,为了完成训练一个神经网络,需要有一部分工作节点作为参数服务器(parameter server),另一部分工作节点则完成无状态(stateless)的高强度计算任务。task受TensorFlow Server进程管控,负责完成job的计算任务。TensorFlow采用了客户端/服务器(C/S)模式,主节点和工作节点的进程均可认为是服务器端。

  TensorFlow系统可分为单机(local)和分布式(distributed)两种架构。其中,单机又可以进一步分为单设备(single-device)和多设备(multi-device)。

1.1

图2 - 单机与分布式集群架构

3 - 执行模型

  当用户在客户端程序中完成数据流图的构建后,通过调用会话中的run()方法,TensorFlow集群才开始执行计算。对于数据流图,TensorFlow支持部分执行(partitial execution)。虽然用户在客户端中定义了完整的数据流图,但是,TensorFlow允许用户执行数据流图的子图。主节点根据用户在run()方法中传入的参数,从数据流图中找到用户指定的输出顶点,并进行反向遍历,根据依赖关系查找所有与该输出顶点相关的顶点,称之为最小子图。将这样的一次调用,称之为步骤(step)。TensorFlow支持同时并发(concurrently)执行多个步骤。如图3所示,用户指定求解输出顶点f的值,TensorFlow将查找其所对应的最小子图a -> c -> f

1.1

图3 - 部分执行

  从上一节可知,TensorFlow集群中一般包含多个设备。那么,如何将数据流图切分,分配给各个设备进行计算呢?TensorFlow中采用了安置(placement)算法来解决这个问题。首先,安置算法模拟执行一次最小子图。根据启发式策略对数据流图中各个顶点的输入、输出数据量进行估计。然后,进一步估计每一个顶点的计算时间。在这个过程中,TensorFlow可将最小子图进一步切分为子图片段,并为子图片段挑选合适的设备。安置算法的好坏,直接决定了每一个工作节点的计算量是否平衡,从而对TensorFlow集群的执行效率有着非常重要的影响。目前,Google也正在不断改进该算法。最后,主节点将所有子图片段发送到各个工作节点。工作节点才开始子图片段的计算过程。

1.1

图4 - send节点和recv节点

  如图4所示,当安置算法完成子图片段的划分后,子图片段被分配到各个设备上进行计算。因此,原数据流图中的横跨不同设备的边将被send节点和recv节点所取代。send节点和recv节点分别负责发送和接收不同设备上的数据。值得注意的是,并不是每一条横跨不同设备的边都会新添一个send节点或recv节点。对于多个顶点的输入是同一个张量的情况,TensorFlow进行了优化,此时,多个顶点将共享一个send节点或recv节点。如图4所示,a和b、a和c节点之间的边将共享同一个recv节点。

4 - 第一个TensorFlow程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# coding=utf-8

import tensorflow as tf

# 定义变量w
w = tf.Variable(tf.random_uniform([1], -0.1, 0.1))

# 定义占位符x和b
x = tf.placeholder("float")
b = tf.placeholder("float")

# y = sigmoid(w * x + b)
y = tf.nn.sigmoid(tf.add(tf.mul(w, x), b))

# 初始化
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

# 执行计算
res = sess.run(y, feed_dict={x: 1, b: 2})
print(res)

# 关闭Session,释放资源
sess.close()
1
2
输出:
[ 0.87484437]
1.1

图5 - 第一个TensorFlow程序

  图5是上述程序的数据流图。第一个TensorFlow程序是计算公式y = sigmoid(w * x + b)的值。其中,w是变量,w的值是通过tf.random_uniform()方法在[-0.1, 0.1]之间随机取值。x和b是占位符,只有当用户调用会话的run()方法时,才由用户通过feed_dict()参数给定。在TensorFlow中,操作是可以自由嵌套的。例如,y将tf.multf.add()tf.nn.sigmoid()嵌套在一起,使得代码更加紧凑。

  很多第一次接触TensorFlow的同学,可能都会有一个疑问,为什么需要init = tf.global_variables_initializer()这样一行代码?其实,这是因为避免变量在上一次迭代时产生的计算结果影响当前迭代。因此,对在定义数据流图中变量的同时,需要定义一个初始程序(initilizer)。数据流图中的变量在执行之前都必须调用初始程序进行初始化。初始程序也是一种操作,TensorFlow通过初始程序,可将初始值赋值(assign)给该变量,从而可以推断该变量的形状和数据类型。

1.1

图6 - 初始化变量

  图6是初始化变量的过程。用户定义变量v的同时,给出了初始值i。通过执行init = tf.global_variables_initializer()sess.run(init)来对变量进行初始化,而不会执行数据流图的其他部分。这正是应用了之前提到过的部分执行特性。

5 - 总结

  为方便读者理解接下来几章的内容,本章对TensorFlow的基本概念和模型架构进行了介绍。如果想了解更多TensorFlow的技术细节,可以进一步参考拓展阅读这一节的资料。

6 - 拓展阅读

  1. TensorFlow White Paper: http://download.tensorflow.org/paper/whitepaper2015.pdf
  2. A Tour of TensorFlow: https://arxiv.org/pdf/1610.01178.pdf
  3. TensorFlow架构与设计,刘光聪:http://www.jianshu.com/p/a5574ebcdeab
  4. A Practical Guide for Debugging TensorFlow Codes: https://github.com/wookayin/tensorflow-talk-debugging