当前位置: 首页>>技术教程>>正文


TensorFlow编程指南: Tensor(张量)

如名称所示,TensorFlow是定义和运行涉及张量(Tensor)的计算框架。一个张量是将向量和矩阵推广到潜在更高的维度。在内部,TensorFlow将张量表示为n维基本数据类型的数组。

当编写一个TensorFlow程序时,你操作和传递的主要对象是tf.Tensor。一个tf.Tensor对象表示一个部分定义的计算,最终会产生一个值。 TensorFlow程序首先建立基于tf.Tensor的计算图,并详细说明如何根据其他可用张量计算每个张量,然后通过运行该图的部分来获得期望的结果。

一个tf.Tensor具有以下属性:

  • 一个数据类型(例如:float32int32, 或者string)
  • 一个形状(shape)

张量中的每个元素具有相同的数据类型,并且数据类型总是已知的。形状(即它具有的维数和每个维度的大小)可能只是部分已知的。大多数操作都会产生完全已知形状的张量,如果它们的输入形状也是完全已知的,但在某些情况下,只能在图形执行时得到张量的形状。

某些类型的张量是特殊的,这些将在程序员指南的其他单元中介绍。主要的是:

  • tf.Variable
  • tf.Constant
  • tf.Placeholder
  • tf.SparseTensor

除了tf.Variable,张量的值是不变的,这意味着在单个执行张量的上下文中只有一个值。然而,两次评估相同的张量可以返回不同的值;例如张量可以是从磁盘读取数据或产生一个随机数的结果。

秩(rank)

是一个tf.Tensor对象的维数。Rank的同义词包括order或者degree或者n-dimension。请注意,TensorFlow中的rank与数学中的矩阵rank并不相同。如下表所示,TensorFlow中的每个rank对应于不同的数学实体:

秩(rank) 数学实体
0 标量(只有大小)
1 矢量(大小和方向)
2 矩阵(数字表)
3 3-Tensor(数字立方体)
ñ n-Tensor(依次类推,你可能已经理解了^_^)

Rank 0

以下片段演示了创建几个Rank 0变量:

mammal = tf.Variable("Elephant", tf.string)
ignition = tf.Variable(451, tf.int16)
floating = tf.Variable(3.14159265359, tf.float64)
its_complicated = tf.Variable((12.3, -4.85), tf.complex64)

Rank 1

创建一个Rank 1tf.Tensor对象,您可以传递一个项目列表作为初始值。例如:

mystr = tf.Variable(["Hello"], tf.string)
cool_numbers  = tf.Variable([3.14159, 2.71828], tf.float32)
first_primes = tf.Variable([2, 3, 5, 7, 11], tf.int32)
its_very_complicated = tf.Variable([(12.3, -4.85), (7.5, -6.23)], tf.complex64)

更高的Rank

Rank 2tf.Tensor对象由至少一行和至少一列组成:

mymat = tf.Variable([[7],[11]], tf.int16)
myxor = tf.Variable([[False, True],[True, False]], tf.bool)
linear_squares = tf.Variable([[4], [9], [16], [25]], tf.int32)
squarish_squares = tf.Variable([ [4, 9], [16, 25] ], tf.int32)
rank_of_squares = tf.rank(squarish_squares)
mymatC = tf.Variable([[7],[11]], tf.int32)

Higher-rank张量同样由n-dimensional数组组成。例如,在图像处理过程中,使用许多Rank为4的张量,尺寸分别对应于example-in-batch,图像宽度,图像高度和颜色通道。

my_image = tf.zeros([10, 299, 299, 3])  # batch x height x width x color

得到一个tf.Tensor对象的Rank

确定一个tf.Tensor对象的Rank,使用tf.rank方法。例如,以下方法以编程方式确定tf.Tensor的Rank:

r = tf.rank(my3d)
# After the graph runs, r will hold the value 3.

引用tf.Tensor片段(slices)

由于tf.Tensor是n维单元格数组,要访问单个单元格tf.Tensor你需要指定n个索引。

对于一个Rank 0张量(一个标量),不需要索引,因为它已经是一个单一的数字。

对于Rank 1张量(矢量),传递单个索引允许您访问一个数字:

my_scalar = my_vector[2]

请注意,如果你想动态地从矢量中选择一个元素,传入[]内部的索引本身可以是一个标量tf.Tensor

对于Rank 2或更高秩的张量,情况更有趣。对于一个Rank 2的tf.Tensor,传递两个数字返回一个标量,如预期的那样:

my_scalar = my_matrix[1, 2]

但是,传递一个数字将返回一个矩阵的子向量,如下所示:

my_row_vector = my_matrix[2]
my_column_vector = my_matrix[:, 3]

:符号是python切片语法,表示“让这个维度独立”。这在higher-rank张量中很有用,因为它允许你访问它的子向量,子矩阵,甚至其他的副本。

形状(shape)

张量的形状是每个维度中元素的数量。图形构建期间,TensorFlow自动推断形状。这些推断的形状可能具有已知或未知的rank。如果rank已知,则每个维度的大小可能是已知的或未知的。

TensorFlow文档使用三个符号约定来描述张量维数:rank(秩),shape(形状)和维数。下表显示了这些如何相互关联:

