TensorFlow 实战Google深度学习框架(第2版)第二

2020-03-11  本文已影响0人  emm_simon

第二章:TensorFlow环境搭建

* 2.1TensorFlow的主要依赖包
       * 2.1.1Protocol Buffer
       * 2.1.2Bazel
* 2.2TensorFlow安装
       * 2.2.1使用Docker安装
       * 2.2.2使用pip安装
       * 2.2.3从源代码编译安装
* 2.3TensorFlow测试样例

-2.1- TensorFlow的主要依赖包

本节将介绍 TensorFlow依赖的两个最主要的工具包--ProtocolBufferBazel
虽然 TensorFlow依赖的工具包不仅限于此节中列出来的两个,但 ProtocolBuffer和 Bazel是笔者 认为相对比较 重要 的,在使用 TensorFlow 的过程中很有可能会接触到。

-2.1.1- Protocol Buffer

* 结构化数据 & 序列化

本节中介绍的结构化数据指的是拥有多种属性的数据。
比如用户信息中包含名字、 ID和 E-mail地址三种不同属性,那么它就是一个结构化数据。
要将这些结构化的用户信息持久化或者进行网络传输时,就需要先将它们序列化 。
所谓序列化,是将结构化的数据变成数据流的格式,简单地说就是变为 一个字符串。
将结构化的数据序列化,井从序列化之后的数据流中还原出原来的结构化数据,统称为处理结构化数据, 这就是 Protocol Buffer 解决的主要问题 。

* 常用的结构化数据处理工具

除 ProtocolBuffer之外, XML和 JSON是两种比较常用的结构化数据处理工具。

* Protocol Buffer 数据量更小,解析更快

Protocol Buffer 格式的数据和 XML 或者 JSON 格式的数据有比较大的区别 。
*首先, Protocol Buffer序列化之后得到的数据不是可读的字符串,而是二进制流
*其次, XML或JSON格式的数据信息都包含在了序列化之后的数据中,不需要任何其他信息就能还原序列化之后的数据。但使用 Protocol Buffer 时需要先定义数据的格式( schema)。 还原一个序列化之后的数据将需要使用到这个定义好的数据格式 。
因为这样的差别,ProtocolBuffer序列化出来的数据要比XML格式的数据小3到10倍,解析时间要快20到100倍。

* Protocol Buffer 定义数据格式

Protocol Buffer 定义数据格式的文件 一般保存在 .proto 文件中。
每 一个 message 代表了 一类结构化的数据,比如这里的用户信息。
message 里面定义了每一个属性的类型和名字。
* 布尔型、整数型 、 实数型、字符型、另外一个 message
Protocol Buffer 里属性的类型可以是像布尔型、整数型 、 实数型、字符型这样的基本类型, 也可以是另外一个 message。这样大大增加了 Protocol Buffer 的灵活性。
* required、optional、repeated
在 message 中, ProtocolBuffer也定义了一个属性是必需的(required)还是可选的 ~optional),或者是可重复的( repeated)。
如果一个属性是必需的(required),那么这个 message 的所有实例都需要 有这个属性
如果一个属性是可选的(optional),那么这个属性的取值可以为空
如果一 个属性是可重复的(repeated),那么这个属性的取值可以是一个列表。
还是以用户信息为例,所有用户都需要有 D,所以 D 这个属性是必需的:不是所有用户都填写了姓名,所 以姓名这个属性是可选的: 一个用户可能有多个 E-mail 地址,所以 E-mail 地址是可重复的。

Protocol Buffer 是 TensorFlow 系统中使用到的重要工具, TensorFlow 中的数据基本都 是通过 ProtocolBuffer来组织的。
在后面的章节中将看到 ProtocolBuffer是如何被使用的。
分布式 TensorFlow 的通信协议 gRPC 也是以 Protocol Buffer作为基础的 。

-2.1.2- Bazel

* Bazel2是自动化构建工具

Bazel2是从谷歌开源的自动化构建工具,谷哥大内部绝大部分的应用都是通过它来编译的。
相比传统的 Makefile、 Ant 或者 Maven, Bazel速度可伸缩性灵活性以及对不同程序语言和平台的支持上都要更加出色。

* 项目空间(workspace)

项目空间(workspace)是Bazel的一个基本概念。
一个项目空间可以简单地理解为一个文件夹,在这个文件夹中包含了:
*编译一个软件所需要的源代码
*以及输出编译结果的软连接(symbolic link)地址

一个项目空间内可以:
*只包含一个应用(比如 TensorFlow),这种 、情况在 2.2.3 节中将会用于从源码安装 TensorFlow。
*一个项目空间也可以包含多个应用。

* WORKSPACE文件

一 个项目空间所对应的文件夹是这个项目的根目录,
在这个根目录中需要有 一个 WORKSPACE 文件,此文件定义了对外部资源的依赖关系
空文件同样也是 一个合法的WORKSPACE 文件 。

* BUILD文件

