3.8 TensorFlow客户端
前面的示例程序可以称为TensorFlow客户端,本节结合示例和上面的内容,对TensorFlow客户端做详细的解读。在使用TensorFlow编写的任何客户端程序中,主要将有两种主要类型的对象:运算(Operation)和张量(Tensor)。在前面的例子中,tf.nn.sigmoid是一个运算,h是张量。
然后,这里还有一个graph对象,它是存储程序数据流的计算图。当我们在代码中添加定义的x、W、b和h的后续代码行时,TensorFlow会自动将这些张量(Tensor)和每个运算(Operation)(例如,tf.matmul())作为节点添加到图中。该图将存储重要信息,例如张量的依赖性以及要执行的运算。在我们的示例中,如果要计算h,那么张量x、W和b是必需的。因此,如果在运行时没有正确初始化其中一个参数,TensorFlow将在这里指出需要修正的具体的初始化错误。
接着,由前面内容,我们知道会话(Session)将扮演执行计算图的角色,方法是将图划分为子图、更精细的图,然后将这些图分配给将执行指定任务的worker,这是通过session.run(...)函数来完成的。下面,我们来看看TensorFlow架构中执行客户端时的情况。
大家知道,TensorFlow擅长创建一个包含所有依赖关系和运算的精确计算图,且它能够准确地知道数据流以何种方式、何时、在哪里流动。当然,还有一个元素使得TensorFlow变得更优秀,那就是能够有效执行计算图的会话(Session),这也是会话进入TensorFlow架构的入口之处。现在让我们来看看会话的内部情况,以了解图形是如何被执行的。
首先,由前面的介绍,我们知道TensorFlow客户端中的相关元素有计算图、张量和会话。创建会话时,它会将计算图作为tf.GraphDef协议缓冲区发送到分布式架构的主机。tf.GraphDef是图的标准化表示。分布式主服务器查看图中的所有计算,并将计算划分到不同的设备(例如,不同的GPU和CPU)。我们的sigmoid示例中的计算图如图3-6所示。
接下来,计算图将被分解为子图,并进一步细分为更细的部分,这在具有许多隐藏层的现实世界解决方案中意义更大。此外,为了并行地执行任务(例如,多个设备),将计算图分解为多个部分就变得很重要。执行此图(若该图被划分为子图,则执行子图)称为单个任务,其中任务被分配给单个TensorFlow服务器。
图3-6 客户端的计算图
然而,在现实中,每个任务都是通过将其分解为两个部分来执行的,每个部分都是由单个worker执行的:
- 一个worker使用参数的当前值(运算执行器)执行TensorFlow操作。
- 一个worker存储参数,并使用执行运算器后获得新值来更新它们(参数服务器)。
TensorFlow客户端的通用工作流程如图3-7所示。
图3-7 TensorFlow客户端的通用执行路线图
图3-8说明了计算图的分解情况。除了分解计算图之外,TensorFlow还插入发送节点和接收节点,以利于参数服务器和运算执行器之间的通信。我们可以理解为每当数据可用时,发送节点就发送数据,其中接收节点在对应的发送节点发送数据时继续侦听和捕获数据。
图3-8 计算图的分解情况
最后,一旦计算完成,会话就将更新的数据从参数服务器端带回到客户端。从现在技术角度来看,我们也可以给出TensorFlow的技术架构,如图3-9所示。此解释基于https://tensorflow.google.cn/extend/architecture上的官方TensorFlow文档。
图3-9 TensorFlow技术架构