一、简介

TensorFlow 是一个开源的、基于 Python 的机器学习框架。由 Google 开发,并在图形分类音频处理推荐系统自然语言处理等场景下有着丰富的应用,是热门的机器学习框架之一。

最初 TensorFlow 是基于 Python 的,可除了 Python,现 TensorFlow 也提供了 C/C++、Java、Go、R 等其他编程语言的接口。


为什么 TensorFlow 在 DNN 研究人员和工程师中这么受欢迎?

开源深度学习库 TensorFlow 允许将深度神经网络的计算部署到任意数量的 CPU 或 GPU 服务器、PC 或移动设备上,且只利用一个 API。那么其他深度学习库,如:Torch、Theano、Caffe 和 MxNet,和 TensorFlow 的区别在哪里?包括 TensorFlow 在内的大多数深度学习库是能够自动求导、开源、支持多种 CPU/GPU、拥有预训练模型,并支持常用 NN 架构,如递归神经网络(RNN)、卷积神经网络(CNN)和深度置信网络(DBN)。


TensorFlow 的特点:

  • 支持所有流行语言,如 Python、C++、Java、R 和 Go
  • 可以在多种平台上工作,包括移动平台和分布式平台
  • 受到所有云服务(AWS、Google 和 Azure)支持
  • Keras——高级神经网络 API,已经和 TensorFlow 整合
  • 与 Torch/Theano 相比,TensorFlow 拥有更好的计算图表可视化
  • 允许模型部署到工业生产,并很容易部署
  • 有非常好的社区支持
  • TensorFlow 不仅仅是一个软件库,还包括一套 TensorFlow,TensorBoard 和 TensorServing 软件。

一些涉及 TensorFlow 的项目:

  • Google 翻译运用的是 TensorFlow 和 TPU(Tensor Processing Units)实现更准确的翻译

参考资料:http://c.biancheng.net/tensorflow/

二、下载和安装 TensorFlow

TensorFlow 可以在主流的 Linux、Mac 和 Windows 系统上使用。Ubuntu 和 MacOS 上基于 native pip、Anaconda、virtualenv 和 Docker 进行安装,在 Windows 上,可以使用 native pip 和 Anaconda。

具体安装过程不再阐述,作者很熟= =!

三、TensorFlow的HelloWorld~

在计算机语言中第一个程序都是 HelloWorld~ ,代码如下,也可以用于安装验证。


TensorFlow 程序解读分析

前面代码分为以下三个主要部分:

  • 第一部分 import 模块包含代码将使用的所有库
  • 第二部分包含图形定义部分,如创建想要的计算图。上代码中就只是一个节点,tensor 常量消息由字符串构成
  • 第三部分是通过会话执行计算图,这部分使用 with 关键字创建了会话,最后在会话中执行了以上计算图

一般在执行后有很多 Warning 出现,如果不想看到,可以通过下面的代码来隐蔽掉:

就是添加一个环境变量值 TF_CPP_MIN_LOG_LEVEL 设定 TensorFlow 忽略级别 2 以下的消息(级别 1 是提示,级别 2 是警告,级别 3 是错误)。

上面的程序运行表现为:打印计算图执行的结果,计算图的执行则使用 sess.run() 语句,sess.run 求取 message 中所定义的 tensor 值;计算图执行结果输入到 print 函数,并用 decode 方法改进。如果不使用 decode ,print 函数会向 stdout 输出结果:

这个输出结果是一个字节字符串。所以要删除字符串引号和 “b”(表示字节,byte) 只保留里面的内容,则需要 decode 方法。

四、TensorFlow程序结构

首先通过将程序分为两个独立的部分,构建任何拟创建神经网络的蓝图,包括计算图的定义以及计算图的执行。虽然麻烦,但正是因为分开涉及让 TensorFlow 可以在多平台上运行。

计算图:是包含节点和边的网络。定义所有要使用的数据,也就是张量(tensor)对象(常量、变量、占位符),同时定义要执行的所有计算,即运算操作对象(Operation Object,简称 OP)。

每个阶段可以有零个或多个输入,但只有一个输出。网络中的节点表示对象(张量和运算操作),边表示运算操作之间流动的张量。计算图定义神经网络的蓝图,但其中的张量还没有相关的数值。

计算图的执行:使用会话对象来实现计算图的执行。会话对象封装了评估张量和操作对象的环境。真正实现了运算操作并将信息从网络的一层传递到另外一层。不同张量对象的值仅在会话对象中被初始化、访问和保存。在此之前张量对象只被抽象定义,在会话中才被赋予实际的意义。


具体实例:

在此以两个向量相加为例设计计算图。

1. 假设有两个向量 v_1 和 v_2 将作为输入提供给 Add 操作。建立计算图:

2. 定义该图的相应代码如下:

3. 然后在会话执行这个“图”:

4. 上面两行代码相当于下面的代码,但好处是不用显式写关闭会话的命令:

5. 运行的结果为:

f. 每个会话都需要使用 close() 来明确关闭,而用 with 格式就不用在意使用 close() 来关闭会话了


阶段解读分析

计算图构建很简单。添加变量和操作,并按照逐层建立神经网络的顺序传递(实际就是让张量流动)。TensorFlow 还允许 with tf.device() 命令来使用具有不同计算图行对象的特定设备(CPU/GPU)。

接下来,为了使这个“图”生效,首先需要使用 tf.Session() 定义一个会话对象 sess。然后用 Session 类中定义的 run 方法运行,方法原型为:

运算结果值在 fetches 中提取;以上面的代码为例,提取的张量为 v_add。run方法将导致在每次执行该计算图的时候,都将对 v_add 相关的张量和操作进行赋值。如果抽取的不是 v_add 而是 v_1,那么最后给出的是向量 v_1 的运行结果了。