在一个项目空间内, Bazel通过BUILD文件来找到需要编译的目标。
BUILD文件采用一种类似于 Python 的语法来指定每一个编译目标的输入、输出以及编译方式。
与 Makefile 这种比较开放式的编译工具不同, Bazel 的编译 方式是事先定义好的。
因为 TensorFlow 主 要使用 Python 语 言 ,所以这里都以编译 Python 程序为例 。
Bazel 对 Python 支持的编译方式 只有三种:
* py_binary,将Python程序编译为可执行文件
* py_library,将 Python程序编译成库函数供其他 py_binary 或 py_test调用
* py_test,编译 Python测试程序

下面给出了 一个简单的样例来说明 Bazel 是如何工作的: 项目空间中有 4 个文件

如图所示,在样例项目空间中有 4 个文件:
* WORKSPACE
* BUILD
* hello_main.py
* hello_lib.py

* WORKSPACE 文件
WORKSPACE 给出此项目的外部依赖关系。
为了简单起见 ,这里使用一个空文件,表明这个项目没有 对外部的依赖

* hello_lib.pyv
hello_lib.py 完成打印“ Hello World,,的简单功能,它的代 码如下 :

def print_hello_world():
    print("Hello World !")

* hello_main.py文件
hello_main.py通过调用hello_lib.py 中定义的函数来完成输出 ,它的代码如下:

import hello_lib

hello_lib.print_hello_world()

* BUILD 文件
在 BUILD 文件中 定义了两个编译目标 :

py_library(
    name = "hello_lib",
    srcs = [
        "hello_lib.py", 
    ]
)

py_binary(
    name = "hello_main",
    srcs = [
        "hello_main.py"
    ],
    deps = [
        ":hello_lib",
    ],
)

从这个样例中可以 看 出, BUILD文件是由 一 系列编译目标组成的 。
定义编译目标的先后顺序不会影响编译的结果 。
*在每一个编译目标的第一行要指定编译方式,在这个样例中 就是 py_library 或者 py_binary。
*在每一个编译目标中的主体需要给出编译的具体信息 。
编译的具体信息是通过定义 name、 srcs、 deps等属性完成的。
name是编译目标的名字, 这个名字将被用来指代这一条编译目标。
srcs是编译所需要的源代码,这一项可以是 一个列表。
deps是编译所需要的依赖关系,比如样例中 hello_main.py 需要调用 hello_lib.py 中的函数,所以 hello_main 的编译目标中将 hello_lib 作为依赖关系 。

* 编译操作 bazel build :hello_main
在这个项目空间中运行编译操作 bazel build :hello_main 将得到类似以下的结果:

bazel build :hello_main

从以上结果可以看到,在原来 4个文件的基础上, Bazel 生成了其他一些文件夹。
这些新生成的文件夹就是编译的结果,它们都是以软连接的形式放在当前的项目空间里 。
实际的编译结果文件都会保存到~/.cache/bazel目录下,这是可以通过 output_user_root 或者 output_base参数来改变的 。
在这些编译出来的结果当中:
* bazel-bin目录下存放了编译产生 的二进制文件以及运行该 二进制文件所需要的所有依赖关系 。 在当前目录下运行 bazel-bin/hello_main 就会在屏幕输出“ Hello World”。
* 其他编译结果在本书中使用较少,这 里不再赘述 。

-2.2- TensorFlow安装

-2.2.1- 使用Docker安装
-2.2.2- 使用pip安装
-2.2.3- 从源代码编译安装

-2.3- TensorFlow测试样例

通过2.2节的安装方法安装完TensorFlow之后,本节将给出一个简单的样例:
* 用TensorFlow实现两个向量的求和
TensorFlow本身支持C、C++、Python三种语言,但其对Python的支持是最全面的,本节使用Python来展示这个简单样例:

import tensorflow as tf 

a = tf.constant([1.0, 2.0], name="a")
b = tf.constant([2.0, 3.0], name="b")

result = a + b

sess = tf.Session()
sess.run(result)

# 得到输出:
# array([3., 5.], dtype=float32)

在这里将\overrightarrow{a}\overrightarrow{b}定义为了两个常量:tf.constant,其中:
*\overrightarrow{a}是shape为{2}\times{1}的向量:\overrightarrow{a} = [1.0, 2.0]
*\overrightarrow{b}是shape为{2}\times{1}的向量:\overrightarrow{b} = [2.0, 3.0]

在两个加数定义好之后,将这两个向量加起来,读者会发现,在TensorFlow中,向量的加法也是可以直接通过加号+来完成的,最后输出相加得到的结果。

要输出相加得到的结果,不能简单地直接输出 result,
而需要先生成一个会话(session), 并通过这个会话( session)来计算结果。
到此,就实现了 一个非常简单的 TensorFlow 模型 。
第 3 章将更加深入地介绍 TensorFlow 的基本概念,并将 TensorFlow 的计算模型和神经网络 模型结合起来。

上一篇下一篇

猜你喜欢

热点阅读