Tensorflow简介:张量(Tensor)、计算图(流、流)
Tensorflow是广泛用于实现机器学习和其他涉及许多数学运算的算法的算法库之一。 Tensorflow 由 Google 开发,是 GitHub 上最受欢迎的机器学习库之一。 Google 使用 Tensorflow 将机器学习应用于几乎所有应用程序。例如,如果您使用 Google Photos 或 Google Voice Search,则您并不是直接使用 Tensorflow 模型。它们与大型 Google 硬件集群配合使用,对于感知任务非常强大。
本文的主要目的是为 TensorFlow 提供一个初学者友好的介绍,我假设你已经了解一些 python 知识。 TensorFlow 的核心组件是通过边遍历所有节点的计算和张量图。我们来一一介绍一下。
张量(Tensor)
![]()
在数学中,张量是一个N维向量,也就是说一个张量可以用来表示一个N维数据集。上图有点复杂,不好理解。让我们看一个简化版本:
![]()
上图显示了一些简化的张量。随着维度不断增加,数据表示将变得更加复杂。比如一个3x3的张量,我只能称之为3行3列的矩阵。如果我选择另一种形式的张量(1000x3x3),我可以将其称为向量或一组 1000 个 3x3 矩阵。这里我们将张量的形状或大小称为 (1000x3x3)。张量可以是常量或变量。
计算图形(流、流)
现在我们了解了Tensor的含义,接下来就该了解流(Flow)了。流程图显示计算图表或简单图表。图不能形成环。图中的每个节点代表一个运算,例如加法、减法等。每次操作都会形成一个新的张量。
![]()
上图展示了一个简单的计算图,对应的表达式为:
e = (a+b)x(b+1)计算图具有以下性质:
- 叶顶点或初始节点始终是张量。也就是说,该操作永远不会在图的开头,由此我们可以得出结论,图中的每个操作都必须接受一个张量并产生一个新的张量。同样,张量不能显示为非叶节点,这意味着它必须作为 /node 操作的输入提供。
- 计算图总是以层次顺序表达复杂的操作。上述表达式可以通过将a+b标记为c、b+1标记为d来分层排列。因此,我们可以将 e 写为:
e = (c)x(d) 这里 c = a+b 且 d = b+1.- 以相反的顺序穿过图,形成子表达式,这些子表达式组合成最终的表达式。
- 当我们向前遍历时,遇到的顶点总是下一个顶点的依赖关系。例如,没有a和b就无法获得c。另外,如果不求解c和d,就无法获得e。
- 同级节点的操作相互独立,这是计算图的重要属性之一。当我们构建如图所示的图时,很自然地,同一级别的节点,例如c和d,彼此不相邻,这意味着不需要在计算d之前先计算c。因此它们可以并行实施。
计算图的并行性
上面提到的最后一个属性可能是最重要的属性之一。清楚地表明,同一级别的节点是独立的,这意味着在计算c之前它们不需要空闲,并且可以在计算c的同时并行计算d。 Tensorflow 利用了这个特性。
分布式执行
Tensorflow 允许用户使用并行计算设备更快地执行操作。计算节点或操作会自动调度以进行并行计算。这一切都发生在内部,例如在上图中,操作 c 可以调度在 CPU 上,操作 d 可以调度在 GPU 上。下图展示了两种分布式执行的流程:
![]()
第一种是单系统分布式执行,其中一个Tensorflow会话(稍后会解释)创建一个worker,这个worker负责在每个设备上调度任务。在第二个系统中,有多个worker,它们可以在同一台机器上,也可以在不同的机器上,每个worker都在自己的上下文中运行。在上图中,工作进程 1 在单独的机器上运行,并在所有可用设备上调度计算。
计算子图
子图是主图的一部分,本身就是计算图。例如,在上图中,我们可以得到很多子图,其中一个如下所示
![]()
上图是主图的一部分,从属性2我们可以说子图总是代表一个子表达式,因为c是 e 的子表达式。子图也满足最后一个属性。同一层级的子图也相互独立,可以并行执行。因此,所有子图都可以安排在一台设备上。
![]()
上图解释了子图的并行执行。这里有2个矩阵乘法运算,因为它们是同一级别的,并且相互独立,这符合最后一个性质。由于独立性,节点被调度在不同的设备gpu_0和gpu_1上。
worker之间的数据交换
现在我们知道Tensorflow将所有操作分发到worker管理的不同设备上。更常见的是,张量形式的数据在工作人员之间交换,例如图中 e = (c) * (d)。 c计算完之后,还需要再经过e,这样就得到了节点前面的Tensor。流入。该流程如图所示:
![]()
此处张量从设备 A 转发到设备 B。这会导致分布式系统中出现一些性能延迟。延迟取决于一个重要属性:张量的大小。设备 B 处于空闲模式,直到收到设备 A 的输入。
需要压缩
显然,在计算图中,张量在节点之间流动。在流到达可以处理的节点之前减少流引起的延迟非常重要。一种方法是使用有损压缩来减小大小。
张量的数据类型可以发挥重要作用,让我们了解原因。显然,机器学习的运算精度更高。例如,如果我们使用float32作为张量的数据类型,那么每个值都表示为32位浮点数,因此每个值占用32位的大小,64位也是如此。如果是张量形式(1000,440,440,3),值的个数是1000 * 440 * 440 * 3。如果数据类型是32位,那么占用的空间是这个大数量的32倍,所以增加了。流的延迟。可以使用压缩技术来减小尺寸。
有损压缩
有损压缩涉及压缩数据大小并且不关心其值,这意味着其值在压缩过程中可能被损坏或不准确。然而,如果我们有一个像这样的 32 位浮点数,那么最低有效数字的意义就微不足道了。更改或省略这些值不会对我们的计算产生任何影响。因此,Tensorflow自动将32位浮点数转换为16位表示,忽略所有不重要的数字。如果是 64 位,这将使大小几乎减少一半。如果将 64 位压缩为 16 位,则几乎缩小了 75%。因此,可以尽可能减少张量占用的空间。
张量到达节点后,可以通过添加 0 将 16 位表示恢复为其原始形式。因此,到达节点后将返回32或64位表示进行处理。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网