2.5 将代码理解为图
假设医生预测一个新生儿的预期体重为7.5磅(1磅≈0.4536千克)。你需要弄清楚预测和实际测量的重量之间的差别。作为一个擅长分析的工程师,你会设计一个函数来描述新生儿所有体重的可能性。例如,体重是8磅的可能性比10磅大。
你可以选择使用高斯(或称为正态)概率分布函数。这个函数接收一个数字作为输入,输出一个非负数来描述输入观察值的概率。这个函数在机器学习中经常出现,并且很容易在TensorFlow中定义。它使用乘法、除法、取反和其他一些基本运算符。
把每个运算符都看作图中的一个节点。当你看到一个加号(+
)或任何数学概念时,把它想象成众多节点中的一个。这些节点之间的边表示数学函数的组合。具体来说,我们一直在研究的negative
运算就是一个节点,它的进出两条边代表了Tensor
经过这个节点的变换。张量在图中流动,这就是为什么这个库被称为TensorFlow。
这里有一个想法:每个运算符都是强类型函数,它接收某个维度的张量作为输入,并产生相同维度的张量输出。图2.3是用TensorFlow设计高斯函数的一个例子。该函数被表示为一个图,其中运算符是节点,边表示节点之间的相互作用。这个图作为一个整体表示了一个复杂的数学函数(例如高斯函数)。图的子部分表示简单的数学概念,例如取反和加倍。
图2.3 此图表示了产生一个高斯分布所需的运算。节点之间的边表示数据从一个运算流转到下一个运算。这些运算符本身很简单,复杂性来自它们的交织关系
TensorFlow算法很容易可视化,它们可以用简单的流程图来描述。这种流程图的技术术语(更正确的术语)是数据流图。数据流图中的每个箭头称为边。此外,数据流图的每个状态都称为节点。会话的目的是将Python代码解释为数据流图,然后将图中的每个节点的计算与CPU或GPU关联。
配置会话
你可以给tf.Session
传入选项。例如,TensorFlow会自动决定为某个操作分配GPU或CPU设备的最佳方式,这取决于什么是可用的。在创建会话时,可以传递一个额外的选项log_device_placement=True
。清单2.7显示了在硬件上触发计算的确切位置。
清单2.7 记录会话
代码输出了每个运算符在会话中使用的CPU/GPU设备的信息。运行清单2.7会产生如下的输出跟踪,以显示使用哪个设备来运行取反运算:
会话在TensorFlow代码中是必不可少的。你需要调用一个会话来“运行”数学运算。图2.4描绘了TensorFlow上的组件如何与机器学习交互。会话不仅可以执行图运算,还可以使用占位符、变量和常量作为输入。到目前为止,我们已经使用了常量,在后面的部分中,我们将开始使用变量和占位符。下面是这三种类型的简单概述:
- 占位符(placeholder)——事先未指定的值,但是一定会在会话执行时被初始化。通常,占位符是模型的输入和输出。
- 变量(variable)——一个可以改变的值,如机器学习模型的参数。变量在使用之前必须由会话初始化。
- 常量(constant)——一个不可变的值,例如超参数或配置数据。
使用TensorFlow进行机器学习的整个流程遵循图2.4所示的流程。TensorFlow中的大部分代码是构建图和会话。在设计好图并连接会话以执行它之后,你的代码就可以运行了。
图2.4 会话决定了如何使用硬件来最有效地运行图。当会话开始时,它为每个节点分配CPU和GPU资源。运行之后,会话输出一个可用格式的数据,例如NumPy数组。一个会话可以有选择地输入占位符、变量和常量