形状 维数 例子
0 [] 0-d 一个0-D张量。一个标量。
1 [D0] 1-d 具有形状[5]的一维张量。
2 [D0,D1] 2-d 一个形状[3,4]二维张量。
3 [D0,D1,D2] 3-d 一个形状[1,4,3]的三维张量。
ñ [D0,D1,… Dn-1] n-D 形状为[D0,D1,… Dn-1]的张量。

形状可以通过Python列表/元组的int或者tf.TensorShape来表示。

得到一个tf.Tensor对象的形状

有两种方法可以访问tf.Tensor的形状。在建立图形的时候,了解已知的张量形状常常是有用的。这可以通过读取tf.Tensor对象的shape属性。这个方法返回一个TensorShape对象,这是表示partially-specified(部分指定)形状的一种方便的方法(因为在构建图形时,并不是所有的形状都是完全已知的)。

在运行时,也有可能得到一个tf.Tensor这将代表另一个的完全已知形状的tf.Tensor,通过调用tf.shape操作。这样,您就可以构建一个图,通过构建其他张量来处理张量的形状,这些张量依赖于输入的动态形状tf.Tensor

例如,制作与给定矩阵中的列数相同大小的零向量:

zeros = tf.zeros(tf.shape(my_matrix)[1])

改变tf.Tensor的形状

张量元素的数量是所有形状大小的乘积。标量的元素数总是一样的1。由于经常有许多不同的形状具有相同数量的元素,所以通常能够方便地改变tf.Tensor形状,但是保持元素不变。这可以用tf.reshape来完成。

以下示例演示如何重构(reshape)张量:

rank_three_tensor = tf.ones([3, 4, 5])
matrix = tf.reshape(rank_three_tensor, [6, 10])  # Reshape existing content into
                                                 # a 6x10 matrix
matrixB = tf.reshape(matrix, [3, -1])  #  Reshape existing content into a 3x20
                                       # matrix. -1 tells reshape to calculate
                                       # the size of this dimension.
matrixAlt = tf.reshape(matrixB, [4, 3, -1])  # Reshape existing content into a
                                             #4x3x5 tensor

# Note that the number of elements of the reshaped Tensors has to match the
# original number of elements. Therefore, the following example generates an
# error because no possible value for the last dimension will match the number
# of elements.
yet_another = tf.reshape(matrixAlt, [13, 2, -1])  # ERROR!

数据类型

除了维度,张量有一个数据类型。

tf.Tensor不能有多个数据类型。但是,可以将任意数据结构序列化为string并存储在tf.Tensor

可以使用tf.casttf.Tensor从一个数据类型强制转为到另一个:

# Cast a constant integer tensor into floating point.
float_tensor = tf.cast(tf.constant([1, 2, 3]), dtype=tf.float32)

要查看tf.Tensor的数据类型,使用Tensor.dtype属性。

当从一个python对象创建一个tf.Tensor,你可以选择指定数据类型。如果你不这样做,TensorFlow会选择一个可以表示数据的数据类型。 TensorFlow将Python整数转换为tf.int32,将python浮点数字转为tf.float32。否则,TensorFlow在转换为数组时使用与numpy相同的规则。

张量求值

一旦计算图已经建立,你可以运行计算产生一个特定的tf.Tensor并获取分配给它的值。这对于调试以及大部分TensorFlow工作都是非常有用的。

张量取值的最简单的方法是使用Tensor.eval方法。例如:

constant = tf.constant([1, 2, 3])
tensor = constant * constant
print tensor.eval()

eval方法只在默认的tf.Session处于活动状态时有效。

Tensor.eval返回与张量相同内容的numpy数组。

有时没有上下文不可能评估一个tf.Tensor,因为它的值可能取决于不可用的动态信息。例如,张量依赖于Placeholder,没有给Placeholder提供价值就不能评估。

p = tf.placeholder(tf.float32)
t = p + 1.0
t.eval()  # This will fail, since the placeholder did not get a value.
t.eval(feed_dict={p:2.0})  # This will succeed because we're feeding a value
                           # to the placeholder.

其他模型的构造可能会导致tf.Tensor的求值变复杂。 TensorFlow无法直接评估在内部函数或内部控制流构造中定义的tf.Tensor。如果一个tf.Tensor依赖队列中的值,只在有东西入队才能工作评估tf.Tensor;否则,评估会挂起。在处理队列时,在评估tf.Tensor之前,要调用tf.train.start_queue_runners

打印张量

出于调试的目的,你可能想打印一个tf.Tensor的值。tfdbg提供高级的调试支持,TensorFlow也有一个操作可以直接打印tf.Tensor的值。

请注意,打印tf.Tensor时很少使用以下模式:

t = <<some tensorflow operation>>
print t  # This will print the symbolic tensor when the graph is being built.
         # This tensor does not have a value in this context.

此代码打印tf.Tensor对象(表示延迟计算)而不是它的值。相反,TensorFlow提供了tf.Print操作,它返回其第一个tf.Tensor参数,并打印第二个tf.Tensor集合参数。

要正确使用tf.Print,它的返回值必须被使用。看下面的例子

t = <<some tensorflow operation>>
tf.Print(t, [t])  # This does nothing
t = tf.Print(t, [t])  # Here we are using the value returned by tf.Print
result = t + 1  # Now when result is evaluated the value of `t` will be printed.

参考资料

本文由《纯净天空》出品。文章地址: https://vimsky.com/article/3649.html,未经允许,请勿转载。