此外,一次可以提取一个或多个张量或操作对象,如,如果结果抽取的是 [v_1 … v_add],那么输出如下:

同一段代码,可以有多个会话对象。


阶段拓展进阶

其实,上面这么多行代码可以用一行代码来实现:

虽然一行就搞定了,但这种代码不仅影响计算图的表达,而且当在 for 循环中重复执行相同的操作时,可能会导致占用大量内存。

使用 TensorBoard 可视化图形是 TensorFlow 最有用的功能之一,特别是在构建复杂的神经网络时。构建的计算图可以在图像对象帮助菜单下进行查看。

五、TensorFlow的常量、变量和占位符

最基本的 TensorFlow 提供了一个库来定义和执行对张量的各种数学运算。张量,可以理解为一个 n 维矩阵,所有类型的数据,包括标量、矢量和矩阵等都是特殊类型的张量。

TensorFlow 支持以下三种类型的张量:

  1. 常量:常量是其值不能改变的张量
  2. 变量:当一个量在会话中的值需要更新时,使用变量来表示。例如,在神经网络中,权重需要在训练期间更新,可以通过将权重声明为变量来实现。变量在使用前需要被显示初始化。另外,常量储存在计算图的定义中,每次加载图时都会加载相关变量。也就是说,它们是占用内存的!!!另一方面来说,变量又是分开存储的。
  3. 占位符:用于将值输入 TensorFlow 图中。可以和 feed_dict 一起使用来输入数据。在训练神经网络时,通常用于提供新的训练样本。在会话中运行计算图时,可以为占位符赋值。这样在构建一个计算图时不需要真正的输入数据。需要注意的是,占位符不包含任何数据,因此不需要初始化它们。

TensorFlow常量

声明一个标量常量或者一个标量向量:

要创建一个所有元素为零的张量,可以使用 tf.zeros() 函数。有点和 Matlab 语言相似。这个语句可以创建一个形如 [M,N] 的零元素矩阵,数据类型(dtype)可以是 int32、float32 等:

还可以创建与现有 Numpy 数组或张量常量具有相同形状的张量常量,如:

更进一步,还有以下语句:

  • 在一定范围内生成一个从初值到终值等差排布的序列:

    相应的值为 (stop-start)/(num-1) 。如:
  • 从开始(默认值=0)生成一个数字序列,增量为 delta(默认值=1),直到终值(但不包括终值):

    举个例子:

Tensorflow 允许创建具有不同分布的随机张量:

  1. 使用一下语句创建一个具有一定均值(默认值=0.0)和标准差(默认值=1.0)、形状为 [M, N] 的正态分布随机数组
  2. 创建一个具有一定均值(默认值=0.0)和标准差(默认值=1.0)、形状为 [M, N] 的截尾正态分布随机数组:
  3. 要在种子的 [ minval(default=0), maxval ] 范围内创建形状为 [M, N] 的给定伽马分布随机数组
  4. 要将给定的张量随机裁剪为指定的大小:

    其中,t_random 是一个已经定义好的张量。这将导致随机从张量 t_random 中裁剪一个大小为 [2,5] 的张量。很多时候需要以随机的顺序来呈现训练样本,可以使用 tf.random_shuffle() 来沿着它的第一维随机排列张量。
  5. 随机生成的张量受初始种子值的影响。要在多次运行或会话中获得相同的随机数,应该将种子设置为一个常数值。当使用大量的随机张量时,可以使用 tf.set_random_seed() 来为所有随机产生的张量设置种子。以下命令将所有会话的随机张量的种子设置为 54 :

    TIP:种子只能为整数值

TensorFlow变量

可以通过使用变量类来创建。变量的定义还包括应该初始化的常量/随机值。

下面的代码定义了两个变量的权重和偏置。权重变量使用正态分布随机初始化,均值为 0,标准差为 2,权重大小为 100×100。偏置由 100 个元素组成,每个元素初始化为 0。在这里也使用了可选参数名以给计算图中定义的变量命名:

前面的例子中,都是利用一些常量来初始化变量,也可以指定一个变量来初始化另一个变量。下面的语句将利用前面定义的权重来初始化 weight2:

变量的定义将指定变量如何被初始化,但是必须显式初始化所有的声明变量。在计算图的定义中通过声明初始化操作对象来实现:

每个变量也可以在运行图中单独使用 tf.Variable.initializer 来初始化:

保存变量:使用 Saver 类来保存变量,定义一个 Saver 操作对象:


TensorFlow占位符

除了常量和变量以外,还有一个最重要的元素——占位符,它们用于将数据提供给计算图。可以使用以下方法定义一个占位符:

dtype 为占位符的数据类型,并且必须在声明占位符时指定。在这里,为 x 定义一个占位符并计算 y = 2 * x,使用 feed_dict 输入一个随机的 4×5 矩阵:


阶段解读分析

需要注意的是,所有常量、变量和占位符将在代码的计算图部分中定义。如果在定义部分使用 print 语句,只会得到有关张量类型的信息,而不是它的值。

为了得到相关的值,需要创建会话图并对需要提取的张量显式使用运行命令,如:


阶段拓展

很多时候需要大规模的常量张量对象;在这种情况下,为了优化内存,最好将它们声明为一个可训练标志设置为 False 的变量:

TensorFlow 被设计成与 Numpy 配合运行,因此所有的 TensorFlow 数据类型都是基于 Numpy 的。使用 tf.convert_to_tensor() 可以将给定的值转换为张量类型,并将其与 TensorFlow 函数和运算符一起使用。该函数接受 Numpy 数组、Python 列表和 Python 标量,并允许与张量对象互操作。

要注意的是,与 Python/Numpy 序列不同,TensorFlow 序列不可迭代。可以试试下面的代码,会得到一个错误的提